|
|
@@ -22,7 +22,6 @@
|
|
|
|
|
|
#include <stdint.h>
|
|
|
#include <stdio.h>
|
|
|
-#include <stddef.h>
|
|
|
#include <string.h>
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
@@ -84,6 +83,7 @@ struct process {
|
|
|
size_t fp;
|
|
|
BTimer wait_timer;
|
|
|
BPending advance_job;
|
|
|
+ BPending work_job;
|
|
|
LinkedList2Node list_node; // node in processes
|
|
|
};
|
|
|
|
|
|
@@ -111,6 +111,7 @@ struct {
|
|
|
int loglevel;
|
|
|
int loglevels[BLOG_NUM_CHANNELS];
|
|
|
char *config_file;
|
|
|
+ int retry_time;
|
|
|
} options;
|
|
|
|
|
|
// reactor
|
|
|
@@ -122,25 +123,12 @@ int terminating;
|
|
|
// process manager
|
|
|
BProcessManager manager;
|
|
|
|
|
|
-// configuration
|
|
|
-struct NCDConfig_interfaces *configuration;
|
|
|
+// config AST
|
|
|
+struct NCDConfig_interfaces *config_ast;
|
|
|
|
|
|
// processes
|
|
|
LinkedList2 processes;
|
|
|
|
|
|
-// job for initializing processes
|
|
|
-BPending init_job;
|
|
|
-
|
|
|
-// next process for init job
|
|
|
-struct NCDConfig_interfaces *init_next;
|
|
|
-
|
|
|
-// job for initiating shutdown of processes
|
|
|
-BPending free_job;
|
|
|
-
|
|
|
-// process iterator for free job
|
|
|
-LinkedList2Iterator free_it;
|
|
|
-
|
|
|
-static void terminate (void);
|
|
|
static void print_help (const char *name);
|
|
|
static void print_version (void);
|
|
|
static int parse_arguments (int argc, char *argv[]);
|
|
|
@@ -155,18 +143,15 @@ static void process_free_statements (struct process *p);
|
|
|
static size_t process_rap (struct process *p);
|
|
|
static void process_assert_pointers (struct process *p);
|
|
|
static void process_log (struct process *p, int level, const char *fmt, ...);
|
|
|
-static void process_work (struct process *p);
|
|
|
+static void process_schedule_work (struct process *p);
|
|
|
+static void process_work_job_handler (struct process *p);
|
|
|
static void process_advance_job_handler (struct process *p);
|
|
|
-static void process_advance (struct process *p);
|
|
|
-static void process_wait (struct process *p);
|
|
|
static void process_wait_timer_handler (struct process *p);
|
|
|
static int process_resolve_variable (struct process *p, size_t pos, const char *modname, const char *varname, NCDValue *out);
|
|
|
static void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...);
|
|
|
static void process_statement_set_error (struct process_statement *ps);
|
|
|
static void process_statement_instance_handler_event (struct process_statement *ps, int event);
|
|
|
-static void process_statement_instance_handler_died (struct process_statement *ps, int is_error);
|
|
|
static int process_statement_instance_handler_getvar (struct process_statement *ps, const char *modname, const char *varname, NCDValue *out);
|
|
|
-static void init_job_handler (void *unused);
|
|
|
static void free_job_handler (void *unused);
|
|
|
|
|
|
int main (int argc, char **argv)
|
|
|
@@ -261,7 +246,7 @@ int main (int argc, char **argv)
|
|
|
}
|
|
|
|
|
|
// parse config file
|
|
|
- if (!NCDConfigParser_Parse((char *)file, file_len, &configuration)) {
|
|
|
+ if (!NCDConfigParser_Parse((char *)file, file_len, &config_ast)) {
|
|
|
BLog(BLOG_ERROR, "NCDConfigParser_Parse failed");
|
|
|
free(file);
|
|
|
goto fail3;
|
|
|
@@ -271,10 +256,9 @@ int main (int argc, char **argv)
|
|
|
free(file);
|
|
|
|
|
|
// init module params
|
|
|
- struct NCDModuleInitParams params = {
|
|
|
- .reactor = &ss,
|
|
|
- .manager = &manager
|
|
|
- };
|
|
|
+ struct NCDModuleInitParams params;
|
|
|
+ params.reactor = &ss;
|
|
|
+ params.manager = &manager;
|
|
|
|
|
|
// init modules
|
|
|
size_t num_inited_modules = 0;
|
|
|
@@ -289,15 +273,12 @@ int main (int argc, char **argv)
|
|
|
// init processes list
|
|
|
LinkedList2_Init(&processes);
|
|
|
|
|
|
- // init init job
|
|
|
- BPending_Init(&init_job, BReactor_PendingGroup(&ss), init_job_handler, NULL);
|
|
|
-
|
|
|
- // init free job
|
|
|
- BPending_Init(&free_job, BReactor_PendingGroup(&ss), free_job_handler, NULL);
|
|
|
-
|
|
|
- // start initializing processes
|
|
|
- init_next = configuration;
|
|
|
- BPending_Set(&init_job);
|
|
|
+ // init processes
|
|
|
+ struct NCDConfig_interfaces *conf = config_ast;
|
|
|
+ while (conf) {
|
|
|
+ process_new(conf);
|
|
|
+ conf = conf->next;
|
|
|
+ }
|
|
|
|
|
|
// enter event loop
|
|
|
BLog(BLOG_NOTICE, "entering event loop");
|
|
|
@@ -309,12 +290,6 @@ int main (int argc, char **argv)
|
|
|
struct process *p = UPPER_OBJECT(n, struct process, list_node);
|
|
|
process_free(p);
|
|
|
}
|
|
|
-
|
|
|
- // free free job
|
|
|
- BPending_Free(&free_job);
|
|
|
-
|
|
|
- // free init job
|
|
|
- BPending_Free(&init_job);
|
|
|
fail5:
|
|
|
// free modules
|
|
|
while (num_inited_modules > 0) {
|
|
|
@@ -325,7 +300,7 @@ fail5:
|
|
|
num_inited_modules--;
|
|
|
}
|
|
|
// free configuration
|
|
|
- NCDConfig_free_interfaces(configuration);
|
|
|
+ NCDConfig_free_interfaces(config_ast);
|
|
|
fail3:
|
|
|
// remove signal handler
|
|
|
BSignal_Finish();
|
|
|
@@ -346,24 +321,6 @@ fail0:
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-void terminate (void)
|
|
|
-{
|
|
|
- ASSERT(!terminating)
|
|
|
-
|
|
|
- BLog(BLOG_NOTICE, "tearing down");
|
|
|
-
|
|
|
- terminating = 1;
|
|
|
-
|
|
|
- if (LinkedList2_IsEmpty(&processes)) {
|
|
|
- BReactor_Quit(&ss, 1);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // start free job
|
|
|
- LinkedList2Iterator_InitForward(&free_it, &processes);
|
|
|
- BPending_Set(&free_job);
|
|
|
-}
|
|
|
-
|
|
|
void print_help (const char *name)
|
|
|
{
|
|
|
printf(
|
|
|
@@ -380,7 +337,8 @@ void print_help (const char *name)
|
|
|
#endif
|
|
|
" [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
|
|
|
" [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
|
|
|
- " --config-file <file>\n",
|
|
|
+ " --config-file <file>\n"
|
|
|
+ " [--retry-time <ms>]\n",
|
|
|
name
|
|
|
);
|
|
|
}
|
|
|
@@ -408,6 +366,7 @@ int parse_arguments (int argc, char *argv[])
|
|
|
options.loglevels[i] = -1;
|
|
|
}
|
|
|
options.config_file = NULL;
|
|
|
+ options.retry_time = DEFAULT_RETRY_TIME;
|
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
char *arg = argv[i];
|
|
|
@@ -492,6 +451,17 @@ int parse_arguments (int argc, char *argv[])
|
|
|
options.config_file = argv[i + 1];
|
|
|
i++;
|
|
|
}
|
|
|
+ else if (!strcmp(arg, "--retry-time")) {
|
|
|
+ if (1 >= argc - i) {
|
|
|
+ fprintf(stderr, "%s: requires an argument\n", arg);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if ((options.retry_time = atoi(argv[i + 1])) < 0) {
|
|
|
+ fprintf(stderr, "%s: wrong argument\n", arg);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ }
|
|
|
else {
|
|
|
fprintf(stderr, "unknown option: %s\n", arg);
|
|
|
return 0;
|
|
|
@@ -514,8 +484,24 @@ void signal_handler (void *unused)
|
|
|
{
|
|
|
BLog(BLOG_NOTICE, "termination requested");
|
|
|
|
|
|
- if (!terminating) {
|
|
|
- terminate();
|
|
|
+ if (terminating) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ terminating = 1;
|
|
|
+
|
|
|
+ if (LinkedList2_IsEmpty(&processes)) {
|
|
|
+ BReactor_Quit(&ss, 1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // schedule work for all processes
|
|
|
+ LinkedList2Iterator it;
|
|
|
+ LinkedList2Iterator_InitForward(&it, &processes);
|
|
|
+ LinkedList2Node *n;
|
|
|
+ while (n = LinkedList2Iterator_Next(&it)) {
|
|
|
+ struct process *p = UPPER_OBJECT(n, struct process, list_node);
|
|
|
+ process_schedule_work(p);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -537,6 +523,7 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
|
|
|
// find module
|
|
|
char *module_name = NCDConfig_concat_strings(conf->names);
|
|
|
if (!module_name) {
|
|
|
+ BLog(BLOG_ERROR, "NCDConfig_concat_strings failed");
|
|
|
goto fail0;
|
|
|
}
|
|
|
const struct NCDModule *m = find_module(module_name);
|
|
|
@@ -557,14 +544,15 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
|
|
|
while (arg) {
|
|
|
struct argument_elem *e = malloc(sizeof(*e));
|
|
|
if (!e) {
|
|
|
- goto fail1;
|
|
|
+ BLog(BLOG_ERROR, "malloc failed");
|
|
|
+ goto loop_fail0;
|
|
|
}
|
|
|
|
|
|
switch (arg->type) {
|
|
|
case NCDCONFIG_ARG_STRING: {
|
|
|
if (!NCDValue_InitString(&e->val, arg->string)) {
|
|
|
- free(e);
|
|
|
- goto fail1;
|
|
|
+ BLog(BLOG_ERROR, "NCDValue_InitString failed");
|
|
|
+ goto loop_fail1;
|
|
|
}
|
|
|
|
|
|
e->is_var = 0;
|
|
|
@@ -572,18 +560,14 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
|
|
|
|
|
|
case NCDCONFIG_ARG_VAR: {
|
|
|
if (!(e->var.modname = strdup(arg->var->value))) {
|
|
|
- free(e);
|
|
|
- goto fail1;
|
|
|
+ BLog(BLOG_ERROR, "strdup failed");
|
|
|
+ goto loop_fail1;
|
|
|
}
|
|
|
|
|
|
- if (!arg->var->next) {
|
|
|
- e->var.varname = NULL;
|
|
|
- } else {
|
|
|
- if (!(e->var.varname = NCDConfig_concat_strings(arg->var->next))) {
|
|
|
- free(e->var.modname);
|
|
|
- free(e);
|
|
|
- goto fail1;
|
|
|
- }
|
|
|
+ if (!(e->var.varname = (arg->var->next ? NCDConfig_concat_strings(arg->var->next) : strdup("")))) {
|
|
|
+ BLog(BLOG_ERROR, "NCDConfig_concat_strings/strdup failed");
|
|
|
+ free(e->var.modname);
|
|
|
+ goto loop_fail1;
|
|
|
}
|
|
|
|
|
|
e->is_var = 1;
|
|
|
@@ -598,6 +582,12 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
|
|
|
prevptr = &e->next_arg;
|
|
|
|
|
|
arg = arg->next;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ loop_fail1:
|
|
|
+ free(e);
|
|
|
+ loop_fail0:
|
|
|
+ goto fail1;
|
|
|
}
|
|
|
|
|
|
// init name
|
|
|
@@ -605,6 +595,7 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
|
|
|
s->name = NULL;
|
|
|
} else {
|
|
|
if (!(s->name = strdup(conf->name))) {
|
|
|
+ BLog(BLOG_ERROR, "strdup failed");
|
|
|
goto fail1;
|
|
|
}
|
|
|
}
|
|
|
@@ -647,11 +638,13 @@ int process_new (struct NCDConfig_interfaces *conf)
|
|
|
// allocate strucure
|
|
|
struct process *p = malloc(sizeof(*p));
|
|
|
if (!p) {
|
|
|
+ BLog(BLOG_ERROR, "malloc failed");
|
|
|
goto fail0;
|
|
|
}
|
|
|
|
|
|
// init name
|
|
|
if (!(p->name = strdup(conf->name))) {
|
|
|
+ BLog(BLOG_ERROR, "strdup failed");
|
|
|
goto fail1;
|
|
|
}
|
|
|
|
|
|
@@ -659,11 +652,15 @@ int process_new (struct NCDConfig_interfaces *conf)
|
|
|
size_t num_st = 0;
|
|
|
struct NCDConfig_statements *st = conf->statements;
|
|
|
while (st) {
|
|
|
+ if (num_st == SIZE_MAX) {
|
|
|
+ BLog(BLOG_ERROR, "too many statements");
|
|
|
+ goto fail2;
|
|
|
+ }
|
|
|
num_st++;
|
|
|
st = st->next;
|
|
|
}
|
|
|
|
|
|
- // statements array
|
|
|
+ // allocate statements array
|
|
|
if (!(p->statements = BAllocArray(num_st, sizeof(p->statements[0])))) {
|
|
|
goto fail2;
|
|
|
}
|
|
|
@@ -697,15 +694,19 @@ int process_new (struct NCDConfig_interfaces *conf)
|
|
|
p->fp = 0;
|
|
|
|
|
|
// init timer
|
|
|
- BTimer_Init(&p->wait_timer, RETRY_TIME, (BTimer_handler)process_wait_timer_handler, p);
|
|
|
+ BTimer_Init(&p->wait_timer, 0, (BTimer_handler)process_wait_timer_handler, p);
|
|
|
|
|
|
// init advance job
|
|
|
BPending_Init(&p->advance_job, BReactor_PendingGroup(&ss), (BPending_handler)process_advance_job_handler, p);
|
|
|
|
|
|
+ // init work job
|
|
|
+ BPending_Init(&p->work_job, BReactor_PendingGroup(&ss), (BPending_handler)process_work_job_handler, p);
|
|
|
+
|
|
|
// insert to processes list
|
|
|
LinkedList2_Append(&processes, &p->list_node);
|
|
|
|
|
|
- process_work(p);
|
|
|
+ // schedule work
|
|
|
+ BPending_Set(&p->work_job);
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
@@ -716,6 +717,7 @@ fail2:
|
|
|
fail1:
|
|
|
free(p);
|
|
|
fail0:
|
|
|
+ BLog(BLOG_ERROR, "failed to initialize process %s", conf->name);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -727,6 +729,9 @@ void process_free (struct process *p)
|
|
|
// remove from processes list
|
|
|
LinkedList2_Remove(&processes, &p->list_node);
|
|
|
|
|
|
+ // free work job
|
|
|
+ BPending_Free(&p->work_job);
|
|
|
+
|
|
|
// free advance job
|
|
|
BPending_Free(&p->advance_job);
|
|
|
|
|
|
@@ -755,9 +760,9 @@ size_t process_rap (struct process *p)
|
|
|
void process_free_statements (struct process *p)
|
|
|
{
|
|
|
// free statments
|
|
|
- for (size_t i = 0; i < p->num_statements; i++) {
|
|
|
- struct process_statement *ps = &p->statements[i];
|
|
|
- statement_free(&ps->s);
|
|
|
+ while (p->num_statements > 0) {
|
|
|
+ statement_free(&p->statements[p->num_statements - 1].s);
|
|
|
+ p->num_statements--;
|
|
|
}
|
|
|
|
|
|
// free stataments array
|
|
|
@@ -796,16 +801,26 @@ void process_log (struct process *p, int level, const char *fmt, ...)
|
|
|
va_end(vl);
|
|
|
}
|
|
|
|
|
|
-void process_work (struct process *p)
|
|
|
+void process_schedule_work (struct process *p)
|
|
|
{
|
|
|
process_assert_pointers(p);
|
|
|
|
|
|
- // stop timer in case we were WAITING
|
|
|
+ // stop timer
|
|
|
BReactor_RemoveTimer(&ss, &p->wait_timer);
|
|
|
|
|
|
- // stop advance job (if we need to advance, we will re-schedule it)
|
|
|
+ // stop advance job
|
|
|
BPending_Unset(&p->advance_job);
|
|
|
|
|
|
+ // schedule work
|
|
|
+ BPending_Set(&p->work_job);
|
|
|
+}
|
|
|
+
|
|
|
+void process_work_job_handler (struct process *p)
|
|
|
+{
|
|
|
+ process_assert_pointers(p);
|
|
|
+ ASSERT(!BTimer_IsRunning(&p->wait_timer))
|
|
|
+ ASSERT(!BPending_IsSet(&p->advance_job))
|
|
|
+
|
|
|
if (terminating) {
|
|
|
if (p->fp == 0) {
|
|
|
// finished retreating
|
|
|
@@ -815,41 +830,65 @@ void process_work (struct process *p)
|
|
|
if (LinkedList2_IsEmpty(&processes)) {
|
|
|
BReactor_Quit(&ss, 1);
|
|
|
}
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // order the last living statement to die, if needed
|
|
|
- struct process_statement *ps = &p->statements[p->fp - 1];
|
|
|
- if (ps->state != SSTATE_DYING) {
|
|
|
- process_statement_log(ps, BLOG_INFO, "killing");
|
|
|
-
|
|
|
- // order it to die
|
|
|
- NCDModuleInst_Event(&ps->inst, NCDMODULE_TOEVENT_DIE);
|
|
|
-
|
|
|
- // set statement state DYING
|
|
|
- ps->state = SSTATE_DYING;
|
|
|
-
|
|
|
- // update AP
|
|
|
- if (p->ap > ps->i) {
|
|
|
- p->ap = ps->i;
|
|
|
+ } else {
|
|
|
+ // order the last living statement to die, if needed
|
|
|
+ struct process_statement *ps = &p->statements[p->fp - 1];
|
|
|
+ ASSERT(ps->state != SSTATE_FORGOTTEN)
|
|
|
+ if (ps->state != SSTATE_DYING) {
|
|
|
+ process_statement_log(ps, BLOG_INFO, "killing");
|
|
|
+
|
|
|
+ // order it to die
|
|
|
+ NCDModuleInst_Event(&ps->inst, NCDMODULE_TOEVENT_DIE);
|
|
|
+
|
|
|
+ // set statement state DYING
|
|
|
+ ps->state = SSTATE_DYING;
|
|
|
+
|
|
|
+ // update AP
|
|
|
+ if (p->ap > ps->i) {
|
|
|
+ p->ap = ps->i;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ process_assert_pointers(p);
|
|
|
}
|
|
|
|
|
|
- process_assert_pointers(p);
|
|
|
-
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (p->ap == p->fp) {
|
|
|
- // schedule advance
|
|
|
- if (!(p->ap > 0 && p->statements[p->ap - 1].state == SSTATE_CHILD)) {
|
|
|
- BPending_Set(&p->advance_job);
|
|
|
- }
|
|
|
-
|
|
|
- // report clean
|
|
|
- if (p->ap > 0) {
|
|
|
- NCDModuleInst_Event(&p->statements[p->ap - 1].inst, NCDMODULE_TOEVENT_CLEAN);
|
|
|
+ if (p->ap == process_rap(p)) {
|
|
|
+ if (p->ap == p->num_statements) {
|
|
|
+ // all statements are up
|
|
|
+ process_log(p, BLOG_INFO, "victory");
|
|
|
+ } else {
|
|
|
+ struct process_statement *ps = &p->statements[p->ap];
|
|
|
+ ASSERT(ps->state == SSTATE_FORGOTTEN)
|
|
|
+
|
|
|
+ // clear expired error
|
|
|
+ if (ps->have_error && ps->error_until <= btime_gettime()) {
|
|
|
+ ps->have_error = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ps->have_error) {
|
|
|
+ // next statement has error, wait
|
|
|
+ process_statement_log(ps, BLOG_INFO, "waiting after error");
|
|
|
+ BReactor_SetTimerAbsolute(&ss, &p->wait_timer, ps->error_until);
|
|
|
+ } else {
|
|
|
+ // schedule advance
|
|
|
+ BPending_Set(&p->advance_job);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ASSERT(p->ap > 0)
|
|
|
+ ASSERT(p->ap <= p->num_statements)
|
|
|
+
|
|
|
+ struct process_statement *ps = &p->statements[p->ap - 1];
|
|
|
+ ASSERT(ps->state == SSTATE_CHILD)
|
|
|
+
|
|
|
+ process_statement_log(ps, BLOG_INFO, "clean");
|
|
|
+
|
|
|
+ // report clean
|
|
|
+ NCDModuleInst_Event(&ps->inst, NCDMODULE_TOEVENT_CLEAN);
|
|
|
}
|
|
|
} else {
|
|
|
// order the last living statement to die, if needed
|
|
|
@@ -870,33 +909,17 @@ void process_work (struct process *p)
|
|
|
|
|
|
void process_advance_job_handler (struct process *p)
|
|
|
{
|
|
|
- ASSERT(p->ap == p->fp)
|
|
|
- ASSERT(!(p->ap > 0 && p->statements[p->ap - 1].state == SSTATE_CHILD))
|
|
|
- ASSERT(!terminating)
|
|
|
-
|
|
|
- // advance
|
|
|
- process_advance(p);
|
|
|
-}
|
|
|
-
|
|
|
-void process_advance (struct process *p)
|
|
|
-{
|
|
|
+ process_assert_pointers(p);
|
|
|
ASSERT(p->ap == p->fp)
|
|
|
ASSERT(p->ap == process_rap(p))
|
|
|
-
|
|
|
- if (p->ap == p->num_statements) {
|
|
|
- process_log(p, BLOG_INFO, "victory");
|
|
|
-
|
|
|
- process_assert_pointers(p);
|
|
|
- return;
|
|
|
- }
|
|
|
+ ASSERT(p->ap < p->num_statements)
|
|
|
+ ASSERT(!p->statements[p->ap].have_error)
|
|
|
+ ASSERT(!BPending_IsSet(&p->work_job))
|
|
|
+ ASSERT(!BTimer_IsRunning(&p->wait_timer))
|
|
|
+ ASSERT(!terminating)
|
|
|
|
|
|
struct process_statement *ps = &p->statements[p->ap];
|
|
|
-
|
|
|
- // check if we need to wait
|
|
|
- if (ps->have_error && ps->error_until > btime_gettime()) {
|
|
|
- process_wait(p);
|
|
|
- return;
|
|
|
- }
|
|
|
+ ASSERT(ps->state == SSTATE_FORGOTTEN)
|
|
|
|
|
|
process_statement_log(ps, BLOG_INFO, "initializing");
|
|
|
|
|
|
@@ -906,12 +929,10 @@ void process_advance (struct process *p)
|
|
|
// build arguments
|
|
|
struct argument_elem *arg = ps->s.first_arg;
|
|
|
while (arg) {
|
|
|
+ // resolve argument
|
|
|
NCDValue v;
|
|
|
-
|
|
|
if (arg->is_var) {
|
|
|
- const char *real_varname = (arg->var.varname ? arg->var.varname : "");
|
|
|
-
|
|
|
- if (!process_resolve_variable(p, p->ap, arg->var.modname, real_varname, &v)) {
|
|
|
+ if (!process_resolve_variable(p, p->ap, arg->var.modname, arg->var.varname, &v)) {
|
|
|
process_statement_log(ps, BLOG_ERROR, "failed to resolve variable");
|
|
|
goto fail1;
|
|
|
}
|
|
|
@@ -936,16 +957,12 @@ void process_advance (struct process *p)
|
|
|
snprintf(ps->logprefix, sizeof(ps->logprefix), "process %s: statement %zu: module: ", p->name, ps->i);
|
|
|
|
|
|
// initialize module instance
|
|
|
- if (!NCDModuleInst_Init(
|
|
|
- &ps->inst, ps->s.name, ps->s.module, &ps->inst_args, ps->logprefix, &ss, &manager,
|
|
|
+ NCDModuleInst_Init(
|
|
|
+ &ps->inst, ps->s.module, &ps->inst_args, ps->logprefix, &ss, &manager,
|
|
|
(NCDModule_handler_event)process_statement_instance_handler_event,
|
|
|
- (NCDModule_handler_died)process_statement_instance_handler_died,
|
|
|
(NCDModule_handler_getvar)process_statement_instance_handler_getvar,
|
|
|
ps
|
|
|
- )) {
|
|
|
- process_statement_log(ps, BLOG_ERROR, "failed to initialize");
|
|
|
- goto fail1;
|
|
|
- }
|
|
|
+ );
|
|
|
|
|
|
// set statement state CHILD
|
|
|
ps->state = SSTATE_CHILD;
|
|
|
@@ -957,62 +974,56 @@ void process_advance (struct process *p)
|
|
|
p->fp++;
|
|
|
|
|
|
process_assert_pointers(p);
|
|
|
-
|
|
|
return;
|
|
|
|
|
|
fail1:
|
|
|
NCDValue_Free(&ps->inst_args);
|
|
|
- process_statement_set_error(ps);
|
|
|
- process_wait(p);
|
|
|
-}
|
|
|
-
|
|
|
-void process_wait (struct process *p)
|
|
|
-{
|
|
|
- ASSERT(p->ap == p->fp)
|
|
|
- ASSERT(p->ap == process_rap(p))
|
|
|
- ASSERT(p->ap < p->num_statements)
|
|
|
- ASSERT(p->statements[p->ap].have_error)
|
|
|
-
|
|
|
- process_statement_log(&p->statements[p->ap], BLOG_INFO, "waiting after error");
|
|
|
|
|
|
- // set timer
|
|
|
- BReactor_SetTimerAbsolute(&ss, &p->wait_timer, p->statements[p->ap].error_until);
|
|
|
+ // mark error
|
|
|
+ process_statement_set_error(ps);
|
|
|
|
|
|
- process_assert_pointers(p);
|
|
|
+ // schedule work to start the timer
|
|
|
+ BPending_Set(&p->work_job);
|
|
|
}
|
|
|
|
|
|
void process_wait_timer_handler (struct process *p)
|
|
|
{
|
|
|
+ process_assert_pointers(p);
|
|
|
ASSERT(p->ap == p->fp)
|
|
|
ASSERT(p->ap == process_rap(p))
|
|
|
ASSERT(p->ap < p->num_statements)
|
|
|
ASSERT(p->statements[p->ap].have_error)
|
|
|
+ ASSERT(!BPending_IsSet(&p->work_job))
|
|
|
+ ASSERT(!BPending_IsSet(&p->advance_job))
|
|
|
+ ASSERT(!terminating)
|
|
|
|
|
|
process_log(p, BLOG_INFO, "retrying");
|
|
|
|
|
|
// clear error
|
|
|
p->statements[p->ap].have_error = 0;
|
|
|
|
|
|
- process_advance(p);
|
|
|
+ // schedule work
|
|
|
+ BPending_Set(&p->work_job);
|
|
|
}
|
|
|
|
|
|
int process_resolve_variable (struct process *p, size_t pos, const char *modname, const char *varname, NCDValue *out)
|
|
|
{
|
|
|
+ process_assert_pointers(p);
|
|
|
ASSERT(pos >= 0)
|
|
|
ASSERT(pos <= process_rap(p))
|
|
|
ASSERT(modname)
|
|
|
ASSERT(varname)
|
|
|
|
|
|
// find referred-to statement
|
|
|
- struct process_statement *rps;
|
|
|
- size_t i;
|
|
|
- for (i = pos; i > 0; i--) {
|
|
|
- rps = &p->statements[i - 1];
|
|
|
- if (rps->s.name && !strcmp(rps->s.name, modname)) {
|
|
|
+ struct process_statement *rps = NULL;
|
|
|
+ for (size_t i = pos; i > 0; i--) {
|
|
|
+ struct process_statement *ps = &p->statements[i - 1];
|
|
|
+ if (ps->s.name && !strcmp(ps->s.name, modname)) {
|
|
|
+ rps = ps;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- if (i == 0) {
|
|
|
+ if (!rps) {
|
|
|
process_log(p, BLOG_ERROR, "unknown statement name in variable: %s.%s", modname, varname);
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -1041,14 +1052,18 @@ void process_statement_set_error (struct process_statement *ps)
|
|
|
ASSERT(ps->state == SSTATE_FORGOTTEN)
|
|
|
|
|
|
ps->have_error = 1;
|
|
|
- ps->error_until = btime_gettime() + RETRY_TIME;
|
|
|
+ ps->error_until = btime_add(btime_gettime(), options.retry_time);
|
|
|
}
|
|
|
|
|
|
void process_statement_instance_handler_event (struct process_statement *ps, int event)
|
|
|
{
|
|
|
- ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT)
|
|
|
+ ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT || ps->state == SSTATE_DYING)
|
|
|
|
|
|
struct process *p = ps->p;
|
|
|
+ process_assert_pointers(p);
|
|
|
+
|
|
|
+ // schedule work
|
|
|
+ process_schedule_work(p);
|
|
|
|
|
|
switch (event) {
|
|
|
case NCDMODULE_EVENT_UP: {
|
|
|
@@ -1073,56 +1088,47 @@ void process_statement_instance_handler_event (struct process_statement *ps, int
|
|
|
p->ap = ps->i + 1;
|
|
|
}
|
|
|
} break;
|
|
|
+
|
|
|
+ case NCDMODULE_EVENT_DEAD: {
|
|
|
+ int is_error = NCDModuleInst_HaveError(&ps->inst);
|
|
|
+
|
|
|
+ if (is_error) {
|
|
|
+ process_statement_log(ps, BLOG_ERROR, "died with error");
|
|
|
+ } else {
|
|
|
+ process_statement_log(ps, BLOG_INFO, "died");
|
|
|
+ }
|
|
|
+
|
|
|
+ // free instance
|
|
|
+ NCDModuleInst_Free(&ps->inst);
|
|
|
+
|
|
|
+ // free instance arguments
|
|
|
+ NCDValue_Free(&ps->inst_args);
|
|
|
+
|
|
|
+ // set state FORGOTTEN
|
|
|
+ ps->state = SSTATE_FORGOTTEN;
|
|
|
+
|
|
|
+ // set error
|
|
|
+ if (is_error) {
|
|
|
+ process_statement_set_error(ps);
|
|
|
+ }
|
|
|
+
|
|
|
+ // update AP
|
|
|
+ if (p->ap > ps->i) {
|
|
|
+ p->ap = ps->i;
|
|
|
+ }
|
|
|
+
|
|
|
+ // update FP
|
|
|
+ while (p->fp > 0 && p->statements[p->fp - 1].state == SSTATE_FORGOTTEN) {
|
|
|
+ p->fp--;
|
|
|
+ }
|
|
|
+ } break;
|
|
|
}
|
|
|
-
|
|
|
- process_work(p);
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-void process_statement_instance_handler_died (struct process_statement *ps, int is_error)
|
|
|
-{
|
|
|
- ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT || ps->state == SSTATE_DYING)
|
|
|
-
|
|
|
- struct process *p = ps->p;
|
|
|
-
|
|
|
- // free instance
|
|
|
- NCDModuleInst_Free(&ps->inst);
|
|
|
-
|
|
|
- // free instance arguments
|
|
|
- NCDValue_Free(&ps->inst_args);
|
|
|
-
|
|
|
- // set state FORGOTTEN
|
|
|
- ps->state = SSTATE_FORGOTTEN;
|
|
|
-
|
|
|
- // set error
|
|
|
- if (is_error) {
|
|
|
- process_statement_set_error(ps);
|
|
|
- } else {
|
|
|
- ps->have_error = 0;
|
|
|
- }
|
|
|
-
|
|
|
- // update AP
|
|
|
- if (p->ap > ps->i) {
|
|
|
- p->ap = ps->i;
|
|
|
- }
|
|
|
-
|
|
|
- // update FP
|
|
|
- while (p->fp > 0 && p->statements[p->fp - 1].state == SSTATE_FORGOTTEN) {
|
|
|
- p->fp--;
|
|
|
- }
|
|
|
-
|
|
|
- process_statement_log(ps, BLOG_INFO, "died");
|
|
|
-
|
|
|
- if (is_error) {
|
|
|
- process_statement_log(ps, BLOG_ERROR, "with error");
|
|
|
- }
|
|
|
-
|
|
|
- process_work(p);
|
|
|
- return;
|
|
|
}
|
|
|
|
|
|
int process_statement_instance_handler_getvar (struct process_statement *ps, const char *modname, const char *varname, NCDValue *out)
|
|
|
{
|
|
|
+ ASSERT(ps->state != SSTATE_FORGOTTEN)
|
|
|
+
|
|
|
if (ps->i > process_rap(ps->p)) {
|
|
|
process_statement_log(ps, BLOG_ERROR, "tried to resolve variable %s.%s but it's dirty", modname, varname);
|
|
|
return 0;
|
|
|
@@ -1130,40 +1136,3 @@ int process_statement_instance_handler_getvar (struct process_statement *ps, con
|
|
|
|
|
|
return process_resolve_variable(ps->p, ps->i, modname, varname, out);
|
|
|
}
|
|
|
-
|
|
|
-void init_job_handler (void *unused)
|
|
|
-{
|
|
|
- ASSERT(!terminating)
|
|
|
-
|
|
|
- if (!init_next) {
|
|
|
- // initialized all processes
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- struct NCDConfig_interfaces *conf = init_next;
|
|
|
-
|
|
|
- // schedule next
|
|
|
- init_next = init_next->next;
|
|
|
- BPending_Set(&init_job);
|
|
|
-
|
|
|
- // init process
|
|
|
- process_new(conf);
|
|
|
-}
|
|
|
-
|
|
|
-void free_job_handler (void *unused)
|
|
|
-{
|
|
|
- ASSERT(terminating)
|
|
|
-
|
|
|
- LinkedList2Node *n = LinkedList2Iterator_Next(&free_it);
|
|
|
- if (!n) {
|
|
|
- // done initiating shutdown for all processes
|
|
|
- return;
|
|
|
- }
|
|
|
- struct process *p = UPPER_OBJECT(n, struct process, list_node);
|
|
|
-
|
|
|
- // schedule next
|
|
|
- BPending_Set(&free_job);
|
|
|
-
|
|
|
- process_work(p);
|
|
|
- return;
|
|
|
-}
|