1 2import sys 3if sys.version_info[0] == 2: 4 import thread 5else: 6 import _thread as thread 7import threading 8 9cmd = sys.modules["pymol.cmd"] 10 11from pymol import _cmd 12 13# WARNING: internal routines, subject to change 14def lock_without_glut(_self=cmd): 15 with _self.lock_api_glut: 16 _self.lock(_self) 17 18class LockCM(object): 19 ''' 20 API lock context manager 21 ''' 22 def __init__(self, _self=cmd): 23 self.cmd = _self._weakrefproxy 24 def __enter__(self): 25 lock(self.cmd) 26 def __exit__(self, type, value, traceback): 27 unlock(None if type is None else -1, self.cmd) 28 29def lock(_self=cmd): # INTERNAL -- API lock 30 return _self.lock_api.acquire() 31 32def lock_attempt(_self=cmd): # INTERNAL 33 return _self.lock_api.acquire(blocking=0) 34 35def block_flush(_self=cmd): 36 with _self.lockcm: 37 _self.lock_api_allow_flush = 0 38 39def unblock_flush(_self=cmd): 40 with _self.lockcm: 41 _self.lock_api_allow_flush = 1 42 43def unlock(result=None,_self=cmd): # INTERNAL 44 ''' 45 Release the API lock and flush the command queue 46 ''' 47 thread_owns_gui = _self.is_gui_thread() 48 49 if thread_owns_gui and _self.reaper is not None: 50 # TODO what's the use case? How can the finish_launching() thread 51 # die and what's the expected behavior? (see PYMOL-3247) 52 try: 53 if not _self.reaper.is_alive(): 54 if _self._pymol.invocation.options.no_gui: 55 _cmd.quit(_self._COb) # TO FIX 56 else: 57 _self.reaper = None 58 except: 59 pass 60 61 _self.lock_api.release() 62 63 # don't flush if we have an incipient error (negative input) 64 if _self.is_error(result): 65 return 66 67 if thread_owns_gui: 68 if _self.lock_api_allow_flush: 69 _cmd.flush_now(_self._COb) 70 else: 71 # TODO: what's the logic here? We assume we have to wait for 72 # cmd.do() calls being executed by GUI thread, but only for 200ms? 73 # What's the concrete use case and would there be a better (more 74 # predictable) logic for it? Isn't this an invitation for race 75 # conditions, e.g. other threads could call cmd.do() and make us 76 # wait for it? (see PYMOL-3248) 77 # NOTE: affects API perf. for "do" and delayed-exec 78 w = 0.0005 79 while w < 0.1 and _cmd.wait_queue(_self._COb): 80 threading.Event().wait(w) 81 w *= 2 82 83def is_gui_thread(_self=cmd): # internal 84 ''' 85 Return true if the current thread is the GUI thread (e.g. GLUT or Qt) 86 or if there is no GUI thread. False otherwise. 87 ''' 88 gui_ident = _self._pymol.glutThread 89 return gui_ident is None or gui_ident == thread.get_ident() 90 91def interrupt(_self=cmd): # asynch -- no locking! 92 _cmd.interrupt(_self._COb,1) 93