Re: How to do proper locking

From: John Baldwin (jhb_at_FreeBSD.org)
Date: 08/04/05

  • Next message: Hans Petter Selasky: "Re: How to do proper locking"
    To: hselasky@c2i.net
    Date: Thu, 4 Aug 2005 09:53:58 -0400
    
    

    On Thursday 04 August 2005 07:40 am, Hans Petter Selasky wrote:
    > On Wednesday 03 August 2005 19:21, John Baldwin wrote:
    > > On Tuesday 02 August 2005 06:23 pm, Hans Petter Selasky wrote:
    > > > Hi,
    > > >
    > > > I am looking for a safe way to access structures that can be freed. The
    > > > solution I am looking for must not:
    > > >
    > > > - hinder scaleability
    > > > - lead to use of a single lock
    > > > - lead to lock order reversal
    >
    > There is one more thing. When the structure is freed it should not block
    > waiting for any reference counts.
    >
    > > These aren't a very clear set of requirements.
    >
    > If you think about the situation of accessing a structure in parallell with
    > freeing it, and want to do it 100 percent safe, you will see that you have
    > to do some kind of test before accessing this structure to see if it is
    > still present. So how should this test look like if you want to keep the
    > points I've listed above in mind?
    >
    > > Note that you can't hold a
    > > lock across malloc(), so your allocation code isn't safe.
    >
    > I was thinking that the M_NOWAIT flag was passed malloc(). Else in this
    > case, I think it is safe to unlock/lock "lock_A" when malloc is called.
    >
    > > You can try taking at look at some existing refcounted structures such
    > > as ucreds, p_args, etc. or looking at structures held in a global list
    > > like proc.
    >
    > It looks to me like some parent lock is held, or that these structures are
    > only accessed from a single thread, to prevent synchronization problems.

    You hold a parent lock (which is what your lock_A is if you think about it)
    while you bump the reference count, yes.

    > This is a copy and paste from the kernel sources:
    >
    > struct ucred *
    > crhold(struct ucred *cr)
    > {
    > The problem is, what happens if the kernel switches thread right here, and
    > then the other thread calls "crfree()" on this structure, that will
    > "free()" memory pointed to by "cr". Then the first line of code below will
    > access freed memory, and then we are going for a segment fault or worse.
    >
    > mtx_lock(cr->cr_mtxp);
    > cr->cr_ref++;
    > mtx_unlock(cr->cr_mtxp);
    > return (cr);
    > }

    crhold() is always called when the caller knows that it has a reference to cr
    that can't go away. Thus, in the case of p_ucred, one holds the associated
    PROC_LOCK() while doing crhold(). After the crhold() you can drop the proc
    lock, so that lock is only held for a very short period of time. You then
    have your own reference to the cred structure that is valid until you call
    crfree(). In the case of curthread->td_ucred, the reference is valid until
    curthread releases it on a cred update at the start of a syscall, so your
    reference is valid without needing locks for the life of a syscall. The key
    here is that you solve this problem at a higher level, not within the
    structure itself.

    > > What actual problem are you trying to solve?
    >
    > Generic callbacks:
    >
    > - setting up timers. Make sure that callback is never called after that
    > timer has been stopped.

    See callout_stop() and callout_drain(). callout_drain() won't return until
    the callout has both been stopped and has finished executing if it was
    already in progress.

    > - setting up devices. Make sure that read/write/ioctl/poll callbacks are
    > never called after that the device has been freed.

    This is managed with refcounts on the dev_t object by devfs. Once you call
    destroy_dev() devfs manages the rest.

    > - setting up interrupts. Make sure that interrupt routine is never called
    > after that it is been teared down.

    bus_teardown_intr() already does this.

    > And more. There are lots of situations in the kernel that run into the same
    > scheme, without a proper solution.

    Are there any other places you can think of that don't handle this already?
    The approach FreeBSD's kernel has taken is to solve this problem by
    duplicating a lot of checks all over the place for each data structure, but
    to solve it in the primitives themselves instead (hence callout_drain(),
    bus_teardown_intr(), destroy_dev(), etc.)

    -- 
    John Baldwin <jhb@FreeBSD.org>  <><  http://www.FreeBSD.org/~jhb/
    "Power Users Use the Power to Serve"  =  http://www.FreeBSD.org
    _______________________________________________
    freebsd-hackers@freebsd.org mailing list
    http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
    To unsubscribe, send any mail to "freebsd-hackers-unsubscribe@freebsd.org"
    

  • Next message: Hans Petter Selasky: "Re: How to do proper locking"

    Relevant Pages

    • Re: [PATCH] tipc: checking returns and Re: Possible Circular Locking in TIPC
      ... Jarek Poplawski wrote: ... until and unless the latter function has returned a valid reference. ... Is it OK to call it without the lock ... One reference entry points to a subscription instance, ...
      (Linux-Kernel)
    • Re: [PATCH] tipc: checking returns and Re: Possible Circular Locking in TIPC
      ... Jarek Poplawski wrote: ... IMHO lockdep ... until and unless the latter function has returned a valid reference. ... Is it OK to call it without the lock ...
      (Linux-Kernel)
    • Re: Threads - why isnt a whole object locked when ...?
      ... reference to A1 on a lock inside some other method (which may very- ... it's not guaranteed to cause dead-lock. ... taken in a different sequence from the code using the "this" reference as the locking object. ... What would be the best way to protect that data? ...
      (microsoft.public.dotnet.languages.csharp)
    • Re: Core i7 CMPXCHG-performance
      ... "find an object and increment its reference ... > a lock anyway. ... synchronization between the constructing thread and the other threads ... It does not matter if one uses locks or atomics to mutate the counter; they both have the same problems. ...
      (comp.programming.threads)

    Loading