[Mailman-Developers] New LockFile.py

bwarsaw@python.org bwarsaw@python.org
Tue, 2 May 2000 14:15:50 -0400 (EDT)


If you're using my new LockFile.py, you'll need this one fix.  Because
the uid of the mail wrapper process probably doesn't equal the uid of
the cgi wrapper process, the os.utime() could fail with an EPERM.

Mailman could require both wrappers to run set-uid, but I don't think
this is necessary.  The __touch() call in __break() just adds a small
comfort buffer, but I don't think it's essential that it succeed.
Here's the new LockFile.__break() method.

    def __break(self):
        # First, touch the global lock file so no other process will try to
        # break the lock while we're doing it.  Specifically, this avoids the
        # race condition where we've decided to break the lock at the same
        # time someone else has, but between the time we made this decision
        # and the time we read the winner out of the global lock file, they've
        # gone ahead and claimed the lock.
        #
        # TBD: This could fail if the process breaking the lock and the
        # process that claimed the lock have different owners.  We could solve
        # this by set-uid'ing the CGI and mail wrappers, but I don't think
        # it's that big a problem.
        try:
            self.__touch(self.__lockfile)
        except OSError, e:
            if e.errno <> errno.EPERM: raise
        # Try to remove the old winner's temp file, since we're assuming the
        # winner process has hung or died.  Don't worry too much if we can't
        # unlink their temp file -- this doesn't break the locking algorithm,
        # but will leave temp file turds laying around, a minor inconvenience.
        try:
            winner = self.__read()
            if winner:
                os.unlink(winner)
        except OSError, e:
            if e.errno <> errno.ENOENT: raise
        # Now remove the global lockfile, which actually breaks the lock.
        try:
            os.unlink(self.__lockfile)
        except OSError, e:
            if e.errno <> errno.ENOENT: raise

I'm going to give this another 24 hours on python.org and if it all
looks good, I'll commit the change.

-Barry