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