Date: Sat, 30 Nov 2002 14:48:25 -0800 From: Terry Lambert <tlambert2@mindspring.com> To: Brian Smith <dbsoft@technologist.com> Cc: "current@FreeBSD.ORG" <current@FreeBSD.ORG> Subject: Re: Are SysV semaphores thread-safe on CURRENT? Message-ID: <3DE94039.5E1DEEFC@mindspring.com> References: <20021130141711.CIZH19077.mailhost.chi1.ameritech.net@bbs.dbsoft-consulting.com>
next in thread | previous in thread | raw e-mail | index | archive | help
Brian Smith wrote: > On Mon, 18 Nov 2002 22:05:34 -0800, Terry Lambert wrote: > >Use mmap of a backing-store file, and then use file locking to > >do record locking in the shared memory segment. > > Ok, I did this, and it actually works considerably better than > the SysV shared memory. However flock() has the same problem > as the SysV semaphores, where they block the entire process, > allowing the same deadlock situation to occur. Has this flock() > behavior changed in CURRENT? > > It seems like this behavior is much more likely to change than > the SysV code. Do you mean "flock()", or do you mean "fcntl(fs, F_SETLKW, ...)"? If you are using range locks, then you mean fcntl(). That's unfortunate: there's an easy way to convert blocking file locks into non-blocking, plus a context switch. I thought th threads library already did this for you in the fcntl() wrapper, in /usr/src/lib/libc_r/uthread/uthread_fcntl.c, but apparently it doesn't. 8-(. The easy way to do this is to convert the blocking request into a non-blocking request, with a retry; e.g., where you have a call to: err = fcntl( fd, F_SETLKW, &flock); Replace it with: while( ( err = fcntl( fs, F_SETLK, &flock)) == -1 && errno == EAGAIN) { sleep( 1); /* use nanosleep(), if 1 second is too big */ } This will cause the processor to be yielded to other threads for as long as the lock can't be acquired, an acquisititon will be retried until it succeeds (effectively, blocking only that thread in "sleep()"). The difference between F_SETLKW and F_SETLK is why I suggested the approach in the first place (FWIW). The cost of doing this is that blocking requests will not be serviced in FIFO order, as they would if F_SETLKW were being used. This may get expensive if you have a highly contended resource, because you are effectively implementing a low cost polling to obtain the lock. The answer to this is that you are not supposed to use semaphores for highly contended resources, or if you do, use a spin-lock before you use the semaphore, so you can fail early at reduced expense. Probably making the above code into an line function and/or actually modifiying the _fcntl() implementation in the threads library is the way to go. Worse comes to worse, I can give you a kernel patch so that an fcntl() to assert a blocking lock on a non-blocking fd returns the EWOULDBLOCK error, with a patch against _fcntl() similar to the code in _read(). I didn't do that this time, because I don't know how much code really depends on a lock assert on a non-blocking fd blocking anyway, and no matter how you slice it, it's still going to have the same non-FIFO ordering, unless I implemented a FIFO ordered request queue, as well (it'd have to, to be correct). -- Terry To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3DE94039.5E1DEEFC>