⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 namedmutex.py

📁 bittorrent source by python. please enjoy
💻 PY
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.1 (the License).  You may not copy or use this file, in either# source code or executable form, except in compliance with the License.  You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License# for the specific language governing rights and limitations under the# License.# Author: David Harrisonif __name__ == "__main__":    def _(s):        return selse:    from BitTorrent.translation import _import osif os.name == 'nt':    import win32file, win32event, win32api, winerror    from win32file import CreateFile, CreateFileW    import pywintypeselif os.name == 'posix':    import fcntl    from BitTorrent import platform    from fcntl import flockclass NamedMutex(object):    """Reasonably cross-platform, cross-process mutex.       It does not implement mutual exclusion between threads in the       same process.  Use threading.Lock or threading.RLock for mutual       exclusion between threads.    """    # In Unix:    #   Same semantics as directly locking a file: mutual exclusion is    #   provided when a process can lock the file.  If    #   the file does not exist, it is created.     #    # In NT:    #   Uses Windows CreateMutex.    # obtain_mutex = 1    # mutex = win32event.CreateMutex(None, obtain_mutex, name)    def __init__(self, name):        self._mylock = False        self._name = name        self._mutex = None         if os.name in ('posix','max'):            # We don't use config["data_dir"] to keep mutex separate from             # other configuration data since bittorrent.py will have a             # separate config directory from bittorrent console and curses             # apps.            ddir = platform.get_dot_dir()            self._path = os.path.join( ddir, "mutex", name )            if not os.path.exists(ddir):                os.mkdir(ddir, 0700)    def owner(self):        return self._mylock        def acquire(self, wait=True):          """Acquires mutual exclusion.  Returns true iff acquired."""        if os.name == 'nt':            # Gotcha: Not checking self._mylock in windows, because it is            # possible to acquire the mutex from more than one object with            # the same name.  This needs some work to make the semantics            # exactly the same between Windows and Unix.            obtain_mutex = 1            self._mutex = win32event.CreateMutex(None,obtain_mutex,self._name)            if self._mutex is None:                return False            lasterror = win32api.GetLastError()            if lasterror == winerror.ERROR_ALREADY_EXISTS:                if wait:                   # mutex exists and has been opened(not created, not locked).                   r = win32event.WaitForSingleObject(self._mutex,                                                       win32event.INFINITE)                else:                   r = win32event.WaitForSingleObject(self._mutex, 0)                # WAIT_OBJECT_0 means the mutex was obtained                # WAIT_ABANDONED means the mutex was obtained,                 # and it had previously been abandoned                if (r != win32event.WAIT_OBJECT_0 and                     r != win32event.WAIT_ABANDONED):                    return False            elif os.name in ('posix','max'):            if self._mylock:                 return True                        if os.path.exists(self._path) and not os.path.isfile(self._path):                raise BTFailure(                     "Cannot lock file that is not regular file." )            (dir,name) = os.path.split(self._path)            if not os.path.exists(dir):                os.mkdir(dir, 0700)  # mode=0700 = allow user access.            while True:  # <--- for file deletion race condition (see __del__)                # UNIX does not support O_TEMPORARY!! Blech. This complicates                # file deletion (see "while True" above and path checking after                # "flock").                #self._mutex = os.open( self._path, os.O_CREAT|os.O_TEMPORARY )                self._mutex = open( self._path, "w" )                if wait:                    flags = fcntl.LOCK_EX                else:                    flags = fcntl.LOCK_EX | fcntl.LOCK_NB                try:                    flock( self._mutex.fileno(), flags)                except IOError:                    return False                # race condition: __del__ may have deleted the file.                if not os.path.exists( self._path ):                    self._mutex.close()                else:                    break            else:            # dangerous, but what should we do if the platform neither            # supports named mutexes nor file locking?   --Dave            pass                    self._mylock = True        return True      def release(self):        # unlock        assert self._mylock        if os.name == 'nt':            win32event.ReleaseMutex(self._mutex)            # Error code 123?             #lasterror = win32api.GetLastError()            #if lasterror != 0:            #    raise IOError( _("Could not release mutex %s due to "            #                     "error windows code %d.") %             #                    (self._name,lasterror) )        elif os.name == 'posix':            self._mylock = False            if not os.path.exists(self._path):                raise IOError( _("Non-existent file: %s") % self._path )            flock( self._mutex.fileno(), fcntl.LOCK_UN )            self._mutex.close()    def __del__(self):        if os.name == 'nt':            if self._mutex is not None:                # Gotchas: Don't close the handle before releasing it or the                # mutex won't release until the python script exits.  It's                 # safe to call ReleaseMutex even if the local process hasn't                 # acquired the mutex.  If this process doesn't have mutex then                 # the call fails.  Note that in Windows, mutexes are literally                 # per process.  Multiple mutexes created with the same name                # from the same process will be treated as one with respect to                 # release and acquire.                self.release()                # windows will destroy the mutex when the last handle to that                # mutex is closed.                win32api.CloseHandle(self._mutex)                del self._mutex           elif os.name == 'posix':            if self._mylock:                self.release()            # relock file non-blocking to see if anyone else was             # waiting on it.  (A race condition exists where another process            # could have just opened but not yet locked the file.  This process            # then deletes the file.  When the other process resumes, the            # flock call fails.  This is however not a particularly bad            # race condition since acquire() simply repeats the open & flock.)            if os.path.exists(self._path) and self.acquire(False):                try:                    os.remove(self._path)                except:                    pass                # Strange to unlock the file after it has been deleted.                # Works on all UNIX platforms?  If I release before                # deleting then I introduce a race condition where the                # another process acquires the lock then                # this process deletes the file.                flock( self._mutex.fileno(), fcntl.LOCK_UN )                self._mutex.close()if __name__ == "__main__":    # perform unit tests.    n_tests = n_tests_passed = 0    n_tests += 1    mutex = NamedMutex("blah")        if mutex.acquire() and mutex._mutex is not None and mutex._mylock:        n_tests_passed += 1    else:        print "FAIL! Failed to acquire mutex on a new NamedMutex."    # attempt to acquire again.  Since already acquired, it should fail.    #n_tests += 1    #if not mutex.acquire():    #    n_tests_passed += 1    #else:    #    print "FAIL! Second acquire should return false but returned true."    n_tests += 1    mutex.release()    if mutex._mutex is not None and not mutex._mylock:        n_tests_passed += 1    else:        print "FAIL! Did not properly release mutex."    n_tests += 1    if mutex.acquire():        if mutex._mutex is not None and mutex._mylock:            n_tests_passed += 1        else:             print ( "FAIL! After calling acquire on a released NamedMutex, "                    "either mutex._mutex is None or mutex._mylock is false." )    else:        print "FAIL! Failed to acquire mutex a released NamedMutex."    # okay.  I should add more tests.    del mutex    if n_tests == n_tests_passed:        print "Passed all %d tests." % n_tests

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -