From a81876072eba6e913952456c984f0e5c9bda27f6 Mon Sep 17 00:00:00 2001 From: fuzzgun Date: Mon, 13 May 2013 10:29:14 +0100 Subject: [PATCH] Prevent multiple instances of the application from running (issue #142) --- src/bitmessagemain.py | 4 +++ src/singleton.py | 61 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/singleton.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index ca3ef1a4..64bcea50 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -47,6 +47,7 @@ import signal #Used to capture a Ctrl-C keypress so that Bitmessage can shutdown from SimpleXMLRPCServer import * import json from subprocess import call #used when the API must execute an outside program +import singleton #For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers. class outgoingSynSender(threading.Thread): @@ -3762,6 +3763,9 @@ if useVeryEasyProofOfWorkForTesting: shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000) if __name__ == "__main__": + # is the application already running? If yes then exit. + thisapp = singleton.singleinstance() + signal.signal(signal.SIGINT, signal_handler) #signal.signal(signal.SIGINT, signal.SIG_DFL) diff --git a/src/singleton.py b/src/singleton.py new file mode 100644 index 00000000..7ecca3b7 --- /dev/null +++ b/src/singleton.py @@ -0,0 +1,61 @@ +#! /usr/bin/env python + +import sys +import os +import errno +import tempfile +from multiprocessing import Process + + +class singleinstance: + """ + Implements a single instance application by creating a lock file based on the full path to the script file. + + This is based upon the singleton class from tendo https://github.com/pycontribs/tendo + which is under the Python Software Foundation License version 2 + """ + def __init__(self, flavor_id=""): + import sys + self.initialized = False + basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace("/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock' + self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + basename) + + if sys.platform == 'win32': + try: + # file already exists, we try to remove (in case previous execution was interrupted) + if os.path.exists(self.lockfile): + os.unlink(self.lockfile) + self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR) + except OSError: + type, e, tb = sys.exc_info() + if e.errno == 13: + print 'Another instance of this application is already running' + sys.exit(-1) + print(e.errno) + raise + else: # non Windows + import fcntl + self.fp = open(self.lockfile, 'w') + try: + fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError: + print 'Another instance of this application is already running' + sys.exit(-1) + self.initialized = True + + def __del__(self): + import sys + if not self.initialized: + return + try: + if sys.platform == 'win32': + if hasattr(self, 'fd'): + os.close(self.fd) + os.unlink(self.lockfile) + else: + import fcntl + fcntl.lockf(self.fp, fcntl.LOCK_UN) + if os.path.isfile(self.lockfile): + os.unlink(self.lockfile) + except Exception, e: + sys.exit(-1)