From: Kay Sievers Date: Thu, 4 Aug 2011 20:59:58 +0000 (+0200) Subject: libudev: list - use binary search for list lookup X-Git-Tag: 174~43 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=869c9031608f0796bb4363d5de5db058fe96fedd;p=systemd libudev: list - use binary search for list lookup --- diff --git a/Makefile.am b/Makefile.am index a0c007a3..7686ca74 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,7 +42,7 @@ dist_libexec_SCRIPTS = # libudev # ------------------------------------------------------------------------------ LIBUDEV_CURRENT=12 -LIBUDEV_REVISION=0 +LIBUDEV_REVISION=1 LIBUDEV_AGE=12 SUBDIRS += libudev/docs diff --git a/TODO b/TODO index 2da73a0b..85e4d9b2 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ - - bluetooth input + - sticky bit for 'dead' pre-created devnodes - have a $attrs{} ? diff --git a/extras/collect/collect.c b/extras/collect/collect.c index 17b3df37..f78f3b77 100644 --- a/extras/collect/collect.c +++ b/extras/collect/collect.c @@ -400,7 +400,7 @@ int main(int argc, char **argv) goto exit; } - udev_list_init(&bunch); + udev_list_node_init(&bunch); if (debug) fprintf(stderr, "Using checkpoint '%s'\n", checkpoint); diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c index 025527bb..76354dc7 100644 --- a/libudev/libudev-device.c +++ b/libudev/libudev-device.c @@ -62,11 +62,11 @@ struct udev_device { char **envp; char *monitor_buf; size_t monitor_buf_len; - struct udev_list_node devlinks_list; - struct udev_list_node properties_list; - struct udev_list_node sysattr_value_list; - struct udev_list_node sysattr_list; - struct udev_list_node tags_list; + struct udev_list devlinks_list; + struct udev_list properties_list; + struct udev_list sysattr_value_list; + struct udev_list sysattr_list; + struct udev_list tags_list; unsigned long long int seqnum; unsigned long long int usec_initialized; int timeout; @@ -357,7 +357,7 @@ struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device udev_list_entry_delete(list_entry); return NULL; } - return udev_list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, UDEV_LIST_UNIQUE); + return udev_list_entry_add(&udev_device->properties_list, key, value); } static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) @@ -489,7 +489,7 @@ UDEV_EXPORT const char *udev_device_get_property_value(struct udev_device *udev_ return NULL; list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); + list_entry = udev_list_entry_get_by_name(list_entry, key); return udev_list_entry_get_value(list_entry); } @@ -628,11 +628,11 @@ struct udev_device *udev_device_new(struct udev *udev) return NULL; udev_device->refcount = 1; udev_device->udev = udev; - udev_list_init(&udev_device->devlinks_list); - udev_list_init(&udev_device->properties_list); - udev_list_init(&udev_device->sysattr_value_list); - udev_list_init(&udev_device->sysattr_list); - udev_list_init(&udev_device->tags_list); + udev_list_init(udev, &udev_device->devlinks_list, true); + udev_list_init(udev, &udev_device->properties_list, true); + udev_list_init(udev, &udev_device->sysattr_value_list, true); + udev_list_init(udev, &udev_device->sysattr_list, false); + udev_list_init(udev, &udev_device->tags_list, true); udev_device->timeout = -1; udev_device->watch_handle = -1; /* copy global properties */ @@ -1082,11 +1082,11 @@ UDEV_EXPORT void udev_device_unref(struct udev_device *udev_device) free(udev_device->devnode); free(udev_device->subsystem); free(udev_device->devtype); - udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list); - udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list); - udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_value_list); - udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list); - udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list); + udev_list_cleanup(&udev_device->devlinks_list); + udev_list_cleanup(&udev_device->properties_list); + udev_list_cleanup(&udev_device->sysattr_value_list); + udev_list_cleanup(&udev_device->sysattr_list); + udev_list_cleanup(&udev_device->tags_list); free(udev_device->action); free(udev_device->driver); free(udev_device->devpath_old); @@ -1212,7 +1212,7 @@ UDEV_EXPORT struct udev_list_entry *udev_device_get_devlinks_list_entry(struct u void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) { udev_device->devlinks_uptodate = false; - udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list); + udev_list_cleanup(&udev_device->devlinks_list); } /** @@ -1351,18 +1351,18 @@ UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_d return NULL; /* look for possibly already cached result */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_device->sysattr_value_list)) { - if (strcmp(udev_list_entry_get_name(list_entry), sysattr) == 0) { - dbg(udev_device->udev, "got '%s' (%s) from cache\n", - sysattr, udev_list_entry_get_value(list_entry)); - return udev_list_entry_get_value(list_entry); - } + list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); + list_entry = udev_list_entry_get_by_name(list_entry, sysattr); + if (list_entry != NULL) { + dbg(udev_device->udev, "got '%s' (%s) from cache\n", + sysattr, udev_list_entry_get_value(list_entry)); + return udev_list_entry_get_value(list_entry); } util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL); if (lstat(path, &statbuf) != 0) { dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path); - udev_list_entry_add(udev_device->udev, &udev_device->sysattr_value_list, sysattr, NULL, 0); + udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL); goto out; } @@ -1386,7 +1386,7 @@ UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_d if (pos != NULL) { pos = &pos[1]; dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos); - list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_value_list, sysattr, pos, 0); + list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, pos); val = udev_list_entry_get_value(list_entry); } @@ -1418,7 +1418,7 @@ UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_d value[size] = '\0'; util_remove_trailing_chars(value, '\n'); dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value); - list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_value_list, sysattr, value, 0); + list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); val = udev_list_entry_get_value(list_entry); out: return val; @@ -1456,8 +1456,7 @@ static int udev_device_sysattr_list_read(struct udev_device *udev_device) if ((statbuf.st_mode & S_IRUSR) == 0) continue; - udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, - dent->d_name, NULL, 0); + udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL); num++; } @@ -1543,7 +1542,7 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink struct udev_list_entry *list_entry; udev_device->devlinks_uptodate = false; - list_entry = udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, UDEV_LIST_UNIQUE); + list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); if (list_entry == NULL) return -ENOMEM; if (unique) @@ -1615,7 +1614,7 @@ int udev_device_add_tag(struct udev_device *udev_device, const char *tag) if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL) return -EINVAL; udev_device->tags_uptodate = false; - if (udev_list_entry_add(udev_device->udev, &udev_device->tags_list, tag, NULL, UDEV_LIST_UNIQUE) != NULL) + if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) return 0; return -ENOMEM; } @@ -1623,7 +1622,7 @@ int udev_device_add_tag(struct udev_device *udev_device, const char *tag) void udev_device_cleanup_tags_list(struct udev_device *udev_device) { udev_device->tags_uptodate = false; - udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list); + udev_list_cleanup(&udev_device->tags_list); } /** diff --git a/libudev/libudev-enumerate.c b/libudev/libudev-enumerate.c index b332ecda..f14d5c8f 100644 --- a/libudev/libudev-enumerate.c +++ b/libudev/libudev-enumerate.c @@ -45,15 +45,15 @@ struct syspath { struct udev_enumerate { struct udev *udev; int refcount; - struct udev_list_node sysattr_match_list; - struct udev_list_node sysattr_nomatch_list; - struct udev_list_node subsystem_match_list; - struct udev_list_node subsystem_nomatch_list; - struct udev_list_node sysname_match_list; - struct udev_list_node properties_match_list; - struct udev_list_node tags_match_list; + struct udev_list sysattr_match_list; + struct udev_list sysattr_nomatch_list; + struct udev_list subsystem_match_list; + struct udev_list subsystem_nomatch_list; + struct udev_list sysname_match_list; + struct udev_list properties_match_list; + struct udev_list tags_match_list; struct udev_device *parent_match; - struct udev_list_node devices_list; + struct udev_list devices_list; struct syspath *devices; unsigned int devices_cur; unsigned int devices_max; @@ -76,14 +76,14 @@ UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev) return NULL; udev_enumerate->refcount = 1; udev_enumerate->udev = udev; - udev_list_init(&udev_enumerate->sysattr_match_list); - udev_list_init(&udev_enumerate->sysattr_nomatch_list); - udev_list_init(&udev_enumerate->subsystem_match_list); - udev_list_init(&udev_enumerate->subsystem_nomatch_list); - udev_list_init(&udev_enumerate->sysname_match_list); - udev_list_init(&udev_enumerate->properties_match_list); - udev_list_init(&udev_enumerate->tags_match_list); - udev_list_init(&udev_enumerate->devices_list); + udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); + udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); + udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); + udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); + udev_list_init(udev, &udev_enumerate->sysname_match_list, true); + udev_list_init(udev, &udev_enumerate->properties_match_list, false); + udev_list_init(udev, &udev_enumerate->tags_match_list, true); + udev_list_init(udev, &udev_enumerate->devices_list, false); return udev_enumerate; } @@ -119,15 +119,15 @@ UDEV_EXPORT void udev_enumerate_unref(struct udev_enumerate *udev_enumerate) udev_enumerate->refcount--; if (udev_enumerate->refcount > 0) return; - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_match_list); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_nomatch_list); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_match_list); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_nomatch_list); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysname_match_list); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->properties_match_list); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->tags_match_list); + udev_list_cleanup(&udev_enumerate->sysattr_match_list); + udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); + udev_list_cleanup(&udev_enumerate->subsystem_match_list); + udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); + udev_list_cleanup(&udev_enumerate->sysname_match_list); + udev_list_cleanup(&udev_enumerate->properties_match_list); + udev_list_cleanup(&udev_enumerate->tags_match_list); udev_device_unref(udev_enumerate->parent_match); - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list); + udev_list_cleanup(&udev_enumerate->devices_list); for (i = 0; i < udev_enumerate->devices_cur; i++) free(udev_enumerate->devices[i].syspath); free(udev_enumerate->devices); @@ -259,7 +259,7 @@ UDEV_EXPORT struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_en struct syspath *prev = NULL, *move_later = NULL; size_t move_later_prefix = 0; - udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list); + udev_list_cleanup(&udev_enumerate->devices_list); qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp); max = udev_enumerate->devices_cur; @@ -296,25 +296,21 @@ UDEV_EXPORT struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_en if (move_later && strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) { - udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list, - move_later->syspath, NULL, 0); + udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL); move_later = NULL; } - udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list, - entry->syspath, NULL, 0); + udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); } if (move_later) - udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list, - move_later->syspath, NULL, 0); + udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL); /* add and cleanup delayed devices from end of list */ for (i = max; i < udev_enumerate->devices_cur; i++) { struct syspath *entry = &udev_enumerate->devices[i]; - udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list, - entry->syspath, NULL, 0); + udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); free(entry->syspath); } udev_enumerate->devices_cur = max; @@ -337,8 +333,7 @@ UDEV_EXPORT int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_e return -EINVAL; if (subsystem == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->subsystem_match_list, subsystem, NULL, UDEV_LIST_UNIQUE) == NULL) + if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) return -ENOMEM; return 0; } @@ -356,8 +351,7 @@ UDEV_EXPORT int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev return -EINVAL; if (subsystem == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->subsystem_nomatch_list, subsystem, NULL, UDEV_LIST_UNIQUE) == NULL) + if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) return -ENOMEM; return 0; } @@ -376,8 +370,7 @@ UDEV_EXPORT int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enu return -EINVAL; if (sysattr == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->sysattr_match_list, sysattr, value, 0) == NULL) + if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) return -ENOMEM; return 0; } @@ -396,8 +389,7 @@ UDEV_EXPORT int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_e return -EINVAL; if (sysattr == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->sysattr_nomatch_list, sysattr, value, 0) == NULL) + if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) return -ENOMEM; return 0; } @@ -436,8 +428,7 @@ UDEV_EXPORT int udev_enumerate_add_match_property(struct udev_enumerate *udev_en return -EINVAL; if (property == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->properties_match_list, property, value, 0) == NULL) + if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL) return -ENOMEM; return 0; } @@ -455,8 +446,7 @@ UDEV_EXPORT int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumera return -EINVAL; if (tag == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->tags_match_list, tag, NULL, UDEV_LIST_UNIQUE) == NULL) + if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL) return -ENOMEM; return 0; } @@ -525,8 +515,7 @@ UDEV_EXPORT int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enu return -EINVAL; if (sysname == NULL) return 0; - if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate), - &udev_enumerate->sysname_match_list, sysname, NULL, UDEV_LIST_UNIQUE) == NULL) + if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) return -ENOMEM; return 0; } diff --git a/libudev/libudev-list.c b/libudev/libudev-list.c index e828a4e4..295ee682 100644 --- a/libudev/libudev-list.c +++ b/libudev/libudev-list.c @@ -34,21 +34,20 @@ */ struct udev_list_entry { struct udev_list_node node; - struct udev *udev; - struct udev_list_node *list; + struct udev_list *list; char *name; char *value; int num; }; /* the list's head points to itself if empty */ -void udev_list_init(struct udev_list_node *list) +void udev_list_node_init(struct udev_list_node *list) { list->next = list; list->prev = list; } -int udev_list_is_empty(struct udev_list_node *list) +int udev_list_node_is_empty(struct udev_list_node *list) { return list->next == list; } @@ -90,19 +89,20 @@ static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) return (struct udev_list_entry *)list; } -/* insert entry into a list as the last element */ -void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list) +void udev_list_init(struct udev *udev, struct udev_list *list, bool unique) { - /* inserting before the list head make the node the last node in the list */ - udev_list_node_insert_between(&new->node, list->prev, list); - new->list = list; + memset(list, 0x00, sizeof(struct udev_list)); + list->udev = udev; + list->unique = unique; + udev_list_node_init(&list->node); } -/* remove entry from a list */ -void udev_list_entry_remove(struct udev_list_entry *entry) +/* insert entry into a list as the last element */ +void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list) { - udev_list_node_remove(&entry->node); - entry->list = NULL; + /* inserting before the list head make the node the last node in the list */ + udev_list_node_insert_between(&new->node, list->node.prev, &list->node); + new->list = list; } /* insert entry into a list, before a given existing entry */ @@ -112,90 +112,144 @@ void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list new->list = entry->list; } -struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list, - const char *name, const char *value, - unsigned int flags) +/* binary search in sorted array */ +static int list_search(struct udev_list *list, const char *name) { - struct udev_list_entry *entry_loop = NULL; - struct udev_list_entry *entry_new; - - if (flags & UDEV_LIST_UNIQUE) { - udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) { - if (strcmp(entry_loop->name, name) == 0) { - dbg(udev, "'%s' is already in the list\n", name); - free(entry_loop->value); - if (value == NULL) { - entry_loop->value = NULL; - dbg(udev, "'%s' value unset\n", name); - return entry_loop; - } - entry_loop->value = strdup(value); - if (entry_loop->value == NULL) - return NULL; - dbg(udev, "'%s' value replaced with '%s'\n", name, value); - return entry_loop; - } - } + unsigned int first, last; + + first = 0; + last = list->entries_cur; + while (first < last) { + unsigned int i; + int cmp; + + i = (first + last)/2; + cmp = strcmp(name, list->entries[i]->name); + if (cmp < 0) + last = i; + else if (cmp > 0) + first = i+1; + else + return i; } - if (flags & UDEV_LIST_SORT) { - udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) { - if (strcmp(entry_loop->name, name) > 0) - break; + /* not found, return negative insertion-index+1 */ + return -(first+1); +} + +struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value) +{ + struct udev_list_entry *entry; + int i = 0; + + if (list->unique) { + /* lookup existing name or insertion-index */ + i = list_search(list, name); + if (i >= 0) { + entry = list->entries[i]; + + dbg(list->udev, "'%s' is already in the list\n", name); + free(entry->value); + if (value == NULL) { + entry->value = NULL; + dbg(list->udev, "'%s' value unset\n", name); + return entry; + } + entry->value = strdup(value); + if (entry->value == NULL) + return NULL; + dbg(list->udev, "'%s' value replaced with '%s'\n", name, value); + return entry; } } - entry_new = malloc(sizeof(struct udev_list_entry)); - if (entry_new == NULL) + /* add new name */ + entry = calloc(1, sizeof(struct udev_list_entry)); + if (entry == NULL) return NULL; - memset(entry_new, 0x00, sizeof(struct udev_list_entry)); - entry_new->udev = udev; - entry_new->name = strdup(name); - if (entry_new->name == NULL) { - free(entry_new); + entry->name = strdup(name); + if (entry->name == NULL) { + free(entry); return NULL; } - if (value != NULL) { - entry_new->value = strdup(value); - if (entry_new->value == NULL) { - free(entry_new->name); - free(entry_new); + entry->value = strdup(value); + if (entry->value == NULL) { + free(entry->name); + free(entry); return NULL; } } + udev_list_entry_append(entry, list); + + if (list->unique) { + /* allocate or enlarge sorted array if needed */ + if (list->entries_cur >= list->entries_max) { + unsigned int add; + + add = list->entries_max; + if (add < 1) + add = 64; + list->entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *)); + if (list->entries == NULL) { + free(entry->name); + free(entry->value); + return NULL; + } + list->entries_max += add; + } - if (entry_loop != NULL) - udev_list_entry_insert_before(entry_new, entry_loop); - else - udev_list_entry_append(entry_new, list); + /* insert into sorted array */ + i = (-i)-1; + memmove(&list->entries[i+1], &list->entries[i], + (list->entries_cur - i) * sizeof(struct udev_list_entry *)); + list->entries[i] = entry; + list->entries_cur++; + } - dbg(udev, "'%s=%s' added\n", entry_new->name, entry_new->value); - return entry_new; + dbg(list->udev, "'%s=%s' added\n", entry->name, entry->value); + return entry; } void udev_list_entry_delete(struct udev_list_entry *entry) { + if (entry->list->entries != NULL) { + int i; + struct udev_list *list = entry->list; + + /* remove entry from sorted array */ + i = list_search(list, entry->name); + if (i >= 0) { + memmove(&list->entries[i], &list->entries[i+1], + ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *)); + list->entries_cur--; + } + } + udev_list_node_remove(&entry->node); free(entry->name); free(entry->value); free(entry); } -void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list) +void udev_list_cleanup(struct udev_list *list) { struct udev_list_entry *entry_loop; struct udev_list_entry *entry_tmp; + free(list->entries); + list->entries = NULL; + list->entries_cur = 0; + list->entries_max = 0; udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) udev_list_entry_delete(entry_loop); } -struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list) +struct udev_list_entry *udev_list_get_entry(struct udev_list *list) { - if (udev_list_is_empty(list)) + if (udev_list_node_is_empty(&list->node)) return NULL; - return list_node_to_entry(list->next); + return list_node_to_entry(list->node.next); } /** @@ -212,7 +266,7 @@ UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_next(struct udev_list_en return NULL; next = list_entry->node.next; /* empty list or no more entries */ - if (next == list_entry->list) + if (next == &list_entry->list->node) return NULL; return list_node_to_entry(next); } @@ -226,15 +280,18 @@ UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_next(struct udev_list_en */ UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) { - struct udev_list_entry *entry; + int i; - udev_list_entry_foreach(entry, list_entry) { - if (strcmp(udev_list_entry_get_name(entry), name) == 0) { - dbg(entry->udev, "found '%s=%s'\n", entry->name, entry->value); - return entry; - } - } - return NULL; + if (list_entry == NULL) + return NULL; + + if (!list_entry->list->unique) + return NULL; + + i = list_search(list_entry->list, name); + if (i < 0) + return NULL; + return list_entry->list->entries[i]; } /** diff --git a/libudev/libudev-monitor.c b/libudev/libudev-monitor.c index 31dd6682..f2f39f95 100644 --- a/libudev/libudev-monitor.c +++ b/libudev/libudev-monitor.c @@ -48,8 +48,8 @@ struct udev_monitor { struct sockaddr_nl snl_destination; struct sockaddr_un sun; socklen_t addrlen; - struct udev_list_node filter_subsystem_list; - struct udev_list_node filter_tag_list; + struct udev_list filter_subsystem_list; + struct udev_list filter_tag_list; bool bound; }; @@ -92,8 +92,8 @@ static struct udev_monitor *udev_monitor_new(struct udev *udev) return NULL; udev_monitor->refcount = 1; udev_monitor->udev = udev; - udev_list_init(&udev_monitor->filter_subsystem_list); - udev_list_init(&udev_monitor->filter_tag_list); + udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); + udev_list_init(udev, &udev_monitor->filter_tag_list, true); return udev_monitor; } @@ -483,8 +483,8 @@ UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor) return; if (udev_monitor->sock >= 0) close(udev_monitor->sock); - udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list); - udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_tag_list); + udev_list_cleanup(&udev_monitor->filter_subsystem_list); + udev_list_cleanup(&udev_monitor->filter_tag_list); dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor); free(udev_monitor); } @@ -647,7 +647,7 @@ retry: /* udev message needs proper version magic */ nlh = (struct udev_monitor_netlink_header *) buf; if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) { - err(udev_monitor->udev, "ignored a message from an invalid release of udevadm (%x != %x)\n", + err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n", nlh->magic, htonl(UDEV_MONITOR_MAGIC)); return NULL; } @@ -830,8 +830,7 @@ UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_moni return -EINVAL; if (subsystem == NULL) return -EINVAL; - if (udev_list_entry_add(udev_monitor->udev, - &udev_monitor->filter_subsystem_list, subsystem, devtype, 0) == NULL) + if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) return -ENOMEM; return 0; } @@ -854,8 +853,7 @@ UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_moni return -EINVAL; if (tag == NULL) return -EINVAL; - if (udev_list_entry_add(udev_monitor->udev, - &udev_monitor->filter_tag_list, tag, NULL, 0) == NULL) + if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL) return -ENOMEM; return 0; } @@ -872,6 +870,6 @@ UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) { static struct sock_fprog filter = { 0, NULL }; - udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list); + udev_list_cleanup(&udev_monitor->filter_subsystem_list); return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); } diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h index 0c17c457..157575c1 100644 --- a/libudev/libudev-private.h +++ b/libudev/libudev-private.h @@ -115,17 +115,20 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd); /* libudev-list.c */ -enum udev_list_flags { - UDEV_LIST_NONE = 0, - UDEV_LIST_UNIQUE = 1, - UDEV_LIST_SORT = 1 << 1, -}; struct udev_list_node { struct udev_list_node *next, *prev; }; +struct udev_list { + struct udev *udev; + struct udev_list_node node; + struct udev_list_entry **entries; + unsigned int entries_cur; + unsigned int entries_max; + bool unique; +}; #define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) } -void udev_list_init(struct udev_list_node *list); -int udev_list_is_empty(struct udev_list_node *list); +void udev_list_node_init(struct udev_list_node *list); +int udev_list_node_is_empty(struct udev_list_node *list); void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list); void udev_list_node_remove(struct udev_list_node *entry); #define udev_list_node_foreach(node, list) \ @@ -136,14 +139,13 @@ void udev_list_node_remove(struct udev_list_node *entry); for (node = (list)->next, tmp = (node)->next; \ node != list; \ node = tmp, tmp = (tmp)->next) -struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list, - const char *name, const char *value, unsigned int flags); +void udev_list_init(struct udev *udev, struct udev_list *list, bool unique); +void udev_list_cleanup(struct udev_list *list); +struct udev_list_entry *udev_list_get_entry(struct udev_list *list); +struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value); void udev_list_entry_delete(struct udev_list_entry *entry); -void udev_list_entry_remove(struct udev_list_entry *entry); void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry); -void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list); -void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *name_list); -struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list); +void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list); int udev_list_entry_get_num(struct udev_list_entry *list_entry); void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); #define udev_list_entry_foreach_safe(entry, tmp, first) \ diff --git a/libudev/libudev-queue.c b/libudev/libudev-queue.c index 73e7fb23..744696df 100644 --- a/libudev/libudev-queue.c +++ b/libudev/libudev-queue.c @@ -42,8 +42,8 @@ struct udev_queue { struct udev *udev; int refcount; - struct udev_list_node queue_list; - struct udev_list_node failed_list; + struct udev_list queue_list; + struct udev_list failed_list; }; /** @@ -67,8 +67,8 @@ UDEV_EXPORT struct udev_queue *udev_queue_new(struct udev *udev) return NULL; udev_queue->refcount = 1; udev_queue->udev = udev; - udev_list_init(&udev_queue->queue_list); - udev_list_init(&udev_queue->failed_list); + udev_list_init(udev, &udev_queue->queue_list, false); + udev_list_init(udev, &udev_queue->failed_list, false); return udev_queue; } @@ -102,8 +102,8 @@ UDEV_EXPORT void udev_queue_unref(struct udev_queue *udev_queue) udev_queue->refcount--; if (udev_queue->refcount > 0) return; - udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list); - udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list); + udev_list_cleanup(&udev_queue->queue_list); + udev_list_cleanup(&udev_queue->failed_list); free(udev_queue); } @@ -429,7 +429,7 @@ UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev if (udev_queue == NULL) return NULL; - udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list); + udev_list_cleanup(&udev_queue->queue_list); queue_file = open_queue_file(udev_queue, &seqnum); if (queue_file == NULL) @@ -454,7 +454,7 @@ UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev break; if (len > 0) { - udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 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 (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) { @@ -483,7 +483,7 @@ UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev if (udev_queue == NULL) return NULL; - udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list); + udev_list_cleanup(&udev_queue->failed_list); util_strscpyl(path, sizeof(path), udev_get_run_path(udev_queue->udev), "/failed", NULL); dir = opendir(path); if (dir == NULL) @@ -508,7 +508,7 @@ UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); if (stat(filename, &statbuf) != 0) continue; - udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0); + udev_list_entry_add(&udev_queue->failed_list, syspath, NULL); } closedir(dir); return udev_list_get_entry(&udev_queue->failed_list); diff --git a/libudev/libudev.c b/libudev/libudev.c index ad8c914e..165c3698 100644 --- a/libudev/libudev.c +++ b/libudev/libudev.c @@ -45,7 +45,7 @@ struct udev { char *rules_path; char *run_config_path; char *run_path; - struct udev_list_node properties_list; + struct udev_list properties_list; int log_priority; }; @@ -130,14 +130,14 @@ UDEV_EXPORT struct udev *udev_new(void) udev->refcount = 1; udev->log_fn = log_stderr; udev->log_priority = LOG_ERR; - udev_list_init(&udev->properties_list); + udev_list_init(udev, &udev->properties_list, true); /* custom config file */ env = getenv("UDEV_CONFIG_FILE"); if (env != NULL) { - udev_add_property(udev, "UDEV_CONFIG_FILE", udev->dev_path); if (set_value(&config_file, env) == NULL) goto err; + udev_add_property(udev, "UDEV_CONFIG_FILE", config_file); } /* default config file */ @@ -307,7 +307,7 @@ UDEV_EXPORT void udev_unref(struct udev *udev) udev->refcount--; if (udev->refcount > 0) return; - udev_list_cleanup_entries(udev, &udev->properties_list); + udev_list_cleanup(&udev->properties_list); free(udev->dev_path); free(udev->sys_path); free(udev->rules_path); @@ -458,7 +458,7 @@ struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, co udev_list_entry_delete(list_entry); return NULL; } - return udev_list_entry_add(udev, &udev->properties_list, key, value, UDEV_LIST_UNIQUE); + return udev_list_entry_add(&udev->properties_list, key, value); } struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev) diff --git a/udev/udev-event.c b/udev/udev-event.c index a4141e9c..823768a3 100644 --- a/udev/udev-event.c +++ b/udev/udev-event.c @@ -38,14 +38,15 @@ struct udev_event *udev_event_new(struct udev_device *dev) { + struct udev *udev = udev_device_get_udev(dev); struct udev_event *event; event = calloc(1, sizeof(struct udev_event)); if (event == NULL) return NULL; event->dev = dev; - event->udev = udev_device_get_udev(dev); - udev_list_init(&event->run_list); + event->udev = udev; + udev_list_init(udev, &event->run_list, false); event->fd_signal = -1; event->birth_usec = now_usec(); event->timeout_usec = 60 * 1000 * 1000; @@ -57,7 +58,7 @@ void udev_event_unref(struct udev_event *event) { if (event == NULL) return; - udev_list_cleanup_entries(event->udev, &event->run_list); + udev_list_cleanup(&event->run_list); free(event->tmp_node); free(event->program_result); free(event->name); diff --git a/udev/udev-rules.c b/udev/udev-rules.c index 89d98248..f345e897 100644 --- a/udev/udev-rules.c +++ b/udev/udev-rules.c @@ -1749,7 +1749,7 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s return 0; } -static int add_matching_files(struct udev *udev, struct udev_list_node *file_list, const char *dirname, const char *suffix) +static int add_matching_files(struct udev *udev, struct udev_list *file_list, const char *dirname, const char *suffix) { DIR *dir; struct dirent *dent; @@ -1783,7 +1783,7 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis * identical basenames from different directories overwrite each other * entries are sorted after basename */ - udev_list_entry_add(udev, file_list, dent->d_name, filename, UDEV_LIST_UNIQUE|UDEV_LIST_SORT); + udev_list_entry_add(file_list, dent->d_name, filename); } closedir(dir); @@ -1793,7 +1793,7 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) { struct udev_rules *rules; - struct udev_list_node file_list; + struct udev_list file_list; struct udev_list_entry *file_loop; struct token end_token; @@ -1802,7 +1802,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) return NULL; rules->udev = udev; rules->resolve_names = resolve_names; - udev_list_init(&file_list); + udev_list_init(udev, &file_list, true); /* init token array and string buffer */ rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token)); @@ -1885,7 +1885,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) } parse_file(rules, filename, filename_off); } - udev_list_cleanup_entries(udev, &file_list); + udev_list_cleanup(&file_list); memset(&end_token, 0x00, sizeof(struct token)); end_token.type = TK_END; @@ -2663,13 +2663,12 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event struct udev_list_entry *list_entry; if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) - udev_list_cleanup_entries(event->udev, &event->run_list); + udev_list_cleanup(&event->run_list); info(event->udev, "RUN '%s' %s:%u\n", &rules->buf[cur->key.value_off], &rules->buf[rule->rule.filename_off], rule->rule.filename_line); - list_entry = udev_list_entry_add(event->udev, &event->run_list, - &rules->buf[cur->key.value_off], NULL, UDEV_LIST_UNIQUE); + list_entry = udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL); if (cur->key.fail_on_error) udev_list_entry_set_num(list_entry, true); break; diff --git a/udev/udev.h b/udev/udev.h index 0c73b502..c1e28145 100644 --- a/udev/udev.h +++ b/udev/udev.h @@ -39,7 +39,7 @@ struct udev_event { mode_t mode; uid_t uid; gid_t gid; - struct udev_list_node run_list; + struct udev_list run_list; int exec_delay; unsigned long long birth_usec; unsigned long long timeout_usec; diff --git a/udev/udevadm-monitor.c b/udev/udevadm-monitor.c index 7ea7aa0f..64913dbd 100644 --- a/udev/udevadm-monitor.c +++ b/udev/udevadm-monitor.c @@ -72,8 +72,8 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) bool prop = false; bool print_kernel = false; bool print_udev = false; - struct udev_list_node subsystem_match_list; - struct udev_list_node tag_match_list; + struct udev_list subsystem_match_list; + struct udev_list tag_match_list; struct udev_monitor *udev_monitor = NULL; struct udev_monitor *kernel_monitor = NULL; int fd_ep = -1; @@ -92,8 +92,8 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {} }; - udev_list_init(&subsystem_match_list); - udev_list_init(&tag_match_list); + udev_list_init(udev, &subsystem_match_list, true); + udev_list_init(udev, &tag_match_list, true); for (;;) { option = getopt_long(argc, argv, "pekus:t:h", options, NULL); @@ -122,11 +122,11 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) devtype[0] = '\0'; devtype++; } - udev_list_entry_add(udev, &subsystem_match_list, subsys, devtype, 0); + udev_list_entry_add(&subsystem_match_list, subsys, devtype); break; } case 't': - udev_list_entry_add(udev, &tag_match_list, optarg, NULL, 0); + udev_list_entry_add(&tag_match_list, optarg, NULL); break; case 'h': printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n" @@ -285,8 +285,8 @@ out: close(fd_ep); udev_monitor_unref(udev_monitor); udev_monitor_unref(kernel_monitor); - udev_list_cleanup_entries(udev, &subsystem_match_list); - udev_list_cleanup_entries(udev, &tag_match_list); + udev_list_cleanup(&subsystem_match_list); + udev_list_cleanup(&tag_match_list); return rc; } diff --git a/udev/udevd.c b/udev/udevd.c index 2fa2a6a4..1220deaa 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -1574,8 +1574,8 @@ int main(int argc, char *argv[]) udev_rules_apply_static_dev_perms(rules); - udev_list_init(&event_list); - udev_list_init(&worker_list); + udev_list_node_init(&event_list); + udev_list_node_init(&worker_list); for (;;) { struct epoll_event ev[8]; @@ -1606,12 +1606,12 @@ int main(int argc, char *argv[]) worker_kill(udev, 0); /* exit after all has cleaned up */ - if (udev_list_is_empty(&event_list) && udev_list_is_empty(&worker_list)) + if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list)) break; /* timeout at exit for workers to finish */ timeout = 60 * 1000; - } else if (udev_list_is_empty(&event_list) && children > 2) { + } else if (udev_list_node_is_empty(&event_list) && children > 2) { /* set timeout to kill idle workers */ timeout = 3 * 1000; } else { @@ -1659,7 +1659,7 @@ int main(int argc, char *argv[]) } /* start new events */ - if (!udev_list_is_empty(&event_list) && !udev_exit && !stop_exec_queue) + if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) event_queue_start(udev); if (is_signal) {