summaryrefslogtreecommitdiff
path: root/src/dged/hook.h
blob: 66e2839dcca3d799a50496f0e852246e4683037c (plain)
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
#ifndef _HOOK_H
#define _HOOK_H

#include <stdint.h>

#include "vec.h"

/** Callback when removing hooks to clean up userdata */
typedef void (*remove_hook_cb)(void *userdata);

#define HOOK_IMPL(name, callback_type)                                         \
  struct name##_hook {                                                         \
    uint32_t id;                                                               \
    callback_type callback;                                                    \
    void *userdata;                                                            \
  };                                                                           \
                                                                               \
  typedef VEC(struct name##_hook) name##_hook_vec;                             \
                                                                               \
  static inline uint32_t insert_##name##_hook(                                 \
      name##_hook_vec *hooks, uint32_t *id, callback_type callback,            \
      void *userdata) {                                                        \
    uint32_t iid = ++(*id);                                                    \
    struct name##_hook hook = (struct name##_hook){                            \
        .id = iid,                                                             \
        .callback = callback,                                                  \
        .userdata = userdata,                                                  \
    };                                                                         \
    VEC_PUSH(hooks, hook);                                                     \
                                                                               \
    return iid;                                                                \
  }                                                                            \
                                                                               \
  static inline void remove_##name##_hook(name##_hook_vec *hooks, uint32_t id, \
                                          remove_hook_cb callback) {           \
    uint64_t found_at = (uint64_t) - 1;                                        \
    VEC_FOR_EACH_INDEXED(hooks, struct name##_hook *h, idx) {                  \
      if (h->id == id) {                                                       \
        if (callback != NULL) {                                                \
          callback(h->userdata);                                               \
        }                                                                      \
        found_at = idx;                                                        \
        break;                                                                 \
      }                                                                        \
    }                                                                          \
    if (found_at != (uint64_t) - 1) {                                          \
      if (found_at < VEC_SIZE(hooks) - 1) {                                    \
        VEC_SWAP(hooks, found_at, VEC_SIZE(hooks) - 1);                        \
      }                                                                        \
      VEC_POP(hooks, struct name##_hook removed);                              \
      (void)removed;                                                           \
    }                                                                          \
  }

#define HOOK_IMPL_NO_REMOVE(name, callback_type)                               \
  struct name##_hook {                                                         \
    uint32_t id;                                                               \
    callback_type callback;                                                    \
    void *userdata;                                                            \
  };                                                                           \
                                                                               \
  typedef VEC(struct name##_hook) name##_hook_vec;                             \
                                                                               \
  static inline uint32_t insert_##name##_hook(                                 \
      name##_hook_vec *hooks, uint32_t *id, callback_type callback,            \
      void *userdata) {                                                        \
    uint32_t iid = ++(*id);                                                    \
    struct name##_hook hook = (struct name##_hook){                            \
        .id = iid,                                                             \
        .callback = callback,                                                  \
        .userdata = userdata,                                                  \
    };                                                                         \
    VEC_PUSH(hooks, hook);                                                     \
                                                                               \
    return iid;                                                                \
  }

#define dispatch_hook(hooks, hook_type, ...)                                   \
  VEC_FOR_EACH(hooks, hook_type *h) { h->callback(__VA_ARGS__, h->userdata); }

#define dispatch_hook_no_args(hooks, hook_type)                                \
  VEC_FOR_EACH(hooks, hook_type *h) { h->callback(h->userdata); }

#endif