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