blob: 31be206f7a533124b28460ec35c7e55647009f2d [file] [log] [blame]
#ifndef _AOS_ASYNC_ACTION_H_
#define _AOS_ASYNC_ACTION_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <string>
#include <map>
#include <type_traits>
#include "aos/aos_core.h"
#include "aos/common/type_traits.h"
class AsyncActionTest;
namespace aos {
// S is status type T is parameter type
template<class S> struct async_action_status {
S status;
uint8_t done_status; // 1 = valid status, 2 = done
uint16_t count;
pid_t pid;
aos_resource_entity *resource_entity;
};
template<class T> struct async_action_start {
T args;
uint16_t count;
aos_resource_entity *parent;
};
class AsyncActionRunner;
class ResourceAction_t;
class AsyncActionStatics {
friend class ResourceAction_t; // a testing AsyncAction that has to mess with resource stuff
protected:
class stopexception : public std::exception {
virtual const char* what() const throw() {
return "This exception indicates that the AsyncAction was stopped. This message should never show up anywhere.";
}
public:
stopexception() : std::exception() {}
};
class resourceexception : public std::exception {
virtual const char* what() const throw() {
return "This exception indicates that the AsyncAction was stopped due to resource contention. This message should never show up anywhere.";
}
public:
resourceexception() : std::exception() {}
};
// 1 = stop current DoAction
// 2 = stop corrent DoAction because of resource issues
// 4 = SIGINT pending (nicely close everything down first)
static volatile uint8_t interrupt;
static const int STOP_SIGNAL;
static aos_resource_entity *resource_entity;
// throw any exceptions indicated by signals
static inline void CheckStop(){
if(interrupt & (0x01 | 0x04)) {
throw stopexception();
fprintf(stderr, "the code should never ever get here (%s: %d)\n", __FILE__, __LINE__);
}else if(interrupt & 0x02) {
throw resourceexception();
fprintf(stderr, "the code should never ever get here (%s: %d)\n", __FILE__, __LINE__);
}
}
};
// S and T have to be structs
// T is sTart and S is status
// public functions (except for constructor) should be called on this AsyncAction
// in processes other than the one Run ing this AsyncAction
// vice versa for protected ones
template<class T, class S> class AsyncAction : public AsyncActionStatics {
static_assert(shm_ok<async_action_start<T>>::value,
"T must go through shared memory");
static_assert(shm_ok<async_action_status<S>>::value,
"S must go through shared memory");
friend class AsyncActionRunner;
friend class ::AsyncActionTest;
public:
AsyncAction(const std::string name);
// returns what the count will be throughout this run
// return of 0 indicates error (didn't start)
uint16_t Start(T &args);
// -1 for count means use the static one
// aka !IsRunning()
bool IsDone(int32_t count = -1);
// returns which one it joined
uint16_t Join(int32_t count = -1);
// return is whether there is an actual status or just garbage
bool GetStatus(S &status_out, int32_t count = -1) __attribute__ ((warn_unused_result));
// waits for a new good status
bool GetNextStatus(S &status_out, int32_t count = -1) __attribute__ ((warn_unused_result));
void Stop(int32_t count = -1);
protected:
// starts infinite loop that waits for Starts
// returns 0 for success, negative for error
// gets called by generated code
int Run(uint8_t priority);
virtual void DoAction(T &args);
// should only be called from DoAction
void PostStatus(S &status_in);
void RequestResource(uint16_t resource);
// returns whether succeeded
bool TryRequestResource(uint16_t resource);
void ReleaseResource(uint16_t resource);
// called at the beginning and end of Run
virtual void OnStart() {}
virtual void OnEnd() {}
// this should be the only sleep (or variant thereof) that gets called
void Sleep(double seconds);
private:
aos_queue *status_queue, *start_queue;
uint16_t local_count;
S local_status;
uint8_t local_done_status;
pid_t local_pid;
template<int (*O)(aos_resource_entity *, aos_resource *)> bool ResourceOp(uint16_t resource);
std::map<uint16_t, uint8_t> resources;
// for read_msg_index
int done_index, status_index;
uint16_t next_status_count; // uses it to figure out when to reset status_index
// return the default if appropriate
inline uint16_t GetCount(int32_t in){
if(in < 0)
return local_count;
else
return (uint16_t)in;
}
static void sig_action(int, siginfo_t *, void *);
};
} // namespace aos
#include "AsyncAction.cpp.inc" // to make the template stuff work
#endif