diff options
author | lambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-10 03:49:59 +0000 |
---|---|---|
committer | lambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-10 03:49:59 +0000 |
commit | 5c373613e7e8987a5d3781cb081e3b94483eeb6a (patch) | |
tree | a043afa20e092dbf98e94f6e4827e8053303a2a6 /remoting/tools | |
parent | be3ab08b7ad47c2a4ba368cb12097c745257f8c6 (diff) | |
download | chromium_src-5c373613e7e8987a5d3781cb081e3b94483eeb6a.zip chromium_src-5c373613e7e8987a5d3781cb081e3b94483eeb6a.tar.gz chromium_src-5c373613e7e8987a5d3781cb081e3b94483eeb6a.tar.bz2 |
Improve PID-file handling in Linux Me2Me script.
BUG=166068,178102
Review URL: https://chromiumcodereview.appspot.com/12377030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187185 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/tools')
-rwxr-xr-x | remoting/tools/me2me_virtual_host.py | 136 |
1 files changed, 36 insertions, 100 deletions
diff --git a/remoting/tools/me2me_virtual_host.py b/remoting/tools/me2me_virtual_host.py index d55716a..e613517 100755 --- a/remoting/tools/me2me_virtual_host.py +++ b/remoting/tools/me2me_virtual_host.py @@ -18,6 +18,7 @@ import logging import optparse import os import pipes +import psutil import signal import socket import subprocess @@ -69,7 +70,6 @@ MAX_LAUNCH_FAILURES = SHORT_BACKOFF_THRESHOLD + 10 # Globals needed by the atexit cleanup() handler. g_desktops = [] -g_pidfile = None g_host_hash = hashlib.md5(socket.gethostname()).hexdigest() class Config: @@ -421,87 +421,39 @@ class Desktop: self.host_proc.stdin.close() -class PidFile: - """Class to allow creating and deleting a file which holds the PID of the - running process. This is used to detect if a process is already running, and - inform the user of the PID. On process termination, the PID file is - deleted. +def get_daemon_pid(): + """Checks if there is already an instance of this script running, and returns + its PID. - Note that PID files are not truly atomic or reliable, see - http://mywiki.wooledge.org/ProcessManagement for more discussion on this. - - So this class is just to prevent the user from accidentally running two - instances of this script, and to report which PID may be the other running - instance. + Returns: + The process ID of the existing daemon process, or 0 if the daemon is not + running. """ + uid = os.getuid() + this_pid = os.getpid() - def __init__(self, filename): - """Create an object to manage a PID file. This does not create the PID - file itself.""" - self.filename = filename - self.created = False - - def check(self): - """Checks current status of the process. - - Returns: - Tuple (running, pid): - |running| is True if the daemon is running. - |pid| holds the process ID of the running instance if |running| is True. - If the PID file exists but the PID couldn't be read from the file - (perhaps if the data hasn't been written yet), 0 is returned. - - Raises: - IOError: Filesystem error occurred. - """ - if os.path.exists(self.filename): - pid_file = open(self.filename, 'r') - file_contents = pid_file.read() - pid_file.close() + for process in psutil.process_iter(): + # Skip any processes that raise an exception, as processes may terminate + # during iteration over the list. + try: + # Skip other users' processes. + if process.uids.real != uid: + continue - try: - pid = int(file_contents) - except ValueError: - return True, 0 - - # Test to see if there's a process currently running with that PID. - # If there is no process running, the existing PID file is definitely - # stale and it is safe to overwrite it. Otherwise, report the PID as - # possibly a running instance of this script. - if os.path.exists("/proc/%d" % pid): - return True, pid - - return False, 0 - - def create(self): - """Creates an empty PID file.""" - pid_file = open(self.filename, 'w') - pid_file.close() - self.created = True - - def write_pid(self): - """Write the current process's PID to the PID file. - - This is done separately from create() as this needs to be called - after any daemonization, when the correct PID becomes known. But - check() and create() has to happen before daemonization, so that - if another instance is already running, this fact can be reported - to the user's terminal session. This also avoids corrupting the - log file of the other process, since daemonize() would create a - new log file. - """ - pid_file = open(self.filename, 'w') - pid_file.write('%d\n' % os.getpid()) - pid_file.close() - self.created = True + # Skip the process for this instance. + if process.pid == this_pid: + continue - def delete_file(self): - """Delete the PID file if it was created by this instance. + # |cmdline| will be [python-interpreter, script-file, other arguments...] + cmdline = process.cmdline + if len(cmdline) < 2: + continue + if cmdline[0] == sys.executable and cmdline[1] == sys.argv[0]: + return process.pid + except psutil.error.Error: + continue - This is called on process termination. - """ - if self.created: - os.remove(self.filename) + return 0 def choose_x_session(): @@ -635,14 +587,6 @@ def daemonize(log_filename): def cleanup(): logging.info("Cleanup.") - global g_pidfile - if g_pidfile: - try: - g_pidfile.delete_file() - g_pidfile = None - except Exception, e: - logging.error("Unexpected error deleting PID file: " + str(e)) - global g_desktops for desktop in g_desktops: if desktop.x_proc: @@ -834,16 +778,15 @@ Web Store: https://chrome.google.com/remotedesktop""" # Determine the filename of the host configuration and PID files. if not options.config: options.config = os.path.join(CONFIG_DIR, "host#%s.json" % g_host_hash) - pid_filename = os.path.splitext(options.config)[0] + ".pid" # Check for a modal command-line option (start, stop, etc.) if options.check_running: - running, pid = PidFile(pid_filename).check() - return 0 if (running and pid != 0) else 1 + pid = get_daemon_pid() + return 0 if pid != 0 else 1 if options.stop: - running, pid = PidFile(pid_filename).check() - if not running: + pid = get_daemon_pid() + if pid == 0: print "The daemon is not currently running" else: print "Killing process %s" % pid @@ -851,8 +794,8 @@ Web Store: https://chrome.google.com/remotedesktop""" return 0 if options.reload: - running, pid = PidFile(pid_filename).check() - if not running: + pid = get_daemon_pid() + if pid == 0: return 1 os.kill(pid, signal.SIGHUP) return 0 @@ -931,18 +874,13 @@ Web Store: https://chrome.google.com/remotedesktop""" # Determine whether a desktop is already active for the specified host # host configuration. - global g_pidfile - g_pidfile = PidFile(pid_filename) - running, pid = g_pidfile.check() - if running: + pid = get_daemon_pid() + if pid != 0: # Debian policy requires that services should "start" cleanly and return 0 # if they are already running. print "Service already running." return 0 - # Record that we are running a desktop against for this configuration. - g_pidfile.create() - # Detach a separate "daemon" process to run the session, unless specifically # requested to run in the foreground. if not options.foreground: @@ -952,8 +890,6 @@ Web Store: https://chrome.google.com/remotedesktop""" os.environ[LOG_FILE_ENV_VAR] = log_file.name daemonize(os.environ[LOG_FILE_ENV_VAR]) - g_pidfile.write_pid() - logging.info("Using host_id: " + host.host_id) desktop = Desktop(sizes) |