Introduce device reference counting
authorKrzysztof Opasiak <k.opasiak@samsung.com>
Mon, 29 Jun 2015 17:06:25 +0000 (19:06 +0200)
committerStanislaw Wadas <s.wadas@samsung.com>
Wed, 2 Dec 2015 12:45:16 +0000 (13:45 +0100)
We should not free() usb devices explicity in
libhusb_free_devices() but just decrement their refcount
and free only if it is realy necessary.

Change-Id: I8474942e0305c25b8f41abb4dd018ce5bc05c9ec
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
include/libhusb.h
src/libhusb.c

index fa26362e582bc37e78a5a0bfdde72f985157620c..868cee16ebfb5df163db0deb36a0a1993c8280ec 100644 (file)
@@ -130,6 +130,10 @@ ssize_t libhusb_get_devices(libhusb_context *ctx, libhusb_device ***devs);
 
 void libhusb_free_devices(libhusb_device **list, int unref_devices);
 
+libhusb_device *libhusb_ref_device(libhusb_device *dev);
+
+void libhusb_unref_device(libhusb_device *dev);
+
 int libhusb_get_max_packet_size(libhusb_device *dev, uint8_t endpoint);
 
 uint8_t libhusb_get_bus_number(libhusb_device *dev);
index 02ca3383cfa3973c866771f2e75f0e2ef63a4145..415f8b15c532a94eba1bbb7b8e536c9790d3adc9 100644 (file)
 #include <stdlib.h>
 #include <sys/queue.h>
 
+#include "libhusb.h"
+#include "uref.h"
+#include "common.h"
+
 struct libhusb_context {
        libusb_context *lusb_ctx;
 };
 
 struct libhusb_device {
+       struct uref ref;
        libusb_device *lusb_dev;
 };
 
+static inline struct libhusb_device *to_libhusb_device(struct uref *_uref)
+{
+       return container_of(_uref, struct libhusb_device, ref);
+}
+
 struct libhusb_device_handle {
        struct libusb_device_handle *lusb_dev_handle;
 };
@@ -105,6 +115,30 @@ int libhusb_get_port_numbers(libhusb_device *dev, uint8_t* port_numbers, int por
        return port_num;
 }
 
+static void free_device(struct uref *uref)
+{
+       struct libhusb_device *dev = to_libhusb_device(uref);
+
+       libusb_unref_device(dev->lusb_dev);
+       free(dev);
+}
+
+static struct libhusb_device *alloc_device(libusb_device *lusb_dev)
+{
+       struct libhusb_device *dev;
+
+       dev = malloc(sizeof(*dev));
+       if (!dev)
+               goto out;
+
+       uref_init(&dev->ref, free_device);
+
+       libusb_ref_device(lusb_dev);
+       dev->lusb_dev = lusb_dev;
+out:
+       return dev;
+}
+
 ssize_t libhusb_get_devices(libhusb_context *context, libhusb_device ***devs)
 {
        ssize_t len;
@@ -121,27 +155,43 @@ ssize_t libhusb_get_devices(libhusb_context *context, libhusb_device ***devs)
                return -1;
 
        list = calloc(len + 1, sizeof(*list));
-       if (!list) {
-               libusb_free_device_list(lusb_list, 1);
-               return -99; /* TODO  replace with propper error*/
-       }
+       if (!list)
+               goto free_lusb_list;
 
        list[len] = NULL;
        for (i = 0; i < len; i++) {
-               rdevice = malloc(sizeof(*rdevice));
-               if (!rdevice) {
-                       libusb_free_device_list(lusb_list, 1);
-                       return -99; /* TODO  replace with propper error*/
-               }
+               rdevice = alloc_device(lusb_list[i]);
+               if (!rdevice)
+                       goto free_dev_list;
+
                list[i] = rdevice;
-               list[i]->lusb_dev = lusb_list[i];
        }
 
        *devs = list;
 
-       libusb_free_device_list(lusb_list, 0);
+       libusb_free_device_list(lusb_list, 1);
 
        return len;
+
+free_dev_list:
+       while (--i <= 0)
+               libhusb_unref_device(list[i]);
+       free(list);
+free_lusb_list:
+       libusb_free_device_list(lusb_list, 1);
+
+       return -99; /* TODO  replace with propper error*/
+}
+
+libhusb_device *libhusb_ref_device(libhusb_device *dev)
+{
+       uref_get(&dev->ref);
+       return dev;
+}
+
+void libhusb_unref_device(libhusb_device *dev)
+{
+       uref_put(&dev->ref);
 }
 
 void libhusb_free_devices(libhusb_device **list, int unref_devices)
@@ -151,14 +201,9 @@ void libhusb_free_devices(libhusb_device **list, int unref_devices)
        if (!list)
                return;
 
-       for (i = 0; list[i] != NULL; i++) {
-               if (unref_devices) {
-                       struct libusb_device *devp = list[i]->lusb_dev;
-                       assert(devp);
-                       libusb_unref_device(devp);
-               }
-               free(list[i]);
-       }
+       for (i = 0; list[i] != NULL; i++)
+               if (unref_devices)
+                       libhusb_unref_device(list[i]);
 
        free(list);
 }
@@ -171,7 +216,7 @@ int libhusb_get_max_packet_size(libhusb_device *dev, uint8_t endpoint)
 
        ret = libusb_get_max_iso_packet_size(dev->lusb_dev, endpoint);
        if (ret < 0)
-               ret = usb_device_get_error_num(ret);
+               ret = -99;
 
        return ret;
 }