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 fcntl
32import glob
33import os
34import signal
35import sys
36import tempfile
37import time
38
39
40class HttpLock(object):
41
42 def __init__(self, lock_path, lock_file_prefix="WebKitHttpd.lock.",
43 guard_lock="WebKit.lock"):
44 if not lock_path:
45 self._lock_path = tempfile.gettempdir()
46 self._lock_file_prefix = lock_file_prefix
47 self._lock_file_path_prefix = os.path.join(self._lock_path,
48 self._lock_file_prefix)
49 self._guard_lock_file = os.path.join(self._lock_path, guard_lock)
50 self._process_lock_file_name = ""
51
52 def cleanup_http_lock(self):
53 """Delete the lock file if exists."""
54 if os.path.exists(self._process_lock_file_name):
55 os.unlink(self._process_lock_file_name)
56
57 def _extract_lock_number(self, lock_file_name):
58 """Return the lock number from lock file."""
59 prefix_length = len(self._lock_file_path_prefix)
60 return int(lock_file_name[prefix_length:])
61
62 def _lock_file_list(self):
63 """Return the list of lock files sequentially."""
64 lock_list = glob.glob(self._lock_file_path_prefix + '*')
65 lock_list.sort(key=self._extract_lock_number)
66 return lock_list
67
68 def _next_lock_number(self):
69 """Return the next available lock number."""
70 lock_list = self._lock_file_list()
71 if not lock_list:
72 return 0
73 return self._extract_lock_number(lock_list[-1]) + 1
74
75 def _check_pid(self, current_pid):
76 """Return True if pid is alive, otherwise return False."""
77 try:
78 os.kill(current_pid, 0)
79 except OSError:
80 return False
81 else:
82 return True
83
84 def _curent_lock_pid(self):
85 """Return with the current lock pid. If the lock is not valid
86 it deletes the lock file."""
87 lock_list = self._lock_file_list()
88 if not lock_list:
89 return
90 try:
91 current_lock_file = open(lock_list[0], 'r')
92 current_pid = current_lock_file.readline()
93 current_lock_file.close()
94 if not (current_pid and
95 sys.platform in ('darwin', 'linux2') and
96 self._check_pid(int(current_pid))):
97 os.unlink(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 sequential guard lock ensures that the lock
106 numbers are sequential."""
107 while(True):
108 try:
109 sequential_guard_lock = os.open(self._guard_lock_file,
110 os.O_CREAT | os.O_NONBLOCK | os.O_EXCL)
111
112 self._process_lock_file_name = (self._lock_file_path_prefix +
113 str(self._next_lock_number()))
114 lock_file = open(self._process_lock_file_name, 'w')
115 lock_file.write(str(os.getpid()))
116 lock_file.close()
117 os.close(sequential_guard_lock)
118 os.unlink(self._guard_lock_file)
119 break
120 except OSError:
121 pass
122
123 def wait_for_httpd_lock(self):
124 """Create a lock file and wait until it's turn comes."""
125 self._create_lock_file()
126 while self._curent_lock_pid() != os.getpid():
127 time.sleep(1)