@c =================================================================== @c
@c    serrano/prgm/project/bigloo/manuals/object.texi                  @c
@c    ------------------------------------------------------------     @c
@c    Author      :  Manuel Serrano                                    @c
@c    Creation    :  Mon Jun 15 15:09:03 1998                          @c
@c    Last change :  Mon Nov 12 15:11:18 2001 (serrano)                @c
@c    ------------------------------------------------------------     @c
@c    The Bigloo threads                                               @c
@c =================================================================== @c

@c ------------------------------------------------------------------- @c
@c    Bigloo's threads                                                 @c
@c ------------------------------------------------------------------- @c
@node Threads, Regular Parsing, Object System, Top
@comment  node-name,  next,  previous,  up
@chapter Threads
@cindex Fair Threads
@cindex Threads

Bigloo supports fair threads (see Section @ref{Thread}), a
specification of cooperative threads. In this framework a thread must
explicitly or implicitly @emph{yield} the processor to the scheduler
(see Section @ref{Scheduler}). Explicit cooperation is achieved by
library functions such as @code{thread-yield!} or
@code{thread-sleep!}.  Implicit cooperation is achieved by forms such
as @code{(thread-await! (make-input-signal p '(#\Newline)))} that 
blocks the current thread until the character @code{#\Newline} is read on 
input port @var{p}. The scheduler @b{does not preempt a running thread} to 
allocate the processor to another waiting thread. Fair threads have two
drawbacks over preemptive threads:

@itemize @bullet
@item Cooperative threads are not skilled to benefit of multi processors
      platforms.
@item Single threads programs must be adapted in order to be ran 
      concurrently. 
@end itemize

On the other hand, Fair threads have advantages that make them
suitable for a high level programming language such as Scheme:

@itemize @bullet
@item Fair threads have a strong and well defined semantic. Multi threaded
      programs using Fair threads are @emph{deterministic} thus programs
      that deploy Fair threads are @emph{predictable}.
@item Fair threads are easier to program with because they hide most the
      of the concurrent programming pitfalls. In particular, since Fair
      threads enforce a strong synchronization, there
      is no need to deploy techniques such as @emph{mutex}, @emph{semaphore}
      or @emph{condition variables}.
@end itemize

@menu
* Introduction::
* Programming with Fair threads::
* Fair Threads Api::
* SRFI-18::
@end menu

This whole chapter has been written in collaboration with @b{Frédéric
Boussinot}. It uses materials on Fair threads that can be found at
@url{http://www-sop.inria.fr/mimosa/rp/FairThreads/html/FairThreads.html}.

@c -- Introduction --------------------------------------------------- @c
@node Introduction, Programming with Fair threads, , Threads
@comment  node-name,  next,  previous,  up
@section Introduction to Fair Threads

Fair threads are cooperative threads run by a fair scheduler which
gives them equal access to the processor. Fair threads can communicate
using broadcast events. Their semantics does not depends on the
executing platform. Fine control over fair threads execution is
possible allowing the programming of specific user-defined scheduling
strategies. 

Contrary to standard sequential programming where the processor
executes a single program, in concurrent programming the processor is
a shared resource which is dispatched to several programs. The term
@emph{concurrent} is appropriate because programs can be seen as
concurrently competing to gain access to the processor, in order to
execute.

Threads are a basic mean for concurrent programming, and are widely
used in operating systems. At language level, threads offer a way to
structure programs by decomposing systems in several concurrent
components; in this respect, threads are useful for modularity.

However, threads are generally considered as low-level primitives
leading to over-complex programming. Moreover, threads generally have
loose semantics, in particular depending on the underlying executing
platform; to give them a precise semantics is a difficult task, and
this is a clearly identified problem to get portable code.

Bigloo proposes a new framework with clear and simple semantics, and
with an efficient implementation. In it, threads are called
@emph{fair}; basically a fair thread is a cooperative thread executed
in a context in which all threads always have equal access to the
processor. Fair threads have a deterministic semantics, relying on
previous work belonging to the so-called reactive approach.

@c -- Example -------------------------------------------------------- @c
@node Programming with Fair threads, Fair Threads Api, Introduction, Threads
@comment  node-name,  next,  previous,  up
@section Programming with Fair threads

All ports of Bigloo JVM back-end (see @ref{Compiler Description})
support Fair threads. Only few ports of Bigloo native back-end support
Fair threads.  Please refer to the installation documentation (file
INSTALL) to check which native ports support Fair threads.

Fair threads are available by the mean of a Bigloo library. That is,
when compiling and linking with threads, it is required to use a
@code{library} module clause (see @ref{Module Declaration}) such as:

@smalllisp
(module http-server
  (library fthread)
  ...)
@end smalllisp

When the Fair thread library is deployed the @code{cond-expand}
form (see @ref{SRFIs}) evaluate @code{fthread} and @code{SRFI-18} clauses.

For the sake of the example we present in this section a small web
server implemented with Fair threads. This server only supports Http
@code{GET} request but it supports concurrent requests. That is, the
server is able to server several clients simultaneously.

First, the server needs to create a @code{socket} server (see the @ref{Socket}
documentation):

@smalllisp
(define (start-http-server)
   (let ((s (make-server-socket)))
      (print "Http server started: " (socket-port-number s))
      s))
@end smalllisp

Then a Fair thread implementing the web server is created and ran:

@smalllisp
(let* ((svr (start-http-server))
       (thd (make-thread (make-http-server svr) 'http-server))
       (ts (thread-start! thd)))
   (scheduler-start!)
   (fprint (current-error-port) "Shuting down http server...")
   (socket-shutdown svr))
@end smalllisp

The functions @code{make-thread} and @code{thread-start!}  (see
Section @ref{Thread}) start the execution of a new thread.  The
function @code{scheduler-start!} (see Section @ref{Scheduler}) manages
the execution of all threads.

The body of the server is a thunk, created by the @code{make-http-server}
function. Its definition is:

@smalllisp
(define (make-http-server s::socket)
   (lambda ()
      (let loop ()
	 (let ((s2 (thread-await! (make-accept-signal s))))
	    (thread-start! (make-thread (lambda () (http-eval s2))))
	    (thread-yield!)
	    (loop)))))
@end smalllisp

The function @code{thread-await!} waits for a connection to the socket
server @var{s2}. This blocks the current thread but it does not block the
scheduler and the execution of other threads in it. That is, when the thread
running the http server waits for a connection to the socket server,
the other threads started in the scheduler keep executing. When a connection
is established, a new thread is created that evaluates
(@code{http-eval}) the request. When this thread is started the http
server cooperates (@code{thread-yield!}).

@smalllisp
(define (http-eval s::socket)
   (define (readline)
      (thread-await! (make-input-signal (socket-input s) 
                                        '(#\Newline #\Return))))
   (let* ((lines (let loop ((line (readline)))
		    (thread-yield!)
		    (if (and (string? line) (=fx (string-length line) 1))
			'()
			(cons (substring line 0 (-fx (string-length line) 1))
			      (loop (readline))))))
	  (line (car lines)))
      (http-get "index.html" s)
      (socket-close s)))
@end smalllisp

The client request is first read. This is done using the non blocking form
of input 
@code{(thread-await! (make-input-signal (socket-input s) '(#\Newline #\Return)))}.
This blocks the current thread until a character @code{#\Newline} or
@code{#\Return} is read. Then, the value of that call is either the
``end of file'' object or the a string of characters.

Each time a line is read, the thread cooperates (@code{thread-yield!}).
The explanation is the same as for the socket connection. Without this
explicit cooperation, the call to @code{thread-await!} would always
return the same string of characters.

At this point, let us suppose that we want our web server able to serve
HTML, Shell and Scheme pages. For this @code{http-get} looks at the
suffix of the file to be downloaded:

@smalllisp
(define (http-get fname s::socket)
   (case (string->symbol (suffix fname)
      ((scm)
       (http-get-scm fname s))
      ((sh)
       (http-get-sh fname s))
      (else
       (http-get-html fname s)))))
@end smalllisp

For the first two requests, a new process is spawned. For the last
one, a file is opened:

@smalllisp
(define (http-get-scm file s::socket)
   (let ((proc (run-process "bigloo" "-i" "-s" file output: pipe:)))
      (http-get-input (process-output-port proc) s)))

(define (http-get-sh file s::socket)
   (let ((proc (run-process "sh" "-f" file output: pipe:)))
      (http-get-input (process-output-port proc) s)))

(define (http-get-html fname s::socket)
   (if (file-exists? fname)
       (let ((p (open-input-file fname)))
	  (http-get-input p s)
	  (close-input-port p))
       (http-reply s "plain" "Can't find file \"" fname "\"")))
@end smalllisp

The function @code{http-get-input} reads all the characters from an input port.

@smalllisp
(define (http-get-input p::input-port s::socket)
   (let loop ((res '()))
      (let ((v (thread-await! (make-input-signal p 1024))))
	 (thread-yield!)
	 (if (eof-object? v)
	     (apply http-reply s "html" (reverse! res))
             (loop (cons v res))))))
@end smalllisp

It must be noted here that since the characters are read with 
@code{thread-await!} which does not block the scheduler, while a client
request is being processed, the scheduler is able to handle 
@emph{simultaneously} other requests. The form 
@code{(thread-await! (make-input-signal p 1024))} blocks the 
current thread until at most @code{1024} characters have been read 
from input port @var{p}.

The function @code{http-reply} simply writes a list of strings to the
output port associated with the socket connection:

@smalllisp
(define (http-reply socket::socket kind . str)
   (let ((p (socket-output socket)))
      (thread-await! (make-output-signal p "HTTP/1.0 200 Ok\r
Server: test_httpd/%x\r
Connection: close\r
Content-type: text/"))
      (thread-await! (make-output-signal p kind))
      (thread-await! (make-output-signal p "\r\n\r\n"))
      (for-each (lambda (s) (thread-await! (make-output-signal p s))) str)
      (thread-await! (make-output-signal p "\r\n"))))
@end smalllisp

@c -- API ------------------------------------------------------------ @c
@node Fair Threads Api, SRFI-18, Programming with Fair threads, Threads
@comment  node-name,  next,  previous,  up
@section Fair Threads Api

@menu
* Thread::
* Scheduler::
* Signal::
@end menu

Bigloo uses a set of @emph{primitive} functions to create, run and
handle thread. For the sake of standardization the name and semantic
of SRFI-18 (Multithreading support) has been used. This section presents
only the mandatory functions to program with Fair threads in Bigloo. The
Section @ref{SRFI-18} presents the functions that are not necessary
to Bigloo but supported for compliance with SRFI-18.

@c -- threads -------------------------------------------------------- @c
@node Thread, Scheduler, ,Fair Threads Api
@subsection Thread

@deffn {SRFI-18 function} current-thread
Returns the current thread.
@end deffn

@deffn {SRFI-18 function} thread? @var{obj}
Returns @code{#t} if @var{obj} is a thread, otherwise returns @code{#f}.
@end deffn

@deffn {SRFI-18 function} make-thread @var{thunk} [@var{name}]
Returns a new thread which is not started yet. The body of the thread
is the body of the procedure @var{thunk}. The optional argument @var{name}
can be use to identify the thread. It can be any Bigloo value.

@smalllisp
(make-thread (lambda () (print 1) (thread-yield!) (print 2)) 'my-thread)
@end smalllisp
@end deffn

@deffn {SRFI-18 function} thread-start! @var{thread} [@var{scheduler}]
Runs a thread created with @code{make-thread}. If @var{scheduler} is
provided, the @var{thread} is started this particular scheduler. Otherwise,
it is started in the current scheduler (see Section @ref{Scheduler}).
Threads are started at the beginning of @emph{reactions} 
(see Section @ref{Scheduler}).
@end deffn

@deffn {SRFI-18 function} thread-name @var{thread}
Returns the name of the @var{thread} that has been passed to 
@code{make-thread}.
@end deffn

@deffn {SRFI-18 function} thread-specific @var{thread}
@deffnx {SRFI-18 function} thread-specific-set! @var{thread} @var{obj}
Returns and sets value in the specific field of the @var{thread}. If no
value has been set, @code{thread-specific} returns an unspecified value.

@smalllisp
(let ((t (make-thread (lambda () 
                         (print (thread-specific (current-thread)))))))
   (thread-specific-set! t 'foo)
   (thread-start! t)) @print{} foo
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-cleanup @var{thread}
@deffnx {Bigloo function} thread-cleanup-set! @var{thread} @var{fun}
Associates a cleanup function to a thread. The cleanup function is called
with the result value of the thread. The cleanup function is executed
in a context where @code{current-thread} is the thread owning the
cleanup function.

@smalllisp
(let ((t (make-thread (lambda () 'done) 'foo)))
   (thread-cleanup-set! t (lambda (v) (print (thread-name (current-thread))
					     ", exit value: " v)))
   (thread-start! t)) @print{} foo, exit value: done
@end smalllisp
@end deffn

@deffn {SRFI-18 function} thread-yield!

The current thread @emph{cooperates}. That is, it is suspend for the
@emph{reaction} and the scheduler selects a new thread to be resumed. The
scheduler resumes the next avaliable thread. If there is only one
thread started in the scheduler, the same thread is resumed. 
A @emph{reaction} correspond to the invocation of a @code{scheduler-react!}
call (see Section @ref{Scheduler}).

@end deffn

@deffn {SRFI-18 function} thread-sleep! @var{timeout}
The current thread @emph{cooperates} during @emph{exactly} @var{timeout}
@emph{reactions} (see @ref{Scheduler}). It is suspended and the scheduler 
selects a new thread to be resumed. If there is only one thread started in the
scheduler, the same thread will be resumed.

@smalllisp
(let ((t1 (make-thread 
           (lambda () (thread-sleep! 2) (display 'foo))))
      (t2 (make-thread 
           (lambda () (let loop ((n 1))
                         (display n) 
                         (thread-yield!)
                         (if (< n 5)
                             (loop (+ n 1))))))))
   (thread-start! t1)
   (thread-start! t2)
   (scheduler-start!)) @print{} 12foo34
@end smalllisp
@end deffn

@deffn {SRFI-18 function} thread-terminate! @var{thread}
Terminates @var{thread} at the end of the current reaction.
@end deffn

@deffn {SRFI-18 function} thread-join! @var{thread} [@var{timeout} [@var{timeout-val}]]
The current thread waits until the @var{thread} terminates or until
the @var{timeout} is reached (when supplied). If the @var{timeout} is
reached, @code{thread-join!} returns @var{timeout-val}. If @var{thread}
terminates, @code{thread-join!} returns the end-result of the @var{thread}
or the end-exception if that thread terminates abnormally.

If several threads wait for the termination of the same thread, they are
all notified of the termination during the current reaction.

@smalllisp
(let* ((t1 (thread-start!
	    (make-thread (lambda ()
			    (thread-sleep! 3)
			    'foo))))
       (t2 (thread-start!
	    (make-thread (lambda ()
			    (print "t1: " (thread-join! t1 1))))))
       (t3 (thread-start!
	    (make-thread (lambda ()
			    (print "t2: " (thread-join! t1 2 'bar))))))
       (t3 (thread-start!
	    (make-thread (lambda ()
			    (print "t3: " (thread-join! t1))))))
       (t4 (thread-start!
	    (make-thread (lambda ()
			    (print "t4: " (thread-join! t1)))))))
   (scheduler-start!))
   @print{} t1: #|%uncaught-exception [reason: (exception . join-timeout)]|
      t2: bar
      t3: foo
      t4: foo
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-suspend! @var{thread}
@deffnx {Bigloo function} thread-resume! @var{thread}
Suspends/resumes the @var{thread} at the end of reaction. While suspended
a thread is not eligible to get the processor by the scheduler. 
@end deffn

@deffn {Bigloo function} thread-await! @var{signal} [@var{timeout}]

Blocks the thread until @var{signal} has been broadcast or until
@var{timeout} is elapsed. The function @code{thread-await!} returns the
list of values associated with the previous emissions of the
signal that took place during the reaction.

@smalllisp
(let ((t1 (thread-start!
           (make-thread
            (lambda ()
             (display (thread-await! 'foo))
             (display (thread-await! 'bar))))))
      (t2 (thread-start! 
           (make-thread
            (lambda ()
             (broadcast! 'foo 'val1-foo)
             (broadcast! 'foo 'val2-foo)))))
      (t3 (thread-start!
           (make-thread
            (lambda ()
             (thread-sleep! 2)
             (broadcast! 'bar 'val-bar))))))
   (let loop ((n 1))
      (display n)
      (scheduler-react! (current-scheduler))
      (loop (+ n 1))))
  @print{} 1(val2-foo2 val1-fo)234(val-bar)456...
@end smalllisp

In general @code{thread-await!} cannot be used to intercept all the signals
broadcasted during a reaction. This is illustrated by the following example
were obviously @code{thread-await!} cannot intercept the emission of the
signal:

@smalllisp
(thread-start! (make-thread (lambda () 
                               (tread-await! 'foo)
                               (broadcast! 'foo 1))))
(thread-start! (make-thread (lambda () 
                               (broadcast! 'foo 2))))
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-get-values! @var{signal}

Terminates the instant for the thread (as @code{thread-yield!}) and
returns, hence at the next instant, all the values associated with
broadcast @var{signal} (see Section @ref{Signal}) during the previous scheduler
reaction (see Section @ref{Scheduler}).

Example:
@smalllisp
(thread-start! (make-thread
                  (lambda ()
                     (for-each print (thread-get-values! 'foo)))))
(thread-start! (make-thread
                  (lambda ()
                     (broadcast! 'foo 1)
                     (broadcast! 'foo 'foo)
                     (broadcast! 'foo "blabla"))))
   @print{} 1
      foo
      blabla
@end smalllisp

Example:
@smalllisp
(let ((t1 (thread-start!
           (make-thread
            (lambda ()
               (for-each print (thread-get-values! 'foo)))
            't1)))
      (t2 (thread-start!
           (make-thread
            (lambda ()
               (broadcast! 'foo (current-thread))
               (thread-yield!)
               ;; this second broadcast won't be intercepted 
               ;; because it occurs during the next reaction
               (broadcast! 'foo (current-thread)))
            't2)))
      (t3 (thread-start!
           (make-thread
            (lambda ()
               (broadcast! 'foo (current-thread))
               (broadcast! 'foo (current-thread)))
            't3))))
   (scheduler-start!))
   @print{} #<thread:t2>
      #<thread:t3>
      #<thread:t3>
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-await-values! @var{signal} [@var{timeout}]
This blocks the current thread until @var{signal} has been broadcast.
It then returns, at the next instant, all the values associated with
all the broadcasts that took place during the instant.
It can be defined as:

@smalllisp
(define (thread-await-values! signal . tmt)
   (apply thread-await! signal tmt)
   (thread-get-values signal))
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-await*! @var{signals} [@var{timeout}]
@cindex select (à la unix)
Wait for one of a list of signals. The function @code{thread-await*!}
can be compared to the Unix @code{select} function. The argument 
@var{signals} is a list of signal identifier. The function 
@code{thread-await*!} blocks the current thread until one of the signal in 
the list @var{signals} is broadcast or until the optional numerical argument 
@var{timeout} is elapsed. If the thread unblocks because the timeout is 
elapsed, @code{thread-await*!} returns @code{#f}. Otherwise it returns two
values that have to be collected with @code{multiple-value-bind} (see
@ref{Control Features}). The first one is the value of the broadcast
signal. The second one is the broadcast signal.

Example:
@smalllisp
(let ((res #f))
   (thread-start!
    (make-thread (lambda ()
                    (let ((sig* (list 'foo 'bar)))
                       (multiple-value-bind (val1 sig1)
                          (thread-await*! sig*)
                          (multiple-value-bind (val2 sig2)
                             (thread-await*! sig*)
                             (thread-yield!)
                             (multiple-value-bind (val3 sig3)
                                (thread-await*! sig*)
                                (set! res (list sig1 sig2 sig3)))))))))
   (thread-start!
    (make-thread (lambda ()
                    (thread-sleep! 2)
                    (broadcast! 'foo 1))))
   (thread-start!
    (make-thread (lambda ()
                    (thread-sleep! 3)
                    (broadcast! 'bar 2))))
   (scheduler-start!)
   res)
  @result{} '(foo foo bar)
@end smalllisp

A second example using timeouts:
@smalllisp
(let ((res #f))
   (thread-start!
    (make-thread (lambda ()
                    (let ((sig* (list 'foo 'bar)))
                       (multiple-value-bind (val1 sig1)
                          (thread-await*! sig* 1)
                          (thread-yield!)
                          (multiple-value-bind (val2 sig2)
                             (thread-await*! sig* 1)
                             (thread-yield!)
                             (multiple-value-bind (val3 sig3)
                                (thread-await*! sig* 2)
                                (set! res (list sig1 sig2 sig3)))))))))
   (thread-start!
    (make-thread (lambda ()
                    (thread-sleep! 2)
                    (broadcast! 'foo 1))))
   (thread-start!
    (make-thread (lambda ()
                    (thread-sleep! 3)
                    (broadcast! 'bar 2))))
   (scheduler-start!)
   res)
  @result{} '(#f foo bar)
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-get-values*! @var{signals}
Terminates the instant for the thread (as @code{thread-yield!}) and
returns, hence at the next instant, all the values associated with
all broadcast @var{signals} (see Section @ref{Signal}) during the previous 
scheduler reaction (see Section @ref{Scheduler}). The function 
@code{thread-get-values*!} returns an @emph{alist} made of the scanned signal
and there values. That is the length of the returns list is the length
of the list @var{signals}. If a signal of the list @var{signals} has not
been broadcast, its associated entry the list returned by 
@code{thread-get-values*!} has an empty @code{cdr}.

Example:
@smalllisp
(let ((s1 'foo)
      (s2 'bar)
      (s3 'gee)
      (res #f))
   (thread-start!
    (make-thread (lambda ()
                    (thread-sleep! 2)
                    (broadcast! 'foo (current-time))
                    (broadcast! 'bar 0))))
   (thread-start!
    (make-thread (lambda ()
                    (thread-await*! (list s1 s2 s3))
                    (set! res (thread-get-values*! (list s1 s2 s3))))))
   (thread-start!
    (make-thread (lambda ()
                    (thread-sleep! 2)
                    (broadcast! 'bar (current-time)))))
   (scheduler-start!)
   res)
  @result{} ((foo 3) (bar 3 0) (gee))
@end smalllisp

Used with asynchronous signal, the functions @code{thread-await*!} and
@code{thread-get-values*!} can be used to read concurrently, in a non 
blocking way, several files. 
@end deffn

@deffn {Bigloo function} thread-await-values*! @var{signals} [@var{timeout}]
This blocks the current thread until at least one of @var{signals} has 
been broadcast. It then returns, at the next instant, all the values associated
with all the broadcasts that took place during the instant. It can be 
defined as:

@smalllisp
(define (thread-await-values*! signal . tmt)
   (apply thread-await*! signal tmt)
   (thread-get-values* signal))
@end smalllisp
@end deffn


@c -- Scheduler ------------------------------------------------------ @c
@node Scheduler, Signal, Thread, Fair Threads Api
@subsection Scheduler

@deffn {Bigloo function} make-scheduler [@var{envs}]
Creates a new scheduler. The optional arguments @var{envs} are
@emph{fair thread environments} which will be defined in forthcoming
Bigloo releases.
@end deffn

@deffn {Bigloo function} scheduler? @var{obj}
Returns @code{#t} if @var{obj} is a scheduler. Otherwise returns @code{#f}.
@end deffn

@deffn {Bigloo function} current-scheduler
Returns the current scheduler. The current scheduler is the scheduler
used in the last call to @code{scheduler-react!} or @code{scheduler-start!}.
It always exists a current scheduler. That is, it is optional for an
application to create a scheduler.
@end deffn

@deffn {Bigloo function} scheduler-react! [@var{scheduler}]
Executes all the treads started (see @code{thread-start!}, 
Section @ref{Thread}) in the scheduler until all the threads are
blocked. A thread is blocked if the has explicitly yield the processor 
(@code{thread-yield!} and @code{thread-sleep!}) or because it is waiting
a signal (@code{thread-await!}). A thread
can be selected several times during the same reaction.
The function @code{scheduler-react!} returns a symbol denoting the
@emph{state} of the scheduler. The possible states are:

@itemize @bullet
@item @code{ready} The Scheduler is ready to execute some threads.
@item @code{done} All the threads started in the scheduler have terminated.
@item @code{await} All the threads  started in the scheduler are waiting for
      a signal.
@end itemize

An invocation of @code{scheduler-react!} is called a @emph{reaction}.
@end deffn

@deffn {Bigloo function} scheduler-start! [@var{arg} [@var{scheduler}]]
Executes @code{scheduler-react!} as long as the scheduler is not done.
If the optional argument @var{scheduler} is not provided, 
@code{scheduler-start!} uses the current scheduler 
(see @code{current-scheduler}). The optional @var{arg} can either be:
@itemize @bullet
@item An integer standing for the number of times @code{scheduler-react!}
      must be called.
@item A procedure @var{f} of one argument. The procedure @var{f}
      is invoked after each reaction. It is passed a value @var{i} which is 
      the iteration number of the scheduler. The reactions of the scheduler
      are stopped when @var{f} returns @code{#f}.
@end itemize

@smalllisp
(let* ((s (make-scheduler))
       (t (make-thread (lambda () 
                          (let loop ((n 0))
                             (display n)
                             (thread-yield!)
                             (loop (+ 1 n)))))))
   (scheduler-start! 10 s))
  @print{} 0123456789

(let* ((s (make-scheduler))
       (t (make-thread (lambda () 
                          (let loop ((n 0))
                             (display n)
                             (thread-yield!)
                             (loop (+ 1 n)))))))
   (scheduler-start! (lambda (i) (read-char)) s))
  @print{} 0123456789
@end smalllisp
@end deffn

@deffn {Bigloo function} scheduler-terminate! [@var{scheduler}]
Terminates all the threads in @var{scheduler}.
@end deffn

@deffn {Bigloo function} scheduler-instant [@var{scheduler}]
Returns the current reaction number of @var{scheduler}. The reaction
number is the number of times @code{scheduler-react!} has been invoked
passing @var{scheduler} as argument.
@end deffn

@c -- Signal --------------------------------------------------------- @c
@node Signal, , Scheduler, Fair Threads Api
@subsection Signal

@deffn {Bigloo function} broadcast! @var{signal} [@var{val}]
Broadcasts @var{signal} to all threads started in @var{scheduler} 
@emph{immediately}, that is during the reaction. This function can only
be called from within a running thread. If the optional argument @var{val}
is omitted, the @var{signal} is broadcast with an unspecified value.

@smalllisp
(thread-start! (make-thread
		(lambda ()
		   (thread-await! 'foo)
		   (print (scheduler-instant (current-scheduler))))))
(thread-start! (make-thread
		(lambda ()
		   (broadcast! 'foo))))
(scheduler-start!)
  @print{} 1
@end smalllisp
@end deffn

@deffn {Bigloo function} scheduler-broadcast! @var{scheduler} @var{signal} [@var{val}]
At the next react broadcasts @var{signal} to all threads started 
in @var{scheduler}. This is used to impact running threads from outside 
any threads. If the optional argument @var{val}
is omitted, the @var{signal} is broadcast with an unspecified value.
@end deffn

@deffn {Bigloo function} make-input-signal @var{input-port} @var{obj} [@var{scheduler}]
@cindex asynchronous input
The argument @var{obj} can either be: a integer, a string, a pair. The 
condition for raising the signal depends on the type of @var{obj}.
See also @code{fair-read/rp}.

@itemize @bullet
@item @emph{integer:} 
This function returns a new signal that can be used anywhere a
signal is expected (e.g., @code{thread-await!}). In addition, it
spawns a asynchronous process that broadcasts, in
@var{scheduler}, the created signal
when @var{len} characters are read to the @var{input-port}. The
value associated with the signal is either the ``end of file'' object when
no more characters are available on the port or a string composed 
of the characters read on @var{input-port}. Note that the string length
could be lesser than @var{len} is less characters are available.

See Section @ref{Introduction} for examples using @code{make-input-signal}.

@item @emph{string:}
The signal is raised when the pattern @var{obj} is read on @var{input-port}.

@item @emph{list of strings:}
The signal is raised when one of the patterns in the list @var{obj} is read on 
@var{input-port}.

@item @emph{list of characters:}
The signal is raised when the character in the list @var{obj} is read
on @var{input-port}.
@end itemize
@end deffn

@deffn {Bigloo function} make-send-chars-signal @var{input-port} @var{output-port} @var{string} [@var{len}] [@var{scheduler}]
@cindex asynchronous data transfer
Copies @var{len} characters from @var{input-port} to @var{output-port}. If 
the optional argument @var{len} is left empty, all the characters of 
@var{input-port} are copied.
@end deffn

@deffn {Bigloo function} make-output-signal @var{output-port} @var{string} [@var{scheduler}]
@cindex asynchronous output
This function behaves as @code{make-input-signal} expect that the
signal is raised when the @var{string} is written on 
on @var{output-port}.
@end deffn

@deffn {Bigloo function} make-connect-signal @var{socket} [@var{scheduler}]
@cindex asynchronous socket connect
This function behaves as @code{make-input-signal} expect that the
signal is raised when a connection is established on @var{socket}.

The connection is established via the function @code{socket-accept-connection}
See Section @ref{Socket} for the definition of this last function.
@end deffn

@deffn {Bigloo function} make-accept-signal @var{socket} [@var{scheduler}]
@cindex asynchronous socket connect
This function behaves as @code{make-input-signal} expect that the
signal is raised when a connection is established on @var{socket}. The
socket client holding the connection is returned. If an error has occurred 
during the connection, the value @code{#f} is returned.

The connection is established via the function @code{socket-accept}.
See Section @ref{Introduction} for an example using @code{make-accept-signal}.
See Section @ref{Socket} for the definition of 
@code{make-accept-signal}.
@end deffn

@deffn {Bigloo function} make-process-signal @var{process} [@var{scheduler}]
@cindex asynchronous process termination
@cindex cooperative process
This function behaves has @code{make-input-signal} expect that the
signal is raised when the @var{process} completes.

Example:
@smalllisp
(thread-start! (make-thread 
                (lambda ()
                   (let* ((p (run-process "bigloo" "-i" "foo.scm"))
                          (r (thread-await! (make-process-signal p))))
                      (print "process termination: " r)))))
(thread-start! (make-thread
                (lambda ()
                   ...)))
@end smalllisp
@end deffn

@deffn {Bigloo function} make-sleep-signal @var{ms} [@var{scheduler}]
@cindex asynchronous sleep
Sleep for at least @var{ms} microseconds.
@end deffn

@deffn {Bigloo procedure} fair-read/rp @var{gram} @var{port}
Read from the input port @var{port} according to the regular grammar 
@var{gram}. This function automatically collaborates with other threads. It 
can thus be used to implement non-blocking readings 
(see also @code{make-input-signal}).
@end deffn


@c -- SRFI-18 -------------------------------------------------------- @c
@node SRFI-18, , Fair Threads Api, Threads
@comment  node-name,  next,  previous,  up
@section SRFI-18
@cindex SRFI-18

Bigloo implements SRFI-18 (Multithreading support). This SRFI is
available at @url{http://srfi.schemers.org/srfi-18/srfi-18.html}. One
should keep in mind that since the Bigloo scheduler is cooperative
Bigloo threads must @emph{cooperate} at some point in order not to
block the execution of other threads. The functions enforcing
cooperation are @code{thread-yield!}, @code{thread-sleep!},
@code{thread-join!}  and @code{thread-await!}. In addition the SRFI-18
@code{mutex-unlock} function enforce cooperation.


@deffn {SRFI-18 function} mutex? @var{obj}
@deffnx {SRFI-18 function} make-mutex @var{obj} [@var{name}]
@deffnx {SRFI-18 function} mutex-name @var{mutex}
@deffnx {SRFI-18 function} mutex-specific @var{mutex}
@deffnx {SRFI-18 function} mutex-specific-set! @var{mutex} @var{obj}
@deffnx {SRFI-18 function} mutex-state @var{mutex}
@deffnx {SRFI-18 function} mutex-lock! @var{mutex} [@var{timeout} [@var{thread}]]
@deffnx {SRFI-18 function} mutex-unlock! @var{mutex} [@var{condition-variable} [@var{timeout}]]

@smalllisp
(let ((m (make-mutex)))
   (thread-start!
    (make-thread (lambda ()
                    (let loop ()
                       (if (mutex-lock! m 0)
                           (begin
                              (display "locked")
                              (mutex-unlock! m))
                           (begin
                              (thread-yield!)
                              (loop))))))))
  @print{} locked

(let ((res '()))
   (define (mutex-lock-recursively! mutex)
      (if (eq? (mutex-state mutex) (current-thread))
          (let ((n (mutex-specific mutex)))
             (mutex-specific-set! mutex (+ n 1)))
          (begin
             (mutex-lock! mutex)
             (mutex-specific-set! mutex 0))))
   (define (mutex-unlock-recursively! mutex)
      (let ((n (mutex-specific mutex)))
         (if (= n 0)
             (mutex-unlock! mutex)
             (mutex-specific-set! mutex (- n 1)))))
   (thread-start!
    (make-thread
     (lambda ()
        (let ((m (make-mutex)))
           (mutex-lock-recursively! m)
           (mutex-lock-recursively! m)
           (mutex-lock-recursively! m)
           (set! res (cons (mutex-specific m) res))
           (mutex-unlock-recursively! m)
           (mutex-unlock-recursively! m)
           (mutex-unlock-recursively! m)
           (set! res (cons (mutex-specific m) res))))))
   res)
  @result{} (0 2)
@end smalllisp

@end deffn

@deffn {SRFI-18 function} condition-variable? @var{obj}
@deffnx {SRFI-18 function} make-condition-variable [@var{name}]
@deffnx {SRFI-18 function} condition-variable-name @var{cv}
@deffnx {SRFI-18 function} condition-variable-specific! @var{cv}
@deffnx {SRFI-18 function} condition-variable-specific-set! @var{cv} @var{obj}
@deffnx {SRFI-18 function} condition-variable-signal! @var{cv}
@deffnx {SRFI-18 function} condition-variable-broadcast! @var{cv}
@smalllisp
(let ((res 0))
   (define (make-semaphore n)
      (vector n (make-mutex) (make-condition-variable)))
   (define (semaphore-wait! sema)
      (mutex-lock! (vector-ref sema 1))
      (let ((n (vector-ref sema 0)))
         (if (> n 0)
             (begin
                (vector-set! sema 0 (- n 1))
                (mutex-unlock! (vector-ref sema 1)))
             (begin
                (mutex-unlock! (vector-ref sema 1) (vector-ref sema 2))
                (semaphore-wait! sema)))))
   (define (semaphore-signal-by! sema increment)
      (mutex-lock! (vector-ref sema 1))
      (let ((n (+ (vector-ref sema 0) increment)))
         (vector-set! sema 0 n)
         (if (> n 0)
             (condition-variable-broadcast! (vector-ref sema 2)))
         (mutex-unlock! (vector-ref sema 1))))
   (let ((sema (make-semaphore 10)))
      (let ((t1 (thread-start! (make-thread
                                (lambda ()
                                   (semaphore-wait! sema)
                                   (set! res (current-time))))))
            (t2 (thread-start! (make-thread
                                (lambda ()
                                   (let loop ((n 10))
                                      (if (> n 0)
                                          (begin
                                             (semaphore-signal-by! sema 1)
                                             (thread-yield!)
                                             (loop (- n 1))))))))))
         (scheduler-start!)
         res)))
  @result{} 2
@end smalllisp
@end deffn

@deffn {SRFI-18 function} current-time [@var{scheduler}]
Returns the reaction number of @var{scheduler}.
@end deffn

@deffn {SRFI-18 function} time? @var{obj}
@deffnx {SRFI-18 function} time->seconds @var{obj}
@end deffn

@deffn {SRFI-18 function} current-exception-handler
@deffnx {SRFI-18 function} with-exception-handler @var{handler} @var{thunk}
@deffnx {SRFI-18 function} raise @var{obj}
@deffnx {SRFI-18 function} join-timeout-exception? @var{obj}
@deffnx {SRFI-18 function} abandoned-mutex-exception? @var{obj}
@deffnx {SRFI-18 function} terminated-thread-exception? @var{obj}
@deffnx {SRFI-18 function} uncaught-exception? @var{obj}
@deffnx {SRFI-18 function} uncaught-exception-reason @var{exc}
@end deffn







