50 lines
1.1 KiB
Python
50 lines
1.1 KiB
Python
|
"""Threading primitives for the network package"""
|
||
|
|
||
|
import logging
|
||
|
import random
|
||
|
import threading
|
||
|
from contextlib import contextmanager
|
||
|
|
||
|
|
||
|
class StoppableThread(threading.Thread):
|
||
|
"""Base class for application threads with stopThread method"""
|
||
|
name = None
|
||
|
logger = logging.getLogger('default')
|
||
|
|
||
|
def __init__(self, name=None):
|
||
|
if name:
|
||
|
self.name = name
|
||
|
super(StoppableThread, self).__init__(name=self.name)
|
||
|
self.stop = threading.Event()
|
||
|
self._stopped = False
|
||
|
random.seed()
|
||
|
self.logger.info('Init thread %s', self.name)
|
||
|
|
||
|
def stopThread(self):
|
||
|
"""Stop the thread"""
|
||
|
self._stopped = True
|
||
|
self.stop.set()
|
||
|
|
||
|
|
||
|
class BusyError(threading.ThreadError):
|
||
|
"""
|
||
|
Thread error raised when another connection holds the lock
|
||
|
we are trying to acquire.
|
||
|
"""
|
||
|
pass
|
||
|
|
||
|
|
||
|
@contextmanager
|
||
|
def nonBlocking(lock):
|
||
|
"""
|
||
|
A context manager which acquires given lock non-blocking
|
||
|
and raises BusyError if failed to acquire.
|
||
|
"""
|
||
|
locked = lock.acquire(False)
|
||
|
if not locked:
|
||
|
raise BusyError
|
||
|
try:
|
||
|
yield
|
||
|
finally:
|
||
|
lock.release()
|