Date: Wed, 10 Jul 2002 14:03:47 -0700 (PDT) From: Julian Elischer <julian@elischer.org> To: Archie Cobbs <archie@dellroad.org> Cc: John Baldwin <jhb@FreeBSD.org>, davidx@viasoft.com.cn, freebsd-arch@FreeBSD.org Subject: Re: Timeout and SMP race Message-ID: <Pine.BSF.4.21.0207101348170.41638-100000@InterJet.elischer.org> In-Reply-To: <200207101815.g6AIFDm28655@arch20m.dellroad.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 10 Jul 2002, Archie Cobbs wrote:
>
> [ NOTE: I'm moving this discussion to freebsd-arch@freebsd.org ]
> 1. The caller supplies a pointer to the 'handle', which must initially
> be NULL. The handle != NULL if and only if the timer is running.
The pointer is NULL or the pointee (tm) is NULL? Why would you have to
send a pointer if it must be NULL? SO assuming that the handle is what is
NULL, what IS it when it is not NULL?? An integer? a pointer? a magic
number? I'm assuming it is an 'int' that makes some sense only to the
callout system.
> 2. timer_cancel() guarantees that tfunc() will not be called subsequently
how? By use of a mutex? If the cancel holds the mutex when the timeout
tries to get it, how do you ensure that the timeout gets scheduled and
notices, before the timeout handle is re-used?
> 3. *handlep is set to NULL by timer_cancel() and by the timer expiring.
> So when *handlep is NULL when tfunc() is invoked (unless
> TIMER_RECURRING).
> 4. Calling timer_start() or timer_stop() from within tfunc() is OK.
> 5. If TIMER_RECURRING, timer started again before calling tfunc()
> 6. If TIMER_OWN_THREAD, timer runs in a newly created thread (rather
> than the timer service thread), which means that tfunc() may sleep
> or be canceled. If tfunc() sleeps or the thread is canceled but
> TIMER_OWN_THREAD was not set -> panic.
> 7. If mutexp != NULL, *mutexp is acquired before calling tfunc() and
> released after it returns.
>
> Items 1, and 2 are guaranteed only if mutexp != NULL and the caller
> acquires *mutexp before any calls to timer_start() or timer_cancel()
> (you would normally be doing this anyway).
What if the timeout handle was a structure that included the mutex?
>
> Errors:
>
> - timer_start() returns EBUSY if *handlep != NULL
> - timer_remaining() returns ESRCH if handle != NULL
>
> The model is: you have some object that has an associated lock and
> one or more associated timers. The object is to be locked whenever
> you muck with it (including when you start, stop, or handle a timer):
>
> struct foobar {
> struct lock mutex;
> timer_handle_t timer1;
> timer_handle_t timer2;
> ...
> };
>
> Then all calls to the timer_* routines are "well behaved" and the
> timeout thread caling tfunc() never races with any other thread
> that may be stopping or starting the timer, or destroying the object.
> E.g., to destroy the object, the following suffices:
>
> void
> foobar_destroy(struct foobar *f)
> {
> mutex_lock(&f->mutex);
> timer_cancel(&f->timer1);
> timer_cancel(&f->timer2);
> mutex_unlock(&f->mutex);
> free(f);
> }
>
> The only remaining complexity for the caller is that if you have
> any TIMER_OWN_THREAD handlers which unlock the object (e.g., in order
> to go to sleep), then you need to reference count the object and
> have a FOOBAR_INVALID flag.
>
> If you are working under a different model then this API may not
> be appropriate, but at least in my multi-threading experience this
> model is very typical.
>
> -Archie
>
> __________________________________________________________________________
> Archie Cobbs * Packet Design * http://www.packetdesign.com
>
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-current" in the body of the message
>
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0207101348170.41638-100000>
