1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#ifndef _SOUL_H_
#define _SOUL_H_
#include <dlfcn.h>
#include <linux/limits.h>
#include <pthread.h>
#include <stdint.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_pointer.h>
#include "soul_types.h"
#include "soul_exports.h"
#define MAX_QUEUED_ACTIONS 8
typedef void *dlhandle_t;
/* Opaque state for a soul. Not to be touched by the harness (not that it
* really can be.) */
struct SOUL;
/* This structure represents an action requested by the soul for the harness.
*/
typedef struct {
int (*action)(struct SOUL *requester, void *arg);
void (*arg_dtor)(void *arg);
union {
void *ptr_arg;
int int_arg;
char *str_arg;
};
} requested_action_t;
/*
* Structure for the soul.
*/
typedef struct SOUL {
/* The argc this soul is loaded with. Typically the argc from main(). */
int argc;
/* The argv this soul is loaded with. Typically the argv from main(). */
char **argv;
/* Filename the soul is loaded from. */
char filename[PATH_MAX];
/* Opaque state of this soul. The state is usually some kind of pointer to
* the soul 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 soul 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 soul'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 soul is initialized, otherwise set to zero. */
int initialized;
/* The handle to the shared library. */
dlhandle_t library_handle;
/* Pointer to the soul name. This is in the shared library and a
* null-terminated string. If the library does not have a soul name, this
* will be NULL. */
const char *soul_name;
/* Soul function table populated by the runtime loader. */
#define SOUL_FN_PTR(ret, name, args) ret (*name) args;
ARKSOUL_EXPORTS(SOUL_FN_PTR)
#undef SOUL_FN_PTR
/* List of requested actions by the soul. 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];
} soul_t;
/* Reloads the soul. This tears down the existing soul, marshals the state
* for it and reloads it.
*
* This function will call dlclose on the soul's library handle.
*/
int soul_hot_reload(int argc, char **argv, const char *filepath, soul_t *soul);
/*
* Like hot-reload, but uses the same parameters the soul was originally
* loaded with.
*/
int soul_hot_reload_same_state(soul_t *soul);
/* Starts a soul in a cold state. Called after load_soul_from_file. */
void soul_cold_start(soul_t *soul);
/* Reads a soul from a filename. */
int load_soul_from_file(int argc, char **argv, const char *filename,
soul_t *soul);
void soul_run_requested_actions(soul_t *soul);
#endif /* _SOUL_H_ */
|