ncd.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633
  1. /**
  2. * @file ncd.c
  3. * @author Ambroz Bizjak <[email protected]>
  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. #include <stdint.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <misc/version.h>
  34. #include <misc/loggers_string.h>
  35. #include <misc/loglevel.h>
  36. #include <misc/offset.h>
  37. #include <misc/read_file.h>
  38. #include <misc/balloc.h>
  39. #include <misc/concat_strings.h>
  40. #include <misc/string_begins_with.h>
  41. #include <misc/parse_number.h>
  42. #include <misc/open_standard_streams.h>
  43. #include <structure/LinkedList1.h>
  44. #include <structure/LinkedList2.h>
  45. #include <base/BLog.h>
  46. #include <system/BReactor.h>
  47. #include <system/BSignal.h>
  48. #include <system/BConnection.h>
  49. #include <system/BProcess.h>
  50. #include <udevmonitor/NCDUdevManager.h>
  51. #include <ncd/NCDConfigParser.h>
  52. #include <ncd/NCDModule.h>
  53. #include <ncd/NCDModuleIndex.h>
  54. #include <ncd/modules/modules.h>
  55. #ifndef BADVPN_USE_WINAPI
  56. #include <base/BLog_syslog.h>
  57. #endif
  58. #include <ncd/ncd.h>
  59. #include <generated/blog_channel_ncd.h>
  60. #define LOGGER_STDOUT 1
  61. #define LOGGER_SYSLOG 2
  62. #define ARG_VALUE_TYPE_STRING 1
  63. #define ARG_VALUE_TYPE_VARIABLE 2
  64. #define ARG_VALUE_TYPE_LIST 3
  65. #define SSTATE_CHILD 1
  66. #define SSTATE_ADULT 2
  67. #define SSTATE_DYING 3
  68. #define SSTATE_FORGOTTEN 4
  69. #define PSTATE_WORKING 1
  70. #define PSTATE_UP 2
  71. #define PSTATE_WAITING 3
  72. #define PSTATE_TERMINATING 4
  73. struct arg_value {
  74. int type;
  75. union {
  76. char *string;
  77. char *variable;
  78. LinkedList1 list;
  79. };
  80. };
  81. struct arg_list_elem {
  82. LinkedList1Node list_node;
  83. struct arg_value value;
  84. };
  85. struct statement {
  86. char *object_name;
  87. char *method_name;
  88. struct arg_value args;
  89. char *name;
  90. };
  91. struct process {
  92. NCDModuleProcess *module_process;
  93. NCDValue args;
  94. char *name;
  95. size_t num_statements;
  96. struct process_statement *statements;
  97. int state;
  98. size_t ap;
  99. size_t fp;
  100. BTimer wait_timer;
  101. BPending advance_job;
  102. BPending work_job;
  103. LinkedList2Node list_node; // node in processes
  104. };
  105. struct process_statement {
  106. struct process *p;
  107. size_t i;
  108. struct statement s;
  109. int state;
  110. const struct NCDModule *module;
  111. int have_error;
  112. btime_t error_until;
  113. NCDModuleInst inst;
  114. NCDValue inst_args;
  115. };
  116. // command-line options
  117. struct {
  118. int help;
  119. int version;
  120. int logger;
  121. #ifndef BADVPN_USE_WINAPI
  122. char *logger_syslog_facility;
  123. char *logger_syslog_ident;
  124. #endif
  125. int loglevel;
  126. int loglevels[BLOG_NUM_CHANNELS];
  127. char *config_file;
  128. int retry_time;
  129. } options;
  130. // reactor
  131. BReactor ss;
  132. // are we terminating
  133. int terminating;
  134. // process manager
  135. BProcessManager manager;
  136. // udev manager
  137. NCDUdevManager umanager;
  138. // module index
  139. NCDModuleIndex mindex;
  140. // config AST
  141. struct NCDConfig_processes *config_ast;
  142. // processes
  143. LinkedList2 processes;
  144. static void print_help (const char *name);
  145. static void print_version (void);
  146. static int parse_arguments (int argc, char *argv[]);
  147. static void signal_handler (void *unused);
  148. static int arg_value_init_string (struct arg_value *o, const char *string);
  149. static int arg_value_init_variable (struct arg_value *o, const char *variable);
  150. static void arg_value_init_list (struct arg_value *o);
  151. static int arg_value_list_append (struct arg_value *o, struct arg_value v);
  152. static void arg_value_free (struct arg_value *o);
  153. static int build_arg_list_from_ast_list (struct arg_value *o, struct NCDConfig_list *list);
  154. static int statement_init (struct statement *s, struct NCDConfig_statements *conf);
  155. static void statement_free (struct statement *s);
  156. static int process_new (struct NCDConfig_processes *conf, NCDModuleProcess *module_process, NCDValue args);
  157. static void process_free (struct process *p);
  158. static void process_start_terminating (struct process *p);
  159. static void process_free_statements (struct process *p);
  160. static size_t process_rap (struct process *p);
  161. static void process_assert_pointers (struct process *p);
  162. static void process_logfunc (struct process *p);
  163. static void process_log (struct process *p, int level, const char *fmt, ...);
  164. static void process_schedule_work (struct process *p);
  165. static void process_work_job_handler (struct process *p);
  166. static void process_advance_job_handler (struct process *p);
  167. static void process_wait_timer_handler (struct process *p);
  168. static struct process_statement * process_find_statement (struct process *p, size_t pos, const char *name);
  169. static int process_resolve_name (struct process *p, size_t pos, const char *name, struct process_statement **first_ps, const char **rest);
  170. static int process_resolve_variable (struct process *p, size_t pos, const char *varname, NCDValue *out);
  171. static struct process_statement * process_resolve_object (struct process *p, size_t pos, const char *objname);
  172. static void process_statement_logfunc (struct process_statement *ps);
  173. static void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...);
  174. static void process_statement_set_error (struct process_statement *ps);
  175. static int process_statement_resolve_argument (struct process_statement *ps, struct arg_value *arg, NCDValue *out);
  176. static void process_statement_instance_func_event (struct process_statement *ps, int event);
  177. static int process_statement_instance_func_getvar (struct process_statement *ps, const char *varname, NCDValue *out);
  178. static NCDModuleInst * process_statement_instance_func_getobj (struct process_statement *ps, const char *objname);
  179. static int process_statement_instance_func_initprocess (struct process_statement *ps, NCDModuleProcess *mp, const char *template_name, NCDValue args);
  180. static void process_statement_instance_logfunc (struct process_statement *ps);
  181. static void process_moduleprocess_func_event (struct process *p, int event);
  182. static int process_moduleprocess_func_getvar (struct process *p, const char *name, NCDValue *out);
  183. static NCDModuleInst * process_moduleprocess_func_getobj (struct process *p, const char *name);
  184. int main (int argc, char **argv)
  185. {
  186. if (argc <= 0) {
  187. return 1;
  188. }
  189. // open standard streams
  190. open_standard_streams();
  191. // parse command-line arguments
  192. if (!parse_arguments(argc, argv)) {
  193. fprintf(stderr, "Failed to parse arguments\n");
  194. print_help(argv[0]);
  195. goto fail0;
  196. }
  197. // handle --help and --version
  198. if (options.help) {
  199. print_version();
  200. print_help(argv[0]);
  201. return 0;
  202. }
  203. if (options.version) {
  204. print_version();
  205. return 0;
  206. }
  207. // initialize logger
  208. switch (options.logger) {
  209. case LOGGER_STDOUT:
  210. BLog_InitStdout();
  211. break;
  212. #ifndef BADVPN_USE_WINAPI
  213. case LOGGER_SYSLOG:
  214. if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) {
  215. fprintf(stderr, "Failed to initialize syslog logger\n");
  216. goto fail0;
  217. }
  218. break;
  219. #endif
  220. default:
  221. ASSERT(0);
  222. }
  223. // configure logger channels
  224. for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
  225. if (options.loglevels[i] >= 0) {
  226. BLog_SetChannelLoglevel(i, options.loglevels[i]);
  227. }
  228. else if (options.loglevel >= 0) {
  229. BLog_SetChannelLoglevel(i, options.loglevel);
  230. }
  231. }
  232. BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
  233. // initialize network
  234. if (!BNetwork_GlobalInit()) {
  235. BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
  236. goto fail1;
  237. }
  238. // init time
  239. BTime_Init();
  240. // init reactor
  241. if (!BReactor_Init(&ss)) {
  242. BLog(BLOG_ERROR, "BReactor_Init failed");
  243. goto fail1;
  244. }
  245. // set not terminating
  246. terminating = 0;
  247. // init process manager
  248. if (!BProcessManager_Init(&manager, &ss)) {
  249. BLog(BLOG_ERROR, "BProcessManager_Init failed");
  250. goto fail1a;
  251. }
  252. // init udev manager
  253. NCDUdevManager_Init(&umanager, &ss, &manager);
  254. // init module index
  255. NCDModuleIndex_Init(&mindex);
  256. // add module groups to index
  257. for (const struct NCDModuleGroup **g = ncd_modules; *g; g++) {
  258. if (!NCDModuleIndex_AddGroup(&mindex, *g)) {
  259. BLog(BLOG_ERROR, "NCDModuleIndex_AddGroup failed");
  260. goto fail2;
  261. }
  262. }
  263. // setup signal handler
  264. if (!BSignal_Init(&ss, signal_handler, NULL)) {
  265. BLog(BLOG_ERROR, "BSignal_Init failed");
  266. goto fail2;
  267. }
  268. // read config file
  269. uint8_t *file;
  270. size_t file_len;
  271. if (!read_file(options.config_file, &file, &file_len)) {
  272. BLog(BLOG_ERROR, "failed to read config file");
  273. goto fail3;
  274. }
  275. // parse config file
  276. if (!NCDConfigParser_Parse((char *)file, file_len, &config_ast)) {
  277. BLog(BLOG_ERROR, "NCDConfigParser_Parse failed");
  278. free(file);
  279. goto fail3;
  280. }
  281. // fee config file memory
  282. free(file);
  283. // init module params
  284. struct NCDModuleInitParams params;
  285. params.reactor = &ss;
  286. params.manager = &manager;
  287. params.umanager = &umanager;
  288. // init modules
  289. size_t num_inited_modules = 0;
  290. for (const struct NCDModuleGroup **g = ncd_modules; *g; g++) {
  291. if ((*g)->func_globalinit && !(*g)->func_globalinit(params)) {
  292. BLog(BLOG_ERROR, "globalinit failed for some module");
  293. goto fail5;
  294. }
  295. num_inited_modules++;
  296. }
  297. // init processes list
  298. LinkedList2_Init(&processes);
  299. // init processes
  300. struct NCDConfig_processes *conf = config_ast;
  301. while (conf) {
  302. if (!conf->is_template) {
  303. NCDValue args;
  304. NCDValue_InitList(&args);
  305. if (!process_new(conf, NULL, args)) {
  306. NCDValue_Free(&args);
  307. }
  308. }
  309. conf = conf->next;
  310. }
  311. // enter event loop
  312. BLog(BLOG_NOTICE, "entering event loop");
  313. BReactor_Exec(&ss);
  314. ASSERT(LinkedList2_IsEmpty(&processes))
  315. fail5:
  316. // free modules
  317. while (num_inited_modules > 0) {
  318. const struct NCDModuleGroup **g = &ncd_modules[num_inited_modules - 1];
  319. if ((*g)->func_globalfree) {
  320. (*g)->func_globalfree();
  321. }
  322. num_inited_modules--;
  323. }
  324. // free configuration
  325. NCDConfig_free_processes(config_ast);
  326. fail3:
  327. // remove signal handler
  328. BSignal_Finish();
  329. fail2:
  330. // free module index
  331. NCDModuleIndex_Free(&mindex);
  332. // free udev manager
  333. NCDUdevManager_Free(&umanager);
  334. // free process manager
  335. BProcessManager_Free(&manager);
  336. fail1a:
  337. // free reactor
  338. BReactor_Free(&ss);
  339. fail1:
  340. // free logger
  341. BLog(BLOG_NOTICE, "exiting");
  342. BLog_Free();
  343. fail0:
  344. // finish objects
  345. DebugObjectGlobal_Finish();
  346. return 1;
  347. }
  348. void print_help (const char *name)
  349. {
  350. printf(
  351. "Usage:\n"
  352. " %s\n"
  353. " [--help]\n"
  354. " [--version]\n"
  355. " [--logger <"LOGGERS_STRING">]\n"
  356. #ifndef BADVPN_USE_WINAPI
  357. " (logger=syslog?\n"
  358. " [--syslog-facility <string>]\n"
  359. " [--syslog-ident <string>]\n"
  360. " )\n"
  361. #endif
  362. " [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
  363. " [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
  364. " --config-file <file>\n"
  365. " [--retry-time <ms>]\n",
  366. name
  367. );
  368. }
  369. void print_version (void)
  370. {
  371. printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
  372. }
  373. int parse_arguments (int argc, char *argv[])
  374. {
  375. if (argc <= 0) {
  376. return 0;
  377. }
  378. options.help = 0;
  379. options.version = 0;
  380. options.logger = LOGGER_STDOUT;
  381. #ifndef BADVPN_USE_WINAPI
  382. options.logger_syslog_facility = "daemon";
  383. options.logger_syslog_ident = argv[0];
  384. #endif
  385. options.loglevel = -1;
  386. for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
  387. options.loglevels[i] = -1;
  388. }
  389. options.config_file = NULL;
  390. options.retry_time = DEFAULT_RETRY_TIME;
  391. for (int i = 1; i < argc; i++) {
  392. char *arg = argv[i];
  393. if (!strcmp(arg, "--help")) {
  394. options.help = 1;
  395. }
  396. else if (!strcmp(arg, "--version")) {
  397. options.version = 1;
  398. }
  399. else if (!strcmp(arg, "--logger")) {
  400. if (1 >= argc - i) {
  401. fprintf(stderr, "%s: requires an argument\n", arg);
  402. return 0;
  403. }
  404. char *arg2 = argv[i + 1];
  405. if (!strcmp(arg2, "stdout")) {
  406. options.logger = LOGGER_STDOUT;
  407. }
  408. #ifndef BADVPN_USE_WINAPI
  409. else if (!strcmp(arg2, "syslog")) {
  410. options.logger = LOGGER_SYSLOG;
  411. }
  412. #endif
  413. else {
  414. fprintf(stderr, "%s: wrong argument\n", arg);
  415. return 0;
  416. }
  417. i++;
  418. }
  419. #ifndef BADVPN_USE_WINAPI
  420. else if (!strcmp(arg, "--syslog-facility")) {
  421. if (1 >= argc - i) {
  422. fprintf(stderr, "%s: requires an argument\n", arg);
  423. return 0;
  424. }
  425. options.logger_syslog_facility = argv[i + 1];
  426. i++;
  427. }
  428. else if (!strcmp(arg, "--syslog-ident")) {
  429. if (1 >= argc - i) {
  430. fprintf(stderr, "%s: requires an argument\n", arg);
  431. return 0;
  432. }
  433. options.logger_syslog_ident = argv[i + 1];
  434. i++;
  435. }
  436. #endif
  437. else if (!strcmp(arg, "--loglevel")) {
  438. if (1 >= argc - i) {
  439. fprintf(stderr, "%s: requires an argument\n", arg);
  440. return 0;
  441. }
  442. if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
  443. fprintf(stderr, "%s: wrong argument\n", arg);
  444. return 0;
  445. }
  446. i++;
  447. }
  448. else if (!strcmp(arg, "--channel-loglevel")) {
  449. if (2 >= argc - i) {
  450. fprintf(stderr, "%s: requires two arguments\n", arg);
  451. return 0;
  452. }
  453. int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
  454. if (channel < 0) {
  455. fprintf(stderr, "%s: wrong channel argument\n", arg);
  456. return 0;
  457. }
  458. int loglevel = parse_loglevel(argv[i + 2]);
  459. if (loglevel < 0) {
  460. fprintf(stderr, "%s: wrong loglevel argument\n", arg);
  461. return 0;
  462. }
  463. options.loglevels[channel] = loglevel;
  464. i += 2;
  465. }
  466. else if (!strcmp(arg, "--config-file")) {
  467. if (1 >= argc - i) {
  468. fprintf(stderr, "%s: requires an argument\n", arg);
  469. return 0;
  470. }
  471. options.config_file = argv[i + 1];
  472. i++;
  473. }
  474. else if (!strcmp(arg, "--retry-time")) {
  475. if (1 >= argc - i) {
  476. fprintf(stderr, "%s: requires an argument\n", arg);
  477. return 0;
  478. }
  479. if ((options.retry_time = atoi(argv[i + 1])) < 0) {
  480. fprintf(stderr, "%s: wrong argument\n", arg);
  481. return 0;
  482. }
  483. i++;
  484. }
  485. else {
  486. fprintf(stderr, "unknown option: %s\n", arg);
  487. return 0;
  488. }
  489. }
  490. if (options.help || options.version) {
  491. return 1;
  492. }
  493. if (!options.config_file) {
  494. fprintf(stderr, "--config-file is required\n");
  495. return 0;
  496. }
  497. return 1;
  498. }
  499. void signal_handler (void *unused)
  500. {
  501. BLog(BLOG_NOTICE, "termination requested");
  502. if (terminating) {
  503. return;
  504. }
  505. terminating = 1;
  506. if (LinkedList2_IsEmpty(&processes)) {
  507. BReactor_Quit(&ss, 1);
  508. return;
  509. }
  510. // start terminating non-template processes
  511. LinkedList2Iterator it;
  512. LinkedList2Iterator_InitForward(&it, &processes);
  513. LinkedList2Node *n;
  514. while (n = LinkedList2Iterator_Next(&it)) {
  515. struct process *p = UPPER_OBJECT(n, struct process, list_node);
  516. if (p->module_process) {
  517. continue;
  518. }
  519. if (p->state != PSTATE_TERMINATING) {
  520. process_start_terminating(p);
  521. }
  522. }
  523. }
  524. int arg_value_init_string (struct arg_value *o, const char *string)
  525. {
  526. o->type = ARG_VALUE_TYPE_STRING;
  527. if (!(o->string = strdup(string))) {
  528. BLog(BLOG_ERROR, "strdup failed");
  529. return 0;
  530. }
  531. return 1;
  532. }
  533. int arg_value_init_variable (struct arg_value *o, const char *variable)
  534. {
  535. o->type = ARG_VALUE_TYPE_VARIABLE;
  536. if (!(o->variable = strdup(variable))) {
  537. BLog(BLOG_ERROR, "strdup failed");
  538. return 0;
  539. }
  540. return 1;
  541. }
  542. void arg_value_init_list (struct arg_value *o)
  543. {
  544. o->type = ARG_VALUE_TYPE_LIST;
  545. LinkedList1_Init(&o->list);
  546. }
  547. int arg_value_list_append (struct arg_value *o, struct arg_value v)
  548. {
  549. ASSERT(o->type == ARG_VALUE_TYPE_LIST)
  550. struct arg_list_elem *elem = malloc(sizeof(*elem));
  551. if (!elem) {
  552. BLog(BLOG_ERROR, "malloc failed");
  553. return 0;
  554. }
  555. LinkedList1_Append(&o->list, &elem->list_node);
  556. elem->value = v;
  557. return 1;
  558. }
  559. void arg_value_free (struct arg_value *o)
  560. {
  561. switch (o->type) {
  562. case ARG_VALUE_TYPE_STRING: {
  563. free(o->string);
  564. } break;
  565. case ARG_VALUE_TYPE_VARIABLE: {
  566. free(o->variable);
  567. } break;
  568. case ARG_VALUE_TYPE_LIST: {
  569. while (!LinkedList1_IsEmpty(&o->list)) {
  570. struct arg_list_elem *elem = UPPER_OBJECT(LinkedList1_GetFirst(&o->list), struct arg_list_elem, list_node);
  571. arg_value_free(&elem->value);
  572. LinkedList1_Remove(&o->list, &elem->list_node);
  573. free(elem);
  574. }
  575. } break;
  576. default: ASSERT(0);
  577. }
  578. }
  579. int build_arg_list_from_ast_list (struct arg_value *o, struct NCDConfig_list *list)
  580. {
  581. arg_value_init_list(o);
  582. for (struct NCDConfig_list *c = list; c; c = c->next) {
  583. struct arg_value e;
  584. switch (c->type) {
  585. case NCDCONFIG_ARG_STRING: {
  586. if (!arg_value_init_string(&e, c->string)) {
  587. goto fail;
  588. }
  589. } break;
  590. case NCDCONFIG_ARG_VAR: {
  591. char *variable = NCDConfig_concat_strings(c->var);
  592. if (!variable) {
  593. BLog(BLOG_ERROR, "NCDConfig_concat_strings failed");
  594. goto fail;
  595. }
  596. if (!arg_value_init_variable(&e, variable)) {
  597. free(variable);
  598. goto fail;
  599. }
  600. free(variable);
  601. } break;
  602. case NCDCONFIG_ARG_LIST: {
  603. if (!build_arg_list_from_ast_list(&e, c->list)) {
  604. goto fail;
  605. }
  606. } break;
  607. default: ASSERT(0);
  608. }
  609. if (!arg_value_list_append(o, e)) {
  610. arg_value_free(&e);
  611. goto fail;
  612. }
  613. }
  614. return 1;
  615. fail:
  616. arg_value_free(o);
  617. return 0;
  618. }
  619. int statement_init (struct statement *s, struct NCDConfig_statements *conf)
  620. {
  621. s->object_name = NULL;
  622. s->method_name = NULL;
  623. s->name = NULL;
  624. // set object name
  625. if (conf->objname) {
  626. if (!(s->object_name = NCDConfig_concat_strings(conf->objname))) {
  627. BLog(BLOG_ERROR, "NCDConfig_concat_strings failed");
  628. goto fail1;
  629. }
  630. }
  631. // set method name
  632. if (!(s->method_name = NCDConfig_concat_strings(conf->names))) {
  633. BLog(BLOG_ERROR, "NCDConfig_concat_strings failed");
  634. goto fail1;
  635. }
  636. // init name
  637. if (conf->name) {
  638. if (!(s->name = strdup(conf->name))) {
  639. BLog(BLOG_ERROR, "strdup failed");
  640. goto fail1;
  641. }
  642. }
  643. // init arguments
  644. if (!build_arg_list_from_ast_list(&s->args, conf->args)) {
  645. BLog(BLOG_ERROR, "build_arg_list_from_ast_list failed");
  646. goto fail1;
  647. }
  648. return 1;
  649. fail1:
  650. free(s->name);
  651. free(s->method_name);
  652. free(s->object_name);
  653. return 0;
  654. }
  655. void statement_free (struct statement *s)
  656. {
  657. // free arguments
  658. arg_value_free(&s->args);
  659. // free names
  660. free(s->name);
  661. free(s->method_name);
  662. free(s->object_name);
  663. }
  664. int process_new (struct NCDConfig_processes *conf, NCDModuleProcess *module_process, NCDValue args)
  665. {
  666. ASSERT(NCDValue_Type(&args) == NCDVALUE_LIST)
  667. // allocate strucure
  668. struct process *p = malloc(sizeof(*p));
  669. if (!p) {
  670. BLog(BLOG_ERROR, "malloc failed");
  671. goto fail0;
  672. }
  673. // set module process
  674. p->module_process = module_process;
  675. // set module process handlers
  676. if (p->module_process) {
  677. NCDModuleProcess_Interp_SetHandlers(p->module_process, p,
  678. (NCDModuleProcess_interp_func_event)process_moduleprocess_func_event,
  679. (NCDModuleProcess_interp_func_getvar)process_moduleprocess_func_getvar,
  680. (NCDModuleProcess_interp_func_getobj)process_moduleprocess_func_getobj);
  681. }
  682. // set arguments
  683. p->args = args;
  684. // init name
  685. if (!(p->name = strdup(conf->name))) {
  686. BLog(BLOG_ERROR, "strdup failed");
  687. goto fail1;
  688. }
  689. // count statements
  690. size_t num_st = 0;
  691. struct NCDConfig_statements *st = conf->statements;
  692. while (st) {
  693. if (num_st == SIZE_MAX) {
  694. BLog(BLOG_ERROR, "too many statements");
  695. goto fail2;
  696. }
  697. num_st++;
  698. st = st->next;
  699. }
  700. // allocate statements array
  701. if (!(p->statements = BAllocArray(num_st, sizeof(p->statements[0])))) {
  702. goto fail2;
  703. }
  704. p->num_statements = 0;
  705. // init statements
  706. st = conf->statements;
  707. while (st) {
  708. struct process_statement *ps = &p->statements[p->num_statements];
  709. ps->p = p;
  710. ps->i = p->num_statements;
  711. if (!statement_init(&ps->s, st)) {
  712. goto fail3;
  713. }
  714. ps->state = SSTATE_FORGOTTEN;
  715. ps->have_error = 0;
  716. p->num_statements++;
  717. st = st->next;
  718. }
  719. // set state working
  720. p->state = PSTATE_WORKING;
  721. // set AP=0
  722. p->ap = 0;
  723. // set FP=0
  724. p->fp = 0;
  725. // init timer
  726. BTimer_Init(&p->wait_timer, 0, (BTimer_handler)process_wait_timer_handler, p);
  727. // init advance job
  728. BPending_Init(&p->advance_job, BReactor_PendingGroup(&ss), (BPending_handler)process_advance_job_handler, p);
  729. // init work job
  730. BPending_Init(&p->work_job, BReactor_PendingGroup(&ss), (BPending_handler)process_work_job_handler, p);
  731. // insert to processes list
  732. LinkedList2_Append(&processes, &p->list_node);
  733. // schedule work
  734. BPending_Set(&p->work_job);
  735. return 1;
  736. fail3:
  737. process_free_statements(p);
  738. fail2:
  739. free(p->name);
  740. fail1:
  741. free(p);
  742. fail0:
  743. BLog(BLOG_ERROR, "failed to initialize process %s", conf->name);
  744. return 0;
  745. }
  746. void process_free (struct process *p)
  747. {
  748. ASSERT(p->ap == 0)
  749. ASSERT(p->fp == 0)
  750. ASSERT(p->state == PSTATE_TERMINATING)
  751. // inform module process that the process is terminated
  752. if (p->module_process) {
  753. NCDModuleProcess_Interp_Terminated(p->module_process);
  754. }
  755. // remove from processes list
  756. LinkedList2_Remove(&processes, &p->list_node);
  757. // free work job
  758. BPending_Free(&p->work_job);
  759. // free advance job
  760. BPending_Free(&p->advance_job);
  761. // free timer
  762. BReactor_RemoveTimer(&ss, &p->wait_timer);
  763. // free statements
  764. process_free_statements(p);
  765. // free name
  766. free(p->name);
  767. // free arguments
  768. NCDValue_Free(&p->args);
  769. // free strucure
  770. free(p);
  771. }
  772. void process_start_terminating (struct process *p)
  773. {
  774. ASSERT(p->state != PSTATE_TERMINATING)
  775. // set terminating
  776. p->state = PSTATE_TERMINATING;
  777. // schedule work
  778. process_schedule_work(p);
  779. }
  780. size_t process_rap (struct process *p)
  781. {
  782. if (p->ap > 0 && p->statements[p->ap - 1].state == SSTATE_CHILD) {
  783. return (p->ap - 1);
  784. } else {
  785. return p->ap;
  786. }
  787. }
  788. void process_free_statements (struct process *p)
  789. {
  790. // free statments
  791. while (p->num_statements > 0) {
  792. statement_free(&p->statements[p->num_statements - 1].s);
  793. p->num_statements--;
  794. }
  795. // free stataments array
  796. free(p->statements);
  797. }
  798. void process_assert_pointers (struct process *p)
  799. {
  800. ASSERT(p->ap <= p->num_statements)
  801. ASSERT(p->fp >= p->ap)
  802. ASSERT(p->fp <= p->num_statements)
  803. #ifndef NDEBUG
  804. // check AP
  805. for (size_t i = 0; i < p->ap; i++) {
  806. if (i == p->ap - 1) {
  807. ASSERT(p->statements[i].state == SSTATE_ADULT || p->statements[i].state == SSTATE_CHILD)
  808. } else {
  809. ASSERT(p->statements[i].state == SSTATE_ADULT)
  810. }
  811. }
  812. // check FP
  813. size_t fp = p->num_statements;
  814. while (fp > 0 && p->statements[fp - 1].state == SSTATE_FORGOTTEN) {
  815. fp--;
  816. }
  817. ASSERT(p->fp == fp)
  818. #endif
  819. }
  820. void process_logfunc (struct process *p)
  821. {
  822. BLog_Append("process %s: ", p->name);
  823. }
  824. void process_log (struct process *p, int level, const char *fmt, ...)
  825. {
  826. va_list vl;
  827. va_start(vl, fmt);
  828. BLog_LogViaFuncVarArg((BLog_logfunc)process_logfunc, p, BLOG_CURRENT_CHANNEL, level, fmt, vl);
  829. va_end(vl);
  830. }
  831. void process_schedule_work (struct process *p)
  832. {
  833. process_assert_pointers(p);
  834. // stop timer
  835. BReactor_RemoveTimer(&ss, &p->wait_timer);
  836. // stop advance job
  837. BPending_Unset(&p->advance_job);
  838. // schedule work
  839. BPending_Set(&p->work_job);
  840. }
  841. void process_work_job_handler (struct process *p)
  842. {
  843. process_assert_pointers(p);
  844. ASSERT(!BTimer_IsRunning(&p->wait_timer))
  845. ASSERT(!BPending_IsSet(&p->advance_job))
  846. if (p->state == PSTATE_WAITING) {
  847. return;
  848. }
  849. if (p->state == PSTATE_TERMINATING) {
  850. if (p->fp == 0) {
  851. // finished retreating
  852. process_free(p);
  853. // if program is terminating amd there are no more processes, exit program
  854. if (terminating && LinkedList2_IsEmpty(&processes)) {
  855. BReactor_Quit(&ss, 1);
  856. }
  857. return;
  858. }
  859. // order the last living statement to die, if needed
  860. struct process_statement *ps = &p->statements[p->fp - 1];
  861. ASSERT(ps->state != SSTATE_FORGOTTEN)
  862. if (ps->state != SSTATE_DYING) {
  863. process_statement_log(ps, BLOG_INFO, "killing");
  864. // order it to die
  865. NCDModuleInst_Die(&ps->inst);
  866. // set statement state DYING
  867. ps->state = SSTATE_DYING;
  868. // update AP
  869. if (p->ap > ps->i) {
  870. p->ap = ps->i;
  871. }
  872. }
  873. return;
  874. }
  875. // process was up but is no longer?
  876. if (p->state == PSTATE_UP && !(p->ap == process_rap(p) && p->ap == p->num_statements)) {
  877. // if we have module process, wait for its permission to continue
  878. if (p->module_process) {
  879. // set module process down
  880. NCDModuleProcess_Interp_Down(p->module_process);
  881. // set state waiting
  882. p->state = PSTATE_WAITING;
  883. return;
  884. }
  885. // set state working
  886. p->state = PSTATE_WORKING;
  887. }
  888. // cleaning up?
  889. if (p->ap < p->fp) {
  890. // order the last living statement to die, if needed
  891. struct process_statement *ps = &p->statements[p->fp - 1];
  892. if (ps->state != SSTATE_DYING) {
  893. process_statement_log(ps, BLOG_INFO, "killing");
  894. // order it to die
  895. NCDModuleInst_Die(&ps->inst);
  896. // set statement state DYING
  897. ps->state = SSTATE_DYING;
  898. }
  899. return;
  900. }
  901. // clean?
  902. if (p->ap > process_rap(p)) {
  903. ASSERT(p->ap > 0)
  904. ASSERT(p->ap <= p->num_statements)
  905. struct process_statement *ps = &p->statements[p->ap - 1];
  906. ASSERT(ps->state == SSTATE_CHILD)
  907. process_statement_log(ps, BLOG_INFO, "clean");
  908. // report clean
  909. NCDModuleInst_Clean(&ps->inst);
  910. return;
  911. }
  912. // advancing?
  913. if (p->ap < p->num_statements) {
  914. ASSERT(p->state == PSTATE_WORKING)
  915. struct process_statement *ps = &p->statements[p->ap];
  916. ASSERT(ps->state == SSTATE_FORGOTTEN)
  917. // clear expired error
  918. if (ps->have_error && ps->error_until <= btime_gettime()) {
  919. ps->have_error = 0;
  920. }
  921. if (ps->have_error) {
  922. process_statement_log(ps, BLOG_INFO, "waiting after error");
  923. // set wait timer
  924. BReactor_SetTimerAbsolute(&ss, &p->wait_timer, ps->error_until);
  925. } else {
  926. // schedule advance
  927. BPending_Set(&p->advance_job);
  928. }
  929. return;
  930. }
  931. // have we just finished?
  932. if (p->state == PSTATE_WORKING) {
  933. process_log(p, BLOG_INFO, "victory");
  934. // set module process up
  935. if (p->module_process) {
  936. NCDModuleProcess_Interp_Up(p->module_process);
  937. }
  938. // set state up
  939. p->state = PSTATE_UP;
  940. }
  941. }
  942. void process_advance_job_handler (struct process *p)
  943. {
  944. process_assert_pointers(p);
  945. ASSERT(p->ap == p->fp)
  946. ASSERT(p->ap == process_rap(p))
  947. ASSERT(p->ap < p->num_statements)
  948. ASSERT(!p->statements[p->ap].have_error)
  949. ASSERT(!BPending_IsSet(&p->work_job))
  950. ASSERT(!BTimer_IsRunning(&p->wait_timer))
  951. ASSERT(p->state == PSTATE_WORKING)
  952. struct process_statement *ps = &p->statements[p->ap];
  953. ASSERT(ps->state == SSTATE_FORGOTTEN)
  954. process_statement_log(ps, BLOG_INFO, "initializing");
  955. NCDModuleInst *method_object = NULL;
  956. char *type;
  957. // construct type
  958. if (!ps->s.object_name) {
  959. // this is a function_call(); type is "function_call"
  960. if (!(type = strdup(ps->s.method_name))) {
  961. process_statement_log(ps, BLOG_ERROR, "strdup failed");
  962. goto fail0;
  963. }
  964. } else {
  965. // this is a some.object.somewhere->method_call(); type is "base_type(some.object.somewhere)::method_call"
  966. // resolve object
  967. struct process_statement *obj_ps = process_resolve_object(p, p->ap, ps->s.object_name);
  968. if (!obj_ps) {
  969. process_statement_log(ps, BLOG_ERROR, "failed to resolve object %s for method call", ps->s.object_name);
  970. goto fail0;
  971. }
  972. ASSERT(obj_ps->state == SSTATE_ADULT)
  973. // base type defaults to type
  974. const char *base_type = (obj_ps->module->base_type ? obj_ps->module->base_type : obj_ps->module->type);
  975. // build type string
  976. if (!(type = concat_strings(3, base_type, "::", ps->s.method_name))) {
  977. process_statement_log(ps, BLOG_ERROR, "concat_strings failed");
  978. goto fail0;
  979. }
  980. method_object = &obj_ps->inst;
  981. }
  982. // find module to instantiate
  983. if (!(ps->module = NCDModuleIndex_FindModule(&mindex, type))) {
  984. process_statement_log(ps, BLOG_ERROR, "failed to find module: %s", type);
  985. goto fail1;
  986. }
  987. // resolve arguments
  988. if (!process_statement_resolve_argument(ps, &ps->s.args, &ps->inst_args)) {
  989. process_statement_log(ps, BLOG_ERROR, "failed to resolve arguments");
  990. goto fail1;
  991. }
  992. // initialize module instance
  993. NCDModuleInst_Init(
  994. &ps->inst, ps->module, method_object, &ps->inst_args, &ss, &manager, &umanager, ps,
  995. (NCDModuleInst_func_event)process_statement_instance_func_event,
  996. (NCDModuleInst_func_getvar)process_statement_instance_func_getvar,
  997. (NCDModuleInst_func_getobj)process_statement_instance_func_getobj,
  998. (NCDModuleInst_func_initprocess)process_statement_instance_func_initprocess,
  999. (BLog_logfunc)process_statement_instance_logfunc
  1000. );
  1001. // set statement state CHILD
  1002. ps->state = SSTATE_CHILD;
  1003. // increment AP
  1004. p->ap++;
  1005. // increment FP
  1006. p->fp++;
  1007. free(type);
  1008. process_assert_pointers(p);
  1009. return;
  1010. fail1:
  1011. free(type);
  1012. fail0:
  1013. // mark error
  1014. process_statement_set_error(ps);
  1015. // schedule work to start the timer
  1016. process_schedule_work(p);
  1017. }
  1018. void process_wait_timer_handler (struct process *p)
  1019. {
  1020. process_assert_pointers(p);
  1021. ASSERT(p->ap == p->fp)
  1022. ASSERT(p->ap == process_rap(p))
  1023. ASSERT(p->ap < p->num_statements)
  1024. ASSERT(p->statements[p->ap].have_error)
  1025. ASSERT(!BPending_IsSet(&p->work_job))
  1026. ASSERT(!BPending_IsSet(&p->advance_job))
  1027. ASSERT(p->state == PSTATE_WORKING)
  1028. process_log(p, BLOG_INFO, "retrying");
  1029. // clear error
  1030. p->statements[p->ap].have_error = 0;
  1031. // schedule work
  1032. BPending_Set(&p->work_job);
  1033. }
  1034. struct process_statement * process_find_statement (struct process *p, size_t pos, const char *name)
  1035. {
  1036. process_assert_pointers(p);
  1037. ASSERT(pos <= p->num_statements)
  1038. for (size_t i = pos; i > 0; i--) {
  1039. struct process_statement *ps = &p->statements[i - 1];
  1040. if (ps->s.name && !strcmp(ps->s.name, name)) {
  1041. return ps;
  1042. }
  1043. }
  1044. return NULL;
  1045. }
  1046. int process_resolve_name (struct process *p, size_t pos, const char *name, struct process_statement **first_ps, const char **rest)
  1047. {
  1048. process_assert_pointers(p);
  1049. ASSERT(pos <= p->num_statements)
  1050. ASSERT(name)
  1051. char *dot = strstr(name, ".");
  1052. if (!dot) {
  1053. *first_ps = process_find_statement(p, pos, name);
  1054. *rest = NULL;
  1055. } else {
  1056. // copy modname and terminate
  1057. char *modname = malloc((dot - name) + 1);
  1058. if (!modname) {
  1059. process_log(p, BLOG_ERROR, "malloc failed");
  1060. return 0;
  1061. }
  1062. memcpy(modname, name, dot - name);
  1063. modname[dot - name] = '\0';
  1064. *first_ps = process_find_statement(p, pos, modname);
  1065. *rest = dot + 1;
  1066. free(modname);
  1067. }
  1068. return 1;
  1069. }
  1070. int process_resolve_variable (struct process *p, size_t pos, const char *varname, NCDValue *out)
  1071. {
  1072. process_assert_pointers(p);
  1073. ASSERT(pos <= p->num_statements)
  1074. ASSERT(varname)
  1075. // find referred statement and remaining name
  1076. struct process_statement *rps;
  1077. const char *rest;
  1078. if (!process_resolve_name(p, pos, varname, &rps, &rest)) {
  1079. return 0;
  1080. }
  1081. if (!rps) {
  1082. // handle _args
  1083. if (!strcmp(varname, "_args")) {
  1084. if (!NCDValue_InitCopy(out, &p->args)) {
  1085. process_log(p, BLOG_ERROR, "NCDValue_InitCopy failed");
  1086. return 0;
  1087. }
  1088. return 1;
  1089. }
  1090. // handle _argN
  1091. size_t len;
  1092. uintmax_t n;
  1093. if ((len = string_begins_with(varname, "_arg")) && parse_unsigned_integer(varname + len, &n) && n < NCDValue_ListCount(&p->args)) {
  1094. if (!NCDValue_InitCopy(out, NCDValue_ListGet(&p->args, n))) {
  1095. process_log(p, BLOG_ERROR, "NCDValue_InitCopy failed");
  1096. return 0;
  1097. }
  1098. return 1;
  1099. }
  1100. // handle special variables
  1101. if (p->module_process) {
  1102. if (NCDModuleProcess_Interp_GetSpecialVar(p->module_process, varname, out)) {
  1103. return 1;
  1104. }
  1105. }
  1106. process_log(p, BLOG_ERROR, "unknown statement name in variable: %s", varname);
  1107. return 0;
  1108. }
  1109. // must not be forgotten
  1110. if (rps->state == SSTATE_FORGOTTEN) {
  1111. process_log(p, BLOG_ERROR, "referred module is uninitialized and cannot resolve variable: %s", varname);
  1112. return 0;
  1113. }
  1114. // resolve variable in referred statement
  1115. if (!NCDModuleInst_GetVar(&rps->inst, (rest ? rest : ""), out)) {
  1116. process_log(p, BLOG_ERROR, "referred module failed to resolve variable: %s", varname);
  1117. return 0;
  1118. }
  1119. return 1;
  1120. }
  1121. struct process_statement * process_resolve_object (struct process *p, size_t pos, const char *objname)
  1122. {
  1123. process_assert_pointers(p);
  1124. ASSERT(pos <= p->num_statements)
  1125. ASSERT(objname)
  1126. // find referred statement and remaining name
  1127. struct process_statement *rps;
  1128. const char *rest;
  1129. if (!process_resolve_name(p, pos, objname, &rps, &rest)) {
  1130. return NULL;
  1131. }
  1132. if (!rps) {
  1133. // handle special objects
  1134. if (p->module_process) {
  1135. NCDModuleInst *inst = NCDModuleProcess_Interp_GetSpecialObj(p->module_process, objname);
  1136. if (inst) {
  1137. struct process_statement *res_ps = UPPER_OBJECT(inst, struct process_statement, inst);
  1138. ASSERT(res_ps->state == SSTATE_ADULT)
  1139. return res_ps;
  1140. }
  1141. }
  1142. process_log(p, BLOG_ERROR, "unknown statement name in object: %s", objname);
  1143. return NULL;
  1144. }
  1145. // must not be forgotten
  1146. if (rps->state == SSTATE_FORGOTTEN) {
  1147. process_log(p, BLOG_ERROR, "referred module is uninitialized and cannot resolve object: %s", objname);
  1148. return NULL;
  1149. }
  1150. // Resolve object in referred statement. If there is no rest, resolve empty string
  1151. // instead, or use this statement if it fails. This allows a statement to forward method
  1152. // calls elsewhere.
  1153. NCDModuleInst *inst = NCDModuleInst_GetObj(&rps->inst, (rest ? rest : ""));
  1154. if (!inst) {
  1155. if (!rest) {
  1156. return rps;
  1157. }
  1158. process_log(p, BLOG_ERROR, "referred module failed to resolve object: %s", objname);
  1159. return NULL;
  1160. }
  1161. struct process_statement *res_ps = UPPER_OBJECT(inst, struct process_statement, inst);
  1162. ASSERT(res_ps->state == SSTATE_ADULT)
  1163. return res_ps;
  1164. }
  1165. void process_statement_logfunc (struct process_statement *ps)
  1166. {
  1167. process_logfunc(ps->p);
  1168. BLog_Append("statement %zu: ", ps->i);
  1169. }
  1170. void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...)
  1171. {
  1172. va_list vl;
  1173. va_start(vl, fmt);
  1174. BLog_LogViaFuncVarArg((BLog_logfunc)process_statement_logfunc, ps, BLOG_CURRENT_CHANNEL, level, fmt, vl);
  1175. va_end(vl);
  1176. }
  1177. void process_statement_set_error (struct process_statement *ps)
  1178. {
  1179. ASSERT(ps->state == SSTATE_FORGOTTEN)
  1180. ps->have_error = 1;
  1181. ps->error_until = btime_add(btime_gettime(), options.retry_time);
  1182. }
  1183. int process_statement_resolve_argument (struct process_statement *ps, struct arg_value *arg, NCDValue *out)
  1184. {
  1185. ASSERT(ps->i <= process_rap(ps->p))
  1186. switch (arg->type) {
  1187. case ARG_VALUE_TYPE_STRING: {
  1188. if (!NCDValue_InitString(out, arg->string)) {
  1189. process_statement_log(ps, BLOG_ERROR, "NCDValue_InitString failed");
  1190. return 0;
  1191. }
  1192. } break;
  1193. case ARG_VALUE_TYPE_VARIABLE: {
  1194. if (!process_resolve_variable(ps->p, ps->i, arg->variable, out)) {
  1195. process_statement_log(ps, BLOG_ERROR, "failed to resolve variable");
  1196. return 0;
  1197. }
  1198. } break;
  1199. case ARG_VALUE_TYPE_LIST: do {
  1200. NCDValue_InitList(out);
  1201. for (LinkedList1Node *n = LinkedList1_GetFirst(&arg->list); n; n = LinkedList1Node_Next(n)) {
  1202. struct arg_list_elem *elem = UPPER_OBJECT(n, struct arg_list_elem, list_node);
  1203. NCDValue v;
  1204. if (!process_statement_resolve_argument(ps, &elem->value, &v)) {
  1205. goto list_fail1;
  1206. }
  1207. if (!NCDValue_ListAppend(out, v)) {
  1208. process_statement_log(ps, BLOG_ERROR, "NCDValue_ListAppend failed");
  1209. NCDValue_Free(&v);
  1210. goto list_fail1;
  1211. }
  1212. }
  1213. break;
  1214. list_fail1:
  1215. NCDValue_Free(out);
  1216. return 0;
  1217. } while (0); break;
  1218. default: ASSERT(0);
  1219. }
  1220. return 1;
  1221. }
  1222. void process_statement_instance_func_event (struct process_statement *ps, int event)
  1223. {
  1224. ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT || ps->state == SSTATE_DYING)
  1225. struct process *p = ps->p;
  1226. process_assert_pointers(p);
  1227. // schedule work
  1228. process_schedule_work(p);
  1229. switch (event) {
  1230. case NCDMODULE_EVENT_UP: {
  1231. ASSERT(ps->state == SSTATE_CHILD)
  1232. process_statement_log(ps, BLOG_INFO, "up");
  1233. // set state ADULT
  1234. ps->state = SSTATE_ADULT;
  1235. } break;
  1236. case NCDMODULE_EVENT_DOWN: {
  1237. ASSERT(ps->state == SSTATE_ADULT)
  1238. process_statement_log(ps, BLOG_INFO, "down");
  1239. // set state CHILD
  1240. ps->state = SSTATE_CHILD;
  1241. // update AP
  1242. if (p->ap > ps->i + 1) {
  1243. p->ap = ps->i + 1;
  1244. }
  1245. } break;
  1246. case NCDMODULE_EVENT_DEAD: {
  1247. int is_error = NCDModuleInst_HaveError(&ps->inst);
  1248. if (is_error) {
  1249. process_statement_log(ps, BLOG_ERROR, "died with error");
  1250. } else {
  1251. process_statement_log(ps, BLOG_INFO, "died");
  1252. }
  1253. // free instance
  1254. NCDModuleInst_Free(&ps->inst);
  1255. // free instance arguments
  1256. NCDValue_Free(&ps->inst_args);
  1257. // set state FORGOTTEN
  1258. ps->state = SSTATE_FORGOTTEN;
  1259. // set error
  1260. if (is_error) {
  1261. process_statement_set_error(ps);
  1262. }
  1263. // update AP
  1264. if (p->ap > ps->i) {
  1265. p->ap = ps->i;
  1266. }
  1267. // update FP
  1268. while (p->fp > 0 && p->statements[p->fp - 1].state == SSTATE_FORGOTTEN) {
  1269. p->fp--;
  1270. }
  1271. } break;
  1272. }
  1273. }
  1274. int process_statement_instance_func_getvar (struct process_statement *ps, const char *varname, NCDValue *out)
  1275. {
  1276. ASSERT(ps->state != SSTATE_FORGOTTEN)
  1277. return process_resolve_variable(ps->p, ps->i, varname, out);
  1278. }
  1279. NCDModuleInst * process_statement_instance_func_getobj (struct process_statement *ps, const char *objname)
  1280. {
  1281. ASSERT(ps->state != SSTATE_FORGOTTEN)
  1282. struct process_statement *rps = process_resolve_object(ps->p, ps->i, objname);
  1283. if (!rps) {
  1284. return NULL;
  1285. }
  1286. return &rps->inst;
  1287. }
  1288. int process_statement_instance_func_initprocess (struct process_statement *ps, NCDModuleProcess *mp, const char *template_name, NCDValue args)
  1289. {
  1290. ASSERT(ps->state != SSTATE_FORGOTTEN)
  1291. ASSERT(NCDValue_Type(&args) == NCDVALUE_LIST)
  1292. // find template
  1293. struct NCDConfig_processes *conf = config_ast;
  1294. while (conf) {
  1295. if (conf->is_template && !strcmp(conf->name, template_name)) {
  1296. break;
  1297. }
  1298. conf = conf->next;
  1299. }
  1300. if (!conf) {
  1301. process_statement_log(ps, BLOG_ERROR, "no template named %s", template_name);
  1302. return 0;
  1303. }
  1304. // create process
  1305. if (!process_new(conf, mp, args)) {
  1306. process_statement_log(ps, BLOG_ERROR, "failed to create process from template %s", template_name);
  1307. return 0;
  1308. }
  1309. process_statement_log(ps, BLOG_INFO, "created process from template %s", template_name);
  1310. return 1;
  1311. }
  1312. void process_statement_instance_logfunc (struct process_statement *ps)
  1313. {
  1314. ASSERT(ps->state != SSTATE_FORGOTTEN)
  1315. process_statement_logfunc(ps);
  1316. BLog_Append("module: ");
  1317. }
  1318. void process_moduleprocess_func_event (struct process *p, int event)
  1319. {
  1320. ASSERT(p->module_process)
  1321. switch (event) {
  1322. case NCDMODULEPROCESS_INTERP_EVENT_CONTINUE: {
  1323. ASSERT(p->state == PSTATE_WAITING)
  1324. // set state working
  1325. p->state = PSTATE_WORKING;
  1326. // schedule work
  1327. process_schedule_work(p);
  1328. } break;
  1329. case NCDMODULEPROCESS_INTERP_EVENT_TERMINATE: {
  1330. ASSERT(p->state != PSTATE_TERMINATING)
  1331. process_log(p, BLOG_INFO, "process termination requested");
  1332. // start terminating
  1333. process_start_terminating(p);
  1334. } break;
  1335. default: ASSERT(0);
  1336. }
  1337. }
  1338. int process_moduleprocess_func_getvar (struct process *p, const char *name, NCDValue *out)
  1339. {
  1340. ASSERT(p->module_process)
  1341. return process_resolve_variable(p, p->num_statements, name, out);
  1342. }
  1343. NCDModuleInst * process_moduleprocess_func_getobj (struct process *p, const char *name)
  1344. {
  1345. ASSERT(p->module_process)
  1346. struct process_statement *rps = process_resolve_object(p, p->num_statements, name);
  1347. if (!rps) {
  1348. return NULL;
  1349. }
  1350. return &rps->inst;
  1351. }