1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-31 02:01:16 +00:00

utils/misc: Add file locking context manager

Enable automation locking and unlocking of a file path provided. Used to
prevent synchronisation issues between multiple wa processes.
This commit is contained in:
Marc Bonnici 2020-01-03 11:15:21 +00:00 committed by setrofim
parent 0f9c20dc69
commit d56f0fbe20

View File

@ -30,9 +30,11 @@ import string
import subprocess import subprocess
import sys import sys
import traceback import traceback
from contextlib import contextmanager
from datetime import datetime, timedelta from datetime import datetime, timedelta
from functools import reduce # pylint: disable=redefined-builtin from functools import reduce # pylint: disable=redefined-builtin
from operator import mul from operator import mul
from time import sleep
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
from io import StringIO from io import StringIO
else: else:
@ -54,6 +56,8 @@ from devlib.utils.misc import (ABI_MAP, check_output, walk_modules,
check_output_logger = logging.getLogger('check_output') check_output_logger = logging.getLogger('check_output')
file_lock_logger = logging.getLogger('file_lock')
# Defined here rather than in wa.exceptions due to module load dependencies # Defined here rather than in wa.exceptions due to module load dependencies
def diff_tokens(before_token, after_token): def diff_tokens(before_token, after_token):
@ -640,3 +644,43 @@ def format_ordered_dict(od):
""" """
return '{{{}}}'.format(', '.join('{}={}'.format(k, v) return '{{{}}}'.format(', '.join('{}={}'.format(k, v)
for k, v in od.items())) for k, v in od.items()))
@contextmanager
def lock_file(path, timeout=30):
"""
Enable automatic locking and unlocking of a file path given. Used to
prevent synchronisation issues between multiple wa processes.
Uses a default timeout of 30 seconds which should be overridden for files
that are expect to be unavailable for longer periods of time.
"""
# Import here to avoid circular imports
# pylint: disable=wrong-import-position,cyclic-import
from wa.framework.exception import ResourceError
locked = False
l_file = '{}.lock'.format(path) if not path.endswith('.lock') else path
file_lock_logger.debug('Acquiring lock on "{}"'.format(l_file))
try:
while timeout:
try:
open(l_file, 'x').close()
locked = True
file_lock_logger.debug('Lock acquired on "{}"'.format(l_file))
break
except FileExistsError:
msg = 'Failed to acquire lock on "{}" Retrying...'
file_lock_logger.debug(msg.format(l_file))
sleep(1)
timeout -= 1
else:
msg = 'Failed to acquire lock file "{}" within the timeout. \n' \
'If there are no other running WA processes please delete ' \
'this file and retry.'
raise ResourceError(msg.format(os.path.abspath(l_file)))
yield
finally:
if locked and os.path.exists(l_file):
os.remove(l_file)
file_lock_logger.debug('Lock released "{}"'.format(l_file))