http_lock.py 5.8 KB

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