3 @@ -132,6 +132,8 @@ struct uevent_t *uevent_dup(const struct
5 dest = xmalloc(sizeof(struct uevent_t));
6 dest->action = src->action;
7 + dest->seqnum = src->seqnum;
8 + dest->action_str = strdup(src->action_str);
9 dest->env_vars_c = src->env_vars_c;
10 dest->env_vars = xmalloc(sizeof(struct env_var_t) * dest->env_vars_c);
11 dest->plain_s = src->plain_s;
12 --- a/workers/worker_fork.c
13 +++ b/workers/worker_fork.c
15 #include "worker_fork.h"
17 static struct worker_fork_ctx_t *global_ctx;
18 +static struct worker_fork_uevent_t *uevent_list;
20 +static void worker_fork_uevent_free(struct worker_fork_uevent_t *node) {
21 + uevent_free(node->uevent);
25 +static void worker_fork_uevent_add(void *in_ctx, struct uevent_t *uevent) {
28 + struct worker_fork_ctx_t *ctx = in_ctx;
29 + struct worker_fork_uevent_t *node, *walker;
31 + node = malloc(sizeof (struct worker_fork_uevent_t));
32 + node->uevent = uevent_dup(uevent);
35 + if (!uevent_list) uevent_list = node;
38 + * Put events that need to fork first and in reverse order
40 + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
41 + for (i = 0; i < node->uevent->env_vars_c; i++) {
42 + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
45 + if (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW) {
46 + node->next = uevent_list;
50 + for (walker = uevent_list; walker->next; walker = walker->next);
51 + walker->next = node;
53 + for (i = 0; i < node->uevent->env_vars_c; i++) {
54 + unsetenv(node->uevent->env_vars[i].key);
61 +static void worker_fork_uevent_del(struct worker_fork_uevent_t *node) {
62 + struct worker_fork_uevent_t *walker;
64 + if (node == uevent_list) {
65 + uevent_list = node->next;
68 + for (walker = uevent_list; walker->next; walker = walker->next)
69 + if (walker->next == node) walker->next = node->next;
71 + worker_fork_uevent_free(node);
74 +static void worker_fork_uevent_empty(void) {
75 + struct worker_fork_uevent_t *walker;
77 + if (!uevent_list) return;
78 + for (walker = uevent_list; walker->next; walker = walker->next) worker_fork_uevent_free(walker);
83 * Destroys data structures related to the given child ID (not PID).
84 @@ -315,6 +378,8 @@ static void *worker_fork_init(struct set
85 struct worker_fork_ctx_t *ctx;
90 ctx = malloc(sizeof(struct worker_fork_ctx_t));
92 ctx->children_count = 0;
93 @@ -376,6 +441,7 @@ static void worker_fork_deinit(void *in_
97 + worker_fork_uevent_empty();
101 @@ -384,15 +450,26 @@ static int worker_fork_process(void *in_
103 struct worker_fork_child_t *child;
104 struct worker_fork_ctx_t *ctx = in_ctx;
105 + struct worker_fork_uevent_t *node, *walker;
106 + event_seqnum_t seqnum;
108 + worker_fork_uevent_add(ctx, uevent);
109 + walker = uevent_list;
112 - * A big loop, because if we fail to process the event,
113 + * A big loop, because if we fail to process the events,
114 * we don't want to give up.
116 * TODO: Decide if we want to limit the number of attempts
117 * or set a time limit before reporting terminal failure.
121 + * If more events are waiting, return to receive them
123 + if (!seqnum_get(&seqnum) && seqnum > uevent->seqnum) break;
126 worker_fork_update_children(ctx);
129 @@ -407,9 +484,9 @@ static int worker_fork_process(void *in_
130 * No child process is currently available.
133 - env = xmalloc(sizeof(char *) * uevent->env_vars_c);
134 - for (i = 0; i < uevent->env_vars_c; i++) {
135 - env[i] = alloc_env(uevent->env_vars[i].key, uevent->env_vars[i].value);
136 + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
137 + for (i = 0; i < node->uevent->env_vars_c; i++) {
138 + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
142 @@ -418,8 +495,11 @@ static int worker_fork_process(void *in_
143 * can execute them in the main process?
145 if (ctx->always_fork == 0 && ctx->settings->dumb == 0 &&
146 - (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_MASK_SLOW) == 0) {
147 - action_perform(ctx->settings, uevent);
148 + (ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_MASK_SLOW) == 0) {
149 + action_perform(ctx->settings, node->uevent);
150 + walker = walker->next;
151 + worker_fork_uevent_del(node);
152 + if (walker) continue;
156 @@ -427,11 +507,11 @@ static int worker_fork_process(void *in_
157 * We have to fork off a new child.
159 if (ctx->children_count < ctx->max_children ||
160 - (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW))
161 + (ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_SLOW))
162 child = worker_fork_spawn(ctx);
164 - for (i = 0; i < uevent->env_vars_c; i++) {
165 - unsetenv(uevent->env_vars[i].key);
166 + for (i = 0; i < node->uevent->env_vars_c; i++) {
167 + unsetenv(node->uevent->env_vars[i].key);
171 @@ -442,9 +522,14 @@ static int worker_fork_process(void *in_
175 - if (!worker_fork_relay_event(child->event_fd, uevent));
178 + if (worker_fork_relay_event(child->event_fd, node->uevent)) {
182 + walker = walker->next;
183 + worker_fork_uevent_del(node);
184 + if (walker) continue;
189 --- a/workers/worker_fork.h
190 +++ b/workers/worker_fork.h
191 @@ -35,4 +35,9 @@ struct worker_fork_ctx_t {
192 struct settings_t *settings;
195 +struct worker_fork_uevent_t {
196 + struct uevent_t *uevent;
197 + struct worker_fork_uevent_t *next;