176404edcSAsim Jamshed #ifdef NEWEV
276404edcSAsim Jamshed
376404edcSAsim Jamshed /* ----------------------------------------------------------------------------
476404edcSAsim Jamshed * Please see 4 Jul. 2015 meeting slides for conceptual explanation.
576404edcSAsim Jamshed * 'Subtree' has special meaning and its 'ID' is very important concept for
676404edcSAsim Jamshed * understanding this code.
776404edcSAsim Jamshed *
876404edcSAsim Jamshed * Please contact Donghwi Kim for further questions,
9a14d6bd4SAsim Jamshed * via e-mail: [email protected]
10a14d6bd4SAsim Jamshed */
11cafe7743SAsim Jamshed #include "debug.h"
1276404edcSAsim Jamshed #include <stdio.h>
1376404edcSAsim Jamshed #include <stdlib.h>
1476404edcSAsim Jamshed #include <string.h>
1576404edcSAsim Jamshed #include <tree.h>
1676404edcSAsim Jamshed #include <key_value_store.h>
1776404edcSAsim Jamshed #include "scalable_event.h"
1876404edcSAsim Jamshed
1976404edcSAsim Jamshed #include "mtcp.h"
2076404edcSAsim Jamshed #include "mos_api.h"
2176404edcSAsim Jamshed #include "mtcp_api.h"
2276404edcSAsim Jamshed
2376404edcSAsim Jamshed #define NEWHASH
2476404edcSAsim Jamshed #ifdef NEWHASH
2576404edcSAsim Jamshed #include "mtcp_util.h"
2676404edcSAsim Jamshed #define XXHSEED 18446744073709551557ULL
2776404edcSAsim Jamshed #endif
2876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
2976404edcSAsim Jamshed #define POWER_OF_TWO(x) (!((x - 1) & (x)))
3076404edcSAsim Jamshed
3176404edcSAsim Jamshed #define MAX_EVENTS 30240
3276404edcSAsim Jamshed #define KVS_BUCKETS 1024
3376404edcSAsim Jamshed #define KVS_ENTRIES 102400
3476404edcSAsim Jamshed #define MAX_DEPTH MAX_EVENTS
3576404edcSAsim Jamshed #define NEWID(id, ev, cb) (id ^ hash64(ev, cb))
3676404edcSAsim Jamshed #define IS_UDE(e) ((e)->ev >= (1 << NUM_BEV))
3776404edcSAsim Jamshed #define IS_FLOATING_EVENT(e) (!(e)->ft && IS_UDE(e))
3876404edcSAsim Jamshed
3976404edcSAsim Jamshed struct _tree_node_t *g_evroot;
4076404edcSAsim Jamshed event_t g_evid;
4176404edcSAsim Jamshed
4276404edcSAsim Jamshed static __thread stree_t *g_cur_stree = NULL;
4376404edcSAsim Jamshed static __thread tree_node_t *g_cur_ev = NULL;
4476404edcSAsim Jamshed
4576404edcSAsim Jamshed static __thread struct {
4676404edcSAsim Jamshed struct _tree_node_t *stack[MAX_EVENTS];
4776404edcSAsim Jamshed struct _tree_node_t **sp;
4876404edcSAsim Jamshed } g_evstack;
4976404edcSAsim Jamshed
5076404edcSAsim Jamshed #define free(x) do { \
5176404edcSAsim Jamshed assert(x); \
5276404edcSAsim Jamshed free(x); \
5376404edcSAsim Jamshed } while (0)
54a14d6bd4SAsim Jamshed
55a14d6bd4SAsim Jamshed /*----------------------------------------------------------------------------*/
56a14d6bd4SAsim Jamshed struct devent {
57a14d6bd4SAsim Jamshed event_t ev; /* event id = key */
58a14d6bd4SAsim Jamshed tree_node_t *ptr; /* ptr to the event node in the d-forest = value */
59a14d6bd4SAsim Jamshed struct devent *next; /* next pointer */
60a14d6bd4SAsim Jamshed };
61a14d6bd4SAsim Jamshed #define MAX_BUCKET 2048
62a14d6bd4SAsim Jamshed #define HASHVAL(x) ((x) & (MAX_BUCKET-1))
63a14d6bd4SAsim Jamshed struct devent* g_dfTable[MAX_BUCKET] = {0}; /* d-forest hash table */
64a14d6bd4SAsim Jamshed /*----------------------------------------------------------------------------*/
65a14d6bd4SAsim Jamshed /* simple hash table implementation */
66a14d6bd4SAsim Jamshed static bool
dforest_store(event_t ev,tree_node_t * ptr)67a14d6bd4SAsim Jamshed dforest_store(event_t ev, tree_node_t* ptr)
68a14d6bd4SAsim Jamshed {
69a14d6bd4SAsim Jamshed struct devent *de, *p;
70a14d6bd4SAsim Jamshed int idx;
71a14d6bd4SAsim Jamshed
72a14d6bd4SAsim Jamshed if ((de = malloc(sizeof(*de))) == NULL) {
73a14d6bd4SAsim Jamshed assert(0); /* should not happen! */
74a14d6bd4SAsim Jamshed return false;
75a14d6bd4SAsim Jamshed }
76a14d6bd4SAsim Jamshed de->ev = ev;
77a14d6bd4SAsim Jamshed de->ptr = ptr;
78a14d6bd4SAsim Jamshed de->next = NULL;
79a14d6bd4SAsim Jamshed
80a14d6bd4SAsim Jamshed idx = HASHVAL(ev);
81a14d6bd4SAsim Jamshed if (g_dfTable[idx] == NULL) {
82a14d6bd4SAsim Jamshed g_dfTable[idx] = de;
83a14d6bd4SAsim Jamshed }
84a14d6bd4SAsim Jamshed else {
85a14d6bd4SAsim Jamshed p = g_dfTable[idx];
86a14d6bd4SAsim Jamshed while (p->next)
87a14d6bd4SAsim Jamshed p = p->next;
88a14d6bd4SAsim Jamshed p->next = de;
89a14d6bd4SAsim Jamshed }
90a14d6bd4SAsim Jamshed return true;
91a14d6bd4SAsim Jamshed }
92a14d6bd4SAsim Jamshed /*----------------------------------------------------------------------------*/
93a14d6bd4SAsim Jamshed static tree_node_t *
dforest_search(event_t ev)94a14d6bd4SAsim Jamshed dforest_search(event_t ev)
95a14d6bd4SAsim Jamshed {
96a14d6bd4SAsim Jamshed int idx;
97a14d6bd4SAsim Jamshed struct devent *p;
98a14d6bd4SAsim Jamshed
99a14d6bd4SAsim Jamshed idx = HASHVAL(ev);
100a14d6bd4SAsim Jamshed if (g_dfTable[idx] == NULL)
101a14d6bd4SAsim Jamshed return NULL;
102a14d6bd4SAsim Jamshed
103a14d6bd4SAsim Jamshed for (p = g_dfTable[idx];
104a14d6bd4SAsim Jamshed p != NULL;
105a14d6bd4SAsim Jamshed p = p->next) {
106a14d6bd4SAsim Jamshed if (p->ev == ev)
107a14d6bd4SAsim Jamshed return p->ptr;
108a14d6bd4SAsim Jamshed }
109a14d6bd4SAsim Jamshed return NULL;
110a14d6bd4SAsim Jamshed }
11176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
11276404edcSAsim Jamshed /** Create a new tree node
11376404edcSAsim Jamshed * @return the new tree node
11476404edcSAsim Jamshed * */
11576404edcSAsim Jamshed inline tree_node_t *
tree_node_new()11676404edcSAsim Jamshed tree_node_new()
11776404edcSAsim Jamshed {
11876404edcSAsim Jamshed return calloc(1, sizeof(tree_node_t));
11976404edcSAsim Jamshed }
12076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
12176404edcSAsim Jamshed /** Delete a tree node */
12276404edcSAsim Jamshed inline void
tree_node_del(tree_node_t * node)12376404edcSAsim Jamshed tree_node_del(tree_node_t *node)
12476404edcSAsim Jamshed {
12576404edcSAsim Jamshed free(node);
12676404edcSAsim Jamshed }
12776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
12876404edcSAsim Jamshed /** Delete a tree node and all of its descendants
12976404edcSAsim Jamshed * @param [in] node: target node
13076404edcSAsim Jamshed * */
13176404edcSAsim Jamshed inline void
tree_del_recursive(tree_node_t * node)13276404edcSAsim Jamshed tree_del_recursive(tree_node_t *node)
13376404edcSAsim Jamshed {
13476404edcSAsim Jamshed struct _tree_node_t *walk = NULL, *del = NULL;
13576404edcSAsim Jamshed TREE_SCRATCH(_tree_node_t, MAX_DEPTH) stack;
13676404edcSAsim Jamshed
13776404edcSAsim Jamshed TREE_DFS_FOREACH(walk, node, &stack, link) {
13876404edcSAsim Jamshed if (del)
13976404edcSAsim Jamshed tree_node_del(del);
14076404edcSAsim Jamshed del = walk;
14176404edcSAsim Jamshed }
14276404edcSAsim Jamshed if (del)
14376404edcSAsim Jamshed tree_node_del(del);
14476404edcSAsim Jamshed }
14576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
14676404edcSAsim Jamshed /** Search a tree node by event ID
14776404edcSAsim Jamshed * @param [in] root: root node
14876404edcSAsim Jamshed * @param [in] ev: event ID
14976404edcSAsim Jamshed * @return target node
15076404edcSAsim Jamshed *
15176404edcSAsim Jamshed * The search is in DFS mannar
15276404edcSAsim Jamshed * */
15376404edcSAsim Jamshed inline tree_node_t *
tree_search(tree_node_t * root,event_t ev)15476404edcSAsim Jamshed tree_search(tree_node_t *root, event_t ev)
15576404edcSAsim Jamshed {
15676404edcSAsim Jamshed struct _tree_node_t *walk = NULL;
15776404edcSAsim Jamshed TREE_SCRATCH(_tree_node_t, MAX_DEPTH) stack;
15876404edcSAsim Jamshed
15976404edcSAsim Jamshed TREE_DFS_FOREACH(walk, root, &stack, link)
16076404edcSAsim Jamshed if (walk->ev == ev) {
16176404edcSAsim Jamshed return walk;
16276404edcSAsim Jamshed }
16376404edcSAsim Jamshed return NULL;
16476404edcSAsim Jamshed }
16576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
16676404edcSAsim Jamshed /** Create a new subtree
16776404edcSAsim Jamshed * @param [in] id: subtree ID
16876404edcSAsim Jamshed * @param [in] root: root of the subtree
16976404edcSAsim Jamshed * @return new subtree
17076404edcSAsim Jamshed *
17176404edcSAsim Jamshed * Allocate and initialize subtree structure, stree_t:
17276404edcSAsim Jamshed * 1. Allocate the structure.
17376404edcSAsim Jamshed * 2. Initialize reference counter and fill ID field.
17476404edcSAsim Jamshed * 3. Set 'root' pointer which points the root node of a tree.
17576404edcSAsim Jamshed * The tree should contain all required tree nodes.
17676404edcSAsim Jamshed * 4. Set built-in event tree node pointers.
17776404edcSAsim Jamshed * */
17876404edcSAsim Jamshed inline stree_t *
stree_create(uint64_t id,tree_node_t * root)179a14d6bd4SAsim Jamshed stree_create(uint64_t id, tree_node_t *root)
18076404edcSAsim Jamshed {
18176404edcSAsim Jamshed tree_node_t *bev;
18276404edcSAsim Jamshed stree_t *nstree = malloc(sizeof(stree_t));
18376404edcSAsim Jamshed if (!nstree)
18476404edcSAsim Jamshed return NULL;
18576404edcSAsim Jamshed
18676404edcSAsim Jamshed nstree->ref_cnt = 0;
18776404edcSAsim Jamshed nstree->id = id;
18876404edcSAsim Jamshed nstree->root = root;
189a14d6bd4SAsim Jamshed memset(nstree->bevs, 0, sizeof(nstree->bevs));
19076404edcSAsim Jamshed
19176404edcSAsim Jamshed for (bev = TREE_FIRSTBORN(root, link); bev; bev = TREE_YOUNGER(bev, link)) {
19276404edcSAsim Jamshed int idx = 0;
19376404edcSAsim Jamshed while (bev->ev >> (idx + 1))
19476404edcSAsim Jamshed idx++;
19576404edcSAsim Jamshed nstree->bevs[idx] = bev;
19676404edcSAsim Jamshed }
19776404edcSAsim Jamshed
19876404edcSAsim Jamshed return nstree;
19976404edcSAsim Jamshed }
20076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
20176404edcSAsim Jamshed /** Destroy the subtree
20276404edcSAsim Jamshed * @param [in] stree: the target subtree */
20376404edcSAsim Jamshed inline void
stree_destroy(kvs_t * store,stree_t * stree)20476404edcSAsim Jamshed stree_destroy(kvs_t *store, stree_t *stree)
20576404edcSAsim Jamshed {
20676404edcSAsim Jamshed tree_del_recursive(stree->root);
20776404edcSAsim Jamshed free(stree);
20876404edcSAsim Jamshed }
20976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
21076404edcSAsim Jamshed /** Increase reference counter of the subtree
21176404edcSAsim Jamshed * @param [in] stree: the target subtree */
21276404edcSAsim Jamshed inline void
stree_inc_ref(stree_t * stree)21376404edcSAsim Jamshed stree_inc_ref(stree_t *stree)
21476404edcSAsim Jamshed {
21576404edcSAsim Jamshed stree->ref_cnt++;
21676404edcSAsim Jamshed }
21776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
21876404edcSAsim Jamshed /** Decrease reference counter of the subtree, and remove it from the key-
21976404edcSAsim Jamshed * value-store if needed
22076404edcSAsim Jamshed * @param [in] store: the key-value-store
22176404edcSAsim Jamshed * @param [in] stree: the target subtree
22276404edcSAsim Jamshed *
22376404edcSAsim Jamshed * In addition to decreasing the reference counter, remove the subtree from
22476404edcSAsim Jamshed * key-value-store if decreased reference counter is zero.
22576404edcSAsim Jamshed * */
22676404edcSAsim Jamshed inline void
stree_dec_ref(kvs_t * store,stree_t * stree)22776404edcSAsim Jamshed stree_dec_ref(kvs_t *store, stree_t *stree)
22876404edcSAsim Jamshed {
22976404edcSAsim Jamshed if (stree && !--stree->ref_cnt) {
23076404edcSAsim Jamshed kvs_remove(store, stree->id);
23176404edcSAsim Jamshed stree_destroy(store, stree);
23276404edcSAsim Jamshed }
23376404edcSAsim Jamshed }
23476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
23576404edcSAsim Jamshed /** Hash the event ID and callback pair
23676404edcSAsim Jamshed * @param [in] ev: the event ID
23776404edcSAsim Jamshed * @param [in] cb: the callback function pointer
23876404edcSAsim Jamshed * @return hash value
23976404edcSAsim Jamshed *
24076404edcSAsim Jamshed * TODO: Replace 32-bit Jenkins hash with better one.
24176404edcSAsim Jamshed * */
24276404edcSAsim Jamshed inline static uint64_t
hash64(event_t ev,callback_t cb)24376404edcSAsim Jamshed hash64(event_t ev, callback_t cb)
24476404edcSAsim Jamshed {
24576404edcSAsim Jamshed #ifdef NEWHASH
24676404edcSAsim Jamshed struct {
24776404edcSAsim Jamshed event_t ev;
24876404edcSAsim Jamshed callback_t cb;
24976404edcSAsim Jamshed } instance;
25076404edcSAsim Jamshed
25176404edcSAsim Jamshed instance.ev = ev;
25276404edcSAsim Jamshed instance.cb = cb;
25376404edcSAsim Jamshed
25476404edcSAsim Jamshed return XXH64(&instance, sizeof(event_t) + sizeof(callback_t), XXHSEED);
25576404edcSAsim Jamshed #else
25676404edcSAsim Jamshed uint64_t hash = 0;
25776404edcSAsim Jamshed int i;
25876404edcSAsim Jamshed
25976404edcSAsim Jamshed for (i = 0; i < sizeof(ev); ++i) {
26076404edcSAsim Jamshed hash += ((uint8_t *)&ev)[i];
26176404edcSAsim Jamshed hash += (hash << 10);
26276404edcSAsim Jamshed hash ^= (hash >> 6);
26376404edcSAsim Jamshed }
26476404edcSAsim Jamshed for (i = 0; i < sizeof(cb); ++i) {
26576404edcSAsim Jamshed hash += ((uint8_t *)&cb)[i];
26676404edcSAsim Jamshed hash += (hash << 10);
26776404edcSAsim Jamshed hash ^= (hash >> 6);
26876404edcSAsim Jamshed }
26976404edcSAsim Jamshed hash += (hash << 3);
27076404edcSAsim Jamshed hash ^= (hash >> 11);
27176404edcSAsim Jamshed hash += (hash << 15);
27276404edcSAsim Jamshed
27376404edcSAsim Jamshed return hash;
27476404edcSAsim Jamshed #endif
27576404edcSAsim Jamshed }
276a14d6bd4SAsim Jamshed
277a14d6bd4SAsim Jamshed /*-------------------------------------------------------------------------*/
278a14d6bd4SAsim Jamshed /* Create a new tree that consists of a tree node (w) with a new
279a14d6bd4SAsim Jamshed * callback and take a snapshot of the subtree from w all the way up to
280a14d6bd4SAsim Jamshed * the root node by traversing the ancestors of w.
281a14d6bd4SAsim Jamshed */
282a14d6bd4SAsim Jamshed /*-------------------------------------------------------------------------*/
283a14d6bd4SAsim Jamshed static tree_node_t*
create_spine(tree_node_t * w,callback_t cb)284a14d6bd4SAsim Jamshed create_spine(tree_node_t* w, callback_t cb)
285a14d6bd4SAsim Jamshed {
286a14d6bd4SAsim Jamshed tree_node_t *ntn, *ntree = NULL;
287a14d6bd4SAsim Jamshed
288a14d6bd4SAsim Jamshed if ((ntn = tree_node_new()) == NULL)
289a14d6bd4SAsim Jamshed return NULL;
290a14d6bd4SAsim Jamshed
291a14d6bd4SAsim Jamshed /* the leaf event node with callback function */
292a14d6bd4SAsim Jamshed ntn->ft = w->ft;
293a14d6bd4SAsim Jamshed ntn->cb = cb;
294a14d6bd4SAsim Jamshed ntn->ev = w->ev;
295a14d6bd4SAsim Jamshed ntn->arg = w->arg;
296a14d6bd4SAsim Jamshed ntree = ntn; /* we start from the leaf */
297a14d6bd4SAsim Jamshed
298a14d6bd4SAsim Jamshed do {
299a14d6bd4SAsim Jamshed if (!(ntn = tree_node_new())) {
300a14d6bd4SAsim Jamshed if (ntree)
301a14d6bd4SAsim Jamshed tree_del_recursive(ntree);
302a14d6bd4SAsim Jamshed return NULL;
303a14d6bd4SAsim Jamshed }
304a14d6bd4SAsim Jamshed ntn->ft = w->ft;
305a14d6bd4SAsim Jamshed ntn->ev = w->ev;
306a14d6bd4SAsim Jamshed ntn->arg = w->arg;
307a14d6bd4SAsim Jamshed
308a14d6bd4SAsim Jamshed TREE_INSERT_CHILD(ntn, ntree, link);
309a14d6bd4SAsim Jamshed if (!IS_FLOATING_EVENT(ntree))
310a14d6bd4SAsim Jamshed TREE_INSERT_CHILD(ntn, ntree, invk);
311a14d6bd4SAsim Jamshed
312a14d6bd4SAsim Jamshed /* ntn becomes the new tree */
313a14d6bd4SAsim Jamshed ntree = ntn;
314a14d6bd4SAsim Jamshed } while ((w = TREE_PARENT(w, link)));
315a14d6bd4SAsim Jamshed
316a14d6bd4SAsim Jamshed return ntree;
317a14d6bd4SAsim Jamshed }
318a14d6bd4SAsim Jamshed #if 0
319a14d6bd4SAsim Jamshed /*----------------------------------------------------------------------------*/
320a14d6bd4SAsim Jamshed static stree_t *
321a14d6bd4SAsim Jamshed clone_stree(stree_t * stree)
322a14d6bd4SAsim Jamshed {
323a14d6bd4SAsim Jamshed stree_t *newstree, *walk;
324a14d6bd4SAsim Jamshed tree_node_t *newtree;
325a14d6bd4SAsim Jamshed TREE_SCRATCH(_tree_node_t, MAX_DEPTH) stack;
326a14d6bd4SAsim Jamshed struct _tree_node_t *walk = NULL, *del = NULL;
327a14d6bd4SAsim Jamshed
328a14d6bd4SAsim Jamshed /* clone the tree */
329a14d6bd4SAsim Jamshed TREE_DFS_FOREACH(walk, stree->root, &stack, link) {
330a14d6bd4SAsim Jamshed new_tree_node_new()
331a14d6bd4SAsim Jamshed if (del)
332a14d6bd4SAsim Jamshed tree_node_del(del);
333a14d6bd4SAsim Jamshed del = walk;
334a14d6bd4SAsim Jamshed }
335a14d6bd4SAsim Jamshed if (del)
336a14d6bd4SAsim Jamshed tree_node_del(del);
337a14d6bd4SAsim Jamshed
338a14d6bd4SAsim Jamshed
339a14d6bd4SAsim Jamshed TREE_DFS_FOREACH(w, stree->root, &stack, link) {
340a14d6bd4SAsim Jamshed tree_node_t *ntn, *ptn = NULL;
341a14d6bd4SAsim Jamshed }
342a14d6bd4SAsim Jamshed }
343a14d6bd4SAsim Jamshed #endif
34476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
34576404edcSAsim Jamshed /** Register a callback
34676404edcSAsim Jamshed * @param [in] store: the key-value-store for subtrees
34776404edcSAsim Jamshed * @param [in, out] pstree: the target subtree pointer
34876404edcSAsim Jamshed * @param [in] ev: the target event
34976404edcSAsim Jamshed * @param [in] cb: the callback to be registered
35076404edcSAsim Jamshed * @return 0 for success, -1 for failure
35176404edcSAsim Jamshed *
35276404edcSAsim Jamshed * For callback registeration, there can be some cases.
35376404edcSAsim Jamshed * 1. A new tree what we want is already there, so we can use it by simply
35476404edcSAsim Jamshed * updating reference counters.
35576404edcSAsim Jamshed * 2. A new tree what we want is not there, so we are going to create a
35676404edcSAsim Jamshed * new subtree. The new subtree will not only have new callback, but also
35776404edcSAsim Jamshed * inherit previous subtree.
35876404edcSAsim Jamshed * 2.1. The reference counter of previous subtree is 1, so we can avoid
35976404edcSAsim Jamshed * new tree allocation by reusing tree nodes of previous subtree.
36076404edcSAsim Jamshed * 2.2. The reference counter of previous subtree is not 1, so we should
36176404edcSAsim Jamshed * copy previous subtree's tree nodes.
36276404edcSAsim Jamshed * 3. Previously, there was no subtree (in other words, this is the first
36376404edcSAsim Jamshed * callback registeration) so we are going to make a new subtree which
36476404edcSAsim Jamshed * has only one callback
36576404edcSAsim Jamshed * */
36676404edcSAsim Jamshed inline int
RegCb(kvs_t * store,stree_t ** pstree,event_t ev,callback_t cb)36776404edcSAsim Jamshed RegCb(kvs_t *store, stree_t **pstree, event_t ev, callback_t cb)
36876404edcSAsim Jamshed {
369cafe7743SAsim Jamshed #ifdef DBGMSG
3708176a49fSAsim Jamshed __PREPARE_DBGLOGGING();
371cafe7743SAsim Jamshed #endif
37276404edcSAsim Jamshed TRACE_DBG("/>>>>>> start <<<<<<\\\n");
37376404edcSAsim Jamshed stree_t *stree, *nstree;
37476404edcSAsim Jamshed TREE_SCRATCH(_tree_node_t, MAX_DEPTH) stack;
375a14d6bd4SAsim Jamshed tree_node_t *w, *w2, *ntree;
37676404edcSAsim Jamshed uint64_t id = 0, nid;
37776404edcSAsim Jamshed
37876404edcSAsim Jamshed if ((stree = *pstree)) {
37976404edcSAsim Jamshed /* XXX: tree_search() is heavy operation, but it is used for only error
38076404edcSAsim Jamshed * checking. Is there any way to avoid this?
38176404edcSAsim Jamshed * --> We can have a key-value-store for this, but is it too much? */
382a14d6bd4SAsim Jamshed #if 0
38376404edcSAsim Jamshed if (tree_search(stree->root, ev))
38476404edcSAsim Jamshed /* Illegal trial of overwriting a previously registerd callback */
38576404edcSAsim Jamshed return -1;
38676404edcSAsim Jamshed #endif
38776404edcSAsim Jamshed
38876404edcSAsim Jamshed id = stree->id;
38976404edcSAsim Jamshed }
39076404edcSAsim Jamshed
39176404edcSAsim Jamshed /* calculate new subtree ID */
39276404edcSAsim Jamshed nid = NEWID(id, ev, cb);
39376404edcSAsim Jamshed
394a14d6bd4SAsim Jamshed TRACE_DBG("nid: 0x%lX, id: 0x%lx, ev: %ld, cb: %p\n", nid, id, ev, cb);
39576404edcSAsim Jamshed
396a14d6bd4SAsim Jamshed if ((nstree = kvs_search(store, nid))) { /* case 1. */
39776404edcSAsim Jamshed TRACE_DBG("Case 1\n");
39876404edcSAsim Jamshed /* update reference counters */
39976404edcSAsim Jamshed if (stree)
40076404edcSAsim Jamshed stree_dec_ref(store, stree);
40176404edcSAsim Jamshed
40276404edcSAsim Jamshed nstree->ref_cnt++;
40376404edcSAsim Jamshed *pstree = nstree;
404a14d6bd4SAsim Jamshed #if 0
405a14d6bd4SAsim Jamshed fprintf(stderr, "sizeof(tcp_stream)=%ld sizeof(tcp_send_vars)=%ld"
406a14d6bd4SAsim Jamshed "sizeof(tcp_recv_vars)=%ld\n",
407a14d6bd4SAsim Jamshed sizeof(tcp_stream),
408a14d6bd4SAsim Jamshed sizeof(struct tcp_send_vars), sizeof(struct tcp_recv_vars));
409a14d6bd4SAsim Jamshed #endif
410a14d6bd4SAsim Jamshed return 0;
411a14d6bd4SAsim Jamshed }
41276404edcSAsim Jamshed
413a14d6bd4SAsim Jamshed /* find the event node with ev and take a snapshot of the ancestors */
414a14d6bd4SAsim Jamshed w = dforest_search(ev);
415a14d6bd4SAsim Jamshed // w = tree_search(g_evroot, ev);
41676404edcSAsim Jamshed assert(w);
417a14d6bd4SAsim Jamshed if ((ntree = create_spine(w, cb)) == NULL)
418a14d6bd4SAsim Jamshed return (-1);
41976404edcSAsim Jamshed
420a14d6bd4SAsim Jamshed if (stree) { /* case 2. */
421a14d6bd4SAsim Jamshed TRACE_DBG("Case 2\n");
422a14d6bd4SAsim Jamshed tree_node_t *sptr;
42376404edcSAsim Jamshed
42476404edcSAsim Jamshed /* attach flesh: Inherit previous subtree */
42576404edcSAsim Jamshed sptr = ntree;
426a14d6bd4SAsim Jamshed
427a14d6bd4SAsim Jamshed #if 0
428a14d6bd4SAsim Jamshed /* new code */
429a14d6bd4SAsim Jamshed if (stree->ref_cnt > 1) {
430a14d6bd4SAsim Jamshed /* take a snapshot of the entire forest */
431a14d6bd4SAsim Jamshed curf = clone_tree(stree);
432a14d6bd4SAsim Jamshed curf->root->ref_cnt = 1;
433a14d6bd4SAsim Jamshed stree->ref_cnt--;
434a14d6bd4SAsim Jamshed } else {
435a14d6bd4SAsim Jamshed assert(stree->ref_cnt == 1);
436a14d6bd4SAsim Jamshed curf = stree;
437a14d6bd4SAsim Jamshed /* remove the current id from hash table */
438a14d6bd4SAsim Jamshed kvs_remove(store, stree->id);
439a14d6bd4SAsim Jamshed }
440a14d6bd4SAsim Jamshed
441a14d6bd4SAsim Jamshed /* merge sptr into curf->root (existing tree) */
442a14d6bd4SAsim Jamshed #endif
443a14d6bd4SAsim Jamshed
44476404edcSAsim Jamshed if (stree->ref_cnt == 1) {
44576404edcSAsim Jamshed /* case 2.1. */
44676404edcSAsim Jamshed TRACE_DBG("Case 2.1\n");
44776404edcSAsim Jamshed w = stree->root;
44876404edcSAsim Jamshed while (w) {
449a14d6bd4SAsim Jamshed tree_node_t *next_walk = NULL, *next_walk2 = NULL,
45076404edcSAsim Jamshed *next_sptr = TREE_FIRSTBORN(sptr, link);
45176404edcSAsim Jamshed
45276404edcSAsim Jamshed for (w2 = TREE_FIRSTBORN(w, link);
45376404edcSAsim Jamshed w2 != NULL;
45476404edcSAsim Jamshed w2 = next_walk2) {
45576404edcSAsim Jamshed next_walk2 = TREE_YOUNGER(w2, link);
45676404edcSAsim Jamshed if (sptr && w2->ev == next_sptr->ev) {
45776404edcSAsim Jamshed assert(next_walk == NULL);
45876404edcSAsim Jamshed next_walk = w2;
45976404edcSAsim Jamshed if (next_sptr->cb != next_walk->cb)
46076404edcSAsim Jamshed next_sptr->cb = next_walk->cb;
46176404edcSAsim Jamshed }
462a14d6bd4SAsim Jamshed else {
463a14d6bd4SAsim Jamshed TREE_DETACH(w2, link);
46476404edcSAsim Jamshed if (!IS_FLOATING_EVENT(w2))
46576404edcSAsim Jamshed TREE_DETACH(w2, invk);
46676404edcSAsim Jamshed if (next_walk) {
46776404edcSAsim Jamshed TREE_INSERT_CHILD(sptr, w2, link);
46876404edcSAsim Jamshed if (!IS_FLOATING_EVENT(w2))
46976404edcSAsim Jamshed TREE_INSERT_CHILD(sptr, w2, invk);
47076404edcSAsim Jamshed } else {
47176404edcSAsim Jamshed tree_node_t *f = TREE_FIRSTBORN(sptr, link);
47276404edcSAsim Jamshed TREE_INSERT_OLDER(f, w2, link);
47376404edcSAsim Jamshed if (!IS_FLOATING_EVENT(w2)) {
47476404edcSAsim Jamshed if ((f = TREE_FIRSTBORN(sptr, invk)))
47576404edcSAsim Jamshed TREE_INSERT_OLDER(f, w2, invk);
47676404edcSAsim Jamshed else
47776404edcSAsim Jamshed TREE_INSERT_CHILD(sptr, w2, invk);
47876404edcSAsim Jamshed }
47976404edcSAsim Jamshed }
48076404edcSAsim Jamshed }
48176404edcSAsim Jamshed }
48276404edcSAsim Jamshed w = next_walk;
48376404edcSAsim Jamshed sptr = next_sptr;
48476404edcSAsim Jamshed next_walk = NULL;
48576404edcSAsim Jamshed }
486a14d6bd4SAsim Jamshed } else { // stree->ref_count != 1
48776404edcSAsim Jamshed /* case 2.2. */
48876404edcSAsim Jamshed TRACE_DBG("Case 2.2\n");
48976404edcSAsim Jamshed TREE_DFS_FOREACH(w, stree->root, &stack, link) {
490a14d6bd4SAsim Jamshed tree_node_t *ntn, *ptn = NULL;
49176404edcSAsim Jamshed
49276404edcSAsim Jamshed if (sptr && w->ev == sptr->ev) {
49376404edcSAsim Jamshed if (w->cb != sptr->cb)
49476404edcSAsim Jamshed sptr->cb = w->cb;
49576404edcSAsim Jamshed sptr = TREE_FIRSTBORN(sptr, link);
49676404edcSAsim Jamshed continue;
49776404edcSAsim Jamshed }
49876404edcSAsim Jamshed
49976404edcSAsim Jamshed if (!(ntn = tree_node_new())) {
50076404edcSAsim Jamshed if (ntree)
50176404edcSAsim Jamshed tree_del_recursive(ntree);
50276404edcSAsim Jamshed return -1;
50376404edcSAsim Jamshed }
50476404edcSAsim Jamshed ntn->ft = w->ft;
50576404edcSAsim Jamshed ntn->cb = w->cb;
50676404edcSAsim Jamshed ntn->ev = w->ev;
50776404edcSAsim Jamshed ntn->arg = w->arg;
50876404edcSAsim Jamshed
50976404edcSAsim Jamshed if (TREE_PARENT(w, link)) {
51076404edcSAsim Jamshed ptn = tree_search(ntree, TREE_PARENT(w, link)->ev);
51176404edcSAsim Jamshed assert(ptn);
51276404edcSAsim Jamshed TREE_INSERT_CHILD(ptn, ntn, link);
51376404edcSAsim Jamshed if (!IS_FLOATING_EVENT(ntn))
51476404edcSAsim Jamshed TREE_INSERT_CHILD(ptn, ntn, invk);
515a14d6bd4SAsim Jamshed } else {
5168a941c7eSAsim Jamshed if (ntree)
5178a941c7eSAsim Jamshed tree_del_recursive(ntree);
5188a941c7eSAsim Jamshed free(ntn);
5198a941c7eSAsim Jamshed TRACE_ERROR("Can't find parent\n");
52076404edcSAsim Jamshed assert(0);
5218a941c7eSAsim Jamshed exit(EXIT_FAILURE);
52276404edcSAsim Jamshed }
52376404edcSAsim Jamshed }
524a14d6bd4SAsim Jamshed }
525a14d6bd4SAsim Jamshed }
52676404edcSAsim Jamshed
527a14d6bd4SAsim Jamshed /* case 3 if (stree == NULL) */
528a14d6bd4SAsim Jamshed nstree = stree_create(nid, ntree);
529a14d6bd4SAsim Jamshed if (nstree == NULL) {
530a14d6bd4SAsim Jamshed TRACE_ERROR("Failed to create stree!\n");
53176404edcSAsim Jamshed assert(nstree);
532c6a5549bSAsim Jamshed exit(EXIT_FAILURE);
533a14d6bd4SAsim Jamshed }
53476404edcSAsim Jamshed nstree->ref_cnt = 1;
53576404edcSAsim Jamshed kvs_insert(store, nid, nstree);
53676404edcSAsim Jamshed /* update reference counters */
537a14d6bd4SAsim Jamshed if (stree)
53876404edcSAsim Jamshed stree_dec_ref(store, stree);
53976404edcSAsim Jamshed *pstree = nstree;
54076404edcSAsim Jamshed
54176404edcSAsim Jamshed TRACE_DBG("\\>>>>>> end <<<<<</\n");
54276404edcSAsim Jamshed return 0;
54376404edcSAsim Jamshed }
54476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
54576404edcSAsim Jamshed /** Unregister a callback
54676404edcSAsim Jamshed * @param [in] store: the key-value-store for subtrees
54776404edcSAsim Jamshed * @param [in, out] pstree: the target subtree pointer
54876404edcSAsim Jamshed * @param [in] ev: the target event
54976404edcSAsim Jamshed * @return 0 for success, -1 for failure
55076404edcSAsim Jamshed *
55176404edcSAsim Jamshed * For callback unregisteration, there can be some cases.
55276404edcSAsim Jamshed * 1. No registered callback will be left after this unregistration.
55376404edcSAsim Jamshed * 2. A new tree what we want is already there, so we can use it by simply
55476404edcSAsim Jamshed * updating reference counters.
55576404edcSAsim Jamshed * 3. A new tree what we want is not there, so we create a new subtree by
55676404edcSAsim Jamshed * copying a part of previous subtree
55776404edcSAsim Jamshed * */
55876404edcSAsim Jamshed inline int
UnregCb(kvs_t * store,stree_t ** pstree,event_t ev)55976404edcSAsim Jamshed UnregCb(kvs_t *store, stree_t **pstree, event_t ev)
56076404edcSAsim Jamshed {
561cafe7743SAsim Jamshed #ifdef DBGMSG
5628176a49fSAsim Jamshed __PREPARE_DBGLOGGING();
563cafe7743SAsim Jamshed #endif
56476404edcSAsim Jamshed TRACE_DBG("/>>>>>> start <<<<<<\\\n");
56576404edcSAsim Jamshed stree_t *stree, *nstree;
56676404edcSAsim Jamshed TREE_SCRATCH(_tree_node_t, MAX_DEPTH) stack;
56776404edcSAsim Jamshed tree_node_t *w, *target;
56876404edcSAsim Jamshed uint64_t id = 0, nid;
56976404edcSAsim Jamshed callback_t cb;
57076404edcSAsim Jamshed
57176404edcSAsim Jamshed if (!(stree = *pstree) || !(target = tree_search(stree->root, ev)) ||
57276404edcSAsim Jamshed !(cb = target->cb))
57376404edcSAsim Jamshed /* Illegal trial of unregistering a callback which is never registered
57476404edcSAsim Jamshed * before. */
57576404edcSAsim Jamshed return -1;
57676404edcSAsim Jamshed
57776404edcSAsim Jamshed id = stree->id;
57876404edcSAsim Jamshed
57976404edcSAsim Jamshed /* Calculate new subtree ID */
58076404edcSAsim Jamshed nid = NEWID(id, ev, cb);
58176404edcSAsim Jamshed
58276404edcSAsim Jamshed TRACE_DBG("nid: 0x%lX, id: 0x%lx, ev: %ld, cb: %p\n",
58376404edcSAsim Jamshed nid, id, ev, cb);
58476404edcSAsim Jamshed
58576404edcSAsim Jamshed if (nid == 0) {
58676404edcSAsim Jamshed /* case 1. */
58776404edcSAsim Jamshed TRACE_DBG("Case 1\n");
58876404edcSAsim Jamshed /* update reference counters */
58976404edcSAsim Jamshed if (stree)
59076404edcSAsim Jamshed stree_dec_ref(store, stree);
59176404edcSAsim Jamshed
59276404edcSAsim Jamshed *pstree = NULL;
59376404edcSAsim Jamshed } else if ((nstree = kvs_search(store, nid))) {
59476404edcSAsim Jamshed /* case 2. */
59576404edcSAsim Jamshed TRACE_DBG("Case 2\n");
59676404edcSAsim Jamshed /* update reference counters */
59776404edcSAsim Jamshed if (stree)
59876404edcSAsim Jamshed stree_dec_ref(store, stree);
59976404edcSAsim Jamshed
60076404edcSAsim Jamshed nstree->ref_cnt++;
60176404edcSAsim Jamshed *pstree = nstree;
60276404edcSAsim Jamshed } else if (stree) {
60376404edcSAsim Jamshed /* case 3. */
60476404edcSAsim Jamshed TRACE_DBG("Case 3\n");
60576404edcSAsim Jamshed bool proceed;
60676404edcSAsim Jamshed tree_node_t *ntree = NULL, *sptr;
60776404edcSAsim Jamshed
60876404edcSAsim Jamshed sptr = TREE_PARENT(target, link);
60976404edcSAsim Jamshed #define TREE_IS_ONLY_CHILD(root, x, field) \
61076404edcSAsim Jamshed (TREE_PARENT((x), field) ? \
61176404edcSAsim Jamshed TREE_PARENT((x), field)->field.tn_first == (x) && \
61276404edcSAsim Jamshed TREE_PARENT((x), field)->field.tn_last == (x) : \
61376404edcSAsim Jamshed (x) == (root) && (x)->field.tn_younger == NULL)
61476404edcSAsim Jamshed while (sptr && !sptr->cb && TREE_IS_ONLY_CHILD(stree->root, sptr, link))
61576404edcSAsim Jamshed sptr = TREE_PARENT(sptr, link);
61676404edcSAsim Jamshed
61776404edcSAsim Jamshed assert(sptr);
61876404edcSAsim Jamshed /* 'sptr == NULL' means the tree will lose the only callback.
61976404edcSAsim Jamshed * This case should be handled by 'Case 1' */
62076404edcSAsim Jamshed
62176404edcSAsim Jamshed TREE_DFS_FOREACH_SELECTIVE(w, stree->root, &stack, link, proceed) {
62276404edcSAsim Jamshed tree_node_t *ntn, *ptn;
62376404edcSAsim Jamshed
62476404edcSAsim Jamshed if (w == sptr)
62576404edcSAsim Jamshed proceed = false;
62676404edcSAsim Jamshed
62776404edcSAsim Jamshed if (!(ntn = tree_node_new())) {
62876404edcSAsim Jamshed /* free incomplete ntree */
62976404edcSAsim Jamshed if (ntree)
63076404edcSAsim Jamshed tree_del_recursive(ntree);
63176404edcSAsim Jamshed return -1;
63276404edcSAsim Jamshed }
63376404edcSAsim Jamshed ntn->ft = w->ft;
63476404edcSAsim Jamshed ntn->cb = w->cb;
63576404edcSAsim Jamshed ntn->ev = w->ev;
63676404edcSAsim Jamshed ntn->arg = w->arg;
63776404edcSAsim Jamshed
63876404edcSAsim Jamshed if (TREE_PARENT(w, link)) {
63976404edcSAsim Jamshed assert(ntree);
64076404edcSAsim Jamshed ptn = tree_search(ntree, TREE_PARENT(w, link)->ev);
64176404edcSAsim Jamshed
64276404edcSAsim Jamshed assert(ptn);
64376404edcSAsim Jamshed
64476404edcSAsim Jamshed TREE_INSERT_CHILD(ptn, ntn, link);
64576404edcSAsim Jamshed if (!IS_FLOATING_EVENT(ntn))
64676404edcSAsim Jamshed TREE_INSERT_CHILD(ptn, ntn, invk);
64776404edcSAsim Jamshed } else
64876404edcSAsim Jamshed /* this is the root node */
64976404edcSAsim Jamshed ntree = ntn;
65076404edcSAsim Jamshed }
65176404edcSAsim Jamshed
652a14d6bd4SAsim Jamshed nstree = stree_create(nid, ntree);
653a14d6bd4SAsim Jamshed if (nstree == NULL) {
654a14d6bd4SAsim Jamshed TRACE_ERROR("Failed to create stree!\n");
65576404edcSAsim Jamshed assert(nstree);
656c6a5549bSAsim Jamshed exit(EXIT_FAILURE);
657a14d6bd4SAsim Jamshed }
65876404edcSAsim Jamshed
65976404edcSAsim Jamshed nstree->ref_cnt = 1;
66076404edcSAsim Jamshed
66176404edcSAsim Jamshed kvs_insert(store, nid, nstree);
66276404edcSAsim Jamshed
66376404edcSAsim Jamshed /* update reference counters */
66476404edcSAsim Jamshed stree_dec_ref(store, stree);
66576404edcSAsim Jamshed
66676404edcSAsim Jamshed *pstree = nstree;
66776404edcSAsim Jamshed } else /* if (!stree) */
66876404edcSAsim Jamshed return -1;
66976404edcSAsim Jamshed
67076404edcSAsim Jamshed TRACE_DBG("\\>>>>>> end <<<<<</\n");
67176404edcSAsim Jamshed return 0;
67276404edcSAsim Jamshed }
67376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
67476404edcSAsim Jamshed inline int
ModCb(kvs_t * store,stree_t ** pstree,event_t ev,callback_t cb)67576404edcSAsim Jamshed ModCb(kvs_t *store, stree_t **pstree, event_t ev, callback_t cb)
67676404edcSAsim Jamshed {
67776404edcSAsim Jamshed assert(*pstree || cb);
67876404edcSAsim Jamshed
67976404edcSAsim Jamshed /* Event ID starts from 1 */
68076404edcSAsim Jamshed if (ev == 0)
68176404edcSAsim Jamshed return -1;
68276404edcSAsim Jamshed
68376404edcSAsim Jamshed if (cb)
68476404edcSAsim Jamshed return RegCb(store, pstree, ev, cb);
68576404edcSAsim Jamshed else
68676404edcSAsim Jamshed return UnregCb(store, pstree, ev);
68776404edcSAsim Jamshed }
68876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
68976404edcSAsim Jamshed void
GlobInitEvent(void)69076404edcSAsim Jamshed GlobInitEvent(void)
69176404edcSAsim Jamshed {
69276404edcSAsim Jamshed int i;
69376404edcSAsim Jamshed
69476404edcSAsim Jamshed if (!(g_evroot = tree_node_new())) {
69576404edcSAsim Jamshed perror("FATAL: Failed to allocate essentials for the system\n");
69676404edcSAsim Jamshed exit(0);
69776404edcSAsim Jamshed }
69876404edcSAsim Jamshed g_evroot->ev = 0;
69976404edcSAsim Jamshed g_evroot->ft = NULL;
70076404edcSAsim Jamshed g_evroot->cb = NULL;
70176404edcSAsim Jamshed TREE_INIT_NODE(g_evroot, link);
70276404edcSAsim Jamshed TREE_INIT_NODE(g_evroot, invk);
703a14d6bd4SAsim Jamshed /* add it to the dforest hash table */
704a14d6bd4SAsim Jamshed dforest_store(g_evroot->ev, g_evroot);
70576404edcSAsim Jamshed for (i = 0; i < NUM_BEV; i++) {
70676404edcSAsim Jamshed tree_node_t *ntn;
70776404edcSAsim Jamshed if (!(ntn = tree_node_new())) {
70876404edcSAsim Jamshed perror("FATAL: Failed to allocate essentials for the system\n");
70976404edcSAsim Jamshed exit(0);
71076404edcSAsim Jamshed }
71176404edcSAsim Jamshed ntn->ev = 1 << i;
71276404edcSAsim Jamshed ntn->ft = NULL;
71376404edcSAsim Jamshed ntn->cb = NULL;
71476404edcSAsim Jamshed TREE_INIT_NODE(ntn, link);
71576404edcSAsim Jamshed TREE_INIT_NODE(ntn, invk);
71676404edcSAsim Jamshed TREE_INSERT_CHILD(g_evroot, ntn, link);
71776404edcSAsim Jamshed TREE_INSERT_CHILD(g_evroot, ntn, invk);
718a14d6bd4SAsim Jamshed /* add it to the dforest hash table */
719a14d6bd4SAsim Jamshed dforest_store(ntn->ev, ntn);
72076404edcSAsim Jamshed }
72176404edcSAsim Jamshed g_evid = 1 << NUM_BEV;
72276404edcSAsim Jamshed }
72376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
72476404edcSAsim Jamshed void
InitEvent(mtcp_manager_t mtcp)72576404edcSAsim Jamshed InitEvent(mtcp_manager_t mtcp)
72676404edcSAsim Jamshed {
72776404edcSAsim Jamshed mtcp->ev_store = kvs_create(KVS_BUCKETS, KVS_ENTRIES);
72876404edcSAsim Jamshed }
72976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
73076404edcSAsim Jamshed event_t
mtcp_alloc_event(event_t event)73176404edcSAsim Jamshed mtcp_alloc_event(event_t event)
73276404edcSAsim Jamshed {
73376404edcSAsim Jamshed tree_node_t *parent, *new;
734a14d6bd4SAsim Jamshed
735a14d6bd4SAsim Jamshed if (!(parent = dforest_search(event)))
736a14d6bd4SAsim Jamshed // if (!(parent = tree_search(g_evroot, event)))
73776404edcSAsim Jamshed return MOS_NULL_EVENT;
73876404edcSAsim Jamshed
73976404edcSAsim Jamshed if ((new = tree_node_new()) == NULL)
74076404edcSAsim Jamshed return MOS_NULL_EVENT;
74176404edcSAsim Jamshed
74276404edcSAsim Jamshed new->ev = g_evid++;
74376404edcSAsim Jamshed new->ft = NULL;
74476404edcSAsim Jamshed new->cb = NULL;
74576404edcSAsim Jamshed new->arg.arg = NULL;
74676404edcSAsim Jamshed new->arg.len = 0;
74776404edcSAsim Jamshed
74876404edcSAsim Jamshed TREE_INIT_NODE(new, link);
74976404edcSAsim Jamshed TREE_INIT_NODE(new, invk);
75076404edcSAsim Jamshed
75176404edcSAsim Jamshed TREE_INSERT_CHILD(parent, new, link);
75276404edcSAsim Jamshed
75376404edcSAsim Jamshed return new->ev;
75476404edcSAsim Jamshed }
75576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
75676404edcSAsim Jamshed event_t
mtcp_define_event(event_t event,filter_t filter,struct filter_arg * arg)75776404edcSAsim Jamshed mtcp_define_event(event_t event, filter_t filter, struct filter_arg *arg)
75876404edcSAsim Jamshed {
759cafe7743SAsim Jamshed #ifdef DBGMSG
7608176a49fSAsim Jamshed __PREPARE_DBGLOGGING();
761cafe7743SAsim Jamshed #endif
76276404edcSAsim Jamshed tree_node_t *parent, *new, *walk;
76376404edcSAsim Jamshed
764a14d6bd4SAsim Jamshed /* FIX - TODO. This code needs to have proper locking since this
765a14d6bd4SAsim Jamshed deals with global variables that are shared across multiple
766a14d6bd4SAsim Jamshed threads
767a14d6bd4SAsim Jamshed */
768a14d6bd4SAsim Jamshed
76976404edcSAsim Jamshed if (!filter)
77076404edcSAsim Jamshed return MOS_NULL_EVENT;
77176404edcSAsim Jamshed if (arg && arg->len > 0 && !arg->arg)
77276404edcSAsim Jamshed return MOS_NULL_EVENT;
773a14d6bd4SAsim Jamshed if (!(parent = dforest_search(event)))
774a14d6bd4SAsim Jamshed // if (!(parent = tree_search(g_evroot, event)))
77576404edcSAsim Jamshed return MOS_NULL_EVENT;
77676404edcSAsim Jamshed for (walk = TREE_FIRSTBORN(parent, link);
77776404edcSAsim Jamshed walk;
77876404edcSAsim Jamshed walk = TREE_YOUNGER(walk, link))
77976404edcSAsim Jamshed if ((walk->ft == filter) &&
78076404edcSAsim Jamshed ((walk->arg.arg == NULL && (!arg || !arg->arg || arg->len <= 0)) ||
78176404edcSAsim Jamshed (walk->arg.len == arg->len &&
78276404edcSAsim Jamshed memcmp(walk->arg.arg, arg->arg, arg->len) == 0)))
78376404edcSAsim Jamshed return walk->ev;
78476404edcSAsim Jamshed
785a14d6bd4SAsim Jamshed if ((new = tree_node_new()) == NULL) {
786a14d6bd4SAsim Jamshed errno = ENOMEM;
78776404edcSAsim Jamshed return MOS_NULL_EVENT;
788a14d6bd4SAsim Jamshed }
78976404edcSAsim Jamshed new->ev = g_evid++;
79076404edcSAsim Jamshed new->ft = filter;
791a14d6bd4SAsim Jamshed
792a14d6bd4SAsim Jamshed /* add it to the dforest hash table */
793a14d6bd4SAsim Jamshed dforest_store(new->ev, new);
794a14d6bd4SAsim Jamshed
795a14d6bd4SAsim Jamshed if (arg && arg->arg && arg->len > 0) {
79676404edcSAsim Jamshed new->arg.arg = malloc(arg->len);
797a14d6bd4SAsim Jamshed if (new->arg.arg == NULL) {
798a14d6bd4SAsim Jamshed errno = ENOMEM;
799a14d6bd4SAsim Jamshed g_evid--;
800a14d6bd4SAsim Jamshed free(new);
801a14d6bd4SAsim Jamshed return MOS_NULL_EVENT;
802a14d6bd4SAsim Jamshed }
80376404edcSAsim Jamshed memcpy(new->arg.arg, arg->arg, arg->len);
80476404edcSAsim Jamshed new->arg.len = arg->len;
80576404edcSAsim Jamshed }
80676404edcSAsim Jamshed
80776404edcSAsim Jamshed TRACE_DBG("parent: %ld\n", parent->ev);
80876404edcSAsim Jamshed TREE_INSERT_CHILD(parent, new, link);
80976404edcSAsim Jamshed TREE_INSERT_CHILD(parent, new, invk);
81076404edcSAsim Jamshed
81176404edcSAsim Jamshed return new->ev;
81276404edcSAsim Jamshed }
81376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
81476404edcSAsim Jamshed #define EVENT_STACK_PUSH(s, var) \
81576404edcSAsim Jamshed (assert(&(s)->stack[sizeof((s)->stack) / sizeof(void *)] > (s)->sp), \
81676404edcSAsim Jamshed *(++((s)->sp)) = (var))
81776404edcSAsim Jamshed #define EVENT_STACK_POP(s) \
81876404edcSAsim Jamshed (*(((s)->sp)--))
81976404edcSAsim Jamshed #define EVENT_STACK_CLR(s) \
82076404edcSAsim Jamshed ((s)->stack[0] = NULL, (s)->sp = (s)->stack)
82176404edcSAsim Jamshed
82276404edcSAsim Jamshed inline int
RaiseEv(kvs_t * store,event_t event)82376404edcSAsim Jamshed RaiseEv(kvs_t *store, event_t event)
82476404edcSAsim Jamshed {
82576404edcSAsim Jamshed tree_node_t *ev = NULL;
82676404edcSAsim Jamshed #if 1
82776404edcSAsim Jamshed struct {
82876404edcSAsim Jamshed event_t ev;
82976404edcSAsim Jamshed uint64_t sid;
83076404edcSAsim Jamshed } instance;
83176404edcSAsim Jamshed
83276404edcSAsim Jamshed instance.ev = event;
83376404edcSAsim Jamshed instance.sid = g_cur_stree->id;
83476404edcSAsim Jamshed
83576404edcSAsim Jamshed _key_t key = XXH64(&instance, sizeof(instance), XXHSEED);
83676404edcSAsim Jamshed ev = (tree_node_t *)kvs_search(store, key);
83776404edcSAsim Jamshed #else
83876404edcSAsim Jamshed tree_node_t *walk;
83976404edcSAsim Jamshed for (walk = TREE_FIRSTBORN(g_cur_ev, link);
84076404edcSAsim Jamshed walk;
84176404edcSAsim Jamshed walk = TREE_YOUNGER(walk, link)) {
84276404edcSAsim Jamshed if (walk->ev == event && IS_FLOATING_EVENT(walk)) {
84376404edcSAsim Jamshed ev = walk;
84476404edcSAsim Jamshed break;
84576404edcSAsim Jamshed }
84676404edcSAsim Jamshed }
84776404edcSAsim Jamshed #endif
84876404edcSAsim Jamshed
84976404edcSAsim Jamshed if (!ev)
85076404edcSAsim Jamshed return -1;
85176404edcSAsim Jamshed
85276404edcSAsim Jamshed if (!ev->is_in_raiseq) {
85376404edcSAsim Jamshed ev->is_in_raiseq = true;
85476404edcSAsim Jamshed EVENT_STACK_PUSH(&g_evstack, ev);
85576404edcSAsim Jamshed }
85676404edcSAsim Jamshed
85776404edcSAsim Jamshed return 0;
85876404edcSAsim Jamshed }
859a14d6bd4SAsim Jamshed /*----------------------------------------------------------------------------*/
86076404edcSAsim Jamshed int
mtcp_raise_event(mctx_t mctx,event_t event)86176404edcSAsim Jamshed mtcp_raise_event(mctx_t mctx, event_t event)
86276404edcSAsim Jamshed {
86376404edcSAsim Jamshed mtcp_manager_t mtcp = GetMTCPManager(mctx);
86476404edcSAsim Jamshed if (!mtcp)
86576404edcSAsim Jamshed return -1;
86676404edcSAsim Jamshed
86776404edcSAsim Jamshed return RaiseEv(mtcp->ev_store, event);
86876404edcSAsim Jamshed }
86976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
87076404edcSAsim Jamshed #define PRINT_EV(event, field) \
87176404edcSAsim Jamshed printf("[%s](node: %p) ev: %ld, older: %ld, younger: %ld, child: %ld, " \
87276404edcSAsim Jamshed "last: %ld, parent: %ld, ft: %p, cb: %p\n", \
87376404edcSAsim Jamshed #field, (event), (event)->ev, \
87476404edcSAsim Jamshed (event)->field.tn_older ? (event)->field.tn_older->ev : -1, \
87576404edcSAsim Jamshed (event)->field.tn_younger ? (event)->field.tn_younger->ev : -1, \
87676404edcSAsim Jamshed (event)->field.tn_first ? (event)->field.tn_first->ev : -1, \
87776404edcSAsim Jamshed (event)->field.tn_last ? (event)->field.tn_last->ev : -1, \
87876404edcSAsim Jamshed (event)->field.tn_parent ? (event)->field.tn_parent->ev : -1, \
87976404edcSAsim Jamshed (event)->ft, (event)->cb)
88076404edcSAsim Jamshed inline void
HandleCb(mctx_t const mctx,int sock,int side,stree_t * const stree,event_t events)88176404edcSAsim Jamshed HandleCb(mctx_t const mctx, int sock, int side,
88276404edcSAsim Jamshed stree_t * const stree, event_t events)
88376404edcSAsim Jamshed {
88476404edcSAsim Jamshed int i;
88576404edcSAsim Jamshed bool proceed;
88676404edcSAsim Jamshed tree_node_t *walk, *bev, *ev;
88776404edcSAsim Jamshed TREE_SCRATCH(_tree_node_t, MAX_DEPTH) queue;
88876404edcSAsim Jamshed assert(stree);
88976404edcSAsim Jamshed
89076404edcSAsim Jamshed g_cur_stree = stree;
89176404edcSAsim Jamshed
89276404edcSAsim Jamshed for (i = 0; i < NUM_BEV; i++) {
89376404edcSAsim Jamshed if (!((1L << i) & events))
89476404edcSAsim Jamshed continue;
89576404edcSAsim Jamshed
89676404edcSAsim Jamshed if (!(bev = stree->bevs[i]))
89776404edcSAsim Jamshed continue;
89876404edcSAsim Jamshed
89976404edcSAsim Jamshed EVENT_STACK_CLR(&g_evstack);
90076404edcSAsim Jamshed tree_node_t **ptr = g_evstack.sp;
90176404edcSAsim Jamshed TREE_DFS_FOREACH_SELECTIVE(walk, bev, &queue, invk, proceed) {
90276404edcSAsim Jamshed //PRINT_EV(walk, link);
90376404edcSAsim Jamshed //PRINT_EV(walk, invk);
90476404edcSAsim Jamshed
90576404edcSAsim Jamshed g_cur_ev = walk;
90676404edcSAsim Jamshed
90776404edcSAsim Jamshed if (walk != bev && walk->ft &&
90876404edcSAsim Jamshed walk->ft(mctx, sock, side, walk->ev, &walk->arg) == false) {
90976404edcSAsim Jamshed ptr = g_evstack.sp;
91076404edcSAsim Jamshed proceed = false;
91176404edcSAsim Jamshed continue;
91276404edcSAsim Jamshed }
91376404edcSAsim Jamshed
91476404edcSAsim Jamshed if (walk->cb)
91576404edcSAsim Jamshed walk->cb(mctx, sock, side, walk->ev, &walk->arg);
91676404edcSAsim Jamshed
91776404edcSAsim Jamshed while (ptr < g_evstack.sp) {
91876404edcSAsim Jamshed ptr++;
91976404edcSAsim Jamshed TREE_INSERT_CHILD(walk, *ptr, invk);
92076404edcSAsim Jamshed }
92176404edcSAsim Jamshed }
92276404edcSAsim Jamshed g_cur_ev = NULL;
92376404edcSAsim Jamshed
92476404edcSAsim Jamshed while ((ev = EVENT_STACK_POP(&g_evstack))) {
92576404edcSAsim Jamshed ev->is_in_raiseq = false;
92676404edcSAsim Jamshed TREE_DETACH(ev, invk);
92776404edcSAsim Jamshed }
92876404edcSAsim Jamshed
92976404edcSAsim Jamshed if (!(events &= ~(1L << i))) {
93076404edcSAsim Jamshed g_cur_stree = NULL;
93176404edcSAsim Jamshed return;
93276404edcSAsim Jamshed }
93376404edcSAsim Jamshed }
93476404edcSAsim Jamshed
93576404edcSAsim Jamshed g_cur_stree = NULL;
93676404edcSAsim Jamshed }
93776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
93876404edcSAsim Jamshed int
mtcp_register_callback(mctx_t mctx,int sockid,event_t event,int hook_point,callback_t callback)93976404edcSAsim Jamshed mtcp_register_callback(mctx_t mctx, int sockid, event_t event,
94076404edcSAsim Jamshed int hook_point, callback_t callback)
94176404edcSAsim Jamshed {
94276404edcSAsim Jamshed socket_map_t socket;
94376404edcSAsim Jamshed stree_t **pstree;
944*f2d62220SAsim Jamshed event_t root_event = event;
945*f2d62220SAsim Jamshed tree_node_t *ev_node;
94676404edcSAsim Jamshed
947*f2d62220SAsim Jamshed /* (1) check if event variable is NULL
948*f2d62220SAsim Jamshed * (2) any event within the built-in event range should be 2^N
949*f2d62220SAsim Jamshed */
95076404edcSAsim Jamshed if (event == MOS_NULL_EVENT ||
951a14d6bd4SAsim Jamshed (event < (1L << NUM_BEV) && !POWER_OF_TWO(event)))
95276404edcSAsim Jamshed return -1;
95376404edcSAsim Jamshed
954*f2d62220SAsim Jamshed /* for UDEs, retrieve the root built-in event */
955*f2d62220SAsim Jamshed if (root_event >= (1L << NUM_BEV)) {
956*f2d62220SAsim Jamshed if ((ev_node = dforest_search(event)) == NULL)
957*f2d62220SAsim Jamshed return -1;
958*f2d62220SAsim Jamshed root_event = (ev_node)->link.tn_parent->ev;
959*f2d62220SAsim Jamshed /* the root built-in event should not be NULL */
960*f2d62220SAsim Jamshed if (root_event == MOS_NULL_EVENT)
961*f2d62220SAsim Jamshed return -1;
962*f2d62220SAsim Jamshed }
963*f2d62220SAsim Jamshed
964*f2d62220SAsim Jamshed /* check if there is any invalid event-hook mapping */
965*f2d62220SAsim Jamshed if (hook_point == MOS_NULL) {
966*f2d62220SAsim Jamshed if (root_event & (MOS_ON_CONN_START | MOS_ON_REXMIT |
967*f2d62220SAsim Jamshed MOS_ON_TCP_STATE_CHANGE | MOS_ON_CONN_END)) {
968*f2d62220SAsim Jamshed errno = EINVAL;
969*f2d62220SAsim Jamshed return -1;
970*f2d62220SAsim Jamshed }
971*f2d62220SAsim Jamshed } else if (hook_point == MOS_HK_RCV || hook_point == MOS_HK_SND) {
972*f2d62220SAsim Jamshed if (root_event & (MOS_ON_CONN_NEW_DATA | MOS_ON_ORPHAN | MOS_ON_ERROR)) {
973*f2d62220SAsim Jamshed errno = EINVAL;
974*f2d62220SAsim Jamshed return -1;
975*f2d62220SAsim Jamshed }
976*f2d62220SAsim Jamshed } else {
977*f2d62220SAsim Jamshed /* invalid hook point */
978*f2d62220SAsim Jamshed errno = EINVAL;
979*f2d62220SAsim Jamshed return -1;
980*f2d62220SAsim Jamshed }
981*f2d62220SAsim Jamshed
98276404edcSAsim Jamshed mtcp_manager_t mtcp = GetMTCPManager(mctx);
98376404edcSAsim Jamshed if (!mtcp)
98476404edcSAsim Jamshed return -1;
98576404edcSAsim Jamshed
98676404edcSAsim Jamshed socket = &mtcp->msmap[sockid];
98776404edcSAsim Jamshed
98876404edcSAsim Jamshed if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) {
98976404edcSAsim Jamshed if (hook_point == MOS_NULL)
99076404edcSAsim Jamshed pstree = &socket->monitor_stream->stree_dontcare;
99176404edcSAsim Jamshed else if (hook_point == MOS_HK_RCV)
99276404edcSAsim Jamshed pstree = &socket->monitor_stream->stree_pre_rcv;
99376404edcSAsim Jamshed else if (hook_point == MOS_HK_SND)
99476404edcSAsim Jamshed pstree = &socket->monitor_stream->stree_post_snd;
99576404edcSAsim Jamshed else
99676404edcSAsim Jamshed return -1;
99776404edcSAsim Jamshed
99876404edcSAsim Jamshed } else if (socket->socktype == MOS_SOCK_MONITOR_STREAM
99976404edcSAsim Jamshed || socket->socktype == MOS_SOCK_MONITOR_RAW) {
100076404edcSAsim Jamshed if (hook_point == MOS_NULL)
100176404edcSAsim Jamshed pstree = &socket->monitor_listener->stree_dontcare;
100276404edcSAsim Jamshed else if (hook_point == MOS_HK_RCV)
100376404edcSAsim Jamshed pstree = &socket->monitor_listener->stree_pre_rcv;
100476404edcSAsim Jamshed else if (hook_point == MOS_HK_SND)
100576404edcSAsim Jamshed pstree = &socket->monitor_listener->stree_post_snd;
100676404edcSAsim Jamshed else
100776404edcSAsim Jamshed return -1;
100876404edcSAsim Jamshed } else {
100976404edcSAsim Jamshed errno = EINVAL;
101076404edcSAsim Jamshed return -1;
101176404edcSAsim Jamshed }
101276404edcSAsim Jamshed
101376404edcSAsim Jamshed return ModCb(mtcp->ev_store, pstree, event, callback);
101476404edcSAsim Jamshed }
101576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
101676404edcSAsim Jamshed int
mtcp_unregister_callback(mctx_t mctx,int sockid,event_t event,int hook_point)101776404edcSAsim Jamshed mtcp_unregister_callback(mctx_t mctx, int sockid, event_t event,
101876404edcSAsim Jamshed int hook_point)
101976404edcSAsim Jamshed {
102076404edcSAsim Jamshed return mtcp_register_callback(mctx, sockid, event, hook_point, NULL);
102176404edcSAsim Jamshed }
102276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
102376404edcSAsim Jamshed inline void
HandleCallback(mtcp_manager_t mtcp,uint32_t hook,socket_map_t socket,int side,struct pkt_ctx * pctx,event_t events)102476404edcSAsim Jamshed HandleCallback(mtcp_manager_t mtcp, uint32_t hook,
102576404edcSAsim Jamshed socket_map_t socket, int side, struct pkt_ctx *pctx, event_t events)
102676404edcSAsim Jamshed {
102776404edcSAsim Jamshed struct sfbpf_program fcode;
102876404edcSAsim Jamshed
102976404edcSAsim Jamshed if (!socket)
103076404edcSAsim Jamshed return;
103176404edcSAsim Jamshed
103276404edcSAsim Jamshed if (!events)
103376404edcSAsim Jamshed return;
103476404edcSAsim Jamshed assert(events);
103576404edcSAsim Jamshed
103676404edcSAsim Jamshed /* if client side monitoring is disabled, then skip */
103776404edcSAsim Jamshed if (side == MOS_SIDE_CLI && socket->monitor_stream->client_mon == 0)
103876404edcSAsim Jamshed return;
103976404edcSAsim Jamshed /* if server side monitoring is disabled, then skip */
104076404edcSAsim Jamshed else if (side == MOS_SIDE_SVR && socket->monitor_stream->server_mon == 0)
104176404edcSAsim Jamshed return;
104276404edcSAsim Jamshed
104376404edcSAsim Jamshed #define MSTRM(sock) (sock)->monitor_stream
104476404edcSAsim Jamshed #define MLSNR(sock) (sock)->monitor_listener
104576404edcSAsim Jamshed /* We use `?:` notation instead of `if/else` to make `evp` as const */
104676404edcSAsim Jamshed stree_t * const stree =
104776404edcSAsim Jamshed (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) ?
104876404edcSAsim Jamshed ((hook == MOS_HK_RCV) ? MSTRM(socket)->stree_pre_rcv :
104976404edcSAsim Jamshed (hook == MOS_HK_SND) ? MSTRM(socket)->stree_post_snd :
105076404edcSAsim Jamshed MSTRM(socket)->stree_dontcare)
105176404edcSAsim Jamshed : (socket->socktype == MOS_SOCK_MONITOR_STREAM)
105276404edcSAsim Jamshed || (socket->socktype == MOS_SOCK_MONITOR_RAW) ?
105376404edcSAsim Jamshed ((hook == MOS_HK_RCV) ? MLSNR(socket)->stree_pre_rcv :
105476404edcSAsim Jamshed (hook == MOS_HK_SND) ? MLSNR(socket)->stree_post_snd :
105576404edcSAsim Jamshed MLSNR(socket)->stree_dontcare) :
105676404edcSAsim Jamshed NULL;
105776404edcSAsim Jamshed
105876404edcSAsim Jamshed if (!stree)
105976404edcSAsim Jamshed return;
106076404edcSAsim Jamshed
106176404edcSAsim Jamshed /* mtcp_bind_monitor_filter()
1062a14d6bd4SAsim Jamshed - BPF filter is evaluated only for RAW socket and PASSIVE
1063a14d6bd4SAsim Jamshed socket (= orphan filter)
1064a14d6bd4SAsim Jamshed - stream syn filter is moved to and evaluated on socket creation
1065a14d6bd4SAsim Jamshed */
106676404edcSAsim Jamshed if (socket->socktype == MOS_SOCK_MONITOR_STREAM) {
106776404edcSAsim Jamshed fcode = MLSNR(socket)->stream_orphan_fcode;
106876404edcSAsim Jamshed /* if not match with filter, return */
106976404edcSAsim Jamshed if (ISSET_BPFFILTER(fcode) && pctx && EVAL_BPFFILTER(fcode,
107076404edcSAsim Jamshed (uint8_t *)pctx->p.iph - sizeof(struct ethhdr),
107176404edcSAsim Jamshed pctx->p.ip_len + sizeof(struct ethhdr)) == 0)
107276404edcSAsim Jamshed return;
107376404edcSAsim Jamshed }
107476404edcSAsim Jamshed if (socket->socktype == MOS_SOCK_MONITOR_RAW) {
107576404edcSAsim Jamshed fcode = MLSNR(socket)->raw_pkt_fcode;
107676404edcSAsim Jamshed /* if not match with filter, return */
107776404edcSAsim Jamshed if (ISSET_BPFFILTER(fcode) && pctx && EVAL_BPFFILTER(fcode,
107876404edcSAsim Jamshed (uint8_t *)pctx->p.iph - sizeof(struct ethhdr),
107976404edcSAsim Jamshed pctx->p.ip_len + sizeof(struct ethhdr)) == 0)
108076404edcSAsim Jamshed return;
108176404edcSAsim Jamshed }
108276404edcSAsim Jamshed
108376404edcSAsim Jamshed mctx_t const mctx = g_ctx[mtcp->ctx->cpu];
108476404edcSAsim Jamshed mtcp->pctx = pctx; /* for mtcp_getcurpkt() */
108576404edcSAsim Jamshed
108676404edcSAsim Jamshed HandleCb(mctx, socket->id, side, stree, events);
108776404edcSAsim Jamshed }
108876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
108976404edcSAsim Jamshed #endif
1090