3 @@ -39,7 +39,7 @@ static void action_dumb(const struct set
4 * Returns: Newly allocated string in "key=value" form
7 -static char* alloc_env(const char *key, const char *value) {
8 +char* alloc_env(const char *key, const char *value) {
17 void action_perform(struct settings_t *, struct uevent_t *);
18 +char* alloc_env(const char *, const char *);
19 #endif /* ifndef ACTION_H */
21 --- a/workers/worker_fork.c
22 +++ b/workers/worker_fork.c
24 #include "worker_fork.h"
26 static struct worker_fork_ctx_t *global_ctx;
27 +static struct worker_fork_uevent_t *uevent_list;
29 +static void worker_fork_uevent_free(struct worker_fork_uevent_t *node) {
30 + uevent_free(node->uevent);
34 +static void worker_fork_uevent_add(void *in_ctx, struct uevent_t *uevent) {
37 + struct worker_fork_ctx_t *ctx = in_ctx;
38 + struct worker_fork_uevent_t *node, *walker;
40 + node = malloc(sizeof (struct worker_fork_uevent_t));
41 + node->uevent = uevent_dup(uevent);
44 + if (!uevent_list) uevent_list = node;
47 + * Put events that need to fork first and in reverse order
49 + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
50 + for (i = 0; i < node->uevent->env_vars_c; i++) {
51 + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
54 + if (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW) {
55 + node->next = uevent_list;
59 + for (walker = uevent_list; walker->next; walker = walker->next);
60 + walker->next = node;
62 + for (i = 0; i < node->uevent->env_vars_c; i++) {
63 + unsetenv(node->uevent->env_vars[i].key);
70 +static void worker_fork_uevent_del(struct worker_fork_uevent_t *node) {
71 + struct worker_fork_uevent_t *walker;
73 + if (node == uevent_list) {
74 + uevent_list = node->next;
77 + for (walker = uevent_list; walker->next; walker = walker->next)
78 + if (walker->next == node) walker->next = node->next;
80 + worker_fork_uevent_free(node);
83 +static void worker_fork_uevent_empty(void) {
84 + struct worker_fork_uevent_t *walker;
86 + if (!uevent_list) return;
87 + for (walker = uevent_list; walker->next; walker = walker->next) worker_fork_uevent_free(walker);
92 * Destroys data structures related to the given child ID (not PID).
93 @@ -315,6 +378,8 @@ static void *worker_fork_init(struct set
94 struct worker_fork_ctx_t *ctx;
99 ctx = malloc(sizeof(struct worker_fork_ctx_t));
100 ctx->children = NULL;
101 ctx->children_count = 0;
102 @@ -376,26 +441,39 @@ static void worker_fork_deinit(void *in_
106 + worker_fork_uevent_empty();
110 static int worker_fork_process(void *in_ctx, struct uevent_t *uevent) {
113 struct worker_fork_child_t *child;
114 struct worker_fork_ctx_t *ctx = in_ctx;
115 + struct worker_fork_uevent_t *node, *walker;
116 + event_seqnum_t seqnum;
118 + worker_fork_uevent_add(ctx, uevent);
119 + walker = uevent_list;
122 - * A big loop, because if we fail to process the event,
123 + * A big loop, because if we fail to process the events,
124 * we don't want to give up.
126 * TODO: Decide if we want to limit the number of attempts
127 * or set a time limit before reporting terminal failure.
131 + * If more events are waiting, return to receive them
133 + if (!seqnum_get(&seqnum) && seqnum > uevent->seqnum) break;
136 worker_fork_update_children(ctx);
139 - for (i = 0; i < ctx->children_count; i++) {
140 + for (i = 0; i < ctx->children_count && i < ctx->max_children; i++) {
141 if (ctx->children[i]->busy == 0) {
142 child = ctx->children[i];
144 @@ -406,21 +484,40 @@ static int worker_fork_process(void *in_
145 * No child process is currently available.
150 + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
151 + for (i = 0; i < node->uevent->env_vars_c; i++) {
152 + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
156 + is_slow = !!(ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_MASK_SLOW);
158 + for (i = 0; i < node->uevent->env_vars_c; i++) {
159 + unsetenv(node->uevent->env_vars[i].key);
165 * Are the matching rules trivial enough that we
166 * can execute them in the main process?
168 - if (ctx->always_fork == 0 && ctx->settings->dumb == 0 &&
169 - (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_MASK_SLOW) == 0) {
170 - action_perform(ctx->settings, uevent);
171 + if (ctx->always_fork == 0 && ctx->settings->dumb == 0 && !is_slow) {
172 + action_perform(ctx->settings, node->uevent);
173 + walker = walker->next;
174 + worker_fork_uevent_del(node);
175 + if (walker) continue;
181 * We have to fork off a new child.
183 if (ctx->children_count < ctx->max_children)
184 child = worker_fork_spawn(ctx);
189 @@ -428,9 +525,14 @@ static int worker_fork_process(void *in_
193 - if (!worker_fork_relay_event(child->event_fd, uevent));
196 + if (worker_fork_relay_event(child->event_fd, node->uevent)) {
200 + walker = walker->next;
201 + worker_fork_uevent_del(node);
202 + if (walker) continue;
209 @@ -132,6 +132,8 @@ struct uevent_t *uevent_dup(const struct
211 dest = xmalloc(sizeof(struct uevent_t));
212 dest->action = src->action;
213 + dest->seqnum = src->seqnum;
214 + dest->action_str = strdup(src->action_str);
215 dest->env_vars_c = src->env_vars_c;
216 dest->env_vars = xmalloc(sizeof(struct env_var_t) * dest->env_vars_c);
217 dest->plain_s = src->plain_s;
218 --- a/workers/worker_fork.h
219 +++ b/workers/worker_fork.h
221 #include <sys/types.h>
222 #include <sys/select.h>
224 +#include <stdbool.h>
226 #include "../rules/execution.h"
228 @@ -35,4 +36,9 @@ struct worker_fork_ctx_t {
229 struct settings_t *settings;
232 +struct worker_fork_uevent_t {
233 + struct uevent_t *uevent;
234 + struct worker_fork_uevent_t *next;