2 # Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
3 # Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
17 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 """This class helps to block NRWT threads when more NRWTs run
29 http and websocket tests in a same time."""
37 from webkitpy.common.system.executive import Executive
38 from webkitpy.common.system.file_lock import FileLock
39 from webkitpy.common.system.filesystem import FileSystem
42 _log = logging.getLogger(__name__)
45 class HttpLock(object):
46 def __init__(self, lock_path, lock_file_prefix="WebKitHttpd.lock.", guard_lock="WebKit.lock", filesystem=None, executive=None):
47 self._executive = executive or Executive()
48 self._filesystem = filesystem or FileSystem()
49 self._lock_path = lock_path
50 if not self._lock_path:
51 # FIXME: FileSystem should have an accessor for tempdir()
52 self._lock_path = tempfile.gettempdir()
53 self._lock_file_prefix = lock_file_prefix
54 self._lock_file_path_prefix = self._filesystem.join(self._lock_path, self._lock_file_prefix)
55 self._guard_lock_file = self._filesystem.join(self._lock_path, guard_lock)
56 self._guard_lock = FileLock(self._guard_lock_file)
57 self._process_lock_file_name = ""
59 def cleanup_http_lock(self):
60 """Delete the lock file if exists."""
61 if self._filesystem.exists(self._process_lock_file_name):
62 _log.debug("Removing lock file: %s" % self._process_lock_file_name)
63 self._filesystem.remove(self._process_lock_file_name)
65 def _extract_lock_number(self, lock_file_name):
66 """Return the lock number from lock file."""
67 prefix_length = len(self._lock_file_path_prefix)
68 return int(lock_file_name[prefix_length:])
70 def _lock_file_list(self):
71 """Return the list of lock files sequentially."""
72 lock_list = self._filesystem.glob(self._lock_file_path_prefix + '*')
73 lock_list.sort(key=self._extract_lock_number)
76 def _next_lock_number(self):
77 """Return the next available lock number."""
78 lock_list = self._lock_file_list()
81 return self._extract_lock_number(lock_list[-1]) + 1
83 def _current_lock_pid(self):
84 """Return with the current lock pid. If the lock is not valid
85 it deletes the lock file."""
86 lock_list = self._lock_file_list()
88 _log.debug("No lock file list")
91 current_pid = self._filesystem.read_text_file(lock_list[0])
92 if not (current_pid and self._executive.check_running_pid(int(current_pid))):
93 _log.debug("Removing stuck lock file: %s" % lock_list[0])
94 self._filesystem.remove(lock_list[0])
97 _log.debug("IOError: %s" % e)
100 _log.debug("OSError: %s" % e)
102 return int(current_pid)
104 def _create_lock_file(self):
105 """The lock files are used to schedule the running test sessions in first
106 come first served order. The guard lock ensures that the lock numbers are
108 if not self._filesystem.exists(self._lock_path):
109 _log.debug("Lock directory does not exist: %s" % self._lock_path)
112 if not self._guard_lock.acquire_lock():
113 _log.debug("Guard lock timed out!")
116 self._process_lock_file_name = (self._lock_file_path_prefix + str(self._next_lock_number()))
117 _log.debug("Creating lock file: %s" % self._process_lock_file_name)
118 # FIXME: Executive.py should have an accessor for getpid()
119 self._filesystem.write_text_file(self._process_lock_file_name, str(os.getpid()))
120 self._guard_lock.release_lock()
123 def wait_for_httpd_lock(self):
124 """Create a lock file and wait until it's turn comes. If something goes wrong
125 it wont do any locking."""
126 if not self._create_lock_file():
127 _log.debug("Warning, http locking failed!")
130 # FIXME: This can hang forever!
131 while self._current_lock_pid() != os.getpid():
134 _log.debug("HTTP lock acquired")