1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

udevd: merge exec and run queue to minimize devpath string compares

This commit is contained in:
Kay Sievers 2008-10-29 17:32:13 +01:00
parent 6270756cdc
commit 0bc74ea79f
3 changed files with 85 additions and 98 deletions

View File

@ -706,6 +706,11 @@ int udev_event_execute_run(struct udev_event *event)
util_strlcpy(program, cmd, sizeof(program)); util_strlcpy(program, cmd, sizeof(program));
udev_event_apply_format(event, program, sizeof(program)); udev_event_apply_format(event, program, sizeof(program));
if (event->trace)
printf("run %s (%llu) '%s'\n",
udev_device_get_syspath(event->dev),
udev_device_get_seqnum(event->dev),
program);
envp = udev_device_get_properties_envp(event->dev); envp = udev_device_get_properties_envp(event->dev);
if (util_run_program(event->udev, program, envp, NULL, 0, NULL) != 0) { if (util_run_program(event->udev, program, envp, NULL, 0, NULL) != 0) {
if (!udev_list_entry_get_flag(list_entry)) if (!udev_list_entry_get_flag(list_entry))

View File

@ -71,6 +71,7 @@ struct udev_event {
pid_t pid; pid_t pid;
int exitstatus; int exitstatus;
time_t queue_time; time_t queue_time;
unsigned long long int delaying_seqnum;
unsigned int group_final:1; unsigned int group_final:1;
unsigned int owner_final:1; unsigned int owner_final:1;
unsigned int mode_final:1; unsigned int mode_final:1;
@ -78,6 +79,7 @@ struct udev_event {
unsigned int devlink_final:1; unsigned int devlink_final:1;
unsigned int run_final:1; unsigned int run_final:1;
unsigned int ignore_device:1; unsigned int ignore_device:1;
unsigned int trace:1;
unsigned int test:1; unsigned int test:1;
}; };

View File

@ -62,7 +62,6 @@ static struct udev_rules *rules;
static struct udev_ctrl *udev_ctrl; static struct udev_ctrl *udev_ctrl;
static struct udev_monitor *kernel_monitor; static struct udev_monitor *kernel_monitor;
static int inotify_fd = -1; static int inotify_fd = -1;
static int signal_pipe[2] = {-1, -1}; static int signal_pipe[2] = {-1, -1};
static volatile int sigchilds_waiting; static volatile int sigchilds_waiting;
static volatile int udev_exit; static volatile int udev_exit;
@ -70,9 +69,8 @@ static volatile int reload_config;
static int run_exec_q; static int run_exec_q;
static int stop_exec_q; static int stop_exec_q;
static int max_childs; static int max_childs;
static int childs;
static struct udev_list_node exec_list; static struct udev_list_node event_list;
static struct udev_list_node running_list;
enum event_state { enum event_state {
EVENT_QUEUED, EVENT_QUEUED,
@ -137,7 +135,7 @@ static void export_event_state(struct udev_event *event, enum event_state state)
unlink(filename); unlink(filename);
/* clean up possibly empty queue directory */ /* clean up possibly empty queue directory */
if (udev_list_is_empty(&exec_list) && udev_list_is_empty(&running_list)) if (udev_list_is_empty(&event_list))
util_delete_path(event->udev, filename); util_delete_path(event->udev, filename);
break; break;
case EVENT_FAILED: case EVENT_FAILED:
@ -146,7 +144,7 @@ static void export_event_state(struct udev_event *event, enum event_state state)
rename(filename, filename_failed); rename(filename, filename_failed);
/* clean up possibly empty queue directory */ /* clean up possibly empty queue directory */
if (udev_list_is_empty(&exec_list) && udev_list_is_empty(&running_list)) if (udev_list_is_empty(&event_list))
util_delete_path(event->udev, filename); util_delete_path(event->udev, filename);
break; break;
} }
@ -180,6 +178,13 @@ static void event_fork(struct udev_event *event)
struct sigaction act; struct sigaction act;
int err; int err;
if (debug_trace) {
event->trace = 1;
printf("fork %s (%llu)\n",
udev_device_get_syspath(event->dev),
udev_device_get_seqnum(event->dev));
}
pid = fork(); pid = fork();
switch (pid) { switch (pid) {
case 0: case 0:
@ -221,6 +226,7 @@ static void event_fork(struct udev_event *event)
/* execute RUN= */ /* execute RUN= */
if (err == 0 && !event->ignore_device && udev_get_run(event->udev)) if (err == 0 && !event->ignore_device && udev_get_run(event->udev))
udev_event_execute_run(event); udev_event_execute_run(event);
info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err);
logging_close(); logging_close();
if (err != 0) if (err != 0)
@ -239,6 +245,7 @@ static void event_fork(struct udev_event *event)
udev_device_get_subsystem(event->dev), udev_device_get_subsystem(event->dev),
time(NULL) - event->queue_time); time(NULL) - event->queue_time);
event->pid = pid; event->pid = pid;
childs++;
} }
} }
@ -265,24 +272,15 @@ static void event_queue_insert(struct udev_event *event)
close(fd); close(fd);
} }
/* run one event after the other in debug mode */
if (debug_trace) { udev_list_node_append(&event->node, &event_list);
udev_list_node_append(&event->node, &running_list); run_exec_q = 1;
event_fork(event);
waitpid(event->pid, NULL, 0);
event_queue_delete(event);
return;
}
/* run all events with a timeout set immediately */ /* run all events with a timeout set immediately */
if (udev_device_get_timeout(event->dev) > 0) { if (udev_device_get_timeout(event->dev) > 0) {
udev_list_node_append(&event->node, &running_list);
event_fork(event); event_fork(event);
return; return;
} }
udev_list_node_append(&event->node, &exec_list);
run_exec_q = 1;
} }
static int mem_size_mb(void) static int mem_size_mb(void)
@ -312,7 +310,7 @@ static int compare_devpath(const char *running, const char *waiting)
{ {
int i = 0; int i = 0;
while (running[i] == waiting[i] && running[i] != '\0') while (running[i] != '\0' && running[i] == waiting[i])
i++; i++;
/* identical device event found */ /* identical device event found */
@ -332,23 +330,34 @@ static int compare_devpath(const char *running, const char *waiting)
} }
/* lookup event for identical, parent, child, or physical device */ /* lookup event for identical, parent, child, or physical device */
static int devpath_busy(struct udev_event *event, int limit) static int devpath_busy(struct udev_event *event)
{ {
struct udev_list_node *loop; struct udev_list_node *loop;
int childs_count = 0;
/* check exec-queue which may still contain delayed events we depend on */ if (event->delaying_seqnum > 0) {
udev_list_node_foreach(loop, &exec_list) { }
/* check if queue contains events we depend on */
udev_list_node_foreach(loop, &event_list) {
struct udev_event *loop_event = node_to_event(loop); struct udev_event *loop_event = node_to_event(loop);
/* skip ourself and all later events */ /* we already found a later event, earlier can not block us, no need to check again */
if (udev_device_get_seqnum(loop_event->dev) < event->delaying_seqnum)
continue;
/* event we checked earlier still exists, no need to check again */
if (udev_device_get_seqnum(loop_event->dev) == event->delaying_seqnum)
return 2;
/* found ourself, no later event can block us */
if (udev_device_get_seqnum(loop_event->dev) >= udev_device_get_seqnum(event->dev)) if (udev_device_get_seqnum(loop_event->dev) >= udev_device_get_seqnum(event->dev))
break; break;
/* check our old name */ /* check our old name */
if (udev_device_get_devpath_old(event->dev) != NULL) if (udev_device_get_devpath_old(event->dev) != NULL)
if (strcmp(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath_old(event->dev)) == 0) if (strcmp(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath_old(event->dev)) == 0) {
return 2; event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev);
return 3;
}
/* check identical, parent, or child device event */ /* check identical, parent, or child device event */
if (compare_devpath(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath(event->dev)) != 0) { if (compare_devpath(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath(event->dev)) != 0) {
@ -356,7 +365,8 @@ static int devpath_busy(struct udev_event *event, int limit)
udev_device_get_seqnum(event->dev), udev_device_get_seqnum(event->dev),
udev_device_get_seqnum(loop_event->dev), udev_device_get_seqnum(loop_event->dev),
udev_device_get_devpath(loop_event->dev)); udev_device_get_devpath(loop_event->dev));
return 3; event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev);
return 4;
} }
/* check for our major:minor number */ /* check for our major:minor number */
@ -367,7 +377,8 @@ static int devpath_busy(struct udev_event *event, int limit)
udev_device_get_seqnum(event->dev), udev_device_get_seqnum(event->dev),
udev_device_get_seqnum(loop_event->dev), udev_device_get_seqnum(loop_event->dev),
major(udev_device_get_devnum(loop_event->dev)), minor(udev_device_get_devnum(loop_event->dev))); major(udev_device_get_devnum(loop_event->dev)), minor(udev_device_get_devnum(loop_event->dev)));
return 4; event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev);
return 5;
} }
/* check physical device event (special case of parent) */ /* check physical device event (special case of parent) */
@ -379,55 +390,8 @@ static int devpath_busy(struct udev_event *event, int limit)
udev_device_get_seqnum(event->dev), udev_device_get_seqnum(event->dev),
udev_device_get_seqnum(loop_event->dev), udev_device_get_seqnum(loop_event->dev),
udev_device_get_devpath(loop_event->dev)); udev_device_get_devpath(loop_event->dev));
return 5; event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev);
} return 6;
}
/* check run queue for still running events */
udev_list_node_foreach(loop, &running_list) {
struct udev_event *loop_event = node_to_event(loop);
if (childs_count++ >= limit) {
info(event->udev, "%llu, maximum number (%i) of childs reached\n",
udev_device_get_seqnum(event->dev), childs_count);
return 1;
}
/* check our old name */
if (udev_device_get_devpath_old(event->dev) != NULL)
if (strcmp(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath_old(event->dev)) == 0)
return 2;
/* check identical, parent, or child device event */
if (compare_devpath(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath(event->dev)) != 0) {
dbg(event->udev, "%llu, device event still running %llu (%s)\n",
udev_device_get_seqnum(event->dev),
udev_device_get_seqnum(loop_event->dev),
udev_device_get_devpath(loop_event->dev));
return 3;
}
/* check for our major:minor number */
if (major(udev_device_get_devnum(event->dev)) > 0 &&
udev_device_get_devnum(loop_event->dev) == udev_device_get_devnum(event->dev) &&
strcmp(udev_device_get_subsystem(event->dev), udev_device_get_subsystem(loop_event->dev)) == 0) {
dbg(event->udev, "%llu, device event still pending %llu (%d:%d)\n",
udev_device_get_seqnum(event->dev),
udev_device_get_seqnum(loop_event->dev),
major(udev_device_get_devnum(loop_event->dev)), minor(udev_device_get_devnum(loop_event->dev)));
return 4;
}
/* check physical device event (special case of parent) */
if (udev_device_get_physdevpath(event->dev) != NULL &&
strcmp(udev_device_get_action(event->dev), "add") == 0)
if (compare_devpath(udev_device_get_devpath(loop_event->dev),
udev_device_get_physdevpath(event->dev)) != 0) {
dbg(event->udev, "%llu, physical device event still pending %llu (%s)\n",
udev_device_get_seqnum(event->dev),
udev_device_get_seqnum(loop_event->dev),
udev_device_get_devpath(loop_event->dev));
return 5;
} }
} }
return 0; return 0;
@ -439,23 +403,34 @@ static void event_queue_manager(struct udev *udev)
struct udev_list_node *loop; struct udev_list_node *loop;
struct udev_list_node *tmp; struct udev_list_node *tmp;
if (udev_list_is_empty(&exec_list)) if (udev_list_is_empty(&event_list)) {
if (childs > 0) {
err(udev, "event list empty, but childs count is %i", childs);
childs = 0;
}
return; return;
}
udev_list_node_foreach_safe(loop, tmp, &exec_list) { udev_list_node_foreach_safe(loop, tmp, &event_list) {
struct udev_event *loop_event = node_to_event(loop); struct udev_event *loop_event = node_to_event(loop);
/* serialize and wait for parent or child events */ if (childs >= max_childs) {
if (devpath_busy(loop_event, max_childs) != 0) { info(udev, "maximum number (%i) of childs reached\n", childs);
break;
}
if (loop_event->pid != 0)
continue;
/* do not start event if parent or child event is still running */
if (devpath_busy(loop_event) != 0) {
dbg(udev, "delay seq %llu (%s)\n", dbg(udev, "delay seq %llu (%s)\n",
udev_device_get_seqnum(loop_event->dev), udev_device_get_seqnum(loop_event->dev),
udev_device_get_devpath(loop_event->dev)); udev_device_get_devpath(loop_event->dev));
continue; continue;
} }
/* move event to run list */ /* do dendencies, start event */
udev_list_node_remove(&loop_event->node);
udev_list_node_append(&loop_event->node, &running_list);
event_fork(loop_event); event_fork(loop_event);
dbg(udev, "moved seq %llu to running list\n", udev_device_get_seqnum(loop_event->dev)); dbg(udev, "moved seq %llu to running list\n", udev_device_get_seqnum(loop_event->dev));
} }
@ -526,7 +501,6 @@ static void handle_ctrl_msg(struct udev_ctrl *uctrl)
info(udev, "udevd message (SET_MAX_CHILDS) received, max_childs=%i\n", i); info(udev, "udevd message (SET_MAX_CHILDS) received, max_childs=%i\n", i);
max_childs = i; max_childs = i;
} }
udev_ctrl_msg_unref(ctrl_msg); udev_ctrl_msg_unref(ctrl_msg);
} }
@ -555,7 +529,7 @@ static void udev_done(int pid, int exitstatus)
struct udev_list_node *loop; struct udev_list_node *loop;
/* find event associated with pid and delete it */ /* find event associated with pid and delete it */
udev_list_node_foreach(loop, &running_list) { udev_list_node_foreach(loop, &event_list) {
struct udev_event *loop_event = node_to_event(loop); struct udev_event *loop_event = node_to_event(loop);
if (loop_event->pid == pid) { if (loop_event->pid == pid) {
@ -563,9 +537,14 @@ static void udev_done(int pid, int exitstatus)
udev_device_get_seqnum(loop_event->dev), loop_event->pid, udev_device_get_seqnum(loop_event->dev), loop_event->pid,
exitstatus, time(NULL) - loop_event->queue_time); exitstatus, time(NULL) - loop_event->queue_time);
loop_event->exitstatus = exitstatus; loop_event->exitstatus = exitstatus;
if (debug_trace)
printf("exit %s (%llu)\n",
udev_device_get_syspath(loop_event->dev),
udev_device_get_seqnum(loop_event->dev));
event_queue_delete(loop_event); event_queue_delete(loop_event);
childs--;
/* there may be events waiting with the same devpath */ /* there may be dependent events waiting */
run_exec_q = 1; run_exec_q = 1;
return; return;
} }
@ -690,8 +669,6 @@ int main(int argc, char *argv[])
fprintf(stderr, "cannot open /dev/null\n"); fprintf(stderr, "cannot open /dev/null\n");
err(udev, "cannot open /dev/null\n"); err(udev, "cannot open /dev/null\n");
} }
if (fd > STDIN_FILENO)
dup2(fd, STDIN_FILENO);
if (write(STDOUT_FILENO, 0, 0) < 0) if (write(STDOUT_FILENO, 0, 0) < 0)
dup2(fd, STDOUT_FILENO); dup2(fd, STDOUT_FILENO);
if (write(STDERR_FILENO, 0, 0) < 0) if (write(STDERR_FILENO, 0, 0) < 0)
@ -755,8 +732,7 @@ int main(int argc, char *argv[])
err(udev, "error reading rules\n"); err(udev, "error reading rules\n");
goto exit; goto exit;
} }
udev_list_init(&running_list); udev_list_init(&event_list);
udev_list_init(&exec_list);
export_initial_seqnum(udev); export_initial_seqnum(udev);
if (daemonize) { if (daemonize) {
@ -779,7 +755,8 @@ int main(int argc, char *argv[])
} }
/* redirect std{out,err} */ /* redirect std{out,err} */
if (!debug) { if (!debug && !debug_trace) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO); dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO); dup2(fd, STDERR_FILENO);
} }
@ -840,7 +817,7 @@ int main(int argc, char *argv[])
inotify_add_watch(inotify_fd, udev_get_rules_path(udev), inotify_add_watch(inotify_fd, udev_get_rules_path(udev),
IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
} else { } else {
char filename[PATH_MAX]; char filename[UTIL_PATH_SIZE];
inotify_add_watch(inotify_fd, UDEV_PREFIX "/lib/udev/rules.d", inotify_add_watch(inotify_fd, UDEV_PREFIX "/lib/udev/rules.d",
IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
@ -858,17 +835,20 @@ int main(int argc, char *argv[])
else else
err(udev, "inotify_init failed: %m\n"); err(udev, "inotify_init failed: %m\n");
/* maximum limit of forked childs */ /* in trace mode run one event after the other */
value = getenv("UDEVD_MAX_CHILDS"); if (debug_trace) {
if (value) max_childs = 1;
max_childs = strtoul(value, NULL, 10); } else {
else {
int memsize = mem_size_mb(); int memsize = mem_size_mb();
if (memsize > 0) if (memsize > 0)
max_childs = 128 + (memsize / 4); max_childs = 128 + (memsize / 4);
else else
max_childs = UDEVD_MAX_CHILDS; max_childs = UDEVD_MAX_CHILDS;
} }
/* possibly overwrite maximum limit of executed events */
value = getenv("UDEVD_MAX_CHILDS");
if (value)
max_childs = strtoul(value, NULL, 10);
info(udev, "initialize max_childs to %u\n", max_childs); info(udev, "initialize max_childs to %u\n", max_childs);
maxfd = udev_ctrl_get_fd(udev_ctrl); maxfd = udev_ctrl_get_fd(udev_ctrl);