Cleanup lockfile on exit

singleton.py design was broken.
Fixed Bitmessage#775
This commit is contained in:
mailchuck 2016-01-26 13:01:28 +01:00 committed by Peter Surda
parent 4f26bf1059
commit 24a2deed8f
4 changed files with 19 additions and 14 deletions

View File

@ -152,13 +152,11 @@ if shared.useVeryEasyProofOfWorkForTesting:
class Main: class Main:
def start(self, daemon=False): def start(self, daemon=False):
global thisapp
_fixWinsock() _fixWinsock()
shared.daemon = daemon shared.daemon = daemon
# is the application already running? If yes then exit. # is the application already running? If yes then exit.
thisapp = singleton.singleinstance("", daemon) shared.thisapp = singleton.singleinstance("", daemon)
# get curses flag # get curses flag
curses = False curses = False

View File

@ -2842,6 +2842,7 @@ class MyForm(settingsmixin.SMainWindow):
self.statusBar().showMessage(_translate( self.statusBar().showMessage(_translate(
"MainWindow", "All done. Closing user interface...")) "MainWindow", "All done. Closing user interface..."))
shared.thisapp.cleanup()
os._exit(0) os._exit(0)
# window close event # window close event

View File

@ -55,6 +55,7 @@ appdata = '' #holds the location of the application data storage directory
statusIconColor = 'red' statusIconColor = 'red'
connectedHostsList = {} #List of hosts to which we are connected. Used to guarantee that the outgoingSynSender threads won't connect to the same remote node twice. connectedHostsList = {} #List of hosts to which we are connected. Used to guarantee that the outgoingSynSender threads won't connect to the same remote node twice.
shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit.
thisapp = None # singleton lock instance
alreadyAttemptedConnectionsList = { alreadyAttemptedConnectionsList = {
} # This is a list of nodes to which we have already attempted a connection } # This is a list of nodes to which we have already attempted a connection
alreadyAttemptedConnectionsListLock = threading.Lock() alreadyAttemptedConnectionsListLock = threading.Lock()
@ -392,7 +393,7 @@ def isProofOfWorkSufficient(data,
return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16)))) return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16))))
def doCleanShutdown(): def doCleanShutdown():
global shutdown global shutdown, thisapp
shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit.
broadcastToSendDataQueues((0, 'shutdown', 'no data')) broadcastToSendDataQueues((0, 'shutdown', 'no data'))
objectProcessorQueue.put(('checkShutdownVariable', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data'))
@ -440,6 +441,7 @@ def doCleanShutdown():
if safeConfigGetBoolean('bitmessagesettings','daemon'): if safeConfigGetBoolean('bitmessagesettings','daemon'):
logger.info('Clean shutdown complete.') logger.info('Clean shutdown complete.')
thisapp.cleanup()
os._exit(0) os._exit(0)
# If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this # If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this

View File

@ -1,10 +1,16 @@
#! /usr/bin/env python #! /usr/bin/env python
import sys import atexit
import os
import errno import errno
import shared
from multiprocessing import Process from multiprocessing import Process
import os
import sys
import shared
try:
import fcntl # @UnresolvedImport
except:
pass
class singleinstance: class singleinstance:
""" """
@ -14,9 +20,8 @@ class singleinstance:
which is under the Python Software Foundation License version 2 which is under the Python Software Foundation License version 2
""" """
def __init__(self, flavor_id="", daemon=False): def __init__(self, flavor_id="", daemon=False):
import sys
self.initialized = False self.initialized = False
self.daemon = daemon; self.daemon = daemon
self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id))
if not self.daemon: if not self.daemon:
@ -38,7 +43,6 @@ class singleinstance:
print(e.errno) print(e.errno)
raise raise
else: # non Windows else: # non Windows
import fcntl # @UnresolvedImport
self.fp = open(self.lockfile, 'w') self.fp = open(self.lockfile, 'w')
try: try:
fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
@ -46,20 +50,20 @@ class singleinstance:
print 'Another instance of this application is already running' print 'Another instance of this application is already running'
sys.exit(-1) sys.exit(-1)
self.initialized = True self.initialized = True
atexit.register(self.cleanup)
def __del__(self): def cleanup(self):
import sys
if not self.initialized: if not self.initialized:
return return
print "Cleaning up lockfile"
try: try:
if sys.platform == 'win32': if sys.platform == 'win32':
if hasattr(self, 'fd'): if hasattr(self, 'fd'):
os.close(self.fd) os.close(self.fd)
os.unlink(self.lockfile) os.unlink(self.lockfile)
else: else:
import fcntl # @UnresolvedImport
fcntl.lockf(self.fp, fcntl.LOCK_UN) fcntl.lockf(self.fp, fcntl.LOCK_UN)
if os.path.isfile(self.lockfile): if os.path.isfile(self.lockfile):
os.unlink(self.lockfile) os.unlink(self.lockfile)
except Exception, e: except Exception, e:
sys.exit(-1) pass