Beremiz_service.py
branchwxPython4
changeset 3584 8a54fd58a552
parent 3443 a47d9debb0d9
child 3585 efdefbad49eb
equal deleted inserted replaced
3583:27e7679ddb99 3584:8a54fd58a552
   433 
   433 
   434 if havetwisted:
   434 if havetwisted:
   435     if havewx:
   435     if havewx:
   436         reactor.registerWxApp(app)
   436         reactor.registerWxApp(app)
   437 
   437 
   438 twisted_reactor_thread_id = None
       
   439 ui_thread = None
       
   440 
   438 
   441 if havewx:
   439 if havewx:
   442     wx_eval_lock = Semaphore(0)
   440     wx_eval_lock = Semaphore(0)
   443 
   441 
   444     def statuschangeTskBar(status):
   442     def statuschangeTskBar(status):
   449     def wx_evaluator(obj, *args, **kwargs):
   447     def wx_evaluator(obj, *args, **kwargs):
   450         tocall, args, kwargs = obj.call
   448         tocall, args, kwargs = obj.call
   451         obj.res = default_evaluator(tocall, *args, **kwargs)
   449         obj.res = default_evaluator(tocall, *args, **kwargs)
   452         wx_eval_lock.release()
   450         wx_eval_lock.release()
   453 
   451 
       
   452     main_thread_id = currentThread().ident
   454     def evaluator(tocall, *args, **kwargs):
   453     def evaluator(tocall, *args, **kwargs):
   455         # To prevent deadlocks, check if current thread is not one of the UI
   454         # To prevent deadlocks, check if current thread is not one already main
   456         # UI threads can be either the one from WX main loop or
       
   457         # worker thread from twisted "threadselect" reactor
       
   458         current_id = currentThread().ident
   455         current_id = currentThread().ident
   459 
   456 
   460         if ui_thread is not None \
   457         if main_thread_id != current_id:
   461             and ui_thread.ident != current_id \
       
   462             and (not havetwisted or (
       
   463                     twisted_reactor_thread_id is not None
       
   464                     and twisted_reactor_thread_id != current_id)):
       
   465 
       
   466             o = type('', (object,), dict(call=(tocall, args, kwargs), res=None))
   458             o = type('', (object,), dict(call=(tocall, args, kwargs), res=None))
   467             wx.CallAfter(wx_evaluator, o)
   459             wx.CallAfter(wx_evaluator, o)
   468             wx_eval_lock.acquire()
   460             wx_eval_lock.acquire()
   469             return o.res
   461             return o.res
   470         else:
   462         else:
   471             # avoid dead lock if called from the wx mainloop
   463             # avoid dead lock if called from main : do job immediately
   472             return default_evaluator(tocall, *args, **kwargs)
   464             return default_evaluator(tocall, *args, **kwargs)
   473 else:
   465 else:
   474     evaluator = default_evaluator
   466     evaluator = default_evaluator
   475 
   467 
   476 # Exception hooks
   468 # Exception hooks
   553             WC.RegisterWampClient(wampconf, PSKpath)
   545             WC.RegisterWampClient(wampconf, PSKpath)
   554             WC.RegisterWebSettings(NS)
   546             WC.RegisterWebSettings(NS)
   555         except Exception:
   547         except Exception:
   556             LogMessageAndException(_("WAMP client startup failed. "))
   548             LogMessageAndException(_("WAMP client startup failed. "))
   557 
   549 
       
   550 if havetwisted or havewx:
       
   551     if havetwisted:
       
   552         # reactor._installSignalHandlersAgain()
       
   553         waker_func = reactor._runInMainThread
       
   554         def ui_blocking_call():
       
   555             # FIXME: had to disable SignaHandlers install because
       
   556             # signal not working in non-main thread
       
   557             reactor.run(installSignalHandlers=False)
       
   558     else:
       
   559         waker_func = wx.CallAfter
       
   560         ui_blocking_call = app.MainLoop
       
   561 
       
   562     def ui_launched_report():
       
   563         # IDE expects to see that string to stop waiting for runtime
       
   564         # to be ready and connnect to it.
       
   565         print("UI thread started successfully.")
       
   566 
       
   567     # This orders ui loop to signal when ready on Stdout
       
   568     if havetwisted:
       
   569         reactor.callLater(0, ui_launched_report)
       
   570     else:
       
   571         wx.CallAfter(ui_launched_report)
       
   572 
       
   573 
       
   574 pyro_thread = None
       
   575 
   558 def FirstWorkerJob():
   576 def FirstWorkerJob():
   559     """
   577     """
   560     RPC through pyro/wamp/UI may lead to delegation to Worker,
   578     RPC through pyro/wamp/UI may lead to delegation to Worker,
   561     then this function ensures that Worker is already
   579     then this function ensures that Worker is already
   562     created when pyro starts
   580     created when pyro starts
   563     """
   581     """
   564     global pyro_thread, pyroserver, ui_thread, reactor, twisted_reactor_thread_id
   582     global pyro_thread, pyroserver
   565 
   583 
   566     pyro_thread_started = Lock()
   584     pyro_thread_started = Lock()
   567     pyro_thread_started.acquire()
   585     pyro_thread_started.acquire()
   568     pyro_thread = Thread(target=pyroserver.PyroLoop,
   586     pyro_thread = Thread(target=pyroserver.PyroLoop,
   569                          kwargs=dict(when_ready=pyro_thread_started.release),
   587                          kwargs=dict(when_ready=pyro_thread_started.release),
   579     # Beremiz IDE detects LOCAL:// runtime is ready by looking
   597     # Beremiz IDE detects LOCAL:// runtime is ready by looking
   580     # for self.workdir in the daemon's stdout.
   598     # for self.workdir in the daemon's stdout.
   581     sys.stdout.write(_("Current working directory :") + WorkingDir + "\n")
   599     sys.stdout.write(_("Current working directory :") + WorkingDir + "\n")
   582     sys.stdout.flush()
   600     sys.stdout.flush()
   583 
   601 
   584     if not (havetwisted or havewx):
   602     runtime.GetPLCObjectSingleton().AutoLoad(autostart)
   585         return
   603 
   586 
   604 try:
   587     ui_thread_started = Lock()
   605     if havetwisted or havewx:
   588     ui_thread_started.acquire()
   606         # worker that copes with wx and (wx)reactor
   589     if havetwisted:
   607         runtime.MainWorker.interleave(waker_func, FirstWorkerJob)
   590         # reactor._installSignalHandlersAgain()
   608         ui_blocking_call()
   591         def ui_thread_target():
   609         runtime.MainWorker.stop()
   592             # FIXME: had to disable SignaHandlers install because
   610 
   593             # signal not working in non-main thread
       
   594             reactor.run(installSignalHandlers=False)
       
   595     else:
   611     else:
   596         ui_thread_target = app.MainLoop
   612         # blocking worker loop
   597 
   613         runtime.MainWorker.runloop(FirstWorkerJob)
   598     ui_thread = Thread(target=ui_thread_target, name="UIThread")
   614 
   599     ui_thread.start()
       
   600 
       
   601     # This order ui loop to unblock main thread when ready.
       
   602     if havetwisted:
       
   603         def signal_uithread_started():
       
   604             global twisted_reactor_thread_id
       
   605             twisted_reactor_thread_id = currentThread().ident
       
   606             ui_thread_started.release()
       
   607         reactor.callLater(0, signal_uithread_started)
       
   608     else:
       
   609         wx.CallAfter(ui_thread_started.release)
       
   610 
       
   611     # Wait for ui thread to be effective
       
   612     ui_thread_started.acquire()
       
   613     print("UI thread started successfully.")
       
   614 
       
   615     runtime.GetPLCObjectSingleton().AutoLoad(autostart)
       
   616 
       
   617 try:
       
   618     runtime.MainWorker.runloop(FirstWorkerJob)
       
   619 except KeyboardInterrupt:
   615 except KeyboardInterrupt:
   620     pass
   616     pass
   621 
   617 
   622 pyroserver.Quit()
   618 pyroserver.Quit()
   623 pyro_thread.join()
   619 pyro_thread.join()
   629 except:
   625 except:
   630     print(traceback.format_exc())
   626     print(traceback.format_exc())
   631 
   627 
   632 if havetwisted:
   628 if havetwisted:
   633     reactor.stop()
   629     reactor.stop()
   634     ui_thread.join()
       
   635 elif havewx:
   630 elif havewx:
   636     app.ExitMainLoop()
   631     app.ExitMainLoop()
   637     ui_thread.join()
       
   638 
   632 
   639 sys.exit(0)
   633 sys.exit(0)