depend.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /**
  2. * @file depend.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. *
  22. * @section DESCRIPTION
  23. *
  24. * Dependencies module.
  25. *
  26. * Synopsis: provide(string name)
  27. *
  28. * Synopsis: depend(string name)
  29. */
  30. #include <stdlib.h>
  31. #include <misc/offset.h>
  32. #include <structure/LinkedList2.h>
  33. #include <ncd/NCDModule.h>
  34. #include <generated/blog_channel_ncd_depend.h>
  35. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  36. struct provide {
  37. NCDModuleInst *i;
  38. char *name;
  39. LinkedList2Node provides_node;
  40. LinkedList2 depends;
  41. int dying;
  42. };
  43. struct depend {
  44. NCDModuleInst *i;
  45. char *name;
  46. struct provide *p;
  47. LinkedList2Node node;
  48. };
  49. LinkedList2 provides;
  50. LinkedList2 free_depends;
  51. static struct provide * find_provide (const char *name)
  52. {
  53. LinkedList2Iterator it;
  54. LinkedList2Iterator_InitForward(&it, &provides);
  55. LinkedList2Node *n;
  56. while (n = LinkedList2Iterator_Next(&it)) {
  57. struct provide *p = UPPER_OBJECT(n, struct provide, provides_node);
  58. if (!strcmp(p->name, name)) {
  59. LinkedList2Iterator_Free(&it);
  60. return p;
  61. }
  62. }
  63. return NULL;
  64. }
  65. static int func_globalinit (void)
  66. {
  67. // init provides list
  68. LinkedList2_Init(&provides);
  69. // init free depends list
  70. LinkedList2_Init(&free_depends);
  71. return 1;
  72. }
  73. static void * provide_func_new (NCDModuleInst *i)
  74. {
  75. // allocate instance
  76. struct provide *o = malloc(sizeof(*o));
  77. if (!o) {
  78. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  79. goto fail0;
  80. }
  81. // init arguments
  82. o->i = i;
  83. // read arguments
  84. NCDValue *name_arg;
  85. if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
  86. ModuleLog(i, BLOG_ERROR, "wrong arity");
  87. goto fail1;
  88. }
  89. if (NCDValue_Type(name_arg) != NCDVALUE_STRING) {
  90. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  91. goto fail1;
  92. }
  93. o->name = NCDValue_StringValue(name_arg);
  94. // check for existing provide with this name
  95. if (find_provide(o->name)) {
  96. ModuleLog(o->i, BLOG_ERROR, "a provide with this name already exists");
  97. goto fail1;
  98. }
  99. // insert to provides list
  100. LinkedList2_Append(&provides, &o->provides_node);
  101. // init depends list
  102. LinkedList2_Init(&o->depends);
  103. // set not dying
  104. o->dying = 0;
  105. // attach free depends with this name
  106. LinkedList2Iterator it;
  107. LinkedList2Iterator_InitForward(&it, &free_depends);
  108. LinkedList2Node *n;
  109. while (n = LinkedList2Iterator_Next(&it)) {
  110. struct depend *d = UPPER_OBJECT(n, struct depend, node);
  111. ASSERT(!d->p)
  112. if (strcmp(d->name, o->name)) {
  113. continue;
  114. }
  115. // remove from free depends list
  116. LinkedList2_Remove(&free_depends, &d->node);
  117. // set provide
  118. d->p = o;
  119. // insert to provide's list
  120. LinkedList2_Append(&o->depends, &d->node);
  121. // signal up
  122. NCDModuleInst_Backend_Event(d->i, NCDMODULE_EVENT_UP);
  123. }
  124. NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
  125. return o;
  126. fail1:
  127. free(o);
  128. fail0:
  129. return NULL;
  130. }
  131. static void provide_func_free (void *vo)
  132. {
  133. struct provide *o = vo;
  134. ASSERT(LinkedList2_IsEmpty(&o->depends))
  135. // remove from provides list
  136. LinkedList2_Remove(&provides, &o->provides_node);
  137. // free instance
  138. free(o);
  139. }
  140. static void provide_func_die (void *vo)
  141. {
  142. struct provide *o = vo;
  143. ASSERT(!o->dying)
  144. // if we have no depends, die immediately
  145. if (LinkedList2_IsEmpty(&o->depends)) {
  146. NCDModuleInst_Backend_Died(o->i, 0);
  147. return;
  148. }
  149. // set dying
  150. o->dying = 1;
  151. // signal our depends down
  152. LinkedList2Iterator it;
  153. LinkedList2Iterator_InitForward(&it, &o->depends);
  154. LinkedList2Node *n;
  155. while (n = LinkedList2Iterator_Next(&it)) {
  156. struct depend *d = UPPER_OBJECT(n, struct depend, node);
  157. ASSERT(d->p == o)
  158. // signal down
  159. NCDModuleInst_Backend_Event(d->i, NCDMODULE_EVENT_DOWN);
  160. }
  161. }
  162. static void * depend_func_new (NCDModuleInst *i)
  163. {
  164. // allocate instance
  165. struct depend *o = malloc(sizeof(*o));
  166. if (!o) {
  167. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  168. goto fail0;
  169. }
  170. // init arguments
  171. o->i = i;
  172. // read arguments
  173. NCDValue *name_arg;
  174. if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
  175. ModuleLog(i, BLOG_ERROR, "wrong arity");
  176. goto fail1;
  177. }
  178. if (NCDValue_Type(name_arg) != NCDVALUE_STRING) {
  179. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  180. goto fail1;
  181. }
  182. o->name = NCDValue_StringValue(name_arg);
  183. // find a provide with our name
  184. o->p = find_provide(o->name);
  185. // do not attach to a dying provide
  186. if (o->p && o->p->dying) {
  187. o->p = NULL;
  188. }
  189. if (o->p) {
  190. // insert to provide's list
  191. LinkedList2_Append(&o->p->depends, &o->node);
  192. // signal up
  193. NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
  194. } else {
  195. // insert to free depends list
  196. LinkedList2_Append(&free_depends, &o->node);
  197. }
  198. return o;
  199. fail1:
  200. free(o);
  201. fail0:
  202. return NULL;
  203. }
  204. static void depend_func_free (void *vo)
  205. {
  206. struct depend *o = vo;
  207. if (o->p) {
  208. // remove from provide's list
  209. LinkedList2_Remove(&o->p->depends, &o->node);
  210. // if provide is dying and is empty, let it die
  211. if (o->p->dying && LinkedList2_IsEmpty(&o->p->depends)) {
  212. NCDModuleInst_Backend_Died(o->p->i, 0);
  213. }
  214. } else {
  215. // remove free depends list
  216. LinkedList2_Remove(&free_depends, &o->node);
  217. }
  218. // free instance
  219. free(o);
  220. }
  221. static void depend_func_clean (void *vo)
  222. {
  223. struct depend *o = vo;
  224. if (!(o->p && o->p->dying)) {
  225. return;
  226. }
  227. struct provide *p = o->p;
  228. // remove from provide's list
  229. LinkedList2_Remove(&o->p->depends, &o->node);
  230. // set no provide
  231. o->p = NULL;
  232. // insert to free depends list
  233. LinkedList2_Append(&free_depends, &o->node);
  234. // if provide is empty, let it die
  235. if (LinkedList2_IsEmpty(&p->depends)) {
  236. NCDModuleInst_Backend_Died(p->i, 0);
  237. }
  238. }
  239. static const struct NCDModule modules[] = {
  240. {
  241. .type = "provide",
  242. .func_new = provide_func_new,
  243. .func_free = provide_func_free,
  244. .func_die = provide_func_die
  245. }, {
  246. .type = "depend",
  247. .func_new = depend_func_new,
  248. .func_free = depend_func_free,
  249. .func_clean = depend_func_clean
  250. }, {
  251. .type = NULL
  252. }
  253. };
  254. const struct NCDModuleGroup ncdmodule_depend = {
  255. .func_globalinit = func_globalinit,
  256. .modules = modules
  257. };