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 69e26498fcd25d6acf512e33fc37411cf738ca6c..89cfec3a68280197c7f23b60327cc212ca3be43e 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 e3e83c3b77d64a62354e6b375db4764d2403f4ae..c02cc56e5826894af335c7da9631c6cc27b2bf5a 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 4335fbe1aabf5abfa54c56e4d18bdf1814a75f2b..161f7e5fcde20676a9b90d6d31d55e0ae561ec40 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 b969633a03727274daa0ef7741e3c6b7ec0e331e..27350fa530773cf081f3f2b84a90accfada4c0b6 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 3c5add653e66e88d66acd56dd6d8e9e220a0bc47..1677fdacc4848c6d21e4aeb3541e1aaf44697010 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 a64d67d6cd8ca4491c7c9ff18a46a4d7e5cc774b..5f5e71b0e2cf539afd84aef3bd623428ff192608 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 c60b3b55fdcbdd08174555065b9da850e0bf1066..cb4fda89bc5a4a58e829039d11a7d1fbcc8a9ba0 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 082d726dcdae0b0eb4ff587e434042a24fc1c8fd..1e727ef610b692829e4304132eca7df9c4811dc5 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 ccf20b285ef84686007ddebe9f2cd628f3d71285..e2f91163d05936a8bce73c5b7fe075a6c9f4aa85 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 f59eebedba5eda80ea263e54e583e3737c8e4a6f..d21e1b94e14d532c589f3899502920c5632735aa 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11529
+#define LIBUSB_NANO 11530