aboutsummaryrefslogtreecommitdiff
path: root/harness/include/plugin.h
blob: 70ca198450e0d4473b30b12cf2c58ec18d676374 (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
#ifndef _PLUGIN_H_
#define _PLUGIN_H_

#include <dlfcn.h>
#include <stdint.h>
#include <pthread.h>

#define PRIVATE(a) a

typedef void* dlhandle_t;

/* Opaque state for a plugin. Not to be touched by the harness (not that it
 * really can be.) */
typedef void* opqst_t;

/*
 * Structure for the plugin.
 */
typedef struct PLUGIN {
  /* Opaque state of this plugin. The state is usually some kind of pointer to
   * the plugin 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 plugin 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. */
  PRIVATE(opqst_t state);

  /* This plugin's lock. This avoids potential issues with multiple threads
   * trying to change the opaque state at once which can lead to undesireable
   * outcomes. */
  PRIVATE(pthread_mutex_t lock);

  /* The handle to the shared library. */
  PRIVATE(dlhandle_t library_handle);

  /* Pointer to the plugin name. This is in the shared library and a
   * null-terminated string. If the library does not have a plugin name, this
   * will be NULL. */
  PRIVATE(const char* plugin_name);

  /** Intializes the plugin with the given argc/argv. This is the first thing
   * called on the plugin and is called immediately after the library is loaded.
   */
  void (*plugin_load)(int argc, char** argv);

  /* Start the plugin with the marshalled state from the previous plugin.
   *
   * This should return the opaque state from the mashalled_state.
   *
   * This function should not fail if the state cannot be demarshalled, rather a
   * default state should be returned. This is because changing the plugin and
   * hot-reloading can produce incompatibilities between the old state and the
   * new state, and this should not cause a failure.
   */
  opqst_t (*plugin_hot_start)(uint8_t* mashalled_state, uint32_t n);

  /*
   * Starts the plugin without a marshalled state. Happens during the first boot
   * when there is not state.
   */
  opqst_t (*plugin_cold_start)();

  /*
   * Marshals the state to a bytestring. The returned pointer should be malloc'd
   * on the heap. The harness takes ownership of the malloc'd pointer.
   *
   * This is usually called in preparation for a teardown followed by a
   * hot-start.
   */
  uint8_t* (*plugin_marshal_state)(opqst_t st, uint32_t* szout);

  /*
   * Teardown the plugin in preperation for the library's imminent unloading.
   */
  void (*plugin_teardown)(opqst_t);

  /* This anonymous structure contains event handlers. It is wrapped in this
   * structure to make it distinct from the management functions above.
   *
   * The handlers are all optional and if any of them are NULL, the opaque state
   * remains untouched.
   */
  struct {
    /* Right now, empty */
  } handlers;

} plugin_t;

/** Loads a plugin from the dynamic library handle. Returns a non-zero error
 * code on error. */
int load_plugin_from_dlhandle(plugin_t* out, dlhandle_t library);

/* Like the above, but load the library from the given file. */
int load_plugin_from_file(plugin_t* out, const char* dlfilename);

#endif /* _PLUGIN_H_ */