hotplug2: merge worker related fixes into one patch
[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,37 @@ static int worker_fork_process(void *in_
145 * No child process is currently available.
146 */
147 if (child == NULL) {
148 + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c);
149 + for (i = 0; i < node->uevent->env_vars_c; i++) {
150 + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value);
151 + putenv(env[i]);
152 + }
153 +
154 /*
155 * Are the matching rules trivial enough that we
156 * can execute them in the main process?
157 */
158 if (ctx->always_fork == 0 && ctx->settings->dumb == 0 &&
159 - (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_MASK_SLOW) == 0) {
160 - action_perform(ctx->settings, uevent);
161 + (ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_MASK_SLOW) == 0) {
162 + action_perform(ctx->settings, node->uevent);
163 + walker = walker->next;
164 + worker_fork_uevent_del(node);
165 + if (walker) continue;
166 break;
167 }
168 -
169 +
170 /*
171 * We have to fork off a new child.
172 */
173 - if (ctx->children_count < ctx->max_children)
174 + if (ctx->children_count < ctx->max_children ||
175 + (ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_SLOW))
176 child = worker_fork_spawn(ctx);
177 +
178 + for (i = 0; i < node->uevent->env_vars_c; i++) {
179 + unsetenv(node->uevent->env_vars[i].key);
180 + free(env[i]);
181 + }
182 + free(env);
183 }
184
185 /*
186 @@ -428,9 +522,14 @@ static int worker_fork_process(void *in_
187 */
188 if (child != NULL) {
189 child->busy = 1;
190 - if (!worker_fork_relay_event(child->event_fd, uevent));
191 - break;
192 - child->busy = 0;
193 + if (worker_fork_relay_event(child->event_fd, node->uevent)) {
194 + child->busy = 0;
195 + continue;
196 + }
197 + walker = walker->next;
198 + worker_fork_uevent_del(node);
199 + if (walker) continue;
200 + break;
201 }
202
203 /*
204 --- a/uevent.c
205 +++ b/uevent.c
206 @@ -132,6 +132,8 @@ struct uevent_t *uevent_dup(const struct
207
208 dest = xmalloc(sizeof(struct uevent_t));
209 dest->action = src->action;
210 + dest->seqnum = src->seqnum;
211 + dest->action_str = strdup(src->action_str);
212 dest->env_vars_c = src->env_vars_c;
213 dest->env_vars = xmalloc(sizeof(struct env_var_t) * dest->env_vars_c);
214 dest->plain_s = src->plain_s;
215 --- a/workers/worker_fork.h
216 +++ b/workers/worker_fork.h
217 @@ -35,4 +35,9 @@ struct worker_fork_ctx_t {
218 struct settings_t *settings;
219 };
220
221 +struct worker_fork_uevent_t {
222 + struct uevent_t *uevent;
223 + struct worker_fork_uevent_t *next;
224 +};
225 +
226 #endif