5e288ae3c51eb94877726ac5b5d281502f67b2f3
[openwrt/svn-archive/archive.git] / package / hotplug2 / patches / 140-worker_fork_fix.patch
1 --- a/action.c
2 +++ b/action.c
3 @@ -39,7 +39,7 @@ static void action_dumb(const struct set
4 * Returns: Newly allocated string in "key=value" form
5 *
6 */
7 -static char* alloc_env(const char *key, const char *value) {
8 +char* alloc_env(const char *key, const char *value) {
9 size_t keylen, vallen;
10 char *combined;
11
12 --- a/action.h
13 +++ b/action.h
14 @@ -12,5 +12,6 @@
15 #include "settings.h"
16
17 void action_perform(struct settings_t *, struct uevent_t *);
18 +char* alloc_env(const char *, const char *);
19 #endif /* ifndef ACTION_H */
20
21 --- a/workers/worker_fork.c
22 +++ b/workers/worker_fork.c
23 @@ -1,6 +1,69 @@
24 #include "worker_fork.h"
25
26 static struct worker_fork_ctx_t *global_ctx;
27 +static struct worker_fork_uevent_t *uevent_list;
28 +
29 +static void worker_fork_uevent_free(struct worker_fork_uevent_t *node) {
30 + uevent_free(node->uevent);
31 + free(node);
32 +}
33 +
34 +static void worker_fork_uevent_add(void *in_ctx, struct uevent_t *uevent) {
35 + char **env;
36 + int i;
37 + struct worker_fork_ctx_t *ctx = in_ctx;
38 + struct worker_fork_uevent_t *node, *walker;
39 +
40 + node = malloc(sizeof (struct worker_fork_uevent_t));
41 + node->uevent = uevent_dup(uevent);
42 + node->next = NULL;
43 +
44 + if (!uevent_list) uevent_list = node;
45 + else {
46 + /*
47 + * Put events that need to fork first and in reverse order
48 + */
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);
52 + putenv(env[i]);
53 + }
54 + if (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW) {
55 + node->next = uevent_list;
56 + uevent_list = node;
57 + }
58 + else {
59 + for (walker = uevent_list; walker->next; walker = walker->next);
60 + walker->next = node;
61 + }
62 + for (i = 0; i < node->uevent->env_vars_c; i++) {
63 + unsetenv(node->uevent->env_vars[i].key);
64 + free(env[i]);
65 + }
66 + free(env);
67 + }
68 +}
69 +
70 +static void worker_fork_uevent_del(struct worker_fork_uevent_t *node) {
71 + struct worker_fork_uevent_t *walker;
72 +
73 + if (node == uevent_list) {
74 + uevent_list = node->next;
75 + }
76 + else {
77 + for (walker = uevent_list; walker->next; walker = walker->next)
78 + if (walker->next == node) walker->next = node->next;
79 + }
80 + worker_fork_uevent_free(node);
81 +}
82 +
83 +static void worker_fork_uevent_empty(void) {
84 + struct worker_fork_uevent_t *walker;
85 +
86 + if (!uevent_list) return;
87 + for (walker = uevent_list; walker->next; walker = walker->next) worker_fork_uevent_free(walker);
88 + uevent_list = NULL;
89 +}
90
91 /**
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;
95 PRINTFUNC();
96
97 + uevent_list = NULL;
98 +
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_
103 free(ctx->children);
104 free(ctx);
105 global_ctx = NULL;
106 + worker_fork_uevent_empty();
107 }
108
109
110 static int worker_fork_process(void *in_ctx, struct uevent_t *uevent) {
111 + char **env;
112 int i;
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;
117 +
118 + worker_fork_uevent_add(ctx, uevent);
119 + walker = uevent_list;
120
121 /*
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.
125 *
126 * TODO: Decide if we want to limit the number of attempts
127 * or set a time limit before reporting terminal failure.
128 */
129 do {
130 + /*
131 + * If more events are waiting, return to receive them
132 + */
133 + if (!seqnum_get(&seqnum) && seqnum > uevent->seqnum) break;
134 +
135 + node = walker;
136 worker_fork_update_children(ctx);
137
138 child = NULL;
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];
143 break;
144 @@ -406,21 +484,40 @@ static int worker_fork_process(void *in_
145 * No child process is currently available.
146 */
147 if (child == NULL) {
148 + bool is_slow;
149 +
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);
153 + putenv(env[i]);
154 + }
155 +
156 + is_slow = !!(ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_MASK_SLOW);
157 +
158 + for (i = 0; i < node->uevent->env_vars_c; i++) {
159 + unsetenv(node->uevent->env_vars[i].key);
160 + free(env[i]);
161 + }
162 + free(env);
163 +
164 /*
165 * Are the matching rules trivial enough that we
166 * can execute them in the main process?
167 */
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;
176 break;
177 }
178 -
179 +
180 /*
181 * We have to fork off a new child.
182 */
183 if (ctx->children_count < ctx->max_children)
184 child = worker_fork_spawn(ctx);
185 +
186 }
187
188 /*
189 @@ -428,9 +525,14 @@ static int worker_fork_process(void *in_
190 */
191 if (child != NULL) {
192 child->busy = 1;
193 - if (!worker_fork_relay_event(child->event_fd, uevent));
194 - break;
195 - child->busy = 0;
196 + if (worker_fork_relay_event(child->event_fd, node->uevent)) {
197 + child->busy = 0;
198 + continue;
199 + }
200 + walker = walker->next;
201 + worker_fork_uevent_del(node);
202 + if (walker) continue;
203 + break;
204 }
205
206 /*
207 --- a/uevent.c
208 +++ b/uevent.c
209 @@ -132,6 +132,8 @@ struct uevent_t *uevent_dup(const struct
210
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
220 @@ -5,6 +5,7 @@
221 #include <sys/types.h>
222 #include <sys/select.h>
223 #include <unistd.h>
224 +#include <stdbool.h>
225
226 #include "../rules/execution.h"
227
228 @@ -35,4 +36,9 @@ struct worker_fork_ctx_t {
229 struct settings_t *settings;
230 };
231
232 +struct worker_fork_uevent_t {
233 + struct uevent_t *uevent;
234 + struct worker_fork_uevent_t *next;
235 +};
236 +
237 #endif