tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: How to destroy a condvar(9) with waiters?



Thanks for your explanation. There are 2 condvars for the object - as
far as I understand should one refcount be enough to make sure there
are no waiters left on both, correct?

2015-12-28 15:33 GMT+01:00 Taylor R Campbell
<campbell+netbsd-tech-kern%mumble.net@localhost>:
>    Date: Mon, 28 Dec 2015 14:35:14 +0100
>    From: Stephan <stephanwib%googlemail.com@localhost>
>
>    given there is an object with the following
>
>    -an interlock (mutex)
>    -a condvar(9)
>    -a "state" variable which can be set to something like state_deleted
>
>    [...]
>
>    How can I safely destroy the condvar and interlock mutex?
>
> In addition to the state, add a reference count to your objects:
> increment and decrement it in the waiter code, and wait for it to
> drain to zero in the destroyer code.  Changing the state to deleted
> tells waiters they need to stop; changing the reference count from
> nonzero to zero tells the destroyer that the waiters have all stopped.
> The destroyer will not wake until the last waiter notifies it and
> releases the lock.
>
>
> /* Waiter: bump reference count, wait, drop reference count.  */
> if (port->kp_refcnt == UINT_MAX) {
>         error = EBUSY;
>         goto fail;
> }
> port->kp_refcnt++;
> while (!ready(port)) {
>         error = cv_timedwait_sig(&port->kp_rdcv, &port->kp_interlock,
>             mstohz(timeout));
>         if (error || (port->kp_state == state_deleted))
>                 break;
> }
> if (--port->kp_refcnt == 0)
>         cv_broadcast(&port->kp_rdcv);
>
>
> /* Destroyer: remove from list, mark deleted, wait for waiters to drain.  */
> mutex_enter(&port_list_lock);
> LIST_REMOVE(port, kp_list);
> mutex_exit(&port_list_lock);
>
> mutex_enter(&port->kp_interlock);
> port->kp_state = state_deleted;
> cv_broadcast(&port->kp_rdcv);
> while (port->kp_refcnt != 0)
>         cv_wait(&port->kp_rdcv, &port->kp_interlock);
> mutex_exit(&port->kp_interlock);
>
> /* Destroyer now has exclusive reference to port.  */
> mutex_destroy(&port->kp_interlock);
> cv_destroy(&port->kp_rdcv);
> ...
> kmem_free(port, sizeof(*port));
>
>
> (You can use a different condvar to notify the destroyer if you like,
> but there's not much benefit to that -- it takes extra space and only
> avoids a negligible number of spurious wakeups, which you have to deal
> with anyway.)


Home | Main Index | Thread Index | Old Index