Index: lldb/trunk/test/lldbtest.py =================================================================== --- lldb/trunk/test/lldbtest.py +++ lldb/trunk/test/lldbtest.py @@ -33,6 +33,7 @@ import abc import glob +import lock import os, sys, traceback import os.path import re @@ -47,6 +48,14 @@ import lldbutil from _pyio import __metaclass__ +# dosep.py starts lots and lots of dotest instances +# This option helps you find if two (or more) dotest instances are using the same +# directory at the same time +# Enable it to cause test failures and stderr messages if dotest instances try to run in +# the same directory simultaneously +# it is disabled by default because it litters the test directories with ".dirlock" files +debug_confirm_directory_exclusivity = False + # See also dotest.parseOptionsAndInitTestdirs(), where the environment variables # LLDB_COMMAND_TRACE and LLDB_DO_CLEANUP are set from '-t' and '-r dir' options. @@ -936,7 +945,6 @@ Python unittest framework class setup fixture. Do current directory manipulation. """ - # Fail fast if 'mydir' attribute is not overridden. if not cls.mydir or len(cls.mydir) == 0: raise Exception("Subclasses must override the 'mydir' attribute.") @@ -947,10 +955,26 @@ # Change current working directory if ${LLDB_TEST} is defined. # See also dotest.py which sets up ${LLDB_TEST}. if ("LLDB_TEST" in os.environ): + full_dir = os.path.join(os.environ["LLDB_TEST"], cls.mydir) if traceAlways: - print >> sys.stderr, "Change dir to:", os.path.join(os.environ["LLDB_TEST"], cls.mydir) + print >> sys.stderr, "Change dir to:", full_dir os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir)) + if debug_confirm_directory_exclusivity: + cls.dir_lock = lock.Lock(os.path.join(full_dir, ".dirlock")) + try: + cls.dir_lock.try_acquire() + # write the class that owns the lock into the lock file + cls.dir_lock.handle.write(cls.__name__) + except IOError as ioerror: + # nothing else should have this directory lock + # wait here until we get a lock + cls.dir_lock.acquire() + # read the previous owner from the lock file + lock_id = cls.dir_lock.handle.read() + print >> sys.stderr, "LOCK ERROR: {} wants to lock '{}' but it is already locked by '{}'".format(cls.__name__, full_dir, lock_id) + raise ioerror + # Set platform context. if platformIsDarwin(): cls.platformContext = _PlatformContext('DYLD_LIBRARY_PATH', 'lib', 'dylib') @@ -982,6 +1006,10 @@ exc_type, exc_value, exc_tb = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_tb) + if debug_confirm_directory_exclusivity: + cls.dir_lock.release() + del cls.dir_lock + # Restore old working directory. if traceAlways: print >> sys.stderr, "Restore dir to:", cls.oldcwd Index: lldb/trunk/test/lock.py =================================================================== --- lldb/trunk/test/lock.py +++ lldb/trunk/test/lock.py @@ -10,12 +10,16 @@ def __init__(self, filename): self.filename = filename # This will create it if it does not exist already - self.handle = open(filename, 'w') + unbuffered = 0 + self.handle = open(filename, 'a+', unbuffered) - # Bitwise OR fcntl.LOCK_NB if you need a non-blocking lock def acquire(self): fcntl.flock(self.handle, fcntl.LOCK_EX) + # will throw IOError if unavailable + def try_acquire(self): + fcntl.flock(self.handle, fcntl.LOCK_NB | fcntl.LOCK_EX) + def release(self): fcntl.flock(self.handle, fcntl.LOCK_UN)