#ifndef _WORLD_H_ #define _WORLD_H_ #include #include #include #include #include #include #include #include "world_exports.h" #include "world_types.h" #define MAX_QUEUED_ACTIONS 8 typedef void *dlhandle_t; /* Opaque state for a world. Not to be touched by the harness (not that it * really can be.) */ struct WORLD; /* This structure represents an action requested by the world for the harness. */ typedef struct { int (*action)(struct WORLD *requester, void *arg); void (*arg_dtor)(void *arg); union { void *ptr_arg; int int_arg; char *str_arg; }; } requested_action_t; /* * Structure for the world. */ typedef struct WORLD { /* The argc this world is loaded with. Typically the argc from main(). */ int argc; /* The argv this world is loaded with. Typically the argv from main(). */ char **argv; /* Filename the world is loaded from. */ char filename[PATH_MAX]; /* Opaque state of this world. The state is usually some kind of pointer to * the world state, but all the harness knows is the opaque state is a * pointer-sized piece of data. * * This opaque state is used in a linear pattern where the handlers take the * opaque state, maybe operate on it, and return a new opaque state, which is * then passed to the next handler, etc. It is on the world to properly * manager the memory for this state and to destroy it upon teardown. * * It's guaranteed that this state is used linearly, meaning the harness gives * up all ownership to it once passed into a handler. */ opqst_t state; /* This world's lock. This avoids potential issues with multiple threads * trying to change the opaque state at once which can lead to undesireable * outcomes. */ pthread_mutex_t lock; /** Set to not-zero if this world is initialized, otherwise set to zero. */ int initialized; /* The handle to the shared library. */ dlhandle_t library_handle; /* Pointer to the world name. This is in the shared library and a * null-terminated string. If the library does not have a world name, this * will be NULL. */ const char *world_name; /* World function table populated by the runtime loader. */ #define WORLD_FN_PTR(ret, name, args) ret(*name) args; ARKWORLD_EXPORTS(WORLD_FN_PTR) #undef WORLD_FN_PTR /* List of requested actions by the world. Right now there is a maximum of 8 * allowed at one time. That should be plenty. The actions should be flushed * after each call to a handler anyway. */ size_t n_requested_actions; requested_action_t requested_actions[MAX_QUEUED_ACTIONS]; } world_t; /* Reloads the world. This tears down the existing world, marshals the state * for it and reloads it. * * This function will call dlclose on the world's library handle. */ int world_hot_reload(int argc, char **argv, const char *filepath, world_t *world); /* * Like hot-reload, but uses the same parameters the world was originally * loaded with. */ int world_hot_reload_same_state(world_t *world); /* Starts a world in a cold state. Called after load_world_from_file. */ void world_cold_start(world_t *world); /* Reads a world from a filename. */ int load_world_from_file(int argc, char **argv, const char *filename, world_t *world); void world_run_requested_actions(world_t *world); #endif /* _WORLD_H_ */