• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
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
4#
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
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.
15#
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.
27
28"""This class helps to block NRWT threads when more NRWTs run
29http and websocket tests in a same time."""
30
31import glob
32import logging
33import os
34import sys
35import tempfile
36import time
37
38from webkitpy.common.system.executive import Executive
39from webkitpy.common.system.file_lock import FileLock
40from webkitpy.common.system.filesystem import FileSystem
41
42
43_log = logging.getLogger("webkitpy.layout_tests.port.http_lock")
44
45
46class HttpLock(object):
47
48    def __init__(self, lock_path, lock_file_prefix="WebKitHttpd.lock.",
49                 guard_lock="WebKit.lock"):
50        self._lock_path = lock_path
51        if not self._lock_path:
52            self._lock_path = tempfile.gettempdir()
53        self._lock_file_prefix = lock_file_prefix
54        self._lock_file_path_prefix = os.path.join(self._lock_path,
55                                                   self._lock_file_prefix)
56        self._guard_lock_file = os.path.join(self._lock_path, guard_lock)
57        self._guard_lock = FileLock(self._guard_lock_file)
58        self._process_lock_file_name = ""
59        self._executive = Executive()
60
61    def cleanup_http_lock(self):
62        """Delete the lock file if exists."""
63        if os.path.exists(self._process_lock_file_name):
64            _log.debug("Removing lock file: %s" % self._process_lock_file_name)
65            FileSystem().remove(self._process_lock_file_name)
66
67    def _extract_lock_number(self, lock_file_name):
68        """Return the lock number from lock file."""
69        prefix_length = len(self._lock_file_path_prefix)
70        return int(lock_file_name[prefix_length:])
71
72    def _lock_file_list(self):
73        """Return the list of lock files sequentially."""
74        lock_list = glob.glob(self._lock_file_path_prefix + '*')
75        lock_list.sort(key=self._extract_lock_number)
76        return lock_list
77
78    def _next_lock_number(self):
79        """Return the next available lock number."""
80        lock_list = self._lock_file_list()
81        if not lock_list:
82            return 0
83        return self._extract_lock_number(lock_list[-1]) + 1
84
85    def _curent_lock_pid(self):
86        """Return with the current lock pid. If the lock is not valid
87        it deletes the lock file."""
88        lock_list = self._lock_file_list()
89        if not lock_list:
90            return
91        try:
92            current_lock_file = open(lock_list[0], 'r')
93            current_pid = current_lock_file.readline()
94            current_lock_file.close()
95            if not (current_pid and self._executive.check_running_pid(int(current_pid))):
96                _log.debug("Removing stuck lock file: %s" % lock_list[0])
97                FileSystem().remove(lock_list[0])
98                return
99        except (IOError, OSError):
100            return
101        return int(current_pid)
102
103    def _create_lock_file(self):
104        """The lock files are used to schedule the running test sessions in first
105        come first served order. The guard lock ensures that the lock numbers are
106        sequential."""
107        if not os.path.exists(self._lock_path):
108            _log.debug("Lock directory does not exist: %s" % self._lock_path)
109            return False
110
111        if not self._guard_lock.acquire_lock():
112            _log.debug("Guard lock timed out!")
113            return False
114
115        self._process_lock_file_name = (self._lock_file_path_prefix +
116                                        str(self._next_lock_number()))
117        _log.debug("Creating lock file: %s" % self._process_lock_file_name)
118        lock_file = open(self._process_lock_file_name, 'w')
119        lock_file.write(str(os.getpid()))
120        lock_file.close()
121        self._guard_lock.release_lock()
122        return True
123
124
125    def wait_for_httpd_lock(self):
126        """Create a lock file and wait until it's turn comes. If something goes wrong
127        it wont do any locking."""
128        if not self._create_lock_file():
129            _log.debug("Warning, http locking failed!")
130            return
131
132        while self._curent_lock_pid() != os.getpid():
133            time.sleep(1)
134