;;;; runq.scm --- the runq data structure ;;;; ;;;; Copyright (C) 1996, 2001, 2006, 2010 Free Software Foundation, Inc. ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public ;;;; License as published by the Free Software Foundation; either ;;;; version 3 of the License, or (at your option) any later version. ;;;; ;;;; This library is distributed in the hope that it will be useful, ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;;; Lesser General Public License for more details. ;;;; ;;;; You should have received a copy of the GNU Lesser General Public ;;;; License along with this library; if not, write to the Free Software ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ;;;; ;;; Commentary: ;;; One way to schedule parallel computations in a serial environment is ;;; to explicitly divide each task up into small, finite execution time, ;;; strips. Then you interleave the execution of strips from various ;;; tasks to achieve a kind of parallelism. Runqs are a handy data ;;; structure for this style of programming. ;;; ;;; We use thunks (nullary procedures) and lists of thunks to represent ;;; strips. By convention, the return value of a strip-thunk must either ;;; be another strip or the value #f. ;;; ;;; A runq is a procedure that manages a queue of strips. Called with no ;;; arguments, it processes one strip from the queue. Called with ;;; arguments, the arguments form a control message for the queue. The ;;; first argument is a symbol which is the message selector. ;;; ;;; A strip is processed this way: If the strip is a thunk, the thunk is ;;; called -- if it returns a strip, that strip is added back to the ;;; queue. To process a strip which is a list of thunks, the CAR of that ;;; list is called. After a call to that CAR, there are 0, 1, or 2 strips ;;; -- perhaps one returned by the thunk, and perhaps the CDR of the ;;; original strip if that CDR is not nil. The runq puts whichever of ;;; these strips exist back on the queue. (The exact order in which ;;; strips are put back on the queue determines the scheduling behavior of ;;; a particular queue -- it's a parameter.) ;;; Code: (define-module (ice-9 runq) :use-module (ice-9 q) :export (runq-control make-void-runq make-fair-runq make-exclusive-runq make-subordinate-runq-to strip-sequence fair-strip-subtask)) ;;;; ;;; (runq-control q msg . args) ;;; ;;; processes in the default way the control messages that ;;; can be sent to a runq. Q should be an ordinary ;;; Q (see utils/q.scm). ;;; ;;; The standard runq messages are: ;;; ;;; 'add! strip0 strip1... ;; to enqueue one or more strips ;;; 'enqueue! strip0 strip1... ;; to enqueue one or more strips ;;; 'push! strip0 ... ;; add strips to the front of the queue ;;; 'empty? ;; true if it is ;;; 'length ;; how many strips in the queue? ;;; 'kill! ;; empty the queue ;;; else ;; throw 'not-understood ;;; (define (runq-control q msg . args) (case msg ((add!) (for-each (lambda (t) (enq! q t)) args) '*unspecified*) ((enqueue!) (for-each (lambda (t) (enq! q t)) args) '*unspecified*) ((push!) (for-each (lambda (t) (q-push! q t)) args) '*unspecified*) ((empty?) (q-empty? q)) ((length) (q-length q)) ((kill!) (set! q (make-q))) (else (throw 'not-understood msg args)))) (define (run-strip thunk) (catch #t thunk (lambda ign (warn 'runq-strip thunk ign) #f))) ;;;; ;;; make-void-runq ;;; ;;; Make a runq that discards all messages except "length", for which ;;; it returns 0. ;;; (define (make-void-runq) (lambda opts (and opts (apply-to-args opts (lambda (msg . args) (case msg ((length) 0) (else #f))))))) ;;;; ;;; (make-fair-runq) ;;; ;;; Returns a runq procedure. ;;; Called with no arguments, the procedure processes one strip from the queue. ;;; Called with arguments, it uses runq-control. ;;; ;;; In a fair runq, if a strip returns a new strip X, X is added ;;; to the end of the queue, meaning it will be the last to execute ;;; of all the remaining procedures. ;;; (define (make-fair-runq) (letrec ((q (make-q)) (self (lambda ctl (if ctl (apply runq-control q ctl) (and (not (q-empty? q)) (let ((next-strip (deq! q))) (cond ((procedure? next-strip) (let ((k (run-strip next-strip))) (and k (enq! q k)))) ((pair? next-strip) (let ((k (run-strip (car next-strip)))) (and k (enq! q k))) (if (not (null? (cdr next-strip))) (enq! q (cdr next-strip))))) self)))))) self)) ;;;; ;;; (make-exclusive-runq) ;;; ;;; Returns a runq procedure. ;;; Called with no arguments, the procedure processes one strip from the queue. ;;; Called with arguments, it uses runq-control. ;;; ;;; In an exclusive runq, if a strip W returns a new strip X, X is added ;;; to the front of the queue, meaning it will be the next to execute ;;; of all the remaining procedures. ;;; ;;; An exception to this occurs if W was the CAR of a list of strips. ;;; In that case, after the return value of W is pushed onto the front ;;; of the queue, the CDR of the list of strips is pushed in front ;;; of that (if the CDR is not nil). This way, the rest of the thunks ;;; in the list that contained W have priority over the return value of W. ;;; (define (make-exclusive-runq) (letrec ((q (make-q)) (self (lambda ctl (if ctl (apply runq-control q ctl) (and (not (q-empty? q)) (let ((next-strip (deq! q))) (cond ((procedure? next-strip) (let ((k (run-strip next-strip))) (and k (q-push! q k)))) ((pair? next-strip) (let ((k (run-strip (car next-strip)))) (and k (q-push! q k))) (if (not (null? (cdr next-strip))) (q-push! q (cdr next-strip))))) self)))))) self)) ;;;; ;;; (make-subordinate-runq-to superior basic-inferior) ;;; ;;; Returns a runq proxy for the runq basic-inferior. ;;; ;;; The proxy watches for operations on the basic-inferior that cause ;;; a transition from a queue length of 0 to a non-zero length and ;;; vice versa. While the basic-inferior queue is not empty, ;;; the proxy installs a task on the superior runq. Each strip ;;; of that task processes N strips from the basic-inferior where ;;; N is the length of the basic-inferior queue when the proxy ;;; strip is entered. [Countless scheduling variations are possible.] ;;; (define (make-subordinate-runq-to superior-runq basic-runq) (let ((runq-task (cons #f #f))) (set-car! runq-task (lambda () (if (basic-runq 'empty?) (set-cdr! runq-task #f) (do ((n (basic-runq 'length) (1- n))) ((<= n 0) #f) (basic-runq))))) (letrec ((self (lambda ctl (if (not ctl) (let ((answer (basic-runq))) (self 'empty?) answer) (begin (case (car ctl) ((suspend) (set-cdr! runq-task #f)) (else (let ((answer (apply basic-runq ctl))) (if (and (not (cdr runq-task)) (not (basic-runq 'empty?))) (begin (set-cdr! runq-task runq-task) (superior-runq 'add! runq-task))) answer)))))))) self))) ;;;; ;;; (define fork-strips (lambda args args)) ;;; Return a strip that starts several strips in ;;; parallel. If this strip is enqueued on a fair ;;; runq, strips of the parallel subtasks will run ;;; round-robin style. ;;; ;;;; ;;; (strip-sequence . strips) ;;; ;;; Returns a new strip which is the concatenation of the argument strips. ;;; (define (strip-sequence . strips) (lambda () (let loop ((st (let ((a strips)) (set! strips #f) a))) (and (not (null? st)) (let ((then ((car st)))) (if then (lambda () (loop (cons then (cdr st)))) (lambda () (loop (cdr st))))))))) ;;;; ;;; (fair-strip-subtask . initial-strips) ;;; ;;; Returns a new strip which is the synchronos, fair, ;;; parallel execution of the argument strips. ;;; ;;; ;;; (define (fair-strip-subtask . initial-strips) (let ((st (make-fair-runq))) (apply st 'add! initial-strips) st)) ;;; runq.scm ends here
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
peg | Folder | 0755 |
|
|
and-let-star.scm | File | 2.53 KB | 0644 |
|
arrays.scm | File | 2.63 KB | 0644 |
|
atomic.scm | File | 1.55 KB | 0644 |
|
binary-ports.scm | File | 1.99 KB | 0644 |
|
boot-9.scm | File | 143.94 KB | 0644 |
|
buffered-input.scm | File | 4.82 KB | 0644 |
|
calling.scm | File | 10.54 KB | 0644 |
|
channel.scm | File | 5.19 KB | 0644 |
|
command-line.scm | File | 18.2 KB | 0644 |
|
common-list.scm | File | 8.95 KB | 0644 |
|
control.scm | File | 4.08 KB | 0644 |
|
curried-definitions.scm | File | 1.79 KB | 0644 |
|
debug.scm | File | 1.09 KB | 0644 |
|
deprecated.scm | File | 2.95 KB | 0644 |
|
documentation.scm | File | 7.41 KB | 0644 |
|
eval-string.scm | File | 2.99 KB | 0644 |
|
eval.scm | File | 25.12 KB | 0644 |
|
expect.scm | File | 5.5 KB | 0644 |
|
fdes-finalizers.scm | File | 1.06 KB | 0644 |
|
format.scm | File | 74.37 KB | 0644 |
|
ftw.scm | File | 24.17 KB | 0644 |
|
futures.scm | File | 10.49 KB | 0644 |
|
gap-buffer.scm | File | 10.14 KB | 0644 |
|
getopt-long.scm | File | 16.49 KB | 0644 |
|
hash-table.scm | File | 1.77 KB | 0644 |
|
hcons.scm | File | 2.55 KB | 0644 |
|
history.scm | File | 2.29 KB | 0644 |
|
i18n.scm | File | 20.51 KB | 0644 |
|
iconv.scm | File | 3.65 KB | 0644 |
|
lineio.scm | File | 3.85 KB | 0644 |
|
list.scm | File | 1.29 KB | 0644 |
|
local-eval.scm | File | 9.96 KB | 0644 |
|
ls.scm | File | 3.2 KB | 0644 |
|
mapping.scm | File | 4.84 KB | 0644 |
|
match.scm | File | 2 KB | 0644 |
|
match.upstream.scm | File | 35.92 KB | 0644 |
|
networking.scm | File | 3.33 KB | 0644 |
|
null.scm | File | 1.13 KB | 0644 |
|
occam-channel.scm | File | 7.26 KB | 0644 |
|
optargs.scm | File | 15.75 KB | 0644 |
|
peg.scm | File | 1.64 KB | 0644 |
|
poe.scm | File | 3.3 KB | 0644 |
|
poll.scm | File | 5.79 KB | 0644 |
|
popen.scm | File | 6.82 KB | 0644 |
|
ports.scm | File | 18.89 KB | 0644 |
|
posix.scm | File | 2.73 KB | 0644 |
|
pretty-print.scm | File | 16.88 KB | 0644 |
|
psyntax-pp.scm | File | 180.55 KB | 0644 |
|
psyntax.scm | File | 148.7 KB | 0644 |
|
q.scm | File | 4.2 KB | 0644 |
|
quasisyntax.scm | File | 5.22 KB | 0644 |
|
r5rs.scm | File | 1.56 KB | 0644 |
|
r6rs-libraries.scm | File | 9.43 KB | 0644 |
|
rdelim.scm | File | 7.72 KB | 0644 |
|
readline.scm | File | 9.56 KB | 0644 |
|
receive.scm | File | 1.06 KB | 0644 |
|
regex.scm | File | 8.87 KB | 0644 |
|
runq.scm | File | 8.18 KB | 0644 |
|
rw.scm | File | 1.02 KB | 0644 |
|
safe-r5rs.scm | File | 3.72 KB | 0644 |
|
safe.scm | File | 1.25 KB | 0644 |
|
sandbox.scm | File | 34.23 KB | 0644 |
|
save-stack.scm | File | 2.15 KB | 0644 |
|
scm-style-repl.scm | File | 11.62 KB | 0644 |
|
serialize.scm | File | 3.78 KB | 0644 |
|
session.scm | File | 17.72 KB | 0644 |
|
slib.scm | File | 1.55 KB | 0644 |
|
stack-catch.scm | File | 1.94 KB | 0644 |
|
streams.scm | File | 5.86 KB | 0644 |
|
string-fun.scm | File | 8.59 KB | 0644 |
|
suspendable-ports.scm | File | 29.87 KB | 0644 |
|
syncase.scm | File | 1.52 KB | 0644 |
|
textual-ports.scm | File | 2.29 KB | 0644 |
|
threads.scm | File | 12.54 KB | 0644 |
|
time.scm | File | 2.07 KB | 0644 |
|
top-repl.scm | File | 2.75 KB | 0644 |
|
unicode.scm | File | 1005 B | 0644 |
|
vlist.scm | File | 21.56 KB | 0644 |
|
weak-vector.scm | File | 1.2 KB | 0644 |
|