- pthread_mutex_init(&msg_lock, NULL);
- pthread_mutex_init(&msg_active_lock, NULL);
- pthread_mutex_init(&exec_lock, NULL);
- pthread_mutex_init(&exec_active_lock, NULL);
- pthread_mutex_init(&running_lock, NULL);
-
- /* set default attributes for created threads */
- pthread_attr_init(&thr_attr);
- pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
-
- /* init queue management */
- pthread_create(&mgr_msg_tid, &thr_attr, msg_queue_manager, NULL);
- pthread_create(&mgr_exec_tid, &thr_attr, exec_queue_manager, NULL);
-
- clen = sizeof(caddr);
- /* main loop */
- while (1) {
- csock = accept(ssock, &caddr, &clen);
- if (csock < 0) {
- if (errno == EINTR)
- continue;
- dbg("client accept failed\n");
+ /* override of forked udev binary, used for testing */
+ udev_bin = getenv("UDEV_BIN");
+ if (udev_bin != NULL)
+ info("udev binary is set to '%s'", udev_bin);
+ else
+ udev_bin = UDEV_BIN;
+
+ /* init of expected_seqnum value */
+ value = getenv("UDEVD_EXPECTED_SEQNUM");
+ if (value) {
+ expected_seqnum = strtoull(value, NULL, 10);
+ info("initialize expected_seqnum to %llu", expected_seqnum);
+ }
+
+ /* timeout to wait for missing events */
+ value = getenv("UDEVD_EVENT_TIMEOUT");
+ if (value)
+ event_timeout = strtoul(value, NULL, 10);
+ else
+ event_timeout = UDEVD_EVENT_TIMEOUT;
+ info("initialize event_timeout to %u", event_timeout);
+
+ /* maximum limit of forked childs */
+ value = getenv("UDEVD_MAX_CHILDS");
+ if (value)
+ max_childs = strtoul(value, NULL, 10);
+ else
+ max_childs = UDEVD_MAX_CHILDS;
+ info("initialize max_childs to %u", max_childs);
+
+ /* start to throttle forking if maximum number of _running_ childs is reached */
+ value = getenv("UDEVD_MAX_CHILDS_RUNNING");
+ if (value)
+ max_childs_running = strtoull(value, NULL, 10);
+ else
+ max_childs_running = UDEVD_MAX_CHILDS_RUNNING;
+ info("initialize max_childs_running to %u", max_childs_running);
+
+ FD_ZERO(&readfds);
+ FD_SET(udevd_sock, &readfds);
+ if (uevent_netlink_sock > 0)
+ FD_SET(uevent_netlink_sock, &readfds);
+ FD_SET(pipefds[0], &readfds);
+ maxsockplus = udevd_sock+1;
+ while (!udev_exit) {
+ struct uevent_msg *msg;
+
+ fd_set workreadfds = readfds;
+ retval = select(maxsockplus, &workreadfds, NULL, NULL, NULL);
+
+ if (retval < 0) {
+ if (errno != EINTR)
+ dbg("error in select: %s", strerror(errno));
+ continue;
+ }
+
+ /* get user socket message */
+ if (FD_ISSET(udevd_sock, &workreadfds)) {
+ msg = get_udevd_msg();
+ if (msg) {
+ /* discard kernel messages if netlink is active */
+ if (uevent_netlink_active && msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) {
+ dbg("skip uevent_helper message, netlink is active");
+ free(msg);
+ continue;
+ }
+ msg_queue_insert(msg);
+ }
+ }
+
+ /* get kernel netlink message */
+ if (FD_ISSET(uevent_netlink_sock, &workreadfds)) {
+ msg = get_netlink_msg();
+ if (msg) {
+ msg_queue_insert(msg);
+ /* disable udevsend with first netlink message */
+ if (!uevent_netlink_active) {
+ info("uevent_nl message received, disable udevsend messages");
+ uevent_netlink_active = 1;
+ }
+ }
+ }
+
+ /* received a signal, clear our notification pipe */
+ if (FD_ISSET(pipefds[0], &workreadfds))
+ user_sighandler();
+
+ /* forked child have returned */
+ if (sigchilds_waiting) {
+ sigchilds_waiting = 0;
+ reap_sigchilds();
+ }
+
+ if (run_msg_q) {
+ run_msg_q = 0;
+ msg_queue_manager();
+ }
+
+ if (run_exec_q) {
+ /* clean up running_list before calling exec_queue_manager() */
+ if (sigchilds_waiting) {
+ sigchilds_waiting = 0;
+ reap_sigchilds();
+ }
+
+ run_exec_q = 0;
+ if (!stop_exec_q)
+ exec_queue_manager();