Files
PlantAI-dev/tools/pymol-open-source/modules/pymol/locking.py
T
2026-08-03 18:42:47 +08:00

90 lines
2.7 KiB
Python

import sys
import _thread as thread
import threading
cmd = sys.modules["pymol.cmd"]
from pymol import _cmd
# WARNING: internal routines, subject to change
def lock_without_glut(_self=cmd):
with _self.lock_api_glut:
_self.lock(_self)
class LockCM(object):
'''
API lock context manager
'''
def __init__(self, _self=cmd):
self.cmd = _self._weakrefproxy
def __enter__(self):
lock(self.cmd)
def __exit__(self, type, value, traceback):
unlock(None if type is None else -1, self.cmd)
def lock(_self=cmd): # INTERNAL -- API lock
return _self.lock_api.acquire()
def lock_attempt(_self=cmd): # INTERNAL
return _self.lock_api.acquire(blocking=0)
def block_flush(_self=cmd):
with _self.lockcm:
_self.lock_api_allow_flush = 0
def unblock_flush(_self=cmd):
with _self.lockcm:
_self.lock_api_allow_flush = 1
def unlock(result=None,_self=cmd): # INTERNAL
'''
Release the API lock and flush the command queue
'''
thread_owns_gui = _self.is_gui_thread()
if thread_owns_gui and _self.reaper is not None:
# TODO what's the use case? How can the finish_launching() thread
# die and what's the expected behavior? (see PYMOL-3247)
try:
if not _self.reaper.is_alive():
if _self._pymol.invocation.options.no_gui:
_cmd.quit(_self._COb) # TO FIX
else:
_self.reaper = None
except:
pass
_self.lock_api.release()
# don't flush if we have an incipient error (negative input)
if _self.is_error(result):
return
if thread_owns_gui:
if _self.lock_api_allow_flush:
_cmd.flush_now(_self._COb)
else:
# TODO: what's the logic here? We assume we have to wait for
# cmd.do() calls being executed by GUI thread, but only for 200ms?
# What's the concrete use case and would there be a better (more
# predictable) logic for it? Isn't this an invitation for race
# conditions, e.g. other threads could call cmd.do() and make us
# wait for it? (see PYMOL-3248)
# NOTE: affects API perf. for "do" and delayed-exec
w = 0.0005
while w < 0.1 and _cmd.wait_queue(_self._COb):
threading.Event().wait(w)
w *= 2
def is_gui_thread(_self=cmd): # internal
'''
Return true if the current thread is the GUI thread (e.g. GLUT or Qt)
or if there is no GUI thread. False otherwise.
'''
gui_ident = _self._pymol.glutThread
return gui_ident is None or gui_ident == thread.get_ident()
def interrupt(_self=cmd): # asynch -- no locking!
_cmd.interrupt(_self._COb,1)