X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=libudev%2Flibudev-queue.c;h=d305db6578e8ece4468693ce5f22492121e462b8;hp=bfd90975069eada8bdab949f0ddbb1128e2554b2;hb=d80f8ffd1a182fe7fff9816e8a4efc09e877964b;hpb=ce1d6d7fb47582588cfbcf0baba0c58e42a90ca6 diff --git a/libudev/libudev-queue.c b/libudev/libudev-queue.c index bfd909750..d305db657 100644 --- a/libudev/libudev-queue.c +++ b/libudev/libudev-queue.c @@ -28,7 +28,7 @@ * SECTION:libudev-queue * @short_description: access to currently active events * - * The udev daemon processes event asynchronously. All events wich do not have + * The udev daemon processes event asynchronously. All events which do not have * interdependencies are run in parallel. This exports the current state of the * event processing queue, and the currently event sequence numbers from the kernel * and the udev daemon. @@ -46,6 +46,15 @@ struct udev_queue { struct udev_list_node failed_list; }; +/** + * udev_queue_new: + * @udev: udev library context + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev queue context. + * + * Returns: the udev queue context, or #NULL on error. + **/ struct udev_queue *udev_queue_new(struct udev *udev) { struct udev_queue *udev_queue; @@ -63,6 +72,14 @@ struct udev_queue *udev_queue_new(struct udev *udev) return udev_queue; } +/** + * udev_queue_ref: + * @udev_queue: udev queue context + * + * Take a reference of a udev queue context. + * + * Returns: the same udev queue context. + **/ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) { if (udev_queue == NULL) @@ -71,6 +88,13 @@ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) return udev_queue; } +/** + * udev_queue_unref: + * @udev_queue: udev queue context + * + * Drop a reference of a udev queue context. If the refcount reaches zero, + * the resources of the queue context will be released. + **/ void udev_queue_unref(struct udev_queue *udev_queue) { if (udev_queue == NULL) @@ -83,6 +107,14 @@ void udev_queue_unref(struct udev_queue *udev_queue) free(udev_queue); } +/** + * udev_queue_get_udev: + * @udev_queue: udev queue context + * + * Retrieve the udev library context the queue context was created with. + * + * Returns: the udev library context. + **/ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) { if (udev_queue == NULL) @@ -99,7 +131,7 @@ unsigned long long int udev_get_kernel_seqnum(struct udev *udev) ssize_t len; util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL); - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY|O_CLOEXEC); if (fd < 0) return 0; len = read(fd, buf, sizeof(buf)); @@ -111,6 +143,12 @@ unsigned long long int udev_get_kernel_seqnum(struct udev *udev) return seqnum; } +/** + * udev_queue_get_kernel_seqnum: + * @udev_queue: udev queue context + * + * Returns: the current kernel event sequence number. + **/ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) { unsigned long long int seqnum; @@ -177,7 +215,7 @@ static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long i FILE *queue_file; util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue->udev), "/.udev/queue.bin", NULL); - queue_file = fopen(filename, "r"); + queue_file = fopen(filename, "re"); if (queue_file == NULL) return NULL; @@ -190,7 +228,12 @@ static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long i return queue_file; } - +/** + * udev_queue_get_udev_seqnum: + * @udev_queue: udev queue context + * + * Returns: the last known udev event sequence number. + **/ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) { unsigned long long int seqnum_udev; @@ -217,6 +260,12 @@ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) return seqnum_udev; } +/** + * udev_queue_get_udev_is_active: + * @udev_queue: udev queue context + * + * Returns: a flag indicating if udev is active. + **/ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) { unsigned long long int seqnum_start; @@ -230,6 +279,12 @@ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) return 1; } +/** + * udev_queue_get_queue_is_empty: + * @udev_queue: udev queue context + * + * Returns: a flag indicating if udev is currently handling events. + **/ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) { unsigned long long int seqnum_kernel; @@ -244,7 +299,7 @@ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) if (queue_file == NULL) return 1; - while (1) { + for (;;) { unsigned long long int seqnum; ssize_t devpath_len; @@ -282,10 +337,18 @@ out: return is_empty; } +/** + * udev_queue_get_seqnum_sequence_is_finished: + * @udev_queue: udev queue context + * @start: first event sequence number + * @end: last event sequence number + * + * Returns: if any of the sequence numbers in the given range is currently active. + **/ 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 = 0; + unsigned long long int seqnum; ssize_t devpath_len; int unfinished; FILE *queue_file; @@ -297,29 +360,53 @@ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, return 1; if (start < seqnum) start = seqnum; - if (start > end) + if (start > end) { + fclose(queue_file); return 1; - if (end - start > INT_MAX - 1) + } + if (end - start > INT_MAX - 1) { + fclose(queue_file); return -EOVERFLOW; - unfinished = (end - start) + 1; + } + + /* + * we might start with 0, and handle the initial seqnum + * only when we find an entry in the queue file + **/ + unfinished = end - start; - while (unfinished > 0) { + 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); } +/** + * udev_queue_get_seqnum_is_finished: + * @udev_queue: udev queue context + * @seqnum: sequence number + * + * Returns: a flag indicating if the given sequence number is handled. + **/ 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)) @@ -329,6 +416,12 @@ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned lo return 1; } +/** + * udev_queue_get_queued_list_entry: + * @udev_queue: udev queue context + * + * Returns: the first entry of the list of queued events. + **/ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) { unsigned long long int seqnum; @@ -376,6 +469,12 @@ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev return udev_list_get_entry(&udev_queue->queue_list); } +/** + * udev_queue_get_failed_list_entry: + * @udev_queue: udev queue context + * + * Returns: the first entry of the list of recorded failed events. + **/ struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue) { char path[UTIL_PATH_SIZE]; @@ -402,7 +501,7 @@ struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev s = syspath; l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL); len = readlinkat(dirfd(dir), dent->d_name, s, l); - if (len < 0 || (size_t)len >= l) + if (len <= 0 || (size_t)len == l) continue; s[len] = '\0'; dbg(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name);