28 from __future__ import print_function |
28 from __future__ import print_function |
29 import os |
29 import os |
30 import sys |
30 import sys |
31 import getopt |
31 import getopt |
32 import threading |
32 import threading |
33 from threading import Thread, Semaphore, Lock |
33 from threading import Thread, Semaphore, Lock, currentThread |
34 import __builtin__ |
34 import __builtin__ |
35 from builtins import str as text |
35 from builtins import str as text |
36 from past.builtins import execfile |
36 from past.builtins import execfile |
37 from six.moves import builtins |
37 from six.moves import builtins |
38 |
38 |
412 |
412 |
413 if havetwisted: |
413 if havetwisted: |
414 if havewx: |
414 if havewx: |
415 reactor.registerWxApp(app) |
415 reactor.registerWxApp(app) |
416 |
416 |
|
417 twisted_reactor_thread_id = None |
|
418 ui_thread = None |
|
419 |
417 if havewx: |
420 if havewx: |
418 wx_eval_lock = Semaphore(0) |
421 wx_eval_lock = Semaphore(0) |
419 # FIXME : beware wx mainloop is _not_ running in main thread |
|
420 # main_thread = currentThread() |
|
421 |
422 |
422 def statuschangeTskBar(status): |
423 def statuschangeTskBar(status): |
423 wx.CallAfter(taskbar_instance.UpdateIcon, status) |
424 wx.CallAfter(taskbar_instance.UpdateIcon, status) |
424 |
425 |
425 statuschange.append(statuschangeTskBar) |
426 statuschange.append(statuschangeTskBar) |
428 tocall, args, kwargs = obj.call |
429 tocall, args, kwargs = obj.call |
429 obj.res = default_evaluator(tocall, *args, **kwargs) |
430 obj.res = default_evaluator(tocall, *args, **kwargs) |
430 wx_eval_lock.release() |
431 wx_eval_lock.release() |
431 |
432 |
432 def evaluator(tocall, *args, **kwargs): |
433 def evaluator(tocall, *args, **kwargs): |
433 # FIXME : should implement anti-deadlock |
434 # To prevent deadlocks, check if current thread is not one of the UI |
434 # if main_thread == currentThread(): |
435 # UI threads can be either the one from WX main loop or |
435 # # avoid dead lock if called from the wx mainloop |
436 # worker thread from twisted "threadselect" reactor |
436 # return default_evaluator(tocall, *args, **kwargs) |
437 current_id = currentThread().ident |
437 # else: |
438 if ui_thread is not None \ |
438 o = type('', (object,), dict(call=(tocall, args, kwargs), res=None)) |
439 and ui_thread.ident != current_id \ |
439 wx.CallAfter(wx_evaluator, o) |
440 and (not havetwisted or ( |
440 wx_eval_lock.acquire() |
441 twisted_reactor_thread_id is not None |
441 return o.res |
442 and twisted_reactor_thread_id != current_id)): |
|
443 |
|
444 o = type('', (object,), dict(call=(tocall, args, kwargs), res=None)) |
|
445 wx.CallAfter(wx_evaluator, o) |
|
446 wx_eval_lock.acquire() |
|
447 return o.res |
|
448 else: |
|
449 # avoid dead lock if called from the wx mainloop |
|
450 return default_evaluator(tocall, *args, **kwargs) |
442 else: |
451 else: |
443 evaluator = default_evaluator |
452 evaluator = default_evaluator |
444 |
453 |
445 # Exception hooks |
454 # Exception hooks |
446 |
455 |
558 ui_thread = Thread(target=ui_thread_target) |
567 ui_thread = Thread(target=ui_thread_target) |
559 ui_thread.start() |
568 ui_thread.start() |
560 |
569 |
561 # This order ui loop to unblock main thread when ready. |
570 # This order ui loop to unblock main thread when ready. |
562 if havetwisted: |
571 if havetwisted: |
563 reactor.callLater(0, ui_thread_started.release) |
572 def signal_uithread_started(): |
|
573 twisted_reactor_thread_id = currentThread().ident |
|
574 ui_thread_started.release() |
|
575 reactor.callLater(0, signal_uithread_started) |
564 else: |
576 else: |
565 wx.CallAfter(ui_thread_started.release) |
577 wx.CallAfter(ui_thread_started.release) |
566 |
578 |
567 # Wait for ui thread to be effective |
579 # Wait for ui thread to be effective |
568 ui_thread_started.acquire() |
580 ui_thread_started.acquire() |