On Mon, 2008-12-22 at 11:25 +0000, Alan Jenkins wrote: > I have some time to look at this again now. > I was just looking at this myself, since it formed a natural part of the performance testing I'm doing on Ubuntu. I got as far as reapplying the patches to current git head, but then hit a segfault :-( Attached is the patch against head. The segfault occurs in the udev_device_get_properties() call at the top of udev_exec(), because that calls update_envp_monitor_buf() which calls free(). I assume this is non-reentrant territory? Scott -- Scott James Remnant scott@xxxxxxxxxxxxx
=== modified file 'configure.ac' --- configure.ac 2008-12-16 15:17:53 +0000 +++ configure.ac 2008-12-24 11:16:17 +0000 @@ -9,6 +9,8 @@ AC_SYS_LARGEFILE AC_PROG_LIBTOOL +sinclude(acx_pthread.m4) + dnl /* libudev version */ LIBUDEV_LT_CURRENT=0 LIBUDEV_LT_REVISION=6 @@ -25,6 +27,8 @@ AC_SUBST(VOLID_LT_REVISION) AC_SUBST(VOLID_LT_AGE) +ACX_PTHREAD(AC_DEFINE(HAVE_PTHREAD), AC_MSG_FAILURE([pthreads unavailable])) + AC_PATH_PROG([XSLTPROC], [xsltproc]) AC_CHECK_LIB(c, inotify_init, === modified file 'udev/Makefile.am' --- udev/Makefile.am 2008-12-06 03:03:08 +0000 +++ udev/Makefile.am 2008-12-24 11:16:17 +0000 @@ -1,5 +1,9 @@ include $(top_srcdir)/Makefile.am.inc +LIBS += $(PTHREAD_LIBS) +CFLAGS += $(PTHREAD_CFLAGS) +CC=$(PTHREAD_CC) + SUBDIRS = \ lib @@ -18,6 +22,7 @@ udev-event.c \ udev-node.c \ udev-rules.c \ + udev-exec.c \ udev-util.c \ lib/libudev.h \ lib/libudev-private.h \ === modified file 'udev/test-udev.c' --- udev/test-udev.c 2008-10-24 08:51:04 +0000 +++ udev/test-udev.c 2008-12-24 11:16:28 +0000 @@ -60,6 +60,9 @@ info(udev, "version %s\n", VERSION); udev_selinux_init(udev); + /* fork exec daemon before opening fds or changing signal handling */ + udev_exec_init(udev); + /* set signal handlers */ memset(&act, 0x00, sizeof(act)); act.sa_handler = (void (*)(int)) sig_handler; @@ -69,9 +72,6 @@ sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); - /* trigger timeout to prevent hanging processes */ - alarm(UDEV_EVENT_TIMEOUT); - action = getenv("ACTION"); devpath = getenv("DEVPATH"); subsystem = getenv("SUBSYSTEM"); @@ -99,10 +99,6 @@ event = udev_event_new(dev); err = udev_event_execute_rules(event, rules); - /* rules may change/disable the timeout */ - if (udev_device_get_event_timeout(dev) >= 0) - alarm(udev_device_get_event_timeout(dev)); - if (err == 0 && !event->ignore_device && udev_get_run(udev)) udev_event_execute_run(event); @@ -111,6 +107,7 @@ fail: udev_rules_unref(rules); exit: + udev_exec_cleanup(udev); udev_selinux_exit(udev); udev_unref(udev); if (err != 0) === modified file 'udev/udev-event.c' --- udev/udev-event.c 2008-12-02 00:04:23 +0000 +++ udev/udev-event.c 2008-12-24 11:10:39 +0000 @@ -717,7 +717,7 @@ udev_device_get_seqnum(event->dev), program); envp = udev_device_get_properties_envp(event->dev); - if (util_run_program(event->udev, program, envp, NULL, 0, NULL) != 0) { + if (udev_exec(event->dev, program, NULL, 0, NULL) != 0) { if (!udev_list_entry_get_flag(list_entry)) err = -1; } === modified file 'udev/udev-rules.c' --- udev/udev-rules.c 2008-11-24 20:24:04 +0000 +++ udev/udev-rules.c 2008-12-24 11:16:01 +0000 @@ -731,13 +731,11 @@ static int import_program_into_properties(struct udev_device *dev, const char *program) { struct udev *udev = udev_device_get_udev(dev); - char **envp; char result[2048]; size_t reslen; char *line; - envp = udev_device_get_properties_envp(dev); - if (util_run_program(udev, program, envp, result, sizeof(result), &reslen) != 0) + if (udev_exec(dev, program, result, sizeof(result), &reslen) != 0) return -1; line = result; @@ -2190,19 +2188,17 @@ case TK_M_PROGRAM: { char program[UTIL_PATH_SIZE]; - char **envp; char result[UTIL_PATH_SIZE]; free(event->program_result); event->program_result = NULL; util_strlcpy(program, &rules->buf[cur->key.value_off], sizeof(program)); udev_event_apply_format(event, program, sizeof(program)); - envp = udev_device_get_properties_envp(event->dev); info(event->udev, "PROGRAM '%s' %s:%u\n", program, &rules->buf[rule->rule.filename_off], rule->rule.filename_line); - if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL) != 0) { + if (udev_exec(event->udev, program, result, sizeof(result), NULL) != 0) { if (cur->key.op != OP_NOMATCH) goto nomatch; } else { === modified file 'udev/udev-util.c' --- udev/udev-util.c 2008-12-19 23:03:53 +0000 +++ udev/udev-util.c 2008-12-24 11:12:52 +0000 @@ -25,7 +25,6 @@ #include <ctype.h> #include <pwd.h> #include <grp.h> -#include <sys/wait.h> #include "udev.h" @@ -238,215 +237,3 @@ udev_device_unref(dev); return 0; } - -int util_run_program(struct udev *udev, const char *command, char **envp, - char *result, size_t ressize, size_t *reslen) -{ - int status; - int outpipe[2] = {-1, -1}; - int errpipe[2] = {-1, -1}; - pid_t pid; - char arg[UTIL_PATH_SIZE]; - char program[UTIL_PATH_SIZE]; - char *argv[(sizeof(arg) / 2) + 1]; - int devnull; - int i; - int err = 0; - - /* build argv from command */ - util_strlcpy(arg, command, sizeof(arg)); - i = 0; - if (strchr(arg, ' ') != NULL) { - char *pos = arg; - - while (pos != NULL && pos[0] != '\0') { - if (pos[0] == '\'') { - /* do not separate quotes */ - pos++; - argv[i] = strsep(&pos, "\'"); - while (pos != NULL && pos[0] == ' ') - pos++; - } else { - argv[i] = strsep(&pos, " "); - } - dbg(udev, "arg[%i] '%s'\n", i, argv[i]); - i++; - } - argv[i] = NULL; - } else { - argv[0] = arg; - argv[1] = NULL; - } - info(udev, "'%s'\n", command); - - /* prepare pipes from child to parent */ - if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) { - if (pipe(outpipe) != 0) { - err(udev, "pipe failed: %m\n"); - return -1; - } - } - if (udev_get_log_priority(udev) >= LOG_INFO) { - if (pipe(errpipe) != 0) { - err(udev, "pipe failed: %m\n"); - return -1; - } - } - - /* allow programs in /lib/udev/ to be called without the path */ - if (strchr(argv[0], '/') == NULL) { - util_strlcpy(program, UDEV_PREFIX "/lib/udev/", sizeof(program)); - util_strlcat(program, argv[0], sizeof(program)); - argv[0] = program; - } - - pid = fork(); - switch(pid) { - case 0: - /* child closes parent ends of pipes */ - if (outpipe[READ_END] > 0) - close(outpipe[READ_END]); - if (errpipe[READ_END] > 0) - close(errpipe[READ_END]); - - /* discard child output or connect to pipe */ - devnull = open("/dev/null", O_RDWR); - if (devnull > 0) { - dup2(devnull, STDIN_FILENO); - if (outpipe[WRITE_END] < 0) - dup2(devnull, STDOUT_FILENO); - if (errpipe[WRITE_END] < 0) - dup2(devnull, STDERR_FILENO); - close(devnull); - } else - err(udev, "open /dev/null failed: %m\n"); - if (outpipe[WRITE_END] > 0) { - dup2(outpipe[WRITE_END], STDOUT_FILENO); - close(outpipe[WRITE_END]); - } - if (errpipe[WRITE_END] > 0) { - dup2(errpipe[WRITE_END], STDERR_FILENO); - close(errpipe[WRITE_END]); - } - execve(argv[0], argv, envp); - if (errno == ENOENT || errno == ENOTDIR) { - /* may be on a filesytem which is not mounted right now */ - info(udev, "program '%s' not found\n", argv[0]); - } else { - /* other problems */ - err(udev, "exec of program '%s' failed\n", argv[0]); - } - _exit(1); - case -1: - err(udev, "fork of '%s' failed: %m\n", argv[0]); - return -1; - default: - /* read from child if requested */ - if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { - ssize_t count; - size_t respos = 0; - - /* parent closes child ends of pipes */ - if (outpipe[WRITE_END] > 0) - close(outpipe[WRITE_END]); - if (errpipe[WRITE_END] > 0) - close(errpipe[WRITE_END]); - - /* read child output */ - while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { - int fdcount; - fd_set readfds; - - FD_ZERO(&readfds); - if (outpipe[READ_END] > 0) - FD_SET(outpipe[READ_END], &readfds); - if (errpipe[READ_END] > 0) - FD_SET(errpipe[READ_END], &readfds); - fdcount = select(UDEV_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL); - if (fdcount < 0) { - if (errno == EINTR) - continue; - err = -1; - break; - } - - /* get stdout */ - if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) { - char inbuf[1024]; - char *pos; - char *line; - - count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1); - if (count <= 0) { - close(outpipe[READ_END]); - outpipe[READ_END] = -1; - if (count < 0) { - err(udev, "stdin read failed: %m\n"); - err = -1; - } - continue; - } - inbuf[count] = '\0'; - - /* store result for rule processing */ - if (result) { - if (respos + count < ressize) { - memcpy(&result[respos], inbuf, count); - respos += count; - } else { - err(udev, "ressize %ld too short\n", (long)ressize); - err = -1; - } - } - pos = inbuf; - while ((line = strsep(&pos, "\n"))) - if (pos || line[0] != '\0') - info(udev, "'%s' (stdout) '%s'\n", argv[0], line); - } - - /* get stderr */ - if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) { - char errbuf[1024]; - char *pos; - char *line; - - count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1); - if (count <= 0) { - close(errpipe[READ_END]); - errpipe[READ_END] = -1; - if (count < 0) - err(udev, "stderr read failed: %m\n"); - continue; - } - errbuf[count] = '\0'; - pos = errbuf; - while ((line = strsep(&pos, "\n"))) - if (pos || line[0] != '\0') - info(udev, "'%s' (stderr) '%s'\n", argv[0], line); - } - } - if (outpipe[READ_END] > 0) - close(outpipe[READ_END]); - if (errpipe[READ_END] > 0) - close(errpipe[READ_END]); - - /* return the childs stdout string */ - if (result) { - result[respos] = '\0'; - dbg(udev, "result='%s'\n", result); - if (reslen) - *reslen = respos; - } - } - waitpid(pid, &status, 0); - if (WIFEXITED(status)) { - info(udev, "'%s' returned with status %i\n", argv[0], WEXITSTATUS(status)); - if (WEXITSTATUS(status) != 0) - err = -1; - } else { - err(udev, "'%s' abnormal exit\n", command); - err = -1; - } - } - return err; -} === modified file 'udev/udev.h' --- udev/udev.h 2008-11-05 20:49:52 +0000 +++ udev/udev.h 2008-12-24 11:16:47 +0000 @@ -35,6 +35,9 @@ #define READ_END 0 #define WRITE_END 1 +#define UDEVD_PRIORITY -4 /* nice level for daemon */ +#define UDEV_PRIORITY -2 /* nice level for programs run by daemon*/ + static inline void logging_init(const char *program_name) { openlog(program_name, LOG_PID | LOG_CONS, LOG_DAEMON); @@ -64,7 +67,7 @@ uid_t uid; gid_t gid; struct udev_list_node run_list; - pid_t pid; + pthread_t thread; int exitstatus; time_t queue_time; unsigned long long int delaying_seqnum; @@ -100,14 +103,18 @@ extern int udev_node_remove(struct udev_device *dev, int test); extern void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old, int test); +/* udev-exec.c */ +extern int udev_exec_init(struct udev *udev); +extern void udev_exec_cleanup(struct udev *udev); +extern int udev_exec(struct udev_device *dev, const char *command, + char *result, size_t ressize, size_t *reslen); + /* udev-util.c */ extern int util_create_path(struct udev *udev, const char *path); extern int util_delete_path(struct udev *udev, const char *path); extern int util_unlink_secure(struct udev *udev, const char *filename); extern uid_t util_lookup_user(struct udev *udev, const char *user); extern gid_t util_lookup_group(struct udev *udev, const char *group); -extern int util_run_program(struct udev *udev, const char *command, char **envp, - char *result, size_t ressize, size_t *reslen); extern int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); === modified file 'udev/udevd.c' --- udev/udevd.c 2008-11-17 13:43:58 +0000 +++ udev/udevd.c 2008-12-24 11:28:17 +0000 @@ -35,12 +35,10 @@ #ifdef HAVE_INOTIFY #include <sys/inotify.h> #endif +#include <pthread.h> #include "udev.h" -#define UDEVD_PRIORITY -4 -#define UDEV_PRIORITY -2 - /* maximum limit of forked childs */ #define UDEVD_MAX_CHILDS 256 @@ -64,7 +62,7 @@ static struct udev_monitor *kernel_monitor; static int inotify_fd = -1; static int signal_pipe[2] = {-1, -1}; -static volatile int sigchilds_waiting; +static int event_done_pipe[2] = {-1, -1}; static volatile int udev_exit; static volatile int reload_config; static int run_exec_q; @@ -73,6 +71,8 @@ static int childs; static struct udev_list_node event_list; +pthread_attr_t thread_attr; + enum event_state { EVENT_QUEUED, EVENT_FINISHED, @@ -167,87 +167,68 @@ udev_event_unref(event); } -static void asmlinkage event_sig_handler(int signum) -{ - if (signum == SIGALRM) - exit(1); -} - -static void event_fork(struct udev_event *event) -{ - pid_t pid; - struct sigaction act; - int err; - - if (debug_trace) { - event->trace = 1; - fprintf(stderr, "fork %s (%llu)\n", - udev_device_get_syspath(event->dev), - udev_device_get_seqnum(event->dev)); - } - - pid = fork(); - switch (pid) { - case 0: - /* child */ - udev_monitor_unref(kernel_monitor); - udev_ctrl_unref(udev_ctrl); - if (inotify_fd >= 0) - close(inotify_fd); - close(signal_pipe[READ_END]); - close(signal_pipe[WRITE_END]); - logging_close(); - logging_init("udevd-event"); - setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); - - /* set signal handlers */ - memset(&act, 0x00, sizeof(act)); - act.sa_handler = (void (*)(int)) event_sig_handler; - sigemptyset (&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGALRM, &act, NULL); - - /* reset to default */ - act.sa_handler = SIG_DFL; - sigaction(SIGINT, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGCHLD, &act, NULL); - sigaction(SIGHUP, &act, NULL); - - /* set timeout to prevent hanging processes */ - alarm(UDEV_EVENT_TIMEOUT); - - /* apply rules, create node, symlinks */ - err = udev_event_execute_rules(event, rules); - - /* rules may change/disable the timeout */ - if (udev_device_get_event_timeout(event->dev) >= 0) - alarm(udev_device_get_event_timeout(event->dev)); - - /* execute RUN= */ - if (err == 0 && !event->ignore_device && udev_get_run(event->udev)) - udev_event_execute_run(event); - - info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); - logging_close(); - if (err != 0) - exit(1); - exit(0); - case -1: - err(event->udev, "fork of child failed: %m\n"); +static int event_run(struct udev_event *event) +{ + int err; + + /* apply rules, create node, symlinks */ + err = udev_event_execute_rules(event, rules); + + /* execute RUN= */ + if (err == 0 && !event->ignore_device && udev_get_run(event->udev)) + udev_event_execute_run(event); + info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); + + return err; +} + +static void *event_run_pthread(void *arg) +{ + struct udev_event *event = arg; + int err; + + err = event_run(event); + + /* write to pipe, which will wakeup select() in our mainloop */ + write(event_done_pipe[WRITE_END], &event, sizeof(struct udev_event *)); + + return (void *) (uintptr_t) err; +} + +static void event_thread_create(struct udev_event *event) +{ + if (pthread_create(&event->thread, &thread_attr, event_run_pthread, event) != 0) { + err(event->udev, "create thread failed: %m\n"); event_queue_delete(event); - break; - default: - /* get SIGCHLD in main loop */ - info(event->udev, "seq %llu forked, pid [%d], '%s' '%s', %ld seconds old\n", - udev_device_get_seqnum(event->dev), - pid, - udev_device_get_action(event->dev), - udev_device_get_subsystem(event->dev), - time(NULL) - event->queue_time); - event->pid = pid; - childs++; - } + } + + info(event->udev, "seq %llu created, '%s' '%s', %ld seconds old\n", + udev_device_get_seqnum(event->dev), + udev_device_get_action(event->dev), + udev_device_get_subsystem(event->dev), + time(NULL) - event->queue_time); +} + +static int event_thread_join(struct udev_event *event) +{ + void *result; + int err; + + err = pthread_join(event->thread, &result); + if (err) { + err(event->udev, "failed to retrieve thread return value: %m\n"); + return -1; + } + + return (int) (uintptr_t) result; +} + +static void event_thread_kill(struct udev_event *event) +{ + pthread_kill(event->thread, SIGTERM); + + /* Make sure thread has died before we return */ + event_thread_join(event); } static void event_queue_insert(struct udev_event *event) @@ -279,7 +260,7 @@ /* run all events with a timeout set immediately */ if (udev_device_get_timeout(event->dev) > 0) { - event_fork(event); + event_thread_create(event); return; } } @@ -420,7 +401,7 @@ break; } - if (loop_event->pid != 0) + if (loop_event->thread) continue; /* do not start event if parent or child event is still running */ @@ -431,7 +412,7 @@ continue; } - event_fork(loop_event); + event_thread_create(loop_event); dbg(udev, "moved seq %llu to running list\n", udev_device_get_seqnum(loop_event->dev)); } } @@ -509,12 +490,9 @@ switch (signum) { case SIGINT: case SIGTERM: + case SIGCHLD: udev_exit = 1; break; - case SIGCHLD: - /* set flag, then write to pipe if needed */ - sigchilds_waiting = 1; - break; case SIGHUP: reload_config = 1; break; @@ -524,50 +502,17 @@ write(signal_pipe[WRITE_END], "", 1); } -static void udev_done(int pid, int exitstatus) -{ - struct udev_list_node *loop; - - /* find event associated with pid and delete it */ - udev_list_node_foreach(loop, &event_list) { - struct udev_event *loop_event = node_to_event(loop); - - if (loop_event->pid == pid) { - info(loop_event->udev, "seq %llu cleanup, pid [%d], status %i, %ld seconds old\n", - udev_device_get_seqnum(loop_event->dev), loop_event->pid, - exitstatus, time(NULL) - loop_event->queue_time); - loop_event->exitstatus = exitstatus; - if (debug_trace) - fprintf(stderr, "exit %s (%llu)\n", - udev_device_get_syspath(loop_event->dev), - udev_device_get_seqnum(loop_event->dev)); - event_queue_delete(loop_event); - childs--; - - /* there may be dependent events waiting */ - run_exec_q = 1; - return; - } - } -} - -static void reap_sigchilds(void) -{ - pid_t pid; - int status; - - while (1) { - pid = waitpid(-1, &status, WNOHANG); - if (pid <= 0) - break; - if (WIFEXITED(status)) - status = WEXITSTATUS(status); - else if (WIFSIGNALED(status)) - status = WTERMSIG(status) + 128; - else - status = 0; - udev_done(pid, status); - } +static void udev_done(struct udev_event *event) +{ + event->exitstatus = event_thread_join(event); + info(event->udev, "seq %llu cleanup, status %i, %ld seconds old\n", + udev_device_get_seqnum(event->dev), + event->exitstatus, time(NULL) - event->queue_time); + + event_queue_delete(event); + + /* there may be events waiting with the same devpath */ + run_exec_q = 1; } static void cleanup_queue_dir(struct udev *udev) @@ -636,6 +581,8 @@ int err; int fd; struct sigaction act; + int pagesize; + int stacksize; fd_set readfds; const char *value; int daemonize = 0; @@ -706,6 +653,13 @@ if (write(STDERR_FILENO, 0, 0) < 0) dup2(fd, STDERR_FILENO); + chdir("/"); + umask(022); + setsid(); + + /* fork exec daemon before opening more fds or changing signal handling */ + udev_exec_init(udev); + /* init control socket, bind() ensures, that only one udevd instance is running */ udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); if (udev_ctrl == NULL) { @@ -736,6 +690,11 @@ err(udev, "error getting pipes: %m\n"); goto exit; } + err = pipe(event_done_pipe); + if (err < 0) { + err(udev, "error getting pipes: %m\n"); + goto exit; + } err = fcntl(signal_pipe[READ_END], F_GETFL, 0); if (err < 0) { @@ -799,9 +758,28 @@ /* set scheduling priority for the daemon */ setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY); - chdir("/"); - umask(022); - setsid(); + pthread_attr_init(&thread_attr); + + /* To create many threads on 32-bit, it may be necessary to explicitly limit the stack size. + + udevd doesn't use crazy recursion or deep call-chains. + But it does allocate quite a few buffers and temporary strings on the stack. + We may also need extra space for exotic NSS modules (user/group lookup, e.g. over LDAP). + Make a generous guess, double it, and double it again! + + This comes to just over 200Kb. The default on i386 is 2Mb. + */ + stacksize = PTHREAD_STACK_MIN; + stacksize += UTIL_PATH_SIZE * 8; + stacksize += UTIL_LINE_SIZE * 8; + stacksize += UTIL_NAME_SIZE * 8; + stacksize += 4096 * 8; + stacksize *= 4; + + /* Round up to a whole number of pages */ + pagesize = sysconf(_SC_PAGESIZE); + stacksize = ((stacksize / pagesize) + 1) * pagesize; + pthread_attr_setstacksize(&thread_attr, stacksize); /* OOM_DISABLE == -17 */ fd = open("/proc/self/oom_adj", O_RDWR); @@ -887,12 +865,14 @@ maxfd = udev_ctrl_get_fd(udev_ctrl); maxfd = UDEV_MAX(maxfd, udev_monitor_get_fd(kernel_monitor)); maxfd = UDEV_MAX(maxfd, signal_pipe[READ_END]); + maxfd = UDEV_MAX(maxfd, event_done_pipe[READ_END]); maxfd = UDEV_MAX(maxfd, inotify_fd); while (!udev_exit) { int fdcount; FD_ZERO(&readfds); FD_SET(signal_pipe[READ_END], &readfds); + FD_SET(event_done_pipe[READ_END], &readfds); FD_SET(udev_ctrl_get_fd(udev_ctrl), &readfds); FD_SET(udev_monitor_get_fd(kernel_monitor), &readfds); if (inotify_fd >= 0) @@ -931,6 +911,21 @@ read(signal_pipe[READ_END], &buf, sizeof(buf)); } + /* processed events */ + if (FD_ISSET(event_done_pipe[READ_END], &readfds)) { + struct udev_event *buf[32]; + ssize_t count; + unsigned i; + + count = read(event_done_pipe[READ_END], &buf, sizeof(buf)); + if (count < 0) { + err(udev, "read error on thread pipe: %m\n"); + } else { + for (i = 0; i < count / sizeof(buf[0]); i++) + udev_done(buf[i]); + } + } + /* rules directory inotify watch */ if ((inotify_fd >= 0) && FD_ISSET(inotify_fd, &readfds)) { int nbytes; @@ -963,11 +958,6 @@ } } - if (sigchilds_waiting) { - sigchilds_waiting = 0; - reap_sigchilds(); - } - if (run_exec_q) { run_exec_q = 0; if (!stop_exec_q) @@ -976,8 +966,19 @@ } cleanup_queue_dir(udev); rc = 0; + /* Kill event threads before destroying global udev context */ + if (!udev_list_is_empty(&event_list)) { + struct udev_list_node *loop; + + udev_list_node_foreach(loop, &event_list) { + struct udev_event *loop_event = node_to_event(loop); + + event_thread_kill(loop_event); + } + } exit: udev_rules_unref(rules); + pthread_attr_destroy(&thread_attr); if (signal_pipe[READ_END] >= 0) close(signal_pipe[READ_END]); if (signal_pipe[WRITE_END] >= 0) @@ -986,6 +987,7 @@ if (inotify_fd >= 0) close(inotify_fd); udev_monitor_unref(kernel_monitor); + udev_exec_cleanup(udev); udev_selinux_exit(udev); udev_unref(udev); logging_close();
Attachment:
signature.asc
Description: This is a digitally signed message part