chiark / gitweb /
udev: remove seqnum API and all assumptions about seqnums
authorKay Sievers <kay@vrfy.org>
Sun, 13 Apr 2014 05:35:50 +0000 (22:35 -0700)
committerKay Sievers <kay@vrfy.org>
Mon, 14 Apr 2014 00:12:14 +0000 (17:12 -0700)
The way the kernel namespaces have been implemented breaks assumptions
udev made regarding uevent sequence numbers. Creating devices in a
namespace "steals" uevents and its sequence numbers from the host. It
confuses the "udevadmin settle" logic, which might block until util a
timeout is reached, even when no uevent is pending.

Remove any assumptions about sequence numbers and deprecate libudev's
API exposing these numbers; none of that can reliably be used anymore
when namespaces are involved.

Makefile.am
man/udevadm.xml
src/libudev/libudev-monitor.c
src/libudev/libudev-queue-private.c [deleted file]
src/libudev/libudev-queue.c
src/libudev/libudev.h
src/shared/udev-util.h
src/test/test-libudev.c
src/udev/udev-ctrl.c
src/udev/udevadm-settle.c
src/udev/udevd.c

index 5d846052d80088bee77a0d97900aab4e4ab4fd43..0ad1729c0b2f0eed7d06c0e3e4bc2a6d814de3b3 100644 (file)
@@ -2587,8 +2587,7 @@ noinst_LTLIBRARIES += \
 
 libudev_internal_la_SOURCES =\
        $(libudev_la_SOURCES) \
-       src/libudev/libudev-device-private.c \
-       src/libudev/libudev-queue-private.c
+       src/libudev/libudev-device-private.c
 
 libudev_internal_la_CFLAGS = \
        $(AM_CFLAGS) \
@@ -5169,6 +5168,9 @@ test_libsystemd_sym_LDADD = \
 
 test_libudev_sym_SOURCES = \
        test-libudev-sym.c
+test_libudev_sym_CFLAGS = \
+       $(AM_CFLAGS) \
+       -Wno-deprecated-declarations
 test_libudev_sym_LDADD = \
        libudev.la
 
index 21d14434a383072f6feb68dcf91658681b7d265a..fbfa85a80475272741e94929f67faf2b11e4ee32 100644 (file)
             return immediately.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-s</option></term>
-          <term><option>--seq-start=<replaceable>SEQNUM</replaceable></option></term>
-          <listitem>
-            <para>Wait only for events after the given sequence
-            number.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>-e</option></term>
-          <term><option>--seq-end=<replaceable>SEQNUM</replaceable></option></term>
-          <listitem>
-            <para>Wait only for events before the given sequence number.</para>
-          </listitem>
-        </varlistentry>
         <varlistentry>
           <term><option>-E</option></term>
           <term><option>--exit-if-exists=<replaceable>FILE</replaceable></option></term>
             <para>Stop waiting if file exists.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-q</option></term>
-          <term><option>--quiet</option></term>
-          <listitem>
-            <para>Do not print any output, like the remaining queue entries when reaching the timeout.</para>
-          </listitem>
-        </varlistentry>
         <varlistentry>
           <term><option>-h</option></term>
           <term><option>--help</option></term>
index ba1b04d4798cc6ee22a9690bbb425539967fe770..3f7436b0947419b9cb25a9ad0688a6e77fdebee8 100644 (file)
@@ -146,21 +146,6 @@ static bool udev_has_devtmpfs(struct udev *udev) {
         return false;
 }
 
-/* we consider udev running when we have running udev service */
-static bool udev_has_service(struct udev *udev) {
-        struct udev_queue *queue;
-        bool active;
-
-        queue = udev_queue_new(udev);
-        if (!queue)
-                return false;
-
-        active = udev_queue_get_udev_is_active(queue);
-        udev_queue_unref(queue);
-
-        return active;
-}
-
 struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
 {
         struct udev_monitor *udev_monitor;
@@ -184,7 +169,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
                  * We do not set a netlink multicast group here, so the socket
                  * will not receive any messages.
                  */
-                if (!udev_has_service(udev) && !udev_has_devtmpfs(udev)) {
+                if (access("/run/udev/control", F_OK) < 0 && !udev_has_devtmpfs(udev)) {
                         udev_dbg(udev, "the udev service seems not to be active, disable the monitor\n");
                         group = UDEV_MONITOR_NONE;
                 } else
diff --git a/src/libudev/libudev-queue-private.c b/src/libudev/libudev-queue-private.c
deleted file mode 100644 (file)
index d5a2b50..0000000
+++ /dev/null
@@ -1,406 +0,0 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
-  Copyright 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * DISCLAIMER - The file format mentioned here is private to udev/libudev,
- *              and may be changed without notice.
- *
- * The udev event queue is exported as a binary log file.
- * Each log record consists of a sequence number followed by the device path.
- *
- * When a new event is queued, its details are appended to the log.
- * When the event finishes, a second record is appended to the log
- * with the same sequence number but a devpath len of 0.
- *
- * Example:
- *        { 0x0000000000000001 }
- *        { 0x0000000000000001, 0x0019, "/devices/virtual/mem/null" },
- *        { 0x0000000000000002, 0x001b, "/devices/virtual/mem/random" },
- *        { 0x0000000000000001, 0x0000 },
- *        { 0x0000000000000003, 0x0019, "/devices/virtual/mem/zero" },
- *
- * Events 2 and 3 are still queued, but event 1 has finished.
- *
- * The queue does not grow indefinitely. It is periodically re-created
- * to remove finished events. Atomic rename() makes this transparent to readers.
- *
- * The queue file starts with a single sequence number which specifies the
- * minimum sequence number in the log that follows. Any events prior to this
- * sequence number have already finished.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
-
-struct udev_queue_export {
-        struct udev *udev;
-        int queued_count;        /* number of unfinished events exported in queue file */
-        FILE *queue_file;
-        unsigned long long int seqnum_max;        /* earliest sequence number in queue file */
-        unsigned long long int seqnum_min;        /* latest sequence number in queue file */
-        int waste_bytes;                        /* queue file bytes wasted on finished events */
-};
-
-struct udev_queue_export *udev_queue_export_new(struct udev *udev)
-{
-        struct udev_queue_export *udev_queue_export;
-        unsigned long long int initial_seqnum;
-
-        if (udev == NULL)
-                return NULL;
-
-        udev_queue_export = new0(struct udev_queue_export, 1);
-        if (udev_queue_export == NULL)
-                return NULL;
-        udev_queue_export->udev = udev;
-
-        initial_seqnum = udev_get_kernel_seqnum(udev);
-        udev_queue_export->seqnum_min = initial_seqnum;
-        udev_queue_export->seqnum_max = initial_seqnum;
-
-        udev_queue_export_cleanup(udev_queue_export);
-        if (rebuild_queue_file(udev_queue_export) != 0) {
-                free(udev_queue_export);
-                return NULL;
-        }
-
-        return udev_queue_export;
-}
-
-struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export)
-{
-        if (udev_queue_export == NULL)
-                return NULL;
-        if (udev_queue_export->queue_file != NULL)
-                fclose(udev_queue_export->queue_file);
-        free(udev_queue_export);
-        return NULL;
-}
-
-void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export)
-{
-        if (udev_queue_export == NULL)
-                return;
-        unlink("/run/udev/queue.tmp");
-        unlink("/run/udev/queue.bin");
-}
-
-static int skip_to(FILE *file, long offset)
-{
-        long old_offset;
-
-        /* fseek may drop buffered data, avoid it for small seeks */
-        old_offset = ftell(file);
-        if (offset > old_offset && offset - old_offset <= BUFSIZ) {
-                size_t skip_bytes = offset - old_offset;
-                char *buf = alloca(skip_bytes);
-
-                if (fread(buf, skip_bytes, 1, file) != skip_bytes)
-                        return -1;
-        }
-
-        return fseek(file, offset, SEEK_SET);
-}
-
-struct queue_devpaths {
-        unsigned int devpaths_first;        /* index of first queued event */
-        unsigned int devpaths_size;
-        long devpaths[];                /* seqnum -> offset of devpath in queue file (or 0) */
-};
-
-/*
- * Returns a table mapping seqnum to devpath file offset for currently queued events.
- * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min.
- */
-static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export)
-{
-        struct queue_devpaths *devpaths;
-        unsigned long long int range;
-        long devpath_offset;
-        ssize_t devpath_len;
-        unsigned long long int seqnum;
-        unsigned long long int n;
-        unsigned int i;
-
-        /* seek to the first event in the file */
-        rewind(udev_queue_export->queue_file);
-        udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum);
-
-        /* allocate the table */
-        range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max;
-        if (range - 1 > INT_MAX) {
-                udev_err(udev_queue_export->udev, "queue file overflow\n");
-                return NULL;
-        }
-        devpaths = malloc0(sizeof(struct queue_devpaths) + (range + 1) * sizeof(long));
-        if (devpaths == NULL)
-                return NULL;
-        devpaths->devpaths_size = range + 1;
-
-        /* read all records and populate the table */
-        for (;;) {
-                if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0)
-                        break;
-                n = seqnum - udev_queue_export->seqnum_max;
-                if (n >= devpaths->devpaths_size)
-                        goto read_error;
-
-                devpath_offset = ftell(udev_queue_export->queue_file);
-                devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file);
-                if (devpath_len < 0)
-                        goto read_error;
-
-                if (devpath_len > 0)
-                        devpaths->devpaths[n] = devpath_offset;
-                else
-                        devpaths->devpaths[n] = 0;
-        }
-
-        /* find first queued event */
-        for (i = 0; i < devpaths->devpaths_size; i++) {
-                if (devpaths->devpaths[i] != 0)
-                        break;
-        }
-        devpaths->devpaths_first = i;
-
-        return devpaths;
-
-read_error:
-        udev_err(udev_queue_export->udev, "queue file corrupted\n");
-        free(devpaths);
-        return NULL;
-}
-
-static int rebuild_queue_file(struct udev_queue_export *udev_queue_export)
-{
-        unsigned long long int seqnum;
-        struct queue_devpaths *devpaths = NULL;
-        FILE *new_queue_file = NULL;
-        unsigned int i;
-
-        /* read old queue file */
-        if (udev_queue_export->queue_file != NULL) {
-                devpaths = build_index(udev_queue_export);
-                if (devpaths != NULL)
-                        udev_queue_export->seqnum_max += devpaths->devpaths_first;
-        }
-        if (devpaths == NULL) {
-                udev_queue_export->queued_count = 0;
-                udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
-        }
-
-        /* create new queue file */
-        new_queue_file = fopen("/run/udev/queue.tmp", "w+e");
-        if (new_queue_file == NULL)
-                goto error;
-        seqnum = udev_queue_export->seqnum_max;
-        fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file);
-
-        /* copy unfinished events only to the new file */
-        if (devpaths != NULL) {
-                for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) {
-                        char devpath[UTIL_PATH_SIZE];
-                        int err;
-                        unsigned short devpath_len;
-
-                        if (devpaths->devpaths[i] != 0)
-                        {
-                                skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]);
-                                err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath));
-                                devpath_len = err;
-
-                                fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file);
-                                fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file);
-                                fwrite(devpath, 1, devpath_len, new_queue_file);
-                        }
-                        seqnum++;
-                }
-                free(devpaths);
-                devpaths = NULL;
-        }
-        fflush(new_queue_file);
-        if (ferror(new_queue_file))
-                goto error;
-
-        /* rename the new file on top of the old one */
-        if (rename("/run/udev/queue.tmp", "/run/udev/queue.bin") != 0)
-                goto error;
-
-        if (udev_queue_export->queue_file != NULL)
-                fclose(udev_queue_export->queue_file);
-        udev_queue_export->queue_file = new_queue_file;
-        udev_queue_export->waste_bytes = 0;
-
-        return 0;
-
-error:
-        udev_err(udev_queue_export->udev, "failed to create queue file: %m\n");
-        udev_queue_export_cleanup(udev_queue_export);
-
-        if (udev_queue_export->queue_file != NULL) {
-                fclose(udev_queue_export->queue_file);
-                udev_queue_export->queue_file = NULL;
-        }
-        if (new_queue_file != NULL)
-                fclose(new_queue_file);
-
-        if (devpaths != NULL)
-                free(devpaths);
-        udev_queue_export->queued_count = 0;
-        udev_queue_export->waste_bytes = 0;
-        udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
-
-        return -1;
-}
-
-static int write_queue_record(struct udev_queue_export *udev_queue_export,
-                              unsigned long long int seqnum, const char *devpath, size_t devpath_len)
-{
-        unsigned short len;
-
-        if (udev_queue_export->queue_file == NULL)
-                return -1;
-
-        if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1)
-                goto write_error;
-
-        len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX;
-        if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1)
-                goto write_error;
-        if (len > 0) {
-                if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len)
-                        goto write_error;
-        }
-
-        /* *must* flush output; caller may fork */
-        if (fflush(udev_queue_export->queue_file) != 0)
-                goto write_error;
-
-        return 0;
-
-write_error:
-        /* if we failed half way through writing a record to a file,
-           we should not try to write any further records to it. */
-        udev_err(udev_queue_export->udev, "error writing to queue file: %m\n");
-        fclose(udev_queue_export->queue_file);
-        udev_queue_export->queue_file = NULL;
-
-        return -1;
-}
-
-enum device_state {
-        DEVICE_QUEUED,
-        DEVICE_FINISHED,
-};
-
-static inline size_t queue_record_size(size_t devpath_len)
-{
-        return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len;
-}
-
-static int update_queue(struct udev_queue_export *udev_queue_export,
-                         struct udev_device *udev_device, enum device_state state)
-{
-        unsigned long long int seqnum = udev_device_get_seqnum(udev_device);
-        const char *devpath = NULL;
-        size_t devpath_len = 0;
-        int bytes;
-        int err;
-
-        /* FINISHED records have a zero length devpath */
-        if (state == DEVICE_QUEUED) {
-                devpath = udev_device_get_devpath(udev_device);
-                devpath_len = strlen(devpath);
-        }
-
-        /* recover from an earlier failed rebuild */
-        if (udev_queue_export->queue_file == NULL) {
-                if (rebuild_queue_file(udev_queue_export) != 0)
-                        return -1;
-        }
-
-        /* if we're removing the last event from the queue, that's the best time to rebuild it */
-        if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1) {
-                /* we don't need to read the old queue file */
-                fclose(udev_queue_export->queue_file);
-                udev_queue_export->queue_file = NULL;
-                rebuild_queue_file(udev_queue_export);
-                return 0;
-        }
-
-        /* try to rebuild the queue files before they grow larger than one page. */
-        bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len);
-        if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096)
-                rebuild_queue_file(udev_queue_export);
-
-        /* don't record a finished event, if we already dropped the event in a failed rebuild */
-        if (seqnum < udev_queue_export->seqnum_max)
-                return 0;
-
-        /* now write to the queue */
-        if (state == DEVICE_QUEUED) {
-                udev_queue_export->queued_count++;
-                udev_queue_export->seqnum_min = seqnum;
-        } else {
-                udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0);
-                udev_queue_export->queued_count--;
-        }
-        err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len);
-
-        /* try to handle ENOSPC */
-        if (err != 0 && udev_queue_export->queued_count == 0) {
-                udev_queue_export_cleanup(udev_queue_export);
-                err = rebuild_queue_file(udev_queue_export);
-        }
-
-        return err;
-}
-
-static int update(struct udev_queue_export *udev_queue_export,
-                  struct udev_device *udev_device, enum device_state state)
-{
-        if (update_queue(udev_queue_export, udev_device, state) != 0)
-                return -1;
-
-        return 0;
-}
-
-int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
-{
-        return update(udev_queue_export, udev_device, DEVICE_QUEUED);
-}
-
-int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
-{
-        return update(udev_queue_export, udev_device, DEVICE_FINISHED);
-}
index 2cb4d67121641351fc5fb7a49eec5e9cbc3020c8..eb0e096f843f44cc0f57ef012bfe83aa35fbab95 100644 (file)
@@ -24,8 +24,6 @@
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
 #include <limits.h>
 #include <sys/stat.h>
 
  * SECTION:libudev-queue
  * @short_description: access to currently active events
  *
- * The udev daemon processes events asynchronously. All events which do not have
- * interdependencies run in parallel. This exports the current state of the
- * event processing queue, and the current event sequence numbers from the kernel
- * and the udev daemon.
+ * This exports the current state of the udev processing queue.
  */
 
 /**
@@ -50,7 +45,6 @@
 struct udev_queue {
         struct udev *udev;
         int refcount;
-        struct udev_list queue_list;
 };
 
 /**
@@ -72,9 +66,9 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
         udev_queue = new0(struct udev_queue, 1);
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount = 1;
         udev_queue->udev = udev;
-        udev_list_init(udev, &udev_queue->queue_list, false);
         return udev_queue;
 }
 
@@ -90,6 +84,7 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
 {
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount++;
         return udev_queue;
 }
@@ -107,10 +102,11 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
 {
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount--;
         if (udev_queue->refcount > 0)
                 return NULL;
-        udev_list_cleanup(&udev_queue->queue_list);
+
         free(udev_queue);
         return NULL;
 }
@@ -130,141 +126,30 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
         return udev_queue->udev;
 }
 
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
-{
-        unsigned long long int seqnum;
-        int fd;
-        char buf[32];
-        ssize_t len;
-
-        fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return 0;
-        len = read(fd, buf, sizeof(buf));
-        close(fd);
-        if (len <= 2)
-                return 0;
-        buf[len-1] = '\0';
-        seqnum = strtoull(buf, NULL, 10);
-        return seqnum;
-}
-
 /**
  * udev_queue_get_kernel_seqnum:
  * @udev_queue: udev queue context
  *
- * Get the current kernel event sequence number.
+ * This function is deprecated.
  *
- * Returns: the sequence number.
+ * Returns: 0.
  **/
 _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum;
-
-        if (udev_queue == NULL)
-                return -EINVAL;
-
-        seqnum = udev_get_kernel_seqnum(udev_queue->udev);
-        return seqnum;
-}
-
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
-{
-        if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
-                return -1;
-
         return 0;
 }
 
-ssize_t udev_queue_skip_devpath(FILE *queue_file)
-{
-        unsigned short int len;
-
-        if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
-                char *devpath = alloca(len);
-
-                /* use fread to skip, fseek might drop buffered data */
-                if (fread(devpath, 1, len, queue_file) == len)
-                        return len;
-        }
-
-        return -1;
-}
-
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
-{
-        unsigned short int read_bytes = 0;
-        unsigned short int len;
-
-        if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
-                return -1;
-
-        read_bytes = (len < size - 1) ? len : size - 1;
-        if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
-                return -1;
-        devpath[read_bytes] = '\0';
-
-        /* if devpath was too long, skip unread characters */
-        if (read_bytes != len) {
-                unsigned short int skip_bytes = len - read_bytes;
-                char *buf = alloca(skip_bytes);
-
-                if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
-                        return -1;
-        }
-
-        return read_bytes;
-}
-
-static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
-{
-        FILE *queue_file;
-
-        queue_file = fopen("/run/udev/queue.bin", "re");
-        if (queue_file == NULL)
-                return NULL;
-
-        if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
-                udev_err(udev_queue->udev, "corrupt queue file\n");
-                fclose(queue_file);
-                return NULL;
-        }
-
-        return queue_file;
-}
-
 /**
  * udev_queue_get_udev_seqnum:
  * @udev_queue: udev queue context
  *
- * Get the last known udev event sequence number.
+ * This function is deprecated.
  *
- * Returns: the sequence number.
+ * Returns: 0.
  **/
 _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum_udev;
-        FILE *queue_file;
-
-        queue_file = open_queue_file(udev_queue, &seqnum_udev);
-        if (queue_file == NULL)
-                return 0;
-
-        for (;;) {
-                unsigned long long int seqnum;
-                ssize_t devpath_len;
-
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                devpath_len = udev_queue_skip_devpath(queue_file);
-                if (devpath_len < 0)
-                        break;
-                if (devpath_len > 0)
-                        seqnum_udev = seqnum;
-        }
-
-        fclose(queue_file);
-        return seqnum_udev;
+        return 0;
 }
 
 /**
@@ -277,15 +162,7 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *ud
  **/
 _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum_start;
-        FILE *queue_file;
-
-        queue_file = open_queue_file(udev_queue, &seqnum_start);
-        if (queue_file == NULL)
-                return 0;
-
-        fclose(queue_file);
-        return 1;
+        return access("/run/udev/control", F_OK) >= 0;
 }
 
 /**
@@ -298,48 +175,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
  **/
 _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum_kernel;
-        unsigned long long int seqnum_udev = 0;
-        int queued = 0;
-        int is_empty = 0;
-        FILE *queue_file;
-
-        if (udev_queue == NULL)
-                return -EINVAL;
-        queue_file = open_queue_file(udev_queue, &seqnum_udev);
-        if (queue_file == NULL)
-                return 1;
-
-        for (;;) {
-                unsigned long long int seqnum;
-                ssize_t devpath_len;
-
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                devpath_len = udev_queue_skip_devpath(queue_file);
-                if (devpath_len < 0)
-                        break;
-
-                if (devpath_len > 0) {
-                        queued++;
-                        seqnum_udev = seqnum;
-                } else {
-                        queued--;
-                }
-        }
-
-        if (queued > 0)
-                goto out;
-
-        seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
-        if (seqnum_udev < seqnum_kernel)
-                goto out;
-
-        is_empty = 1;
-
-out:
-        fclose(queue_file);
-        return is_empty;
+        return access("/run/udev/queue", F_OK) >= 0;
 }
 
 /**
@@ -348,63 +184,15 @@ out:
  * @start: first event sequence number
  * @end: last event sequence number
  *
- * Check if udev is currently processing any events in a given sequence number range.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
  *
- * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
+ * Returns: a flag indicating if udev is currently handling events.
  **/
 _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
                                                unsigned long long int start, unsigned long long int end)
 {
-        unsigned long long int seqnum;
-        ssize_t devpath_len;
-        int unfinished;
-        FILE *queue_file;
-
-        if (udev_queue == NULL)
-                return -EINVAL;
-        queue_file = open_queue_file(udev_queue, &seqnum);
-        if (queue_file == NULL)
-                return 1;
-        if (start < seqnum)
-                start = seqnum;
-        if (start > end) {
-                fclose(queue_file);
-                return 1;
-        }
-        if (end - start > INT_MAX - 1) {
-                fclose(queue_file);
-                return -EOVERFLOW;
-        }
-
-        /*
-         * we might start with 0, and handle the initial seqnum
-         * only when we find an entry in the queue file
-         **/
-        unfinished = end - start;
-
-        do {
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                devpath_len = udev_queue_skip_devpath(queue_file);
-                if (devpath_len < 0)
-                        break;
-
-                /*
-                 * we might start with an empty or re-build queue file, where
-                 * the initial seqnum is not recorded as finished
-                 */
-                if (start == seqnum && devpath_len > 0)
-                        unfinished++;
-
-                if (devpath_len == 0) {
-                        if (seqnum >= start && seqnum <= end)
-                                unfinished--;
-                }
-        } while (unfinished > 0);
-
-        fclose(queue_file);
-
-        return (unfinished == 0);
+        return udev_queue_get_queue_is_empty(udev_queue);
 }
 
 /**
@@ -412,69 +200,25 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_
  * @udev_queue: udev queue context
  * @seqnum: sequence number
  *
- * Check if udev is currently processing a given sequence number.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
  *
- * Returns: a flag indicating if the given sequence number is currently active.
+ * Returns: a flag indicating if udev is currently handling events.
  **/
 _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
 {
-        if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
-                return 0;
-
-        return 1;
+        return udev_queue_get_queue_is_empty(udev_queue);
 }
 
 /**
  * udev_queue_get_queued_list_entry:
  * @udev_queue: udev queue context
  *
- * Get the first entry of the list of queued events.
+ * This function is deprecated.
  *
- * Returns: a udev_list_entry.
+ * Returns: NULL.
  **/
 _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum;
-        FILE *queue_file;
-
-        if (udev_queue == NULL)
-                return NULL;
-        udev_list_cleanup(&udev_queue->queue_list);
-
-        queue_file = open_queue_file(udev_queue, &seqnum);
-        if (queue_file == NULL)
-                return NULL;
-
-        for (;;) {
-                char syspath[UTIL_PATH_SIZE];
-                char *s;
-                size_t l;
-                ssize_t len;
-                char seqnum_str[32];
-                struct udev_list_entry *list_entry;
-
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
-
-                s = syspath;
-                l = strpcpy(&s, sizeof(syspath), "/sys");
-                len = udev_queue_read_devpath(queue_file, s, l);
-                if (len < 0)
-                        break;
-
-                if (len > 0) {
-                        udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
-                } else {
-                        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
-                                if (streq(seqnum_str, udev_list_entry_get_value(list_entry))) {
-                                        udev_list_entry_delete(list_entry);
-                                        break;
-                                }
-                        }
-                }
-        }
-        fclose(queue_file);
-
-        return udev_list_get_entry(&udev_queue->queue_list);
+        return NULL;
 }
index b9b8f13e44f5b253646760b6d4ee7e2050547a6e..ceb89bd593c66236320cb4a69b8e670caa1dc0f3 100644 (file)
@@ -170,14 +170,14 @@ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
 struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
 struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
 struct udev_queue *udev_queue_new(struct udev *udev);
-unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
-unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
+unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) __attribute__ ((deprecated));
+unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) __attribute__ ((deprecated));
 int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
 int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
-int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
+int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) __attribute__ ((deprecated));
 int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
-                                               unsigned long long int start, unsigned long long int end);
-struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
+                                               unsigned long long int start, unsigned long long int end) __attribute__ ((deprecated));
+struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) __attribute__ ((deprecated));
 
 /*
  *  udev_hwdb
index 40f8b776cecf48568ed07cc33c6fe69c8a7a14aa..5f09ce181f17da033931f297ecba1ded6b5926a8 100644 (file)
@@ -31,7 +31,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_queue*, udev_queue_unref);
 
 #define _cleanup_udev_unref_ _cleanup_(udev_unrefp)
 #define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp)
@@ -40,5 +39,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_queue*, udev_queue_unref);
 #define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp)
 #define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp)
 #define _cleanup_udev_monitor_unref_ _cleanup_(udev_monitor_unrefp)
-#define _cleanup_udev_queue_unref_ _cleanup_(udev_queue_unrefp)
 #define _cleanup_udev_list_cleanup_ _cleanup_(udev_list_cleanup)
index c233b1ea1d9ed80844b7fd5e7f6a3f7fecefb370..f5c8bc768d9745396a1cda2a7b8a6e6d38a91ec9 100644 (file)
@@ -303,38 +303,14 @@ out:
 
 static int test_queue(struct udev *udev) {
         struct udev_queue *udev_queue;
-        unsigned long long int seqnum;
-        struct udev_list_entry *list_entry;
 
         udev_queue = udev_queue_new(udev);
         if (udev_queue == NULL)
                 return -1;
-        seqnum = udev_queue_get_kernel_seqnum(udev_queue);
-        printf("seqnum kernel: %llu\n", seqnum);
-        seqnum = udev_queue_get_udev_seqnum(udev_queue);
-        printf("seqnum udev  : %llu\n", seqnum);
 
         if (udev_queue_get_queue_is_empty(udev_queue))
                 printf("queue is empty\n");
-        printf("get queue list\n");
-        udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
-                printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
-        printf("\n");
-        printf("get queue list again\n");
-        udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
-                printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
-        printf("\n");
 
-        list_entry = udev_queue_get_queued_list_entry(udev_queue);
-        if (list_entry != NULL) {
-                printf("event [%llu] is queued\n", seqnum);
-                seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10);
-                if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum))
-                        printf("event [%llu] is not finished\n", seqnum);
-                else
-                        printf("event [%llu] is finished\n", seqnum);
-        }
-        printf("\n");
         udev_queue_unref(udev_queue);
         return 0;
 }
index 1e91ec20a1f8930460a91016daa22d8be8bcbada..74bbd3a99eade7b908ed3524125a7f3efee7124a 100644 (file)
@@ -275,7 +275,7 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int
 
                 pfd[0].fd = uctrl->sock;
                 pfd[0].events = POLLIN;
-                r = poll(pfd, 1, timeout * 1000);
+                r = poll(pfd, 1, timeout * MSEC_PER_SEC);
                 if (r  < 0) {
                         if (errno == EINTR)
                                 continue;
index 927ea2a7f2e37ba5dc6e8b841c4429f68d1b2c6d..65fc35f9a076f87c45c1712e2464a56ba98b0e52 100644 (file)
 static void help(void) {
         printf("Usage: udevadm settle OPTIONS\n"
                "  -t,--timeout=<seconds>     maximum time to wait for events\n"
-               "  -s,--seq-start=<seqnum>    first seqnum to wait for\n"
-               "  -e,--seq-end=<seqnum>      last seqnum to wait for\n"
                "  -E,--exit-if-exists=<file> stop waiting if file exists\n"
-               "  -q,--quiet                 do not print list after timeout\n"
                "  -h,--help\n\n");
 }
 
 static int adm_settle(struct udev *udev, int argc, char *argv[])
 {
         static const struct option options[] = {
-                { "seq-start",      required_argument, NULL, 's' },
-                { "seq-end",        required_argument, NULL, 'e' },
+                { "seq-start",      required_argument, NULL, '\0' }, /* removed */
+                { "seq-end",        required_argument, NULL, '\0' }, /* removed */
                 { "timeout",        required_argument, NULL, 't' },
                 { "exit-if-exists", required_argument, NULL, 'E' },
-                { "quiet",          no_argument,       NULL, 'q' },
+                { "quiet",          no_argument,       NULL, 'q' },  /* removed */
                 { "help",           no_argument,       NULL, 'h' },
                 {}
         };
-        usec_t start_usec = now(CLOCK_MONOTONIC);
-        usec_t start = 0;
-        usec_t end = 0;
-        int quiet = 0;
         const char *exists = NULL;
         unsigned int timeout = 120;
         struct pollfd pfd[1] = { {.fd = -1}, };
-        _cleanup_udev_queue_unref_ struct udev_queue *udev_queue = NULL;
         int rc = EXIT_FAILURE, c;
 
-        while ((c = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL)) >= 0) {
                 switch (c) {
-                case 's':
-                        start = strtoull(optarg, NULL, 0);
-                        break;
-                case 'e':
-                        end = strtoull(optarg, NULL, 0);
-                        break;
                 case 't': {
                         int r;
 
@@ -91,9 +77,6 @@ static int adm_settle(struct udev *udev, int argc, char *argv[])
                 case 'E':
                         exists = optarg;
                         break;
-                case 'q':
-                        quiet = 1;
-                        break;
                 case 'h':
                         help();
                         exit(EXIT_SUCCESS);
@@ -102,44 +85,13 @@ static int adm_settle(struct udev *udev, int argc, char *argv[])
                 default:
                         assert_not_reached("Unknown argument");
                 }
+        }
 
         if (optind < argc) {
                 fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]);
                 exit(EXIT_FAILURE);
         }
 
-        udev_queue = udev_queue_new(udev);
-        if (udev_queue == NULL)
-                exit(2);
-
-        if (start > 0) {
-                unsigned long long kernel_seq;
-
-                kernel_seq = udev_queue_get_kernel_seqnum(udev_queue);
-
-                /* unless specified, the last event is the current kernel seqnum */
-                if (end == 0)
-                        end = udev_queue_get_kernel_seqnum(udev_queue);
-
-                if (start > end) {
-                        log_error("seq-start larger than seq-end, ignoring");
-                        start = 0;
-                        end = 0;
-                }
-
-                if (start > kernel_seq || end > kernel_seq) {
-                        log_error("seq-start or seq-end larger than current kernel value, ignoring");
-                        start = 0;
-                        end = 0;
-                }
-                log_debug("start=%llu end=%llu current=%llu", (unsigned long long)start, (unsigned long long)end, kernel_seq);
-        } else {
-                if (end > 0) {
-                        log_error("seq-end needs seq-start parameter, ignoring");
-                        end = 0;
-                }
-        }
-
         /* guarantee that the udev daemon isn't pre-processing */
         if (getuid() == 0) {
                 struct udev_ctrl *uctrl;
@@ -160,73 +112,34 @@ static int adm_settle(struct udev *udev, int argc, char *argv[])
         pfd[0].fd = inotify_init1(IN_CLOEXEC);
         if (pfd[0].fd < 0) {
                 log_error("inotify_init failed: %m");
-        } else {
-                if (inotify_add_watch(pfd[0].fd, "/run/udev" , IN_MOVED_TO) < 0) {
-                        log_error("watching /run/udev failed");
-                        close(pfd[0].fd);
-                        pfd[0].fd = -1;
-                }
+                goto out;
         }
 
-        for (;;) {
-                struct stat statbuf;
+        if (inotify_add_watch(pfd[0].fd, "/run/udev/queue" , IN_DELETE) < 0) {
+                log_debug("watching /run/udev failed");
+                goto out;
+        }
 
-                if (exists != NULL && stat(exists, &statbuf) == 0) {
+        for (;;) {
+                if (exists && access(exists, F_OK) >= 0) {
                         rc = EXIT_SUCCESS;
                         break;
                 }
 
-                if (start > 0) {
-                        /* if asked for, wait for a specific sequence of events */
-                        if (udev_queue_get_seqnum_sequence_is_finished(udev_queue, start, end) == 1) {
-                                rc = EXIT_SUCCESS;
-                                break;
-                        }
-                } else {
-                        /* exit if queue is empty */
-                        if (udev_queue_get_queue_is_empty(udev_queue)) {
-                                rc = EXIT_SUCCESS;
-                                break;
-                        }
-                }
-
-                if (pfd[0].fd >= 0) {
-                        int delay;
-
-                        if (exists != NULL || start > 0)
-                                delay = 100;
-                        else
-                                delay = 1000;
-                        /* wake up after delay, or immediately after the queue is rebuilt */
-                        if (poll(pfd, 1, delay) > 0 && pfd[0].revents & POLLIN) {
-                                char buf[sizeof(struct inotify_event) + PATH_MAX];
-
-                                read(pfd[0].fd, buf, sizeof(buf));
-                        }
-                } else {
-                        sleep(1);
+                /* exit if queue is empty */
+                if (access("/run/udev/queue", F_OK) < 0) {
+                        rc = EXIT_SUCCESS;
+                        break;
                 }
 
-                if (timeout > 0) {
-                        usec_t age_usec;
+                /* wake up when "queue" file is deleted */
+                if (poll(pfd, 1, 100) > 0 && pfd[0].revents & POLLIN) {
+                        char buf[sizeof(struct inotify_event) + PATH_MAX];
 
-                        age_usec = now(CLOCK_MONOTONIC) - start_usec;
-                        if (age_usec / (1000 * 1000) >= timeout) {
-                                struct udev_list_entry *list_entry;
-
-                                if (!quiet && udev_queue_get_queued_list_entry(udev_queue) != NULL) {
-                                        log_debug("timeout waiting for udev queue");
-                                        printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout);
-                                        udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
-                                                printf("  %s (%s)\n",
-                                                udev_list_entry_get_name(list_entry),
-                                                udev_list_entry_get_value(list_entry));
-                                }
-
-                                break;
-                        }
+                        read(pfd[0].fd, buf, sizeof(buf));
                 }
         }
+
 out:
         if (pfd[0].fd >= 0)
                 close(pfd[0].fd);
@@ -236,5 +149,5 @@ out:
 const struct udevadm_cmd udevadm_settle = {
         .name = "settle",
         .cmd = adm_settle,
-        .help = "wait for the event queue to finish",
+        .help = "wait for pending udev events",
 };
index f21c227d173c02f53b35dc814593592dac72179e..f9ee36870bd3727dca1d01702050f76bef1c781b 100644 (file)
@@ -60,7 +60,6 @@ void udev_main_log(struct udev *udev, int priority,
 }
 
 static struct udev_rules *rules;
-static struct udev_queue_export *udev_queue_export;
 static struct udev_ctrl *udev_ctrl;
 static struct udev_monitor *monitor;
 static int worker_watch[2] = { -1, -1 };
@@ -139,14 +138,9 @@ static inline struct worker *node_to_worker(struct udev_list_node *node)
         return container_of(node, struct worker, node);
 }
 
-static void event_queue_delete(struct event *event, bool export)
+static void event_queue_delete(struct event *event)
 {
         udev_list_node_remove(&event->node);
-
-        if (export) {
-                udev_queue_export_device_finished(udev_queue_export, event->dev);
-                log_debug("seq %llu done with %i", udev_device_get_seqnum(event->dev), event->exitcode);
-        }
         udev_device_unref(event->dev);
         free(event);
 }
@@ -225,7 +219,6 @@ static void worker_new(struct event *event)
                 free(worker);
                 worker_list_cleanup(udev);
                 event_queue_cleanup(udev, EVENT_UNDEF);
-                udev_queue_export_unref(udev_queue_export);
                 udev_monitor_unref(monitor);
                 udev_ctrl_unref(udev_ctrl);
                 close(fd_signal);
@@ -449,7 +442,6 @@ static int event_queue_insert(struct udev_device *dev)
                 event->nodelay = true;
 #endif
 
-        udev_queue_export_device_queued(udev_queue_export, dev);
         log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev),
              udev_device_get_action(dev), udev_device_get_subsystem(dev));
 
@@ -580,7 +572,7 @@ static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
                 if (match_type != EVENT_UNDEF && match_type != event->state)
                         continue;
 
-                event_queue_delete(event, false);
+                event_queue_delete(event);
         }
 }
 
@@ -605,7 +597,7 @@ static void worker_returned(int fd_worker)
                         /* worker returned */
                         if (worker->event) {
                                 worker->event->exitcode = msg.exitcode;
-                                event_queue_delete(worker->event, true);
+                                event_queue_delete(worker->event);
                                 worker->event = NULL;
                         }
                         if (worker->state != WORKER_KILLED)
@@ -797,7 +789,8 @@ static void handle_signal(struct udev *udev, int signo)
                                                 log_error("worker [%u] failed while handling '%s'",
                                                           pid, worker->event->devpath);
                                                 worker->event->exitcode = -32;
-                                                event_queue_delete(worker->event, true);
+                                                event_queue_delete(worker->event);
+
                                                 /* drop reference taken for state 'running' */
                                                 worker_unref(worker);
                                         }
@@ -1076,14 +1069,7 @@ int main(int argc, char *argv[])
                 goto exit;
         }
 
-        udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
-
-        /* create queue file before signalling 'ready', to make sure we block 'settle' */
-        udev_queue_export = udev_queue_export_new(udev);
-        if (udev_queue_export == NULL) {
-                log_error("error creating queue file");
-                goto exit;
-        }
+        udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
 
         if (daemonize) {
                 pid_t pid;
@@ -1241,12 +1227,12 @@ int main(int argc, char *argv[])
                         worker_kill(udev);
 
                         /* exit after all has cleaned up */
-                        if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list))
+                        if (udev_list_node_is_empty(&event_list) && children == 0)
                                 break;
 
                         /* timeout at exit for workers to finish */
-                        timeout = 30 * 1000;
-                } else if (udev_list_node_is_empty(&event_list) && !children) {
+                        timeout = 30 * MSEC_PER_SEC;
+                } else if (udev_list_node_is_empty(&event_list) && children == 0) {
                         /* we are idle */
                         timeout = -1;
 
@@ -1255,8 +1241,20 @@ int main(int argc, char *argv[])
                                 cg_kill(SYSTEMD_CGROUP_CONTROLLER, udev_cgroup, SIGKILL, false, true, NULL);
                 } else {
                         /* kill idle or hanging workers */
-                        timeout = 3 * 1000;
+                        timeout = 3 * MSEC_PER_SEC;
                 }
+
+                /* tell settle that we are busy or idle */
+                if (!udev_list_node_is_empty(&event_list)) {
+                        int fd;
+
+                        fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
+                        if (fd >= 0)
+                                close(fd);
+                } else {
+                        unlink("/run/udev/queue");
+                }
+
                 fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout);
                 if (fdcount < 0)
                         continue;
@@ -1283,18 +1281,18 @@ int main(int argc, char *argv[])
                                 if (worker->state != WORKER_RUNNING)
                                         continue;
 
-                                if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > 30 * 1000 * 1000) {
+                                if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > 30 * USEC_PER_SEC) {
                                         log_error("worker [%u] %s timeout; kill it", worker->pid,
                                             worker->event ? worker->event->devpath : "<idle>");
                                         kill(worker->pid, SIGKILL);
                                         worker->state = WORKER_KILLED;
+
                                         /* drop reference taken for state 'running' */
                                         worker_unref(worker);
                                         if (worker->event) {
-                                                log_error("seq %llu '%s' killed",
-                                                          udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
+                                                log_error("seq %llu '%s' killed", udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
                                                 worker->event->exitcode = -64;
-                                                event_queue_delete(worker->event, true);
+                                                event_queue_delete(worker->event);
                                                 worker->event = NULL;
                                         }
                                 }
@@ -1317,7 +1315,7 @@ int main(int argc, char *argv[])
                 }
 
                 /* check for changed config, every 3 seconds at most */
-                if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * 1000 * 1000) {
+                if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
                         if (udev_rules_check_timestamp(rules))
                                 reload = true;
                         if (udev_builtin_validate(udev))
@@ -1390,8 +1388,8 @@ int main(int argc, char *argv[])
 
         rc = EXIT_SUCCESS;
 exit:
-        udev_queue_export_cleanup(udev_queue_export);
         udev_ctrl_cleanup(udev_ctrl);
+        unlink("/run/udev/queue");
 exit_daemonize:
         if (fd_ep >= 0)
                 close(fd_ep);
@@ -1406,7 +1404,6 @@ exit_daemonize:
         if (worker_watch[WRITE_END] >= 0)
                 close(worker_watch[WRITE_END]);
         udev_monitor_unref(monitor);
-        udev_queue_export_unref(udev_queue_export);
         udev_ctrl_connection_unref(ctrl_conn);
         udev_ctrl_unref(udev_ctrl);
         label_finish();