Question: posix fcntl module

Ignacio Vazquez-Abrams ignacio at openservices.net
Tue Aug 28 20:02:51 EDT 2001


On Tue, 28 Aug 2001, Sheila King wrote:

> On Tue, 28 Aug 2001 18:51:40 -0400 (EDT), Ignacio Vazquez-Abrams
> <ignacio at openservices.net> wrote in comp.lang.python in article
> <mailman.999039163.17806.python-list at python.org>:
>
> :>From the fcntl(2) man page:
> :
> :"
> :       F_SETLK
> :              The lock is set (when l_type is F_RDLCK or F_WRLCK)
> :              or cleared (when it is F_UNLCK).  If  the  lock  is
> :              held by someone else, this call returns -1 and sets
> :              errno to EACCES or EAGAIN.
> :"
> :
> :>From <bits/fcntl.h>:
> :---
> :#define F_RDLCK         0       /* Read lock.  */
> :#define F_WRLCK         1       /* Write lock.  */
> :#define F_UNLCK         2       /* Remove lock.  */
> :---
> :
> :Those are the values you want to use. It looks like Python may have this one
> :wrong.
>
> Well, this sounded good to me. So, I tried this:
>
> ''' posixLock.py
>
> class lockfile
> supports the same function calls as
> winLock.lockfile
> export to LockFile.py: a wrapper module
> around the win and posix lockfiles
> '''
>
> import os, fcntl
>
> class lockfile:
>     def __init__(self, filename):
>         if os.access(filename, os.F_OK):
>             self.filename = filename
>         else:
>             errmssg = filename + " does not exist. Can't lock non-existent file."
>             raise IOError, errmssg
>
>     def getReadLock(self):
>         self.f = open(self.filename)
>         self.fd = self.f.fileno()
>         fcntl.lockf(self.fd, fcntl.F_RDLCK)
>
>     def getWriteLock(self):
>         self.f = open(self.filename)
>         self.fd = self.f.fileno()
>         fcntl.lockf(self.fd, fcntl.F_WRLCK)
>
>     def unlock(self):
>         fcntl.lockf(self.fd, fcntl.F_UNLCK)
>         self.f.close()
>         del self.fd
>
>     def flock(self, flag):
>         '''flags are:
>         LOCK_UN - unlock
>         LOCK_SH - acquire a shared (or read) lock
>         LOCK_EX - acquire an exclusive (or write) lock
>         '''
>         if flag == 'LOCK_SH':
>             self.getReadLock()
>         elif flag == 'LOCK_EX':
>             self.getWriteLock()
>         elif flag == 'LOCK_UN':
>             self.unlock()
>         else:
>             errmssg = "The flag " + flag + " is not implemented for flock"
>             raise NotImplementedError, errmssg
>
>
> But, in an interactive session, I got:
>
>  [snip]
>
> Additional advice is welcome...
>
> --
> Sheila King
> http://www.thinkspot.net/sheila/
> http://www.k12groups.org/

Oh hell. fcntlmodule.so munges the parameter passed to it so that LOCK_UN
looks like F_UNLCK, LOCK_SH like F_RDLCK, and LOCK_EX like F_WRLCK. Whose
bright idea was that anyway?

But I think I have found the real reason this time. Passing no mode argument
to open() tells Python to open the file read-only. Guess what? By rejecting
LOCK_EX Linux is telling you "Write lock? Why the hell does a read-only file
need a write lock?". Same thing with 'w' and LOCK_SH. 'w+' and 'r+' can take
both.

So it seems that you need to take both a filename _and_ a mode in __init__(),
and then raise an exception in the appropriate locking methods based on
f.mode. You may also want to take a third parameter for initial lock mode,
just in case.

Also, you should make it so that the file is immediately opened in __init__(),
then close the file both in a close() method and in __del__(). In both methods
you should probably check f.closed to make sure that the file hasn't already
been closed.

Hopefully your problem has now been solved. Third (or fourth or whatever :) )
time's the charm, right?

-- 
Ignacio Vazquez-Abrams  <ignacio at openservices.net>





More information about the Python-list mailing list