core: Introduce list iteration helpers
authorChris Dickens <christopher.a.dickens@gmail.com>
Tue, 11 Aug 2020 02:01:42 +0000 (19:01 -0700)
committerChris Dickens <christopher.a.dickens@gmail.com>
Tue, 11 Aug 2020 02:01:42 +0000 (19:01 -0700)
The syntax for traversing over lists is somewhat cluttered. It could be
made much better with the use of the 'typeof' keyword, but unfortunately
this is not universally supported by all compilers. We can, however,
improve the situation by introducing some macros for the common cases.
To that end, this commit introduces a number of 'for_each' macros that
iterate over a specific linked list.

Current syntax:

  list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer)

New syntax:

  for_each_transfer(ctx, itransfer)

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
libusb/core.c
libusb/hotplug.c
libusb/hotplug.h
libusb/io.c
libusb/libusbi.h
libusb/os/darwin_usb.c
libusb/os/haiku_pollfs.cpp
libusb/os/linux_usbfs.c
libusb/os/windows_common.c
libusb/version_nano.h

index 69e2649..89cfec3 100644 (file)
@@ -766,11 +766,12 @@ struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx,
        struct libusb_device *ret = NULL;
 
        usbi_mutex_lock(&ctx->usb_devs_lock);
-       list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device)
+       for_each_device(ctx, dev) {
                if (dev->session_data == session_id) {
                        ret = libusb_ref_device(dev);
                        break;
                }
+       }
        usbi_mutex_unlock(&ctx->usb_devs_lock);
 
        return ret;
@@ -819,7 +820,7 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
                        usbi_backend.hotplug_poll();
 
                usbi_mutex_lock(&ctx->usb_devs_lock);
-               list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
+               for_each_device(ctx, dev) {
                        discdevs = discovered_devs_append(discdevs, dev);
 
                        if (!discdevs) {
@@ -1416,7 +1417,7 @@ static void do_close(struct libusb_context *ctx,
        usbi_mutex_lock(&ctx->flying_transfers_lock);
 
        /* safe iteration because transfers may be being deleted */
-       list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) {
+       for_each_transfer_safe(ctx, itransfer, tmp) {
                struct libusb_transfer *transfer =
                        USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 
@@ -2359,7 +2360,7 @@ err_free_ctx:
        usbi_mutex_static_unlock(&active_contexts_lock);
 
        usbi_mutex_lock(&ctx->usb_devs_lock);
-       list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
+       for_each_device_safe(ctx, dev, next) {
                list_del(&dev->list);
                libusb_unref_device(dev);
        }
@@ -2439,7 +2440,7 @@ void API_EXPORTED libusb_exit(libusb_context *ctx)
                        libusb_handle_events_timeout(ctx, &tv);
 
                usbi_mutex_lock(&ctx->usb_devs_lock);
-               list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
+               for_each_device_safe(ctx, dev, next) {
                        list_del(&dev->list);
                        libusb_unref_device(dev);
                }
index e3e83c3..c02cc56 100644 (file)
@@ -184,7 +184,7 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
 
        usbi_mutex_lock(&ctx->hotplug_cbs_lock);
 
-       list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+       for_each_hotplug_cb_safe(ctx, hotplug_cb, next) {
                if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
                        /* process deregistration in usbi_hotplug_deregister() */
                        continue;
@@ -331,7 +331,7 @@ void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx,
        ctx = usbi_get_context(ctx);
 
        usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-       list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+       for_each_hotplug_cb(ctx, hotplug_cb) {
                if (callback_handle == hotplug_cb->handle) {
                        /* Mark this callback for deregistration */
                        hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
@@ -369,7 +369,7 @@ void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx,
        ctx = usbi_get_context(ctx);
 
        usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-       list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+       for_each_hotplug_cb(ctx, hotplug_cb) {
                if (callback_handle == hotplug_cb->handle) {
                        user_data = hotplug_cb->user_data;
                }
@@ -384,7 +384,7 @@ void usbi_hotplug_deregister(struct libusb_context *ctx, int forced)
        struct libusb_hotplug_callback *hotplug_cb, *next;
 
        usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-       list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+       for_each_hotplug_cb_safe(ctx, hotplug_cb, next) {
                if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) {
                        usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb,
                                 hotplug_cb->handle);
index 4335fbe..161f7e5 100644 (file)
@@ -90,6 +90,12 @@ struct libusb_hotplug_message {
        struct list_head list;
 };
 
+#define for_each_hotplug_cb(ctx, c) \
+       for_each_helper(c, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback)
+
+#define for_each_hotplug_cb_safe(ctx, c, n) \
+       for_each_safe_helper(c, n, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback)
+
 void usbi_hotplug_deregister(struct libusb_context *ctx, int forced);
 void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
        libusb_hotplug_event event);
index b969633..27350fa 100644 (file)
@@ -1172,7 +1172,8 @@ err:
 static void cleanup_removed_pollfds(struct libusb_context *ctx)
 {
        struct usbi_pollfd *ipollfd, *tmp;
-       list_for_each_entry_safe(ipollfd, tmp, &ctx->removed_ipollfds, list, struct usbi_pollfd) {
+
+       for_each_removed_pollfd_safe(ctx, ipollfd, tmp) {
                list_del(&ipollfd->list);
                free(ipollfd);
        }
@@ -1344,7 +1345,7 @@ static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
 {
        struct usbi_transfer *itransfer;
 
-       list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+       for_each_transfer(ctx, itransfer) {
                struct timespec *cur_ts = &itransfer->timeout;
 
                /* if we've reached transfers of infinite timeout, then we have no
@@ -1405,7 +1406,7 @@ static int add_to_flying_list(struct usbi_transfer *itransfer)
        }
 
        /* otherwise, find appropriate place in list */
-       list_for_each_entry(cur, &ctx->flying_transfers, list, struct usbi_transfer) {
+       for_each_transfer(ctx, cur) {
                /* find first timeout that occurs after the transfer in question */
                struct timespec *cur_ts = &cur->timeout;
 
@@ -2035,7 +2036,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
 
        /* iterate through flying transfers list, finding all transfers that
         * have expired timeouts */
-       list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+       for_each_transfer(ctx, itransfer) {
                struct timespec *cur_ts = &itransfer->timeout;
 
                /* if we've reached transfers of infinite timeout, we're all done */
@@ -2150,7 +2151,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
                        goto done;
                }
 
-               list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd) {
+               for_each_pollfd(ctx, ipollfd) {
                        struct libusb_pollfd *pollfd = &ipollfd->pollfd;
                        ctx->pollfds[i].fd = pollfd->fd;
                        ctx->pollfds[i].events = pollfd->events;
@@ -2293,7 +2294,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
        }
 #endif
 
-       list_for_each_entry(ipollfd, &ctx->removed_ipollfds, list, struct usbi_pollfd) {
+       for_each_removed_pollfd(ctx, ipollfd) {
                usbi_nfds_t n;
 
                for (n = internal_nfds ; n < nfds ; n++) {
@@ -2611,7 +2612,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
        }
 
        /* find next transfer which hasn't already been processed as timed out */
-       list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+       for_each_transfer(ctx, itransfer) {
                if (itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
                        continue;
 
@@ -2725,11 +2726,12 @@ void usbi_remove_pollfd(struct libusb_context *ctx, int fd)
 
        usbi_dbg("remove fd %d", fd);
        usbi_mutex_lock(&ctx->event_data_lock);
-       list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd)
+       for_each_pollfd(ctx, ipollfd) {
                if (ipollfd->pollfd.fd == fd) {
                        found = 1;
                        break;
                }
+       }
 
        if (!found) {
                usbi_dbg("couldn't find fd %d to remove", fd);
@@ -2779,7 +2781,7 @@ const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
        if (!ret)
                goto out;
 
-       list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd)
+       for_each_pollfd(ctx, ipollfd)
                ret[i++] = (struct libusb_pollfd *)ipollfd;
        ret[ctx->pollfds_cnt] = NULL;
 
@@ -2815,6 +2817,7 @@ void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds)
  */
 void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
 {
+       struct libusb_context *ctx = HANDLE_CTX(dev_handle);
        struct usbi_transfer *cur;
        struct usbi_transfer *to_cancel;
 
@@ -2836,8 +2839,8 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
 
        while (1) {
                to_cancel = NULL;
-               usbi_mutex_lock(&HANDLE_CTX(dev_handle)->flying_transfers_lock);
-               list_for_each_entry(cur, &HANDLE_CTX(dev_handle)->flying_transfers, list, struct usbi_transfer)
+               usbi_mutex_lock(&ctx->flying_transfers_lock);
+               for_each_transfer(ctx, cur) {
                        if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == dev_handle) {
                                usbi_mutex_lock(&cur->lock);
                                if (cur->state_flags & USBI_TRANSFER_IN_FLIGHT)
@@ -2847,7 +2850,8 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
                                if (to_cancel)
                                        break;
                        }
-               usbi_mutex_unlock(&HANDLE_CTX(dev_handle)->flying_transfers_lock);
+               }
+               usbi_mutex_unlock(&ctx->flying_transfers_lock);
 
                if (!to_cancel)
                        break;
index 3c5add6..1677fda 100644 (file)
@@ -139,6 +139,9 @@ struct list_head {
 #define list_first_entry(ptr, type, member) \
        list_entry((ptr)->next, type, member)
 
+#define list_next_entry(ptr, type, member) \
+       list_entry((ptr)->member.next, type, member)
+
 /* Get each entry from a list
  *  pos - A structure pointer has a "member" element
  *  head - list head
@@ -146,15 +149,24 @@ struct list_head {
  *  type - the type of the first parameter
  */
 #define list_for_each_entry(pos, head, member, type)                   \
-       for (pos = list_entry((head)->next, type, member);              \
+       for (pos = list_first_entry(head, type, member);                \
                 &pos->member != (head);                                \
-                pos = list_entry(pos->member.next, type, member))
+                pos = list_next_entry(pos, type, member))
 
 #define list_for_each_entry_safe(pos, n, head, member, type)           \
-       for (pos = list_entry((head)->next, type, member),              \
-                n = list_entry(pos->member.next, type, member);        \
+       for (pos = list_first_entry(head, type, member),                \
+                n = list_next_entry(pos, type, member);                \
                 &pos->member != (head);                                \
-                pos = n, n = list_entry(n->member.next, type, member))
+                pos = n, n = list_next_entry(n, type, member))
+
+/* Helper macros to iterate over a list. The structure pointed
+ * to by "pos" must have a list_head member named "list".
+ */
+#define for_each_helper(pos, head, type) \
+       list_for_each_entry(pos, head, list, type)
+
+#define for_each_safe_helper(pos, n, head, type) \
+       list_for_each_entry_safe(pos, n, head, list, type)
 
 #define list_empty(entry) ((entry)->next == (entry))
 
@@ -1244,6 +1256,33 @@ extern const struct usbi_os_backend usbi_backend;
 extern struct list_head active_contexts_list;
 extern usbi_mutex_static_t active_contexts_lock;
 
+#define for_each_context(c) \
+       for_each_helper(c, &active_contexts_list, struct libusb_context)
+
+#define for_each_device(ctx, d) \
+       for_each_helper(d, &(ctx)->usb_devs, struct libusb_device)
+
+#define for_each_device_safe(ctx, d, n) \
+       for_each_safe_helper(d, n, &(ctx)->usb_devs, struct libusb_device)
+
+#define for_each_open_device(ctx, h) \
+       for_each_helper(h, &(ctx)->open_devs, struct libusb_device_handle)
+
+#define for_each_transfer(ctx, t) \
+       for_each_helper(t, &(ctx)->flying_transfers, struct usbi_transfer)
+
+#define for_each_transfer_safe(ctx, t, n) \
+       for_each_safe_helper(t, n, &(ctx)->flying_transfers, struct usbi_transfer)
+
+#define for_each_pollfd(ctx, p) \
+       for_each_helper(p, &(ctx)->ipollfds, struct usbi_pollfd)
+
+#define for_each_removed_pollfd(ctx, p) \
+       for_each_helper(p, &(ctx)->removed_ipollfds, struct usbi_pollfd)
+
+#define for_each_removed_pollfd_safe(ctx, p, n) \
+       for_each_safe_helper(p, n, &(ctx)->removed_ipollfds, struct usbi_pollfd)
+
 #ifdef __cplusplus
 }
 #endif
index a64d67d..5f5e71b 100644 (file)
@@ -337,7 +337,7 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
     }
 
     /* add this device to each active context's device list */
-    list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+    for_each_context(ctx) {
       process_new_device (ctx, cached_device, old_session_id);
     }
 
@@ -403,7 +403,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
       continue;
     }
 
-    list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+    for_each_context(ctx) {
       usbi_dbg ("notifying context %p of device disconnect", ctx);
 
       dev = usbi_get_device_by_session_id(ctx, (unsigned long) session);
index c60b3b5..cb4fda8 100644 (file)
@@ -97,7 +97,7 @@ WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
                        unsigned long session_id = (unsigned long)&fDevice;
 
                        usbi_mutex_lock(&active_contexts_lock);
-                       list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+                       for_each_context(ctx) {
                                struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
                                if (dev) {
                                        usbi_dbg("using previously allocated device with location %lu", session_id);
@@ -172,7 +172,7 @@ WatchedEntry::~WatchedEntry()
                unsigned long session_id = (unsigned long)&fDevice;
 
                usbi_mutex_lock(&active_contexts_lock);
-               list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+               for_each_context(ctx) {
                        dev = usbi_get_device_by_session_id(ctx, session_id);
                        if (dev != NULL) {
                                usbi_disconnect_device(dev);
index 082d726..1e727ef 100644 (file)
@@ -991,7 +991,7 @@ static int linux_get_parent_info(struct libusb_device *dev, const char *sysfs_di
 retry:
        /* find the parent in the context */
        usbi_mutex_lock(&ctx->usb_devs_lock);
-       list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) {
+       for_each_device(ctx, it) {
                struct linux_device_priv *priv = usbi_get_device_priv(it);
 
                if (priv->sysfs_dir) {
@@ -1070,7 +1070,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na
        struct libusb_context *ctx;
 
        usbi_mutex_static_lock(&active_contexts_lock);
-       list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+       for_each_context(ctx) {
                linux_enumerate_device(ctx, busnum, devaddr, sys_name);
        }
        usbi_mutex_static_unlock(&active_contexts_lock);
@@ -1083,7 +1083,7 @@ void linux_device_disconnected(uint8_t busnum, uint8_t devaddr)
        unsigned long session_id = busnum << 8 | devaddr;
 
        usbi_mutex_static_lock(&active_contexts_lock);
-       list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+       for_each_context(ctx) {
                dev = usbi_get_device_by_session_id(ctx, session_id);
                if (dev) {
                        usbi_disconnect_device(dev);
@@ -2629,7 +2629,7 @@ static int op_handle_events(struct libusb_context *ctx,
                        continue;
 
                num_ready--;
-               list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+               for_each_open_device(ctx, handle) {
                        hpriv = usbi_get_device_handle_priv(handle);
                        if (hpriv->fd == pollfd->fd)
                                break;
index ccf20b2..e2f9116 100644 (file)
@@ -779,7 +779,7 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds,
 
                transfer_priv = NULL;
                usbi_mutex_lock(&ctx->flying_transfers_lock);
-               list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+               for_each_transfer(ctx, itransfer) {
                        transfer_priv = usbi_get_transfer_priv(itransfer);
                        if (transfer_priv->pollable_fd.fd == fds[i].fd)
                                break;
index f59eebe..d21e1b9 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11529
+#define LIBUSB_NANO 11530