* boot-9.scm (duplicate-handlers): Make sure the merge-generics
[bpt/guile.git] / ice-9 / threads.scm
CommitLineData
f4719f31 1;;;; Copyright (C) 1996, 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
c7a813af 2;;;;
1188fb05
MD
3;;;; This program is free software; you can redistribute it and/or modify
4;;;; it under the terms of the GNU General Public License as published by
5;;;; the Free Software Foundation; either version 2, or (at your option)
6;;;; any later version.
c7a813af 7;;;;
1188fb05
MD
8;;;; This program is distributed in the hope that it will be useful,
9;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11;;;; GNU General Public License for more details.
c7a813af 12;;;;
1188fb05
MD
13;;;; You should have received a copy of the GNU General Public License
14;;;; along with this software; see the file COPYING. If not, write to
15328041
JB
15;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16;;;; Boston, MA 02111-1307 USA
1188fb05 17;;;;
a482f2cc
MV
18;;;; As a special exception, the Free Software Foundation gives permission
19;;;; for additional uses of the text contained in its release of GUILE.
20;;;;
21;;;; The exception is that, if you link the GUILE library with other files
22;;;; to produce an executable, this does not by itself cause the
23;;;; resulting executable to be covered by the GNU General Public License.
24;;;; Your use of that executable is in no way restricted on account of
25;;;; linking the GUILE library code into it.
26;;;;
27;;;; This exception does not however invalidate any other reasons why
28;;;; the executable file might be covered by the GNU General Public License.
29;;;;
30;;;; This exception applies only to the code released by the
31;;;; Free Software Foundation under the name GUILE. If you copy
32;;;; code from other Free Software Foundation releases into a copy of
33;;;; GUILE, as the General Public License permits, the exception does
34;;;; not apply to the code that you add in this way. To avoid misleading
35;;;; anyone as to the status of such modified files, you must delete
36;;;; this exception notice from them.
37;;;;
38;;;; If you write modifications of your own for GUILE, it is your choice
39;;;; whether to permit this exception to apply to your modifications.
40;;;; If you do not wish that, delete this exception notice.
41;;;;
1188fb05
MD
42;;;; ----------------------------------------------------------------
43;;;; threads.scm -- User-level interface to Guile's thread system
44;;;; 4 March 1996, Anthony Green <green@cygnus.com>
45;;;; Modified 5 October 1996, MDJ <djurfeldt@nada.kth.se>
c7a813af 46;;;; Modified 6 April 2001, ttn
1188fb05
MD
47;;;; ----------------------------------------------------------------
48;;;;
49\f
e7d82feb
TTN
50;;; Commentary:
51
52;; This module is documented in the Guile Reference Manual.
53;; Briefly, one procedure is exported: `%thread-handler';
54;; as well as four macros: `make-thread', `begin-thread',
55;; `with-mutex' and `monitor'.
56
57;;; Code:
1188fb05 58
1a179b03 59(define-module (ice-9 threads)
f595ccfe 60 :export (par-map
abce330c 61 par-for-each
87623595
MD
62 n-par-map
63 n-par-for-each)
f595ccfe 64 :re-export (future-ref)
87623595 65 :export-syntax (begin-thread
abce330c 66 parallel
fc85d095 67 letpar
87623595 68 make-thread
1a179b03 69 with-mutex
f595ccfe
MD
70 monitor)
71 :re-export-syntax (future))
1188fb05
MD
72
73\f
74
87623595 75(define ((par-mapper mapper) proc . arglists)
f4719f31 76 (mapper future-ref
87623595
MD
77 (apply map
78 (lambda args
f4719f31 79 (future (apply proc args)))
87623595
MD
80 arglists)))
81
82(define par-map (par-mapper map))
83(define par-for-each (par-mapper for-each))
84
85(define (n-par-map n proc . arglists)
abce330c 86 (let* ((m (make-mutex))
f4719f31 87 (futures '())
87623595
MD
88 (results (make-list (length (car arglists))))
89 (result results))
90 (do ((i 0 (+ 1 i)))
91 ((= i n)
f4719f31 92 (for-each future-ref futures)
87623595 93 results)
f4719f31
MD
94 (set! futures
95 (cons (future
96 (let loop ()
97 (lock-mutex m)
98 (if (null? result)
99 (unlock-mutex m)
100 (let ((args (map car arglists))
101 (my-result result))
102 (set! arglists (map cdr arglists))
103 (set! result (cdr result))
87623595 104 (unlock-mutex m)
f4719f31
MD
105 (set-car! my-result (apply proc args))
106 (loop)))))
107 futures)))))
87623595
MD
108
109(define (n-par-for-each n proc . arglists)
110 (let ((m (make-mutex))
f4719f31 111 (futures '()))
87623595
MD
112 (do ((i 0 (+ 1 i)))
113 ((= i n)
f4719f31
MD
114 (for-each future-ref futures))
115 (set! futures
116 (cons (future
117 (let loop ()
118 (lock-mutex m)
119 (if (null? (car arglists))
120 (unlock-mutex m)
121 (let ((args (map car arglists)))
122 (set! arglists (map cdr arglists))
87623595 123 (unlock-mutex m)
f4719f31
MD
124 (apply proc args)
125 (loop)))))
126 futures)))))
87623595
MD
127
128(define (thread-handler tag . args)
13dc0cae 129 (fluid-set! the-last-stack #f)
13dc0cae
MD
130 (let ((n (length args))
131 (p (current-error-port)))
c7a813af
TTN
132 (display "In thread:" p)
133 (newline p)
134 (if (>= n 3)
135 (display-error #f
136 p
137 (car args)
138 (cadr args)
139 (caddr args)
140 (if (= n 4)
141 (cadddr args)
142 '()))
143 (begin
144 (display "uncaught throw to " p)
145 (display tag p)
146 (display ": " p)
147 (display args p)
f4f16ecc
MV
148 (newline p)))
149 #f))
13dc0cae 150
87623595
MD
151;;; Set system thread handler
152(set! %thread-handler thread-handler)
c7a813af 153
87623595 154; --- MACROS -------------------------------------------------------
1188fb05 155
87623595
MD
156(define-macro (begin-thread . forms)
157 (if (null? forms)
158 '(begin)
159 `(call-with-new-thread
160 (lambda ()
161 ,@forms)
162 %thread-handler)))
1188fb05 163
87623595 164(define-macro (parallel . forms)
abce330c
MD
165 (cond ((null? forms) '(begin))
166 ((null? (cdr forms)) (car forms))
167 (else
c2950e36
MD
168 (let ((vars (map (lambda (f)
169 (make-symbol "f"))
170 forms)))
171 `((lambda ,vars
172 (values ,@(map (lambda (v) `(future-ref ,v)) vars)))
173 ,@(map (lambda (form) `(future ,form)) forms))))))
87623595
MD
174
175(define-macro (letpar bindings . body)
c2950e36
MD
176 (cond ((or (null? bindings) (null? (cdr bindings)))
177 `(let ,bindings ,@body))
178 (else
179 (let ((vars (map car bindings)))
180 `((lambda ,vars
181 ((lambda ,vars ,@body)
182 ,@(map (lambda (v) `(future-ref ,v)) vars)))
183 ,@(map (lambda (b) `(future ,(cadr b))) bindings))))))
fc85d095 184
87623595
MD
185(define-macro (make-thread proc . args)
186 `(call-with-new-thread
187 (lambda ()
188 (,proc ,@args))
189 %thread-handler))
190
191(define-macro (with-mutex m . body)
1188fb05 192 `(dynamic-wind
c7a813af
TTN
193 (lambda () (lock-mutex ,m))
194 (lambda () (begin ,@body))
195 (lambda () (unlock-mutex ,m))))
1188fb05 196
87623595 197(define-macro (monitor first . rest)
1188fb05 198 `(with-mutex ,(make-mutex)
c7a813af
TTN
199 (begin
200 ,first ,@rest)))
201
c7a813af 202;;; threads.scm ends here