BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file dynamic_depend.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * Dynamic dependencies module.
32 *
33 * Synopsis: dynamic_provide(string name, order_value)
34 * Synopsis: dynamic_depend(string name)
35 */
36  
37 #include <stdlib.h>
38 #include <string.h>
39  
40 #include <misc/offset.h>
41 #include <misc/debug.h>
42 #include <misc/compare.h>
43 #include <misc/strdup.h>
44 #include <misc/balloc.h>
45 #include <structure/LinkedList0.h>
46 #include <structure/BAVL.h>
47  
48 #include <ncd/module_common.h>
49  
50 #include <generated/blog_channel_ncd_dynamic_depend.h>
51  
52 struct provide;
53  
54 struct name_string {
55 char *data;
56 size_t len;
57 };
58  
59 struct name {
60 struct global *g;
61 struct name_string name;
62 BAVLNode names_tree_node;
63 BAVL provides_tree;
64 LinkedList0 waiting_depends_list;
65 struct provide *cur_p;
66 LinkedList0 cur_bound_depends_list;
67 int cur_resetting;
68 };
69  
70 struct provide {
71 NCDModuleInst *i;
72 struct name *n;
73 NCDValRef order_value;
74 BAVLNode provides_tree_node;
75 int dying;
76 };
77  
78 struct depend {
79 NCDModuleInst *i;
80 struct name *n;
81 int is_bound;
82 LinkedList0Node depends_list_node;
83 };
84  
85 struct global {
86 BAVL names_tree;
87 };
88  
89 static void provide_free (struct provide *o);
90 static void depend_free (struct depend *o);
91  
92 static int name_string_comparator (void *user, void *vv1, void *vv2)
93 {
94 struct name_string *v1 = vv1;
95 struct name_string *v2 = vv2;
96  
97 size_t min_len = (v1->len < v2->len ? v1->len : v2->len);
98  
99 int cmp = memcmp(v1->data, v2->data, min_len);
100 if (cmp) {
101 return B_COMPARE(cmp, 0);
102 }
103  
104 return B_COMPARE(v1->len, v2->len);
105 }
106  
107 static int val_comparator (void *user, NCDValRef *v1, NCDValRef *v2)
108 {
109 return NCDVal_Compare(*v1, *v2);
110 }
111  
112 static struct name * find_name (struct global *g, const char *name, size_t name_len)
113 {
114 struct name_string ns = {(char *)name, name_len};
115 BAVLNode *tn = BAVL_LookupExact(&g->names_tree, &ns);
116 if (!tn) {
117 return NULL;
118 }
119  
120 struct name *n = UPPER_OBJECT(tn, struct name, names_tree_node);
121 ASSERT(n->name.len == name_len)
122 ASSERT(!memcmp(n->name.data, name, name_len))
123  
124 return n;
125 }
126  
127 static struct name * name_init (NCDModuleInst *i, struct global *g, const char *name, size_t name_len)
128 {
129 ASSERT(!find_name(g, name, name_len))
130  
131 // allocate structure
132 struct name *o = malloc(sizeof(*o));
133 if (!o) {
134 ModuleLog(i, BLOG_ERROR, "malloc failed");
135 goto fail0;
136 }
137  
138 // set global state
139 o->g = g;
140  
141 // copy name
142 if (!(o->name.data = b_strdup_bin(name, name_len))) {
143 ModuleLog(i, BLOG_ERROR, "strdup failed");
144 goto fail1;
145 }
146 o->name.len = name_len;
147  
148 // insert to names tree
149 ASSERT_EXECUTE(BAVL_Insert(&g->names_tree, &o->names_tree_node, NULL))
150  
151 // init provides tree
152 BAVL_Init(&o->provides_tree, OFFSET_DIFF(struct provide, order_value, provides_tree_node), (BAVL_comparator)val_comparator, NULL);
153  
154 // init waiting depends list
155 LinkedList0_Init(&o->waiting_depends_list);
156  
157 // set no current provide
158 o->cur_p = NULL;
159  
160 return o;
161  
162 fail1:
163 free(o);
164 fail0:
165 return NULL;
166 }
167  
168 static void name_free (struct name *o)
169 {
170 ASSERT(BAVL_IsEmpty(&o->provides_tree))
171 ASSERT(LinkedList0_IsEmpty(&o->waiting_depends_list))
172 ASSERT(!o->cur_p)
173  
174 // remove from names tree
175 BAVL_Remove(&o->g->names_tree, &o->names_tree_node);
176  
177 // free name
178 free(o->name.data);
179  
180 // free structure
181 free(o);
182 }
183  
184 static struct provide * name_get_first_provide (struct name *o)
185 {
186 BAVLNode *tn = BAVL_GetFirst(&o->provides_tree);
187 if (!tn) {
188 return NULL;
189 }
190  
191 struct provide *p = UPPER_OBJECT(tn, struct provide, provides_tree_node);
192 ASSERT(p->n == o)
193  
194 return p;
195 }
196  
197 static void name_new_current (struct name *o)
198 {
199 ASSERT(!o->cur_p)
200 ASSERT(!BAVL_IsEmpty(&o->provides_tree))
201  
202 // set current provide
203 o->cur_p = name_get_first_provide(o);
204  
205 // init bound depends list
206 LinkedList0_Init(&o->cur_bound_depends_list);
207  
208 // set not resetting
209 o->cur_resetting = 0;
210  
211 // bind waiting depends
212 while (!LinkedList0_IsEmpty(&o->waiting_depends_list)) {
213 struct depend *d = UPPER_OBJECT(LinkedList0_GetFirst(&o->waiting_depends_list), struct depend, depends_list_node);
214 ASSERT(d->n == o)
215 ASSERT(!d->is_bound)
216  
217 // remove from waiting depends list
218 LinkedList0_Remove(&o->waiting_depends_list, &d->depends_list_node);
219  
220 // set bound
221 d->is_bound = 1;
222  
223 // add to bound depends list
224 LinkedList0_Prepend(&o->cur_bound_depends_list, &d->depends_list_node);
225  
226 // signal up
227 NCDModuleInst_Backend_Up(d->i);
228 }
229 }
230  
231 static void name_free_if_unused (struct name *o)
232 {
233 if (BAVL_IsEmpty(&o->provides_tree) && LinkedList0_IsEmpty(&o->waiting_depends_list)) {
234 name_free(o);
235 }
236 }
237  
238 static void name_continue_resetting (struct name *o)
239 {
240 ASSERT(o->cur_p)
241 ASSERT(o->cur_resetting)
242  
243 // still have bound depends?
244 if (!LinkedList0_IsEmpty(&o->cur_bound_depends_list)) {
245 return;
246 }
247  
248 struct provide *old_p = o->cur_p;
249  
250 // set no current provide
251 o->cur_p = NULL;
252  
253 // free old current provide if it's dying
254 if (old_p->dying) {
255 provide_free(old_p);
256 }
257  
258 if (!BAVL_IsEmpty(&o->provides_tree)) {
259 // get new current provide
260 name_new_current(o);
261 } else {
262 // free name if unused
263 name_free_if_unused(o);
264 }
265 }
266  
267 static void name_start_resetting (struct name *o)
268 {
269 ASSERT(o->cur_p)
270 ASSERT(!o->cur_resetting)
271  
272 // set resetting
273 o->cur_resetting = 1;
274  
275 // signal bound depends down
276 for (LinkedList0Node *ln = LinkedList0_GetFirst(&o->cur_bound_depends_list); ln; ln = LinkedList0Node_Next(ln)) {
277 struct depend *d = UPPER_OBJECT(ln, struct depend, depends_list_node);
278 ASSERT(d->n == o)
279 ASSERT(d->is_bound)
280 NCDModuleInst_Backend_Down(d->i);
281 }
282  
283 // if there were no bound depends, continue right away
284 name_continue_resetting(o);
285 }
286  
287 static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
288 {
289 // allocate global state structure
290 struct global *g = BAlloc(sizeof(*g));
291 if (!g) {
292 BLog(BLOG_ERROR, "BAlloc failed");
293 return 0;
294 }
295  
296 // set group state pointer
297 group->group_state = g;
298  
299 // init names tree
300 BAVL_Init(&g->names_tree, OFFSET_DIFF(struct name, name, names_tree_node), name_string_comparator, NULL);
301  
302 return 1;
303 }
304  
305 static void func_globalfree (struct NCDInterpModuleGroup *group)
306 {
307 struct global *g = group->group_state;
308 ASSERT(BAVL_IsEmpty(&g->names_tree))
309  
310 // free global state structure
311 BFree(g);
312 }
313  
314 static void provide_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
315 {
316 struct global *g = ModuleGlobal(i);
317 struct provide *o = vo;
318 o->i = i;
319  
320 // read arguments
321 NCDValRef name_arg;
322 if (!NCDVal_ListRead(params->args, 2, &name_arg, &o->order_value)) {
323 ModuleLog(i, BLOG_ERROR, "wrong arity");
324 goto fail0;
325 }
326 if (!NCDVal_IsString(name_arg)) {
327 ModuleLog(i, BLOG_ERROR, "wrong type");
328 goto fail0;
329 }
330 MemRef name = NCDVal_StringMemRef(name_arg);
331  
332 // find name, create new if needed
333 struct name *n = find_name(g, name.ptr, name.len);
334 if (!n && !(n = name_init(i, g, name.ptr, name.len))) {
335 goto fail0;
336 }
337  
338 // set name
339 o->n = n;
340  
341 // check for order value conflict
342 if (BAVL_LookupExact(&n->provides_tree, &o->order_value)) {
343 ModuleLog(i, BLOG_ERROR, "order value already exists");
344 goto fail0;
345 }
346  
347 // add to name's provides tree
348 ASSERT_EXECUTE(BAVL_Insert(&n->provides_tree, &o->provides_tree_node, NULL))
349  
350 // set not dying
351 o->dying = 0;
352  
353 // signal up
354 NCDModuleInst_Backend_Up(i);
355  
356 // should this be the current provide?
357 if (o == name_get_first_provide(n)) {
358 if (!n->cur_p) {
359 name_new_current(n);
360 }
361 else if (!n->cur_resetting) {
362 name_start_resetting(n);
363 }
364 }
365  
366 return;
367  
368 fail0:
369 NCDModuleInst_Backend_DeadError(i);
370 }
371  
372 static void provide_free (struct provide *o)
373 {
374 struct name *n = o->n;
375 ASSERT(o->dying)
376 ASSERT(o != n->cur_p)
377  
378 // remove from name's provides tree
379 BAVL_Remove(&n->provides_tree, &o->provides_tree_node);
380  
381 NCDModuleInst_Backend_Dead(o->i);
382 }
383  
384 static void provide_func_die (void *vo)
385 {
386 struct provide *o = vo;
387 struct name *n = o->n;
388 ASSERT(!o->dying)
389  
390 // set dying
391 o->dying = 1;
392  
393 // if this is not the current provide, die right away
394 if (o != n->cur_p) {
395 // free provide
396 provide_free(o);
397  
398 // free name if unused
399 name_free_if_unused(n);
400 return;
401 }
402  
403 ASSERT(!n->cur_resetting)
404  
405 // start resetting
406 name_start_resetting(n);
407 }
408  
409 static void depend_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
410 {
411 struct global *g = ModuleGlobal(i);
412 struct depend *o = vo;
413 o->i = i;
414  
415 // read arguments
416 NCDValRef name_arg;
417 if (!NCDVal_ListRead(params->args, 1, &name_arg)) {
418 ModuleLog(i, BLOG_ERROR, "wrong arity");
419 goto fail0;
420 }
421 if (!NCDVal_IsString(name_arg)) {
422 ModuleLog(i, BLOG_ERROR, "wrong type");
423 goto fail0;
424 }
425 MemRef name = NCDVal_StringMemRef(name_arg);
426  
427 // find name, create new if needed
428 struct name *n = find_name(g, name.ptr, name.len);
429 if (!n && !(n = name_init(i, g, name.ptr, name.len))) {
430 goto fail0;
431 }
432  
433 // set name
434 o->n = n;
435  
436 if (n->cur_p && !n->cur_resetting) {
437 // set bound
438 o->is_bound = 1;
439  
440 // add to bound depends list
441 LinkedList0_Prepend(&n->cur_bound_depends_list, &o->depends_list_node);
442  
443 // signal up
444 NCDModuleInst_Backend_Up(i);
445 } else {
446 // set not bound
447 o->is_bound = 0;
448  
449 // add to waiting depends list
450 LinkedList0_Prepend(&n->waiting_depends_list, &o->depends_list_node);
451 }
452  
453 return;
454  
455 fail0:
456 NCDModuleInst_Backend_DeadError(i);
457 }
458  
459 static void depend_func_die (void *vo)
460 {
461 struct depend *o = vo;
462 struct name *n = o->n;
463  
464 if (o->is_bound) {
465 ASSERT(n->cur_p)
466  
467 // remove from bound depends list
468 LinkedList0_Remove(&n->cur_bound_depends_list, &o->depends_list_node);
469  
470 // continue resetting
471 if (n->cur_resetting) {
472 name_continue_resetting(n);
473 }
474 } else {
475 // remove from waiting depends list
476 LinkedList0_Remove(&n->waiting_depends_list, &o->depends_list_node);
477  
478 // free name if unused
479 name_free_if_unused(n);
480 }
481  
482 NCDModuleInst_Backend_Dead(o->i);
483 }
484  
485 static void depend_func_clean (void *vo)
486 {
487 struct depend *o = vo;
488 struct name *n = o->n;
489 ASSERT(!o->is_bound || n->cur_p)
490  
491 if (!(o->is_bound && n->cur_resetting)) {
492 return;
493 }
494  
495 // remove from bound depends list
496 LinkedList0_Remove(&n->cur_bound_depends_list, &o->depends_list_node);
497  
498 // set not bound
499 o->is_bound = 0;
500  
501 // add to waiting depends list
502 LinkedList0_Prepend(&n->waiting_depends_list, &o->depends_list_node);
503  
504 // continue resetting
505 name_continue_resetting(n);
506 }
507  
508 static int depend_func_getobj (void *vo, NCD_string_id_t objname, NCDObject *out_object)
509 {
510 struct depend *o = vo;
511 struct name *n = o->n;
512 ASSERT(!o->is_bound || n->cur_p)
513  
514 if (!o->is_bound) {
515 return 0;
516 }
517  
518 return NCDModuleInst_Backend_GetObj(n->cur_p->i, objname, out_object);
519 }
520  
521 static struct NCDModule modules[] = {
522 {
523 .type = "dynamic_provide",
524 .func_new2 = provide_func_new,
525 .func_die = provide_func_die,
526 .alloc_size = sizeof(struct provide)
527 }, {
528 .type = "dynamic_depend",
529 .func_new2 = depend_func_new,
530 .func_die = depend_func_die,
531 .func_clean = depend_func_clean,
532 .func_getobj = depend_func_getobj,
533 .flags = NCDMODULE_FLAG_CAN_RESOLVE_WHEN_DOWN,
534 .alloc_size = sizeof(struct depend)
535 }, {
536 .type = NULL
537 }
538 };
539  
540 const struct NCDModuleGroup ncdmodule_dynamic_depend = {
541 .func_globalinit = func_globalinit,
542 .func_globalfree = func_globalfree,
543 .modules = modules
544 };