Source code for iterm2.dispatchq
import logging
import os
import threading
import time
[docs]class AbstractDispatchQueue(object):
"""Facilitates running a function on another thread.
Clients invoke dispatch_async() to run a function on the thread that pulls from this queue.
Owning threads invoke run_jobs() periodically.
"""
def __init__(self):
self.queue = []
self.cond = threading.Condition()
[docs] def dispatch_async(self, f):
self.cond.acquire()
self.queue.append(f)
self.notify()
self.cond.release()
[docs] def run_jobs(self):
n = 0
job = self._dequeue()
while job is not None:
job()
job = self._dequeue()
n += 1
return n
def _run_jobs_locked(self):
n = 0
job = self._dequeue_locked()
while job is not None:
self.cond.release()
job()
n += 1
self.cond.acquire()
job = self._dequeue_locked()
return n
def _dequeue(self):
self.cond.acquire()
job = self._dequeue_locked()
self.cond.release()
return job
def _dequeue_locked(self):
job = None
if len(self.queue) > 0:
job = self.queue[0]
del self.queue[0]
return job
[docs]class IODispatchQueue(AbstractDispatchQueue):
"""A dispatch queue owned by a select loop.
The select loop should select on self.read_pipe, which becomes readable when run_jobs has works to do.
"""
def __init__(self):
AbstractDispatchQueue.__init__(self)
self.read_pipe, self.write_pipe = os.pipe()
[docs] def run_jobs(self):
n = AbstractDispatchQueue.run_jobs(self)
os.read(self.read_pipe, n)
[docs] def notify(self):
os.write(self.write_pipe, " ")
[docs]class IdleDispatchQueue(AbstractDispatchQueue):
"""A condition variable-based dispatch queue that adds the ability to wait
for a set period of time and notify the condition variable.
Adds a wait API that blocks until there is work to do.
"""
[docs] def notify(self):
self.cond.notify_all()
[docs] def wait(self, timeout=None):
"""Waits until there is work to do.
timeout: If None, wait indefinitely. Otherwise, don't block for more than this many seconds.
Returns the number of jobs run.
"""
start_time = time.time()
n = 0
if timeout is None:
self.cond.acquire()
c = self._run_jobs_locked()
n += c
while c == 0:
self.cond.wait()
c = self._run_jobs_locked()
n += c
self.cond.release()
else:
end_time = start_time + timeout
now = time.time()
self.cond.acquire()
while True:
n = self._run_jobs_locked()
if n == 0 and now < end_time:
self.cond.wait(timeout=end_time - now)
now = time.time()
if n > 0 or now >= end_time:
break;
self.cond.release()
return n