예제 #1
0
 def processRequests(self):
     try:
         RemoteEventHandler.processRequests(self)
     except ClosedError:
         from pyqtgraph.Qt import QtGui, QtCore
         QtGui.QApplication.instance().quit()
         self.timer.stop()
예제 #2
0
def startEventLoop(name, port, authkey):
    conn = multiprocessing.connection.Client(('localhost', int(port)), authkey=authkey)
    global HANDLER
    HANDLER = RemoteEventHandler(conn, name, os.getppid())
    while True:
        try:
            HANDLER.processRequests()  # exception raised when the loop should exit
            time.sleep(0.01)
        except ClosedError:
            break
예제 #3
0
 def __init__(self, name=None, target=None, executable=None, copySysPath=True):
     """
     ============  =============================================================
     Arguments:
     name          Optional name for this process used when printing messages
                   from the remote process.
     target        Optional function to call after starting remote process. 
                   By default, this is startEventLoop(), which causes the remote
                   process to process requests from the parent process until it
                   is asked to quit. If you wish to specify a different target,
                   it must be picklable (bound methods are not).
     copySysPath   If true, copy the contents of sys.path to the remote process
     ============  =============================================================
     
     """
     if target is None:
         target = startEventLoop
     if name is None:
         name = str(self)
     if executable is None:
         executable = sys.executable
     
     ## random authentication key
     authkey = ''.join([chr(random.getrandbits(7)) for i in range(20)])
     
     ## Listen for connection from remote process (and find free port number)
     port = 10000
     while True:
         try:
             l = multiprocessing.connection.Listener(('localhost', int(port)), authkey=authkey)
             break
         except socket.error as ex:
             if ex.errno != 98:
                 raise
             port += 1
     
     ## start remote process, instruct it to run target function
     sysPath = sys.path if copySysPath else None
     bootstrap = os.path.abspath(os.path.join(os.path.dirname(__file__), 'bootstrap.py'))
     self.proc = subprocess.Popen((executable, bootstrap), stdin=subprocess.PIPE)
     targetStr = pickle.dumps(target)  ## double-pickle target so that child has a chance to 
                                       ## set its sys.path properly before unpickling the target
     pickle.dump((name+'_child', port, authkey, targetStr, sysPath), self.proc.stdin)
     self.proc.stdin.close()
     
     ## open connection for remote process
     conn = l.accept()
     RemoteEventHandler.__init__(self, conn, name+'_parent', pid=self.proc.pid)
     
     atexit.register(self.join)
예제 #4
0
 def __init__(self, *args, **kwds):
     RemoteEventHandler.__init__(self, *args, **kwds)
예제 #5
0
 def __init__(self, name=None, target=0, preProxy=None, randomReseed=True):
     """
     When initializing, an optional target may be given. 
     If no target is specified, self.eventLoop will be used.
     If None is given, no target will be called (and it will be up 
     to the caller to properly shut down the forked process)
     
     preProxy may be a dict of values that will appear as ObjectProxy
     in the remote process (but do not need to be sent explicitly since 
     they are available immediately before the call to fork().
     Proxies will be availabe as self.proxies[name].
     
     If randomReseed is True, the built-in random and numpy.random generators
     will be reseeded in the child process.
     """
     self.hasJoined = False
     if target == 0:
         target = self.eventLoop
     if name is None:
         name = str(self)
     
     conn, remoteConn = multiprocessing.Pipe()
     
     proxyIDs = {}
     if preProxy is not None:
         for k, v in preProxy.iteritems():
             proxyId = LocalObjectProxy.registerObject(v)
             proxyIDs[k] = proxyId
     
     pid = os.fork()
     if pid == 0:
         self.isParent = False
         ## We are now in the forked process; need to be extra careful what we touch while here.
         ##   - no reading/writing file handles/sockets owned by parent process (stdout is ok)
         ##   - don't touch QtGui or QApplication at all; these are landmines.
         ##   - don't let the process call exit handlers
         
         os.setpgrp()  ## prevents signals (notably keyboard interrupt) being forwarded from parent to this process
         
         ## close all file handles we do not want shared with parent
         conn.close()
         sys.stdin.close()  ## otherwise we screw with interactive prompts.
         fid = remoteConn.fileno()
         os.closerange(3, fid)
         os.closerange(fid+1, 4096) ## just guessing on the maximum descriptor count..
         
         ## Override any custom exception hooks
         def excepthook(*args):
             import traceback
             traceback.print_exception(*args)
         sys.excepthook = excepthook 
         
         ## Make it harder to access QApplication instance
         if 'PyQt4.QtGui' in sys.modules:
             sys.modules['PyQt4.QtGui'].QApplication = None
         sys.modules.pop('PyQt4.QtGui', None)
         sys.modules.pop('PyQt4.QtCore', None)
         
         ## sabotage atexit callbacks
         atexit._exithandlers = []
         atexit.register(lambda: os._exit(0))
         
         if randomReseed:
             if 'numpy.random' in sys.modules:
                 sys.modules['numpy.random'].seed(os.getpid() ^ int(time.time()*10000%10000))
             if 'random' in sys.modules:
                 sys.modules['random'].seed(os.getpid() ^ int(time.time()*10000%10000))
         
         RemoteEventHandler.__init__(self, remoteConn, name+'_child', pid=os.getppid())
         
         ppid = os.getppid()
         self.forkedProxies = {}
         for name, proxyId in proxyIDs.iteritems():
             self.forkedProxies[name] = ObjectProxy(ppid, proxyId=proxyId, typeStr=repr(preProxy[name]))
         
         if target is not None:
             target()
             
     else:
         self.isParent = True
         self.childPid = pid
         remoteConn.close()
         RemoteEventHandler.handlers = {}  ## don't want to inherit any of this from the parent.
         
         RemoteEventHandler.__init__(self, conn, name+'_parent', pid=pid)
         atexit.register(self.join)