Changeset 0f0f8bc in mainline for uspace/lib/drv/generic/driver.c


Ignore:
Timestamp:
2011-08-29T18:46:37Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4d94002d
Parents:
8cc4ddb
Message:

Use reference counting to synchronize freeing of ddf_fun_t and ddf_dev_t.
This ensures that a function structure (device structure, potentially)
passed as argument to a driver entry point is not deallocated until
control returns from that entry point. We still need similar guarantee
for driver data.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/generic/driver.c

    r8cc4ddb r0f0f8bc  
    8686static ddf_dev_t *create_device(void);
    8787static void delete_device(ddf_dev_t *);
     88static void dev_add_ref(ddf_dev_t *);
     89static void dev_del_ref(ddf_dev_t *);
     90static void fun_add_ref(ddf_fun_t *);
     91static void fun_del_ref(ddf_fun_t *);
    8892static remote_handler_t *function_get_default_handler(ddf_fun_t *);
    8993static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
     
    261265}
    262266
    263 static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
     267static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    264268{
    265269        char *dev_name = NULL;
     
    270274       
    271275        ddf_dev_t *dev = create_device();
     276
     277        /* Add one reference that will be dropped by driver_dev_remove() */
     278        dev_add_ref(dev);
    272279        dev->handle = dev_handle;
    273280
     
    282289       
    283290        res = driver->driver_ops->add_device(dev);
    284         if (res != EOK)
    285                 delete_device(dev);
     291       
     292        if (res != EOK) {
     293                dev_del_ref(dev);
     294                async_answer_0(iid, res);
     295                return;
     296        }
    286297       
    287298        fibril_mutex_lock(&devices_mutex);
     
    303314        fibril_mutex_lock(&devices_mutex);
    304315        dev = driver_get_device(devh);
     316        dev_add_ref(dev);
    305317        fibril_mutex_unlock(&devices_mutex);
    306         /* XXX need lock on dev */
    307318       
    308319        if (dev == NULL) {
     
    316327                rc = ENOTSUP;
    317328       
     329        if (rc == EOK)
     330                dev_del_ref(dev);
     331       
    318332        async_answer_0(iid, (sysarg_t) rc);
    319333}
     
    326340       
    327341        funh = IPC_GET_ARG1(*icall);
     342       
     343        /*
     344         * Look up the function. Bump reference count so that
     345         * the function continues to exist until we return
     346         * from the driver.
     347         */
    328348        fibril_mutex_lock(&functions_mutex);
     349       
    329350        fun = driver_get_function(funh);
     351        if (fun != NULL)
     352                fun_add_ref(fun);
     353       
    330354        fibril_mutex_unlock(&functions_mutex);
    331         /* XXX Need lock on fun */
    332355       
    333356        if (fun == NULL) {
     
    336359        }
    337360       
     361        /* Call driver entry point */
    338362        if (driver->driver_ops->fun_online != NULL)
    339363                rc = driver->driver_ops->fun_online(fun);
     
    341365                rc = ENOTSUP;
    342366       
     367        fun_del_ref(fun);
     368       
    343369        async_answer_0(iid, (sysarg_t) rc);
    344370}
     
    351377       
    352378        funh = IPC_GET_ARG1(*icall);
     379       
     380        /*
     381         * Look up the function. Bump reference count so that
     382         * the function continues to exist until we return
     383         * from the driver.
     384         */
    353385        fibril_mutex_lock(&functions_mutex);
     386       
    354387        fun = driver_get_function(funh);
     388        if (fun != NULL)
     389                fun_add_ref(fun);
     390       
    355391        fibril_mutex_unlock(&functions_mutex);
    356         /* XXX Need lock on fun */
    357392       
    358393        if (fun == NULL) {
     
    361396        }
    362397       
     398        /* Call driver entry point */
    363399        if (driver->driver_ops->fun_offline != NULL)
    364400                rc = driver->driver_ops->fun_offline(fun);
     
    383419                switch (IPC_GET_IMETHOD(call)) {
    384420                case DRIVER_DEV_ADD:
    385                         driver_add_device(callid, &call);
     421                        driver_dev_add(callid, &call);
    386422                        break;
    387423                case DRIVER_DEV_REMOVE:
     
    575611        ddf_dev_t *dev;
    576612
    577         dev = malloc(sizeof(ddf_dev_t));
     613        dev = calloc(1, sizeof(ddf_dev_t));
    578614        if (dev == NULL)
    579615                return NULL;
    580616
    581         memset(dev, 0, sizeof(ddf_dev_t));
    582617        return dev;
    583618}
     
    610645}
    611646
    612 /** Delete device structure.
     647/** Delete function structure.
    613648 *
    614649 * @param dev           The device structure.
     
    622657}
    623658
     659/** Increase device reference count. */
     660static void dev_add_ref(ddf_dev_t *dev)
     661{
     662        atomic_inc(&dev->refcnt);
     663}
     664
     665/** Decrease device reference count.
     666 *
     667 * Free the device structure if the reference count drops to zero.
     668 */
     669static void dev_del_ref(ddf_dev_t *dev)
     670{
     671        if (atomic_predec(&dev->refcnt) == 0)
     672                delete_device(dev);
     673}
     674
     675/** Increase function reference count. */
     676static void fun_add_ref(ddf_fun_t *fun)
     677{
     678        atomic_inc(&fun->refcnt);
     679}
     680
     681/** Decrease function reference count.
     682 *
     683 * Free the function structure if the reference count drops to zero.
     684 */
     685static void fun_del_ref(ddf_fun_t *fun)
     686{
     687        if (atomic_predec(&fun->refcnt) == 0)
     688                delete_function(fun);
     689}
     690
    624691/** Create a DDF function node.
    625692 *
     
    652719        if (fun == NULL)
    653720                return NULL;
     721
     722        /* Add one reference that will be dropped by ddf_fun_destroy() */
     723        fun_add_ref(fun);
    654724
    655725        fun->bound = false;
     
    676746{
    677747        assert(fun->bound == false);
    678         delete_function(fun);
     748
     749        /*
     750         * Drop the reference added by ddf_fun_create(). This will deallocate
     751         * the function as soon as all other references are dropped (i.e.
     752         * as soon control leaves all driver entry points called in context
     753         * of this function.
     754         */
     755        fun_del_ref(fun);
    679756}
    680757
Note: See TracChangeset for help on using the changeset viewer.