aboutsummaryrefslogtreecommitdiff
path: root/ark/include/soul.h
blob: fa3415b19efd8bd1d455f0ec2df645bb6379a160 (plain) (blame)
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_ */