Add inline fls() function for linux
[project/netifd.git] / device.c
index bc870c2..3f83cb4 100644 (file)
--- a/device.c
+++ b/device.c
@@ -120,10 +120,15 @@ static int set_device_state(struct device *dev, bool state)
        return 0;
 }
 
-int device_claim(struct device *dev)
+int device_claim(struct device_user *dep)
 {
+       struct device *dev = dep->dev;
        int ret;
 
+       if (dep->claimed)
+               return 0;
+
+       dep->claimed = true;
        DPRINTF("claim device %s, new refcount: %d\n", dev->ifname, dev->active + 1);
        if (++dev->active != 1)
                return 0;
@@ -138,8 +143,14 @@ int device_claim(struct device *dev)
        return ret;
 }
 
-void device_release(struct device *dev)
+void device_release(struct device_user *dep)
 {
+       struct device *dev = dep->dev;
+
+       if (!dep->claimed)
+               return;
+
+       dep->claimed = false;
        dev->active--;
        DPRINTF("release device %s, new refcount: %d\n", dev->ifname, dev->active);
        assert(dev->active >= 0);
@@ -242,7 +253,7 @@ void device_set_present(struct device *dev, bool state)
 void device_add_user(struct device_user *dep, struct device *dev)
 {
        dep->dev = dev;
-       list_add(&dep->list, &dev->users);
+       list_add_tail(&dep->list, &dev->users);
        if (dep->cb && dev->present) {
                dep->cb(dep, DEV_EVENT_ADD);
                if (dev->active)
@@ -250,29 +261,35 @@ void device_add_user(struct device_user *dep, struct device *dev)
        }
 }
 
+static void
+__device_free_unused(struct device *dev)
+{
+       if (!list_empty(&dev->users))
+               return;
+
+       device_free(dev);
+}
+
 void device_remove_user(struct device_user *dep)
 {
        struct device *dev = dep->dev;
 
-       list_del(&dep->list);
-
-       if (list_empty(&dev->users)) {
-               /* all references have gone away, remove this device */
-               device_free(dev);
-       }
+       if (dep->claimed)
+               device_release(dep);
 
+       list_del(&dep->list);
        dep->dev = NULL;
+       __device_free_unused(dev);
 }
 
 void
-device_free_all(void)
+device_free_unused(struct device *dev)
 {
-       struct device *dev, *tmp;
+       struct device *tmp;
 
-       avl_for_each_element_safe(&devices, dev, avl, tmp) {
-               if (!list_empty(&dev->users))
-                       continue;
+       if (dev)
+               return __device_free_unused(dev);
 
-               device_free(dev);
-       }
+       avl_for_each_element_safe(&devices, dev, avl, tmp)
+               __device_free_unused(dev);
 }