diff --git a/NEWS b/NEWS index 047ab8818..f6478fede 100644 --- a/NEWS +++ b/NEWS @@ -77,6 +77,41 @@ portable way. The default is now "coop-pthread", unless your platform doesn't have pthreads, in which case "null" threads are used. +** New module (ice-9 serialize): + +(serialize FORM1 ...) and (parallelize FORM1 ...) are useful when +you don't trust the thread safety of most of your program, but +where you have some section(s) of code which you consider can run +in parallel to other sections. + +They "flag" (with dynamic extent) sections of code to be of +"serial" or "parallel" nature and have the single effect of +preventing a serial section from being run in parallel with any +serial section (including itself). + +Both serialize and parallelize can be nested. If so, the +inner-most construct is in effect. + +NOTE 1: A serial section can run in parallel with a parallel +section. + +NOTE 2: If a serial section S is "interrupted" by a parallel +section P in the following manner: S = S1 P S2, S2 is not +guaranteed to be resumed by the same thread that previously +executed S1. + +WARNING: Spawning new threads within a serial section have +undefined effects. It is OK, though, to spawn threads in unflagged +sections of code where neither serialize or parallelize is in +effect. + +A typical usage is when Guile is used as scripting language in some +application doing heavy computations. If each thread is +encapsulated with a serialize form, you can then put a parallelize +form around the code performing the heavy computations (typically a +C code primitive), enabling the computations to run in parallel +while the scripting code runs single-threadedly. + ** Guile now includes its own version of libltdl. We now use a modified version of libltdl that allows us to make diff --git a/ice-9/ChangeLog b/ice-9/ChangeLog index 3e60654a5..50ad23b23 100644 --- a/ice-9/ChangeLog +++ b/ice-9/ChangeLog @@ -1,3 +1,7 @@ +2003-04-25 Mikael Djurfeldt + + * serialize.scm: New file. + 2003-04-24 Mikael Djurfeldt * threads.scm (n-for-each-par-map): New procedure. diff --git a/ice-9/Makefile.am b/ice-9/Makefile.am index 7a7a1b563..1864a730a 100644 --- a/ice-9/Makefile.am +++ b/ice-9/Makefile.am @@ -35,7 +35,7 @@ ice9_sources = \ streams.scm string-fun.scm syncase.scm threads.scm \ buffered-input.scm time.scm history.scm channel.scm \ pretty-print.scm ftw.scm gap-buffer.scm occam-channel.scm \ - weak-vector.scm deprecated.scm list.scm + weak-vector.scm deprecated.scm list.scm serialize.scm subpkgdatadir = $(pkgdatadir)/${GUILE_EFFECTIVE_VERSION}/ice-9 subpkgdata_DATA = $(ice9_sources) diff --git a/ice-9/serialize.scm b/ice-9/serialize.scm new file mode 100644 index 000000000..df69d4e42 --- /dev/null +++ b/ice-9/serialize.scm @@ -0,0 +1,114 @@ +;;;; Copyright (C) 2003 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 2.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +;;;; + +;;; Commentary: + +;; (serialize FORM1 ...) and (parallelize FORM1 ...) are useful when +;; you don't trust the thread safety of most of your program, but +;; where you have some section(s) of code which you consider can run +;; in parallel to other sections. +;; +;; They "flag" (with dynamic extent) sections of code to be of +;; "serial" or "parallel" nature and have the single effect of +;; preventing a serial section from being run in parallel with any +;; serial section (including itself). +;; +;; Both serialize and parallelize can be nested. If so, the +;; inner-most construct is in effect. +;; +;; NOTE 1: A serial section can run in parallel with a parallel +;; section. +;; +;; NOTE 2: If a serial section S is "interrupted" by a parallel +;; section P in the following manner: S = S1 P S2, S2 is not +;; guaranteed to be resumed by the same thread that previously +;; executed S1. +;; +;; WARNING: Spawning new threads within a serial section have +;; undefined effects. It is OK, though, to spawn threads in unflagged +;; sections of code where neither serialize or parallelize is in +;; effect. +;; +;; A typical usage is when Guile is used as scripting language in some +;; application doing heavy computations. If each thread is +;; encapsulated with a serialize form, you can then put a parallelize +;; form around the code performing the heavy computations (typically a +;; C code primitive), enabling the computations to run in parallel +;; while the scripting code runs single-threadedly. +;; + +;;; Code: + +(define-module (ice-9 serialize) + :use-module (ice-9 threads) + :export (call-with-serialization + call-with-parallelization) + :export-syntax (serialize + parallelize)) + + +(define serialization-mutex (make-mutex)) +(define admin-mutex (make-mutex)) +(define owner #f) + +(define (call-with-serialization thunk) + (let ((outer-owner #f)) + (dynamic-wind + (lambda () + (lock-mutex admin-mutex) + (set! outer-owner owner) + (if (not (eqv? outer-owner (dynamic-root))) + (begin + (unlock-mutex admin-mutex) + (lock-mutex serialization-mutex) + (set! owner (dynamic-root))) + (unlock-mutex admin-mutex))) + thunk + (lambda () + (lock-mutex admin-mutex) + (if (not (eqv? outer-owner (dynamic-root))) + (begin + (set! owner #f) + (unlock-mutex serialization-mutex))) + (unlock-mutex admin-mutex))))) + +(define-macro (serialize . forms) + `(call-with-serialization (lambda () ,@forms))) + +(define (call-with-parallelization thunk) + (let ((outer-owner #f)) + (dynamic-wind + (lambda () + (lock-mutex admin-mutex) + (set! outer-owner owner) + (if (eqv? outer-owner (dynamic-root)) + (begin + (set! owner #f) + (unlock-mutex serialization-mutex))) + (unlock-mutex admin-mutex)) + thunk + (lambda () + (lock-mutex admin-mutex) + (if (eqv? outer-owner (dynamic-root)) + (begin + (unlock-mutex admin-mutex) + (lock-mutex serialization-mutex) + (set! owner outer-owner)) + (unlock-mutex admin-mutex)))))) + +(define-macro (parallelize . forms) + `(call-with-parallelization (lambda () ,@forms)))