diff -x '*~' -ur hotplug2-201/uevent.c hotplug2-201.patched/uevent.c --- hotplug2-201/uevent.c 2009-12-09 20:44:14.000000000 +0200 +++ hotplug2-201.patched/uevent.c 2010-04-02 23:03:11.000000000 +0300 @@ -132,6 +132,8 @@ dest = xmalloc(sizeof(struct uevent_t)); dest->action = src->action; + dest->seqnum = src->seqnum; + dest->action_str = strdup(src->action_str); dest->env_vars_c = src->env_vars_c; dest->env_vars = xmalloc(sizeof(struct env_var_t) * dest->env_vars_c); dest->plain_s = src->plain_s; diff -x '*~' -ur hotplug2-201/workers/worker_fork.c hotplug2-201.patched/workers/worker_fork.c --- hotplug2-201/workers/worker_fork.c 2010-04-03 17:02:15.000000000 +0300 +++ hotplug2-201.patched/workers/worker_fork.c 2010-04-03 17:04:27.000000000 +0300 @@ -1,6 +1,69 @@ #include "worker_fork.h" static struct worker_fork_ctx_t *global_ctx; +static struct worker_fork_uevent_t *uevent_list; + +static void worker_fork_uevent_free(struct worker_fork_uevent_t *node) { + uevent_free(node->uevent); + free(node); +} + +static void worker_fork_uevent_add(void *in_ctx, struct uevent_t *uevent) { + char **env; + int i; + struct worker_fork_ctx_t *ctx = in_ctx; + struct worker_fork_uevent_t *node, *walker; + + node = malloc(sizeof (struct worker_fork_uevent_t)); + node->uevent = uevent_dup(uevent); + node->next = NULL; + + if (!uevent_list) uevent_list = node; + else { + /* + * Put events that need to fork first and in reverse order + */ + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c); + for (i = 0; i < node->uevent->env_vars_c; i++) { + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value); + putenv(env[i]); + } + if (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW) { + node->next = uevent_list; + uevent_list = node; + } + else { + for (walker = uevent_list; walker->next; walker = walker->next); + walker->next = node; + } + for (i = 0; i < node->uevent->env_vars_c; i++) { + unsetenv(node->uevent->env_vars[i].key); + free(env[i]); + } + free(env); + } +} + +static void worker_fork_uevent_del(struct worker_fork_uevent_t *node) { + struct worker_fork_uevent_t *walker; + + if (node == uevent_list) { + uevent_list = node->next; + } + else { + for (walker = uevent_list; walker->next; walker = walker->next) + if (walker->next == node) walker->next = node->next; + } + worker_fork_uevent_free(node); +} + +static void worker_fork_uevent_empty(void) { + struct worker_fork_uevent_t *walker; + + if (!uevent_list) return; + for (walker = uevent_list; walker->next; walker = walker->next) worker_fork_uevent_free(walker); + uevent_list = NULL; +} /** * Destroys data structures related to the given child ID (not PID). @@ -315,6 +378,8 @@ struct worker_fork_ctx_t *ctx; PRINTFUNC(); + uevent_list = NULL; + ctx = malloc(sizeof(struct worker_fork_ctx_t)); ctx->children = NULL; ctx->children_count = 0; @@ -376,6 +441,7 @@ free(ctx->children); free(ctx); global_ctx = NULL; + worker_fork_uevent_empty(); } @@ -384,15 +450,26 @@ int i; struct worker_fork_child_t *child; struct worker_fork_ctx_t *ctx = in_ctx; + struct worker_fork_uevent_t *node, *walker; + event_seqnum_t seqnum; + + worker_fork_uevent_add(ctx, uevent); + walker = uevent_list; /* - * A big loop, because if we fail to process the event, + * A big loop, because if we fail to process the events, * we don't want to give up. * * TODO: Decide if we want to limit the number of attempts * or set a time limit before reporting terminal failure. */ do { + /* + * If more events are waiting, return to receive them + */ + if (!seqnum_get(&seqnum) && seqnum > uevent->seqnum) break; + + node = walker; worker_fork_update_children(ctx); child = NULL; @@ -407,9 +484,9 @@ * No child process is currently available. */ if (child == NULL) { - env = xmalloc(sizeof(char *) * uevent->env_vars_c); - for (i = 0; i < uevent->env_vars_c; i++) { - env[i] = alloc_env(uevent->env_vars[i].key, uevent->env_vars[i].value); + env = xmalloc(sizeof(char *) * node->uevent->env_vars_c); + for (i = 0; i < node->uevent->env_vars_c; i++) { + env[i] = alloc_env(node->uevent->env_vars[i].key, node->uevent->env_vars[i].value); putenv(env[i]); } @@ -418,8 +495,11 @@ * can execute them in the main process? */ if (ctx->always_fork == 0 && ctx->settings->dumb == 0 && - (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_MASK_SLOW) == 0) { - action_perform(ctx->settings, uevent); + (ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_MASK_SLOW) == 0) { + action_perform(ctx->settings, node->uevent); + walker = walker->next; + worker_fork_uevent_del(node); + if (walker) continue; break; } @@ -427,11 +507,11 @@ * We have to fork off a new child. */ if (ctx->children_count < ctx->max_children || - (ruleset_flags(&ctx->settings->rules, uevent) & FLAG_SLOW)) + (ruleset_flags(&ctx->settings->rules, node->uevent) & FLAG_SLOW)) child = worker_fork_spawn(ctx); - for (i = 0; i < uevent->env_vars_c; i++) { - unsetenv(uevent->env_vars[i].key); + for (i = 0; i < node->uevent->env_vars_c; i++) { + unsetenv(node->uevent->env_vars[i].key); free(env[i]); } free(env); @@ -442,9 +522,14 @@ */ if (child != NULL) { child->busy = 1; - if (!worker_fork_relay_event(child->event_fd, uevent)); - break; - child->busy = 0; + if (worker_fork_relay_event(child->event_fd, node->uevent)) { + child->busy = 0; + continue; + } + walker = walker->next; + worker_fork_uevent_del(node); + if (walker) continue; + break; } /* diff -x '*~' -ur hotplug2-201/workers/worker_fork.h hotplug2-201.patched/workers/worker_fork.h --- hotplug2-201/workers/worker_fork.h 2009-12-09 20:44:13.000000000 +0200 +++ hotplug2-201.patched/workers/worker_fork.h 2010-04-03 01:00:24.000000000 +0300 @@ -35,4 +35,9 @@ struct settings_t *settings; }; +struct worker_fork_uevent_t { + struct uevent_t *uevent; + struct worker_fork_uevent_t *next; +}; + #endif