ATLAS Offline Software
SingleAppInstance.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
2 
3 
7 
8 import os
9 import socket
10 import time
11 import fcntl
12 
14  '''Class to handle creating and removing lockfiles'''
15 
16  # custom exceptions
17 
18  class FileLockAcquisitionError(Exception): pass
19  class FileLockReleaseError(Exception): pass
20 
21  # convenience callables for formatting
22  addr = lambda self: '%d@%s' % (self.pid, self.host)
23  fddr = lambda self: '<%s %s>' % (self.path, self.addr())
24  pddr = lambda self, lock: '<%s %s@%s>' %\
25  (self.path, lock['pid'], lock['host'])
26 
27  def __init__(self, path, debug=None, blocking = False):
28  self.pid = os.getpid()
29  self.host = socket.gethostname()
30  self.path = path
31  self.debug = debug # set this to get status messages
32  self.locked = False
33  self.lockfile = None
34  self.blocking = blocking
35 
36  def acquire(self):
37  '''Acquire a lock, returning self if successful, False otherwise'''
38  if self.islocked():
39  if self.debug:
40  lock = self._readlock()
41  print('Previous lock detected: %s' % self.pddr(lock))
42  return False
43  try:
44  fd = os.open(self.path, os.O_RDWR | os.O_CREAT, 0o777)
45  fh = os.fdopen(fd, 'r+')
46  self.lockfile = fh
47  fh.seek(0)
48  try:
49  fcntlflag = fcntl.LOCK_EX
50  if not self.blocking:
51  fcntlflag |= fcntl.LOCK_NB
52  fcntl.lockf(fh, fcntlflag)
53  self.locked = True
54  except IOError:
55  print('Unable to acquire lock on %s: existing lock %s' % (self.path, fh.read()))
56  fh.close()
57  return False
58  fh.write(self.addr())
59  fh.truncate()
60  fh.flush()
61  os.fsync(fh)
62  if self.debug:
63  modtime = os.stat(self.path)
64  outstring = 'Acquired lock: '+ self.fddr() + ' at time '+ time.ctime(modtime.st_mtime)
65  print(outstring)
66  except Exception as e:
67  if os.path.isfile(self.path):
68  try:
69  # my guess is this causes problems
70  #os.unlink(self.path)
71  pass
72  except Exception:
73  pass
74  raise self.FileLockAcquisitionError(
75  'Error acquiring lock: %s, reason %s' % (self.fddr(), e))
76  return self
77 
78  def release(self):
79  '''Release lock, returning self'''
80  if self.ownlock():
81  try:
82  fh = self.lockfile
83  fcntl.lockf(fh, fcntl.LOCK_UN)
84  self.locked = False
85  self.lockfile.close()
86  self.lockfile = None
87  if not self.blocking:
88  # some space for a small race here unfortunately
89  os.unlink(self.path)
90  if self.debug:
91  outstring = 'Released lock: ' + self.fddr() +' at time ' + time.ctime()
92  print(outstring)
93  except Exception as e:
94  print(e)
95  raise self.FileLockReleaseError(
96  'Error releasing lock: %s, reason %s' % (self.fddr(), e))
97  return self
98 
99  def _readlock(self):
100  '''Internal method to read lock info'''
101  try:
102  lock = {}
103  fh = open(self.path)
104  data = fh.read().rstrip().split('@')
105  fh.close()
106  lock['pid'], lock['host'] = data
107  return lock
108  except Exception:
109  return {'pid': 8**10, 'host': ''}
110 
111  def islocked(self):
112  '''Check if we already have a lock'''
113  return self.locked
114 
115  def ownlock(self):
116  '''Check if we own the lock'''
117  return self.locked
118 
119  def __del__(self):
120  '''Magic method to clean up lock when program exits'''
121  self.release()
122 
123  def __enter__(self):
124  self.acquire()
125  return self
126 
127  def __exit__(self, typ, value, tb):
128  self.release()
129  return self
python.SingleAppInstance.SingleAppInstance.__enter__
def __enter__(self)
Definition: SingleAppInstance.py:123
python.SingleAppInstance.SingleAppInstance.fddr
string fddr
Definition: SingleAppInstance.py:23
python.SingleAppInstance.SingleAppInstance.FileLockAcquisitionError
Definition: SingleAppInstance.py:18
python.SingleAppInstance.SingleAppInstance
Definition: SingleAppInstance.py:13
python.SingleAppInstance.SingleAppInstance.__exit__
def __exit__(self, typ, value, tb)
Definition: SingleAppInstance.py:127
python.SingleAppInstance.SingleAppInstance.release
def release(self)
Definition: SingleAppInstance.py:78
python.SingleAppInstance.SingleAppInstance.__del__
def __del__(self)
Definition: SingleAppInstance.py:119
python.SingleAppInstance.SingleAppInstance.__init__
def __init__(self, path, debug=None, blocking=False)
Definition: SingleAppInstance.py:27
python.SingleAppInstance.SingleAppInstance.host
host
Definition: SingleAppInstance.py:29
python.SingleAppInstance.SingleAppInstance.pid
pid
Definition: SingleAppInstance.py:28
python.SingleAppInstance.SingleAppInstance.path
path
Definition: SingleAppInstance.py:30
python.SingleAppInstance.SingleAppInstance.lockfile
lockfile
Definition: SingleAppInstance.py:33
python.SingleAppInstance.SingleAppInstance.ownlock
def ownlock(self)
Definition: SingleAppInstance.py:115
python.SingleAppInstance.SingleAppInstance._readlock
def _readlock(self)
Definition: SingleAppInstance.py:99
print
void print(char *figname, TCanvas *c1)
Definition: TRTCalib_StrawStatusPlots.cxx:25
python.SingleAppInstance.SingleAppInstance.locked
locked
Definition: SingleAppInstance.py:32
python.SingleAppInstance.SingleAppInstance.blocking
blocking
Definition: SingleAppInstance.py:34
python.SingleAppInstance.SingleAppInstance.acquire
def acquire(self)
Definition: SingleAppInstance.py:36
Trk::open
@ open
Definition: BinningType.h:40
python.SingleAppInstance.SingleAppInstance.pddr
string pddr
Definition: SingleAppInstance.py:24
pickleTool.object
object
Definition: pickleTool.py:29
python.SingleAppInstance.SingleAppInstance.debug
debug
Definition: SingleAppInstance.py:31
python.SingleAppInstance.SingleAppInstance.FileLockReleaseError
Definition: SingleAppInstance.py:19
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.SingleAppInstance.SingleAppInstance.islocked
def islocked(self)
Definition: SingleAppInstance.py:111
python.SingleAppInstance.SingleAppInstance.addr
string addr
Definition: SingleAppInstance.py:22