--- /dev/null
+import os, sys
+
+from errno import ECHILD, EINTR
+
+from org.diplodocus.util import nothing
+
+def newjob(f, jobs, debug):
+ if not debug:
+ pid = os.fork()
+
+ if debug or pid == 0:
+ sys.exit(f())
+
+ jobs.append(pid)
+
+ return pid
+
+def run(get_job, maxjobs=1, notify_start=nothing, notify_finish=nothing,
+ debug=False):
+ jobs = []
+
+ while True:
+ if len(jobs) < maxjobs:
+ while True:
+ job = get_job()
+ if job == None:
+ break
+ pid = newjob(job, jobs, debug)
+ notify_start(pid, jobs)
+ if len(jobs) == maxjobs:
+ break
+
+ # No jobs running and get-job returned undef; we're finished.
+ if len(jobs) == 0 and job == None:
+ return
+
+ # Now running as many jobs as we can, block waiting for one to die.
+ while True:
+ try:
+ (pid, status) = os.waitpid(-1, 0)
+ except EnvironmentError, error:
+ if error.errno != ECHILD and error.errno != EINTR:
+ raise
+ if pid > 0:
+ break
+
+ # Handle the finished job, and see if others have finished.
+ while True:
+ jobs.remove(pid)
+ notify_finish(pid, status, jobs)
+ try:
+ (pid, status) = os.waitpid(-1, os.WNOHANG)
+ except EnvironmentError, error:
+ if error.errno != ECHILD and error.errno != EINTR:
+ raise
+ break
+ if pid == 0:
+ break
--- /dev/null
+import os
+import sys
+import jobs
+
+work = range(17)
+
+def getjob():
+ try:
+ job = work.pop()
+ except IndexError:
+ return None
+ return lambda: sys.stdout.write('%d %d\n' % (os.getpid(), job))
+
+jobs.run(get_job=getjob, maxjobs=8,
+ notify_start=lambda pid, jobs: sys.stdout.write('%d %d jobs\n' % (pid, len(jobs))),
+ notify_finish=lambda pid, status, jobs: sys.stdout.write('%d %d %d jobs\n' % (pid, status, len(jobs))))