Fix abstract named socket used for GUI IPC on linux not being shutdown till process exit, thereby preventing restart from working. Fixes #1298756 [error restarting](https://bugs.launchpad.net/calibre/+bug/1298756)

This commit is contained in:
Kovid Goyal 2014-03-28 10:42:00 +05:30
parent a1d2bc80f9
commit 8a902e7810
2 changed files with 22 additions and 12 deletions

View File

@ -418,13 +418,11 @@ def communicate(opts, args):
raise SystemExit(0)
def create_listener():
from multiprocessing.connection import Listener
listener = Listener(address=gui_socket_address())
if islinux and hasattr(listener._listener._unlink, 'cancel'):
# multiprocessing tries to call unlink even on abstract
# named sockets, prevent it from doing so.
listener._listener._unlink.cancel()
return listener
if islinux:
from calibre.utils.ipc.server import LinuxListener as Listener
else:
from multiprocessing.connection import Listener
return Listener(address=gui_socket_address())
def main(args=sys.argv):
gui_debug = None

View File

@ -87,6 +87,22 @@ class CriticalError(Exception):
_name_counter = 0
if islinux:
class LinuxListener(Listener):
def __init__(self, *args, **kwargs):
Listener.__init__(self, *args, **kwargs)
# multiprocessing tries to call unlink even on abstract
# named sockets, prevent it from doing so.
self._listener._unlink.cancel()
def close(self):
# To ensure that the socket is released, we have to call
# shutdown() not close(). This is needed to allow calibre to
# restart using the same socket address.
import socket
self._listener._socket.shutdown(socket.SHUT_RDWR)
self._listener._socket.close()
def create_listener(authkey, backlog=4):
# Use abstract named sockets on linux to avoid creating unnecessary temp files
global _name_counter
@ -95,11 +111,7 @@ if islinux:
_name_counter += 1
address = (prefix % _name_counter).encode('ascii')
try:
l = Listener(address=address, authkey=authkey, backlog=backlog)
if hasattr(l._listener._unlink, 'cancel'):
# multiprocessing tries to call unlink even on abstract
# named sockets, prevent it from doing so.
l._listener._unlink.cancel()
l = LinuxListener(address=address, authkey=authkey, backlog=backlog)
return address, l
except EnvironmentError as err:
if err.errno == errno.EADDRINUSE: