Author: vharron Date: Thu May 21 14:09:29 2015 New Revision: 237935 URL: http://llvm.org/viewvc/llvm-project?rev=237935&view=rev Log: dotest.py - debug feature that helps find dosep races
SUMMARY 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 TEST PLAN Set lldbtest.debug_confirm_directory_exclusivity = True run ./dosep.py Differential Revision: http://reviews.llvm.org/D9868 Modified: lldb/trunk/test/lldbtest.py lldb/trunk/test/lock.py Modified: lldb/trunk/test/lldbtest.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=237935&r1=237934&r2=237935&view=diff ============================================================================== --- lldb/trunk/test/lldbtest.py (original) +++ lldb/trunk/test/lldbtest.py Thu May 21 14:09:29 2015 @@ -33,6 +33,7 @@ $ import abc import glob +import lock import os, sys, traceback import os.path import re @@ -47,6 +48,14 @@ import lldbtest_config 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 @@ class Base(unittest2.TestCase): 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 @@ class Base(unittest2.TestCase): # 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 @@ class Base(unittest2.TestCase): 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 Modified: lldb/trunk/test/lock.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lock.py?rev=237935&r1=237934&r2=237935&view=diff ============================================================================== --- lldb/trunk/test/lock.py (original) +++ lldb/trunk/test/lock.py Thu May 21 14:09:29 2015 @@ -10,12 +10,16 @@ class Lock: 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) _______________________________________________ lldb-commits mailing list lldb-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits