Commit f4c6e988 authored by Per Cederqvist's avatar Per Cederqvist
Browse files

Initial commit.

parent a2385755
# Lock the test suite.
# Copyright (C) 2002 Lysator Academic Computer Association.
#
# This file is part of the LysKOM server.
#
# LysKOM is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 1, or (at your option)
# any later version.
#
# LysKOM is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with LysKOM; see the file COPYING. If not, write to
# Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
# or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
# MA 02139, USA.
#
# Please mail bug reports to bug-lyskom@lysator.liu.se.
# This program is used by the test suite to ensure that only one test
# is running at a time. It obtains two locks:
#
# - first, a socket bound to a specific port. This lock ensures
# that only a single test is run on this computer. If two tests
# were run at the same time, they would interfere with each other,
# since static port is used by the test suite.
#
# - secondly, a symlink in the current working directory, that
# points to the host and pid of this process. This lock ensures
# that the test suite isn't used by two processes over a shared
# filesystem (such as NFS).
#
# This process communicates with the test suite on stdin/stdout.
# It understands a single command: "exit\n". It can send these
# responses:
#
# "locking...\n": this is sent as soon as the process is started.
#
# "waiting: socket $USER $CWD\n": if the socket lock is already taken,
# this message will be printed, with $USER replaced by the
# username and $CWD with the current working directory of the
# process that already holds the lock. This message may be issued
# several times, but never with the same values of both $USER and
# $CWD.
#
# "waiting: file $LOCK $HOST:$PID\n": if the symlink lock is already
# taken, this message will be printed, with $LOCK replaced by the
# full path to the symlink lock file, $HOST replaced by the host
# name and $PID by the pid of the process holding the lock. This
# message may be issued several times, but never with the same
# values of bot $HOST and $PID.
#
# "failed: file $LOCK $HOST $PID\n": the symlink lock may be a stale
# lock. If $HOST is the local host, the program can check for
# stale locks and break them. However, it it is held by a remote
# host, that isn't possible. After waiting an hour for a lock
# that is still held by the same remote host and pid, this program
# will print this message and stop trying to obtain the lock. If
# this happens, the process should send the "exit\n" command.
#
# "locked\n": the lock has been successfully obtained.
#
# "queued: socket $USER $CWD\n": this is printed when the lock is
# held, and another process wants it. The lock is still held.
#
# "bye\n": this is sent as a response to the "exit\n" command. If any
# locks were held, they are now released. After printing this
# response, the process will exit.
import socket
import select
import sys
import errno
import string
import os
import select
import getpass
import time
LOCKNAME = "locksuite.lock"
__reported_queued = {}
def try_socket():
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind(('', 53263))
except socket.error, e:
if e[0] != errno.EADDRINUSE:
raise
return None
s.listen(3)
return s
def try_symlink(hostname, pid):
"""Try to lock the symlink.
Return values:
None: ok
'host:pid': the lock was already held.
"""
fn = "%s:%d" % (hostname, pid)
while 1:
try:
os.symlink(fn, LOCKNAME)
return None
except os.error, e:
if e.errno != errno.EEXIST:
raise
try:
return os.readlink(LOCKNAME)
except os.error, e:
if e.errno != errno.ENOENT:
raise
time.sleep(1) # Just in case...
def myhostname():
host = socket.gethostname()
try:
fqdn = socket.gethostbyaddr(host)
return fqdn[0]
except socket.error:
return host
def my_id():
return "%s %s" % (getpass.getuser(), os.getcwd())
def poll_input(s, timeout):
global __reported_queued
pend = [sys.stdin]
if s != None:
pend.append(s)
(r, w, e) = select.select(pend, [], [], timeout)
if sys.stdin in r:
line = sys.stdin.readline() # Ignore the result.
sys.exit(0)
if s in r:
(other, addr) = s.accept()
other.send(my_id())
their_id = other.recv(100)
if not __reported_queued.has_key(their_id):
print "queued: socket", their_id
sys.stdout.flush()
__reported_queued[their_id] = None
other.close()
def get_socket_lock():
reported_sockets = {}
while 1:
s = try_socket()
if s != None:
return s
holder = get_holder()
if holder != None and not reported_sockets.has_key(holder):
print "waiting: socket", holder
sys.stdout.flush()
reported_sockets[holder] = None
poll_input(None, 1.0)
def get_holder():
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.connect(('', 53263))
except socket.error:
return None
s.send(my_id())
their_id = s.recv(100)
s.close()
return their_id
def get_link_lock():
reported_symlinks = {}
start = time.time()
host = myhostname()
pid = os.getpid()
while time.time() < start + 3600:
lnk = try_symlink(host, pid)
if lnk == None:
return LOCKNAME
if not reported_symlinks.has_key(lnk):
print "waiting: file", os.path.join(os.getcwd(), LOCKNAME), lnk
sys.stdout.flush()
reported_symlinks[lnk] = None
start = time.time()
time.sleep(5)
print "failed: file", os.path.join(os.getcwd(), LOCKNAME), lnk
return None
def main():
print "locking..."
sys.stdout.flush()
host = myhostname()
s = None
link = None
try:
s = get_socket_lock()
link = get_link_lock()
if link != None:
print "locked"
sys.stdout.flush()
while 1:
poll_input(s, 3600)
finally:
if s != None:
s.close()
if link != None:
os.unlink(link)
print "bye"
sys.stdout.flush()
if __name__ == '__main__':
main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment