Coverage for misc/fairlock/fairlock.py : 97%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import os
2import socket
3import inspect
4import time
6SOCKDIR = "/run/fairlock"
7START_SERVICE_TIMEOUT_SECS = 2
9class SingletonWithArgs(type):
10 _instances = {}
11 _init = {}
13 def __init__(cls, name, bases, dct):
14 cls._init[cls] = dct.get('__init__', None)
16 def __call__(cls, *args, **kwargs):
17 init = cls._init[cls]
18 if init is not None: 18 ↛ 22line 18 didn't jump to line 22, because the condition on line 18 was never false
19 key = (cls, frozenset(
20 inspect.getcallargs(init, None, *args, **kwargs).items()))
21 else:
22 key = cls
24 if key not in cls._instances:
25 cls._instances[key] = super(SingletonWithArgs, cls).__call__(*args, **kwargs)
26 return cls._instances[key]
28class FairlockDeadlock(Exception):
29 pass
31class FairlockServiceTimeout(Exception):
32 pass
34class Fairlock(metaclass=SingletonWithArgs):
35 def __init__(self, name):
36 self.name = name
37 self.sockname = os.path.join(SOCKDIR, name)
38 self.connected = False
40 def _ensure_service(self):
41 service=f"fairlock@{self.name}.service"
42 os.system(f"/usr/bin/systemctl start {service}")
43 timeout = time.time() + START_SERVICE_TIMEOUT_SECS
44 time.sleep(0.1)
45 while os.system(f"/usr/bin/systemctl --quiet is-active {service}") != 0:
46 time.sleep(0.1)
47 if time.time() > timeout:
48 raise FairlockServiceTimeout(f"Timed out starting service {service}")
50 def __enter__(self):
51 if self.connected:
52 raise FairlockDeadlock(f"Deadlock on Fairlock resource '{self.name}'")
54 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
55 try:
56 self.sock.connect(self.sockname)
57 except (FileNotFoundError, ConnectionRefusedError):
58 self._ensure_service()
59 self.sock.connect(self.sockname)
61 self.sock.send(f'{os.getpid()} - {time.monotonic()}'.encode())
62 self.connected = True
63 return self
65 def __exit__(self, type, value, traceback):
66 self.sock.close()
67 self.connected = False
68 return False