Changeset 58cbb0c8 in mainline for uspace/srv/devman/devman.c


Ignore:
Timestamp:
2011-09-01T22:19:21Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
aff587f
Parents:
5f6e25e
Message:

Reference counting of device and function nodes in devman.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/devman.c

    r5f6e25e r58cbb0c8  
    3030 * @{
    3131 */
     32/** @file Device Manager
     33 *
     34 * Locking order:
     35 *   (1) driver_t.driver_mutex
     36 *   (2) dev_tree_t.rwlock
     37 *
     38 * Synchronization:
     39 *    - device_tree.rwlock protects:
     40 *        - tree root, complete tree topology
     41 *        - complete contents of device and function nodes
     42 *    - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
     43 *      being deallocated
     44 *    - find_xxx() functions increase reference count of returned object
     45 *    - find_xxx_no_lock() do not increase reference count
     46 *
     47 * TODO
     48 *    - Track all steady and transient device/function states
     49 *    - Check states, wait for steady state on certain operations
     50 */
    3251
    3352#include <errno.h>
     
    4362#include "devman.h"
    4463
    45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);
     64static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
    4665
    4766/* hash table operations */
     
    406425        }
    407426       
     427        fun_add_ref(fun);
    408428        insert_fun_node(tree, fun, str_dup(""), NULL);
     429       
    409430        match_id_t *id = create_match_id();
    410431        id->id = str_dup("root");
     
    422443        }
    423444       
     445        dev_add_ref(dev);
    424446        insert_dev_node(tree, dev, fun);
    425447       
     
    467489/** Assign a driver to a device.
    468490 *
     491 * @param tree          Device tree
    469492 * @param node          The device's node in the device tree.
    470493 * @param drv           The driver.
    471494 */
    472 void attach_driver(dev_node_t *dev, driver_t *drv)
     495void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
    473496{
    474497        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    476499       
    477500        fibril_mutex_lock(&drv->driver_mutex);
     501        fibril_rwlock_write_lock(&tree->rwlock);
    478502       
    479503        dev->drv = drv;
    480504        list_append(&dev->driver_devices, &drv->devices);
    481505       
     506        fibril_rwlock_write_unlock(&tree->rwlock);
    482507        fibril_mutex_unlock(&drv->driver_mutex);
    483508}
     
    485510/** Detach driver from device.
    486511 *
     512 * @param tree          Device tree
    487513 * @param node          The device's node in the device tree.
    488514 * @param drv           The driver.
    489515 */
    490 void detach_driver(dev_node_t *dev)
    491 {
    492         /* XXX need lock on dev */
     516void detach_driver(dev_tree_t *tree, dev_node_t *dev)
     517{
    493518        driver_t *drv = dev->drv;
    494519       
    495520        assert(drv != NULL);
     521       
    496522        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
    497523            dev->pfun->pathname, drv->name);
    498524       
    499525        fibril_mutex_lock(&drv->driver_mutex);
     526        fibril_rwlock_write_lock(&tree->rwlock);
    500527       
    501528        dev->drv = NULL;
    502529        list_remove(&dev->driver_devices);
    503530       
     531        fibril_rwlock_write_unlock(&tree->rwlock);
    504532        fibril_mutex_unlock(&drv->driver_mutex);
    505533}
     
    578606        while (link != &driver->devices.head) {
    579607                dev = list_get_instance(link, dev_node_t, driver_devices);
     608                fibril_rwlock_write_lock(&tree->rwlock);
     609               
    580610                if (dev->passed_to_driver) {
     611                        fibril_rwlock_write_unlock(&tree->rwlock);
    581612                        link = link->next;
    582613                        continue;
    583614                }
    584615
    585                 /*
    586                  * We remove the device from the list to allow safe adding
    587                  * of new devices (no one will touch our item this way).
    588                  */
    589                 list_remove(link);
     616                log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
     617                    (int)atomic_get(&dev->refcnt));
     618                dev_add_ref(dev);
    590619
    591620                /*
     
    594623                 */
    595624                fibril_mutex_unlock(&driver->driver_mutex);
     625                fibril_rwlock_write_unlock(&tree->rwlock);
    596626
    597627                add_device(driver, dev, tree);
     628
     629                dev_del_ref(dev);
    598630
    599631                /*
     
    602634                 */
    603635                fibril_mutex_lock(&driver->driver_mutex);
    604 
    605                 /*
    606                  * Insert the device back.
    607                  * The order is not relevant here so no harm is done
    608                  * (actually, the order would be preserved in most cases).
    609                  */
    610                 list_append(link, &driver->devices);
    611636
    612637                /*
     
    701726        char *loc_name = NULL;
    702727       
     728        assert(fibril_rwlock_is_locked(&tree->rwlock));
     729       
    703730        asprintf(&loc_name, "%s", fun->pathname);
    704731        if (loc_name == NULL)
     
    805832       
    806833        /* Attach the driver to the device. */
    807         attach_driver(dev, drv);
     834        attach_driver(tree, dev, drv);
    808835       
    809836        fibril_mutex_lock(&drv->driver_mutex);
     
    822849}
    823850
    824 int driver_dev_remove(dev_node_t *dev)
     851int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
    825852{
    826853        async_exch_t *exch;
    827854        sysarg_t retval;
    828855        driver_t *drv;
     856        devman_handle_t handle;
    829857       
    830858        assert(dev != NULL);
     859       
    831860        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     861       
     862        fibril_rwlock_read_lock(&tree->rwlock);
    832863        drv = dev->drv;
     864        handle = dev->handle;
     865        fibril_rwlock_read_unlock(&tree->rwlock);
    833866       
    834867        exch = async_exchange_begin(drv->sess);
    835         retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, dev->handle);
     868        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
    836869        async_exchange_end(exch);
    837870       
     
    840873}
    841874
    842 int driver_fun_online(fun_node_t *fun)
     875int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
    843876{
    844877        async_exch_t *exch;
    845878        sysarg_t retval;
    846879        driver_t *drv;
     880        devman_handle_t handle;
    847881       
    848882        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     883
     884        fibril_rwlock_read_lock(&tree->rwlock);
     885       
    849886        if (fun->dev == NULL) {
    850887                /* XXX root function? */
     888                fibril_rwlock_read_unlock(&tree->rwlock);
    851889                return EINVAL;
    852890        }
    853891       
    854892        drv = fun->dev->drv;
     893        handle = fun->handle;
     894        fibril_rwlock_read_unlock(&tree->rwlock);
    855895       
    856896        exch = async_exchange_begin(drv->sess);
    857         retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, fun->handle);
     897        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
    858898        loc_exchange_end(exch);
    859899       
     
    861901}
    862902
    863 int driver_fun_offline(fun_node_t *fun)
     903int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
    864904{
    865905        async_exch_t *exch;
    866906        sysarg_t retval;
    867907        driver_t *drv;
     908        devman_handle_t handle;
    868909       
    869910        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     911
     912        fibril_rwlock_read_lock(&tree->rwlock);
    870913        if (fun->dev == NULL) {
    871914                /* XXX root function? */
     915                fibril_rwlock_read_unlock(&tree->rwlock);
    872916                return EINVAL;
    873917        }
    874918       
    875919        drv = fun->dev->drv;
     920        handle = fun->handle;
     921        fibril_rwlock_read_unlock(&tree->rwlock);
    876922       
    877923        exch = async_exchange_begin(drv->sess);
    878         retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, fun->handle);
     924        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
    879925        loc_exchange_end(exch);
    880926       
     
    909955        if (!create_root_nodes(tree))
    910956                return false;
    911 
     957   
    912958        /* Find suitable driver and start it. */
    913         return assign_driver(tree->root_node->child, drivers_list, tree);
     959        dev_node_t *rdev = tree->root_node->child;
     960        dev_add_ref(rdev);
     961        int rc = assign_driver(rdev, drivers_list, tree);
     962        dev_del_ref(rdev);
     963       
     964        return rc;
    914965}
    915966
     
    922973dev_node_t *create_dev_node(void)
    923974{
    924         dev_node_t *res = malloc(sizeof(dev_node_t));
    925        
    926         if (res != NULL) {
    927                 memset(res, 0, sizeof(dev_node_t));
    928                 list_initialize(&res->functions);
    929                 link_initialize(&res->driver_devices);
    930                 link_initialize(&res->devman_dev);
    931         }
    932        
    933         return res;
     975        dev_node_t *dev;
     976       
     977        dev = calloc(1, sizeof(dev_node_t));
     978        if (dev == NULL)
     979                return NULL;
     980       
     981        atomic_set(&dev->refcnt, 0);
     982        list_initialize(&dev->functions);
     983        link_initialize(&dev->driver_devices);
     984        link_initialize(&dev->devman_dev);
     985       
     986        return dev;
    934987}
    935988
     
    9471000}
    9481001
     1002/** Increase device node reference count.
     1003 *
     1004 * @param dev   Device node
     1005 */
     1006void dev_add_ref(dev_node_t *dev)
     1007{
     1008        atomic_inc(&dev->refcnt);
     1009}
     1010
     1011/** Decrease device node reference count.
     1012 *
     1013 * When the count drops to zero the device node is freed.
     1014 *
     1015 * @param dev   Device node
     1016 */
     1017void dev_del_ref(dev_node_t *dev)
     1018{
     1019        if (atomic_predec(&dev->refcnt) == 0)
     1020                delete_dev_node(dev);
     1021}
     1022
     1023
    9491024/** Find the device node structure of the device witch has the specified handle.
    9501025 *
     
    9761051        fibril_rwlock_read_lock(&tree->rwlock);
    9771052        dev = find_dev_node_no_lock(tree, handle);
     1053        if (dev != NULL)
     1054                dev_add_ref(dev);
     1055       
    9781056        fibril_rwlock_read_unlock(&tree->rwlock);
    9791057       
     
    10031081                    list_get_instance(item, fun_node_t, dev_functions);
    10041082
    1005                 if (pos < buf_cnt)
     1083                if (pos < buf_cnt) {
    10061084                        hdl_buf[pos] = fun->handle;
     1085                }
     1086
    10071087                pos++;
    10081088        }
     
    10201100fun_node_t *create_fun_node(void)
    10211101{
    1022         fun_node_t *res = malloc(sizeof(fun_node_t));
    1023        
    1024         if (res != NULL) {
    1025                 memset(res, 0, sizeof(fun_node_t));
    1026                 link_initialize(&res->dev_functions);
    1027                 list_initialize(&res->match_ids.ids);
    1028                 link_initialize(&res->devman_fun);
    1029                 link_initialize(&res->loc_fun);
    1030         }
    1031        
    1032         return res;
     1102        fun_node_t *fun;
     1103
     1104        fun = calloc(1, sizeof(fun_node_t));
     1105        if (fun == NULL)
     1106                return NULL;
     1107       
     1108        atomic_set(&fun->refcnt, 0);
     1109        link_initialize(&fun->dev_functions);
     1110        list_initialize(&fun->match_ids.ids);
     1111        link_initialize(&fun->devman_fun);
     1112        link_initialize(&fun->loc_fun);
     1113       
     1114        return fun;
    10331115}
    10341116
     
    10481130}
    10491131
     1132/** Increase function node reference count.
     1133 *
     1134 * @param fun   Function node
     1135 */
     1136void fun_add_ref(fun_node_t *fun)
     1137{
     1138        atomic_inc(&fun->refcnt);
     1139}
     1140
     1141/** Decrease function node reference count.
     1142 *
     1143 * When the count drops to zero the function node is freed.
     1144 *
     1145 * @param fun   Function node
     1146 */
     1147void fun_del_ref(fun_node_t *fun)
     1148{
     1149        if (atomic_predec(&fun->refcnt) == 0)
     1150                delete_fun_node(fun);
     1151}
     1152
    10501153/** Find the function node with the specified handle.
    10511154 *
     
    10581161        unsigned long key = handle;
    10591162        link_t *link;
     1163        fun_node_t *fun;
    10601164       
    10611165        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    10651169                return NULL;
    10661170       
    1067         return hash_table_get_instance(link, fun_node_t, devman_fun);
     1171        fun = hash_table_get_instance(link, fun_node_t, devman_fun);
     1172       
     1173        return fun;
    10681174}
    10691175
     
    10791185       
    10801186        fibril_rwlock_read_lock(&tree->rwlock);
     1187       
    10811188        fun = find_fun_node_no_lock(tree, handle);
     1189        if (fun != NULL)
     1190                fun_add_ref(fun);
     1191       
    10821192        fibril_rwlock_read_unlock(&tree->rwlock);
    10831193       
     
    10871197/** Create and set device's full path in device tree.
    10881198 *
     1199 * @param tree          Device tree
    10891200 * @param node          The device's device node.
    10901201 * @param parent        The parent device node.
     
    10921203 *                      resources etc.).
    10931204 */
    1094 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
    1095 {
     1205static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
     1206{
     1207        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10961208        assert(fun->name != NULL);
    10971209       
     
    11201232 *
    11211233 * @param tree          The device tree.
    1122  * @param node          The newly added device node.
    1123  * @param dev_name      The name of the newly added device.
    1124  * @param parent        The parent device node.
     1234 * @param dev           The newly added device node.
     1235 * @param pfun          The parent function node.
    11251236 *
    11261237 * @return              True on success, false otherwise (insufficient resources
     
    11291240bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    11301241{
    1131         assert(dev != NULL);
    1132         assert(tree != NULL);
    11331242        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    11341243       
     
    11551264void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
    11561265{
    1157         assert(tree != NULL);
    1158         assert(dev != NULL);
    11591266        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    11601267       
     
    11741281 *
    11751282 * @param tree          The device tree.
    1176  * @param node          The newly added function node.
    1177  * @param dev_name      The name of the newly added function.
    1178  * @param parent        Owning device node.
     1283 * @param fun           The newly added function node.
     1284 * @param fun_name      The name of the newly added function.
     1285 * @param dev           Owning device node.
    11791286 *
    11801287 * @return              True on success, false otherwise (insufficient resources
     
    11861293        fun_node_t *pfun;
    11871294       
    1188         assert(fun != NULL);
    1189         assert(tree != NULL);
    11901295        assert(fun_name != NULL);
    11911296        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    11981303       
    11991304        fun->name = fun_name;
    1200         if (!set_fun_path(fun, pfun)) {
     1305        if (!set_fun_path(tree, fun, pfun)) {
    12011306                return false;
    12021307        }
     
    12221327void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    12231328{
    1224         assert(tree != NULL);
    1225         assert(fun != NULL);
    12261329        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12271330       
     
    12561359       
    12571360        fun_node_t *fun = tree->root_node;
     1361        fun_add_ref(fun);
    12581362        /*
    12591363         * Relative path to the function from its parent (but with '/' at the
     
    12731377                }
    12741378               
    1275                 fun = find_node_child(fun, rel_path + 1);
     1379                fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
     1380                fun_del_ref(fun);
     1381                fun = cfun;
    12761382               
    12771383                if (cont) {
     
    12911397 * Device tree rwlock should be held at least for reading.
    12921398 *
     1399 * @param tree Device tree
    12931400 * @param dev Device the function belongs to.
    12941401 * @param name Function name (not path).
     
    12961403 * @retval NULL No function with given name.
    12971404 */
    1298 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
    1299 {
    1300         assert(dev != NULL);
     1405fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
     1406    const char *name)
     1407{
    13011408        assert(name != NULL);
     1409        assert(fibril_rwlock_is_locked(&tree->rwlock));
    13021410
    13031411        fun_node_t *fun;
     
    13061414                fun = list_get_instance(link, fun_node_t, dev_functions);
    13071415
    1308                 if (str_cmp(name, fun->name) == 0)
     1416                if (str_cmp(name, fun->name) == 0) {
     1417                        fun_add_ref(fun);
    13091418                        return fun;
     1419                }
    13101420        }
    13111421
     
    13171427 * Device tree rwlock should be held at least for reading.
    13181428 *
     1429 * @param tree          Device tree
    13191430 * @param parent        The parent function node.
    13201431 * @param name          The name of the child function.
    13211432 * @return              The child function node.
    13221433 */
    1323 fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
    1324 {
    1325         return find_fun_node_in_device(pfun->child, name);
     1434static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
     1435    const char *name)
     1436{
     1437        return find_fun_node_in_device(tree, pfun->child, name);
    13261438}
    13271439
     
    13361448        fibril_rwlock_read_lock(&tree->rwlock);
    13371449        link = hash_table_find(&tree->loc_functions, &key);
    1338         if (link != NULL)
     1450        if (link != NULL) {
    13391451                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
     1452                fun_add_ref(fun);
     1453        }
    13401454        fibril_rwlock_read_unlock(&tree->rwlock);
    13411455       
     
    13451459void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    13461460{
     1461        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1462       
    13471463        unsigned long key = (unsigned long) fun->service_id;
    1348         fibril_rwlock_write_lock(&tree->rwlock);
    13491464        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
    1350         fibril_rwlock_write_unlock(&tree->rwlock);
    13511465}
    13521466
Note: See TracChangeset for help on using the changeset viewer.