t | class LockDescriptor: | t | class LockDescriptor: |
| _semaphores = {} | | _semaphores = {} |
| _waiting_queues = {} | | _waiting_queues = {} |
| _temp = {} | | _temp = {} |
| | | |
| def __get__(self, instance, owner): | | def __get__(self, instance, owner): |
| instance_id = id(instance) | | instance_id = id(instance) |
| name = self._temp.get(instance_id, None) | | name = self._temp.get(instance_id, None) |
| if name is not None and name not in self._semaphores.values(): | | if name is not None and name not in self._semaphores.values(): |
| self._semaphores[instance_id] = name | | self._semaphores[instance_id] = name |
| return self._semaphores.get(id(instance), None) | | return self._semaphores.get(id(instance), None) |
| | | |
| def __set__(self, instance, name): | | def __set__(self, instance, name): |
| instance_id = id(instance) | | instance_id = id(instance) |
| current_lock = self._semaphores.get(instance_id) | | current_lock = self._semaphores.get(instance_id) |
| if current_lock == name: | | if current_lock == name: |
| self.__delete__(instance) | | self.__delete__(instance) |
| if self._waiting_queues.get(name): | | if self._waiting_queues.get(name): |
| next_instance = self._waiting_queues[name].pop(0) | | next_instance = self._waiting_queues[name].pop(0) |
| self._temp[id(next_instance)] = name | | self._temp[id(next_instance)] = name |
| elif (instance_id, name) not in self._temp.items() and name not in self._semaphores.values(): | | elif (instance_id, name) not in self._temp.items() and name not in self._semaphores.values(): |
| self._temp[instance_id] = name | | self._temp[instance_id] = name |
| else: | | else: |
| if current_lock is not None and current_lock != name: | | if current_lock is not None and current_lock != name: |
| del self._semaphores[instance_id] | | del self._semaphores[instance_id] |
| del self._temp[instance_id] | | del self._temp[instance_id] |
| self._waiting_queues.setdefault(name, []).append(instance) | | self._waiting_queues.setdefault(name, []).append(instance) |
| | | |
| def __delete__(self, instance): | | def __delete__(self, instance): |
| instance_id = id(instance) | | instance_id = id(instance) |
| semaphore_to_release = self._semaphores.pop(instance_id, None) | | semaphore_to_release = self._semaphores.pop(instance_id, None) |
| self._temp.pop(instance_id, None) | | self._temp.pop(instance_id, None) |
| if semaphore_to_release: | | if semaphore_to_release: |
| if semaphore_to_release in self._waiting_queues: | | if semaphore_to_release in self._waiting_queues: |
| waiting_instances = self._waiting_queues[semaphore_to_release] | | waiting_instances = self._waiting_queues[semaphore_to_release] |
| if waiting_instances: | | if waiting_instances: |
| next_instance = waiting_instances.pop(0) | | next_instance = waiting_instances.pop(0) |
| self._temp[id(next_instance)] = semaphore_to_release | | self._temp[id(next_instance)] = semaphore_to_release |
| | | |
| @classmethod | | @classmethod |
| def release_all(cls, instance): | | def release_all(cls, instance): |
| instance_id = id(instance) | | instance_id = id(instance) |
| semaphore_to_release = cls._semaphores.pop(instance_id, None) | | semaphore_to_release = cls._semaphores.pop(instance_id, None) |
| cls._temp.pop(instance_id, None) | | cls._temp.pop(instance_id, None) |
| if semaphore_to_release and semaphore_to_release in cls._waiting_queues: | | if semaphore_to_release and semaphore_to_release in cls._waiting_queues: |
| waiting_instances = cls._waiting_queues[semaphore_to_release] | | waiting_instances = cls._waiting_queues[semaphore_to_release] |
| if waiting_instances: | | if waiting_instances: |
| next_instance = waiting_instances.pop(0) | | next_instance = waiting_instances.pop(0) |
| cls._temp[id(next_instance)] = semaphore_to_release | | cls._temp[id(next_instance)] = semaphore_to_release |
| | | |
| class Lock: | | class Lock: |
| | | |
| @staticmethod | | @staticmethod |
| def locked(cls): | | def locked(cls): |
| | | |
| class Wrapped(cls): | | class Wrapped(cls): |
| lock = LockDescriptor() | | lock = LockDescriptor() |
| | | |
| def __del__(self): | | def __del__(self): |
| try: | | try: |
| LockDescriptor.release_all(self) | | LockDescriptor.release_all(self) |
| except AttributeError: | | except AttributeError: |
| pass | | pass |
| super_del = getattr(super(), '__del__', None) | | super_del = getattr(super(), '__del__', None) |
| if callable(super_del): | | if callable(super_del): |
| super_del(self) | | super_del(self) |
| return Wrapped | | return Wrapped |