diff options
Diffstat (limited to 'doc/ref')
-rw-r--r-- | doc/ref/api-init.texi | 128 | ||||
-rw-r--r-- | doc/ref/api-scheduling.texi | 2 | ||||
-rw-r--r-- | doc/ref/libguile-concepts.texi | 221 |
3 files changed, 49 insertions, 302 deletions
diff --git a/doc/ref/api-init.texi b/doc/ref/api-init.texi index 795b6d5f9..94407114b 100644 --- a/doc/ref/api-init.texi +++ b/doc/ref/api-init.texi @@ -8,96 +8,50 @@ @node Initialization @section Initializing Guile -Each thread that wants to use function from the Guile API needs to put -itself into guile mode with either @code{scm_with_guile} or -@code{scm_init_guile}. The global state of Guile is initialized -automatically when the first thread enters guile mode. - -When a thread wants to block outside of a Guile API function, it should -leave guile mode temporarily with either @code{scm_without_guile} or -@code{scm_leave_guile}, @xref{Threads}. - -Threads that are created by @code{call-with-new-thread} or -@code{scm_spawn_thread} start out in guile mode so you don't need to -initialize them. - -@deftypefn {C Function} void *scm_with_guile (void *(*func)(void *), void *data) -Call @var{func}, passing it @var{data} and return what @var{func} -returns. While @var{func} is running, the current thread is in guile -mode and can thus use the Guile API. - -When @code{scm_with_guile} is called from guile mode, the thread remains -in guile mode when @code{scm_with_guile} returns. - -Otherwise, it puts the current thread into guile mode and, if needed, -gives it a Scheme representation that is contained in the list returned -by @code{all-threads}, for example. This Scheme representation is not -removed when @code{scm_with_guile} returns so that a given thread is -always represented by the same Scheme value during its lifetime, if at -all. - -When this is the first thread that enters guile mode, the global state -of Guile is initialized before calling @code{func}. - -When a throw happens while @var{func} runs (such as a signalled error) -that is not caught, a short message is printed to the current error port -and @code{scm_with_guile} returns @code{NULL}. When a continuation is -invoked that would make the control flow cross this call to -@code{scm_with_guile}, an error will be signalled at the point of -continuation invokation. Thus, @code{scm_with_guile} guaranteed to -return exactly once. - -When @code{scm_with_guile} returns, the thread is no longer in guile -mode (except when @code{scm_with_guile} was called from guile mode, see -above). Thus, only @code{func} can store @code{SCM} variables on the -stack and be sure that they are protected from the garbage collector. -See @code{scm_init_guile} for another approach at initializing Guile -that does not have this restriction. - -It is OK to call @code{scm_with_guile} while a thread has temporarily -left guile mode via @code{scm_without_guile} or @code{scm_leave_guile}. -It will then simply temporarily enter guile mode again. +@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data}) +Initialize the Guile Scheme interpreter. Then call @var{main_func}, +passing it @var{data}, @var{argc}, and @var{argv} as indicated. The +function @var{main_func} should do all the work of the program +(initializing other packages, defining application-specific functions, +reading user input, and so on) before returning. When @var{main_func} +returns, @code{scm_boot_guile} calls @code{exit (0)}; +@code{scm_boot_guile} never returns. If you want some other exit +value, have @var{main_func} call @code{exit} itself. + +@code{scm_boot_guile} arranges for the Scheme @code{command-line} +function to return the strings given by @var{argc} and @var{argv}. If +@var{main_func} modifies @var{argc} or @var{argv}, it should call +@code{scm_set_program_arguments} with the final list, so Scheme code +will know which arguments have been processed. + +Why must the caller do all the real work from @var{main_func}? Guile's +garbage collector scans the stack to find all local variables that +reference Scheme objects. To do this, it needs to know the bounds of +the stack that might contain such references. Because there is no +portable way in C to find the base of the stack, @code{scm_boot_guile} +assumes that all references are above its own stack frame. If you try +to manipulate Scheme objects after this function returns, it's the luck +of the draw whether Guile's storage manager will be able to find the +objects you allocate. So, @code{scm_boot_guile} function exits, rather +than returning, to discourage you from making that mistake. + +See @code{scm_init_guile}, below, for a function that can find the real +base of the stack, but not in a portable way. @end deftypefn @deftypefn {C Function} void scm_init_guile () -Arrange things so as if all of the code of the current thread would be -executed from within a call to @code{scm_with_guile}. That is, all -functions called by the current thread can assume that @code{SCM} values -on their stack frames are protected from the garbage collector (except -when the thread has explicitely left guile mode, of course). - -When @code{scm_init_guile} is called from a thread that already has been -in guile mode once, nothing happens. This behavior matters when you -call @code{scm_init_guile} while the thread has only temporarily left -guile mode: in that case the thread will not be in guile mode after -@code{scm_init_guile} returns. Thus, you should not use -@code{scm_init_guile} in such a scenario. - -When a uncaught throw happens in a thread that has been put into guile -mode via @code{scm_init_guile}, a short message is printed to the -current error port and the thread is exited via @code{scm_pthread_exit -(NULL)}. No restrictions are placed on continuations. - -The function @code{scm_init_guile} might not be available on all -platforms since it requires some stack-bounds-finding magic that might -not have been to all platforms that Guile runs on. Thus, if you can, it -is better to use @code{scm_with_guile} or its variation -@code{scm_boot_guile} instead of this function. -@end deftypefn - -@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data}) -Enter guile mode as with @code{scm_with_guile} and call @var{main_func}, -passing it @var{data}, @var{argc}, and @var{argv} as indicated. When -@var{main_func} returns, @code{scm_boot_guile} calls @code{exit (0)}; -@code{scm_boot_guile} never returns. If you want some other exit value, -have @var{main_func} call @code{exit} itself. If you don't want to exit -at all, use @code{scm_with_guile} instead of @code{scm_boot_guile}. - -The function @code{scm_boot_guile} arranges for the Scheme -@code{command-line} function to return the strings given by @var{argc} -and @var{argv}. If @var{main_func} modifies @var{argc} or @var{argv}, -it should call @code{scm_set_program_arguments} with the final list, so -Scheme code will know which arguments have been processed. +Initialize the Guile Scheme interpreter. + +In contrast to @code{scm_boot_guile}, this function knows how to find +the true base of the stack and thus does not need to usurp the control +flow of your program. However, since finding the stack base can not be +done portably, this function might not be available in all installations +of Guile. If you can, you should use @code{scm_boot_guile} instead. + +Note that @code{scm_init_guile} does not inform Guile about the command +line arguments that should be returned by the Scheme function +@code{command-line}. You can use @code{scm_set_program_arguments} to do +this. @end deftypefn @deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv}) diff --git a/doc/ref/api-scheduling.texi b/doc/ref/api-scheduling.texi index 7abaed331..dd830fa34 100644 --- a/doc/ref/api-scheduling.texi +++ b/doc/ref/api-scheduling.texi @@ -113,7 +113,7 @@ them temporarily. In addition to the C versions of @code{call-with-blocked-asyncs} and @code{call-with-unblocked-asyncs}, C code can use -@code{scm_frame_block_asyncs} and @code{scm_frame_unblock_asyncs} +@code{scm_with_blocked_asyncs} and @code{scm_with_unblocked_asyncs} inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs temporarily. diff --git a/doc/ref/libguile-concepts.texi b/doc/ref/libguile-concepts.texi index 7fc0a6c34..870c051f3 100644 --- a/doc/ref/libguile-concepts.texi +++ b/doc/ref/libguile-concepts.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005 +@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @@ -8,12 +8,12 @@ @node General Libguile Concepts @section General concepts for using libguile -When you want to embed the Guile Scheme interpreter into your program or -library, you need to link it against the @file{libguile} library -(@pxref{Linking Programs With Guile}). Once you have done this, your C -code has access to a number of data types and functions that can be used -to invoke the interpreter, or make new functions that you have written -in C available to be called from Scheme code, among other things. +When you want to embed the Guile Scheme interpreter into your program, +you need to link it against the @file{libguile} library (@pxref{Linking +Programs With Guile}). Once you have done this, your C code has access +to a number of data types and functions that can be used to invoke the +interpreter, or make new functions that you have written in C available +to be called from Scheme code, among other things. Scheme is different from C in a number of significant ways, and Guile tries to make the advantages of Scheme available to C as well. Thus, in @@ -26,16 +26,10 @@ You need to understand how libguile offers them to C programs in order to use the rest of libguile. Also, the more general control flow of Scheme caused by continuations needs to be dealt with. -Running asynchronous signal handlers and multi-threading is known to C -code already, but there are of course a few additional rules when using -them together with libguile. - @menu * Dynamic Types:: Dynamic Types. * Garbage Collection:: Garbage Collection. * Control Flow:: Control Flow. -* Asynchronous Signals:: Asynchronous Signals -* Multi-Threading:: Multi-Threading @end menu @node Dynamic Types @@ -383,204 +377,3 @@ corresponding @code{scm_internal_dynamic_wind} function, but it might prefer to use the @dfn{frames} concept that is more natural for C code, (@pxref{Frames}). -@node Asynchronous Signals -@subsection Asynchronous Signals - -You can not call libguile functions from handlers for POSIX signals, but -you can register Scheme handlers for POSIX signals such as -@code{SIGINT}. These handlers do not run during the actual signal -delivery. Instead, they are run when the program (more precisely, the -thread that the handler has been registered for) reaches the next -@emph{safe point}. - -The libguile functions themselves have many such safe points. -Consequently, you must be prepared for arbitrary actions anytime you -call a libguile function. For example, even @code{scm_cons} can contain -a safe point and when a signal handler is pending for your thread, -calling @code{scm_cons} will run this handler and anything might happen, -including a non-local exit although @code{scm_cons} would not ordinarily -do such a thing on its own. - -If you do not want to allow the running of asynchronous signal handlers, -you can block them temporarily with @code{scm_frame_block_asyncs}, for -example. See @xref{System asyncs}. - -Since signal handling in Guile relies on safe points, you need to make -sure that your functions do offer enough of them. Normally, calling -libguile functions in the normal course of action is all that is needed. -But when a thread might spent a long time in a code section that calls -no libguile function, it is good to include explicit safe points. This -can allow the user to interrupt your code with @key{C-c}, for example. - -You can do this with the macro @code{SCM_TICK}. This macro is -syntactically a statement. That is, you could use it like this: - -@example -while (1) - @{ - SCM_TICK; - do_some_work (); - @} -@end example - -Frequent execution of a safe point is even more important in multi -threaded programs, @xref{Multi-Threading}. - -@node Multi-Threading -@subsection Multi-Threading - -Guile can be used in multi-threaded programs just as well as in -single-threaded ones. - -Each thread that wants to use functions from libguile must put itself -into @emph{guile mode} and must then follow a few rules. If it doesn't -want to honor these rules in certain situations, a thread can -temporarily leave guile mode (but can no longer use libguile functions -during that time, of course). - -Threads enter guile mode by calling @code{scm_with_guile}, -@code{scm_boot_guile}, or @code{scm_init_guile}. As explained in the -reference documentation for these functions, Guile will then learn about -the stack bounds of the thread and can protect the @code{SCM} values -that are stored in local variables. When a thread puts itself into -guile mode for the first time, it gets a Scheme representation and is -listed by @code{all-threads}, for example. - -While in guile mode, a thread promises to reach a safe point reasonably -frequently (@pxref{Asynchronous Signals}). In addition to running -signal handlers, these points are also potential rendezvous points of -all guile mode threads where Guile can orchestrate global things like -garbage collection. Consequently, when a thread in guile mode blocks -and does no longer frequent safe points, it might cause all other guile -mode threads to block as well. To prevent this from happening, a guile -mode thread should either only block in libguile functions (who know how -to do it right), or should temporarily leave guile mode with -@code{scm_without_guile} or -@code{scm_leave_guile}/@code{scm_enter_guile}. - -For some common blocking operations, Guile provides convenience -functions. For example, if you want to lock a pthread mutex while in -guile mode, you might want to use @code{scm_pthread_mutex_lock} which is -just like @code{pthread_mutex_lock} except that it leaves guile mode -while blocking. - - -All libguile functions are (intended to be) robust in the face of -multiple threads using them concurrently. This means that there is no -risk of the internal data structures of libguile becoming corrupted in -such a way that the process crashes. - -A program might still produce non-sensical results, though. Taking -hashtables as an example, Guile guarantees that you can use them from -multiple threads concurrently and a hashtable will always remain a valid -hashtable and Guile will not crash when you access it. It does not -guarantee, however, that inserting into it concurrently from two threads -will give useful results: only one insertion might actually happen, none -might happen, or the table might in general be modified in a totally -arbitrary manner. (It will still be a valid hashtable, but not the one -that you might have expected.) Guile might also signal an error when it -detects a harmful race condition. - -Thus, you need to put in additional synchronizations when multiple -threads want to use a single hashtable, or any other mutable Scheme -object. - -When writing C code for use with libguile, you should try to make it -robust as well. An example that converts a list into a vector will help -to illustrate. Here is a correct version: - -@example -SCM -my_list_to_vector (SCM list) -@{ - SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED); - size_t len, i; - - len = SCM_SIMPLE_VECTOR_LENGTH (vector); - i = 0; - while (i < len && scm_is_pair (list)) - @{ - SCM_SIMPLE_VECTOR_SET (vector, i, SCM_CAR (list)); - list = SCM_CDR (list); - i++; - @} - - return vector; -@} -@end example - -The first thing to note is that storing into a @code{SCM} location -concurrently from multiple threads is guaranteed to be robust: you don't -know which value wins but it will in any case be a valid @code{SCM} -value. - -But there is no guarantee that the list referenced by @var{list} is not -modified in another thread while the loop iterates over it. Thus, while -copying its elements into the vector, the list might get longer or -shorter. For this reason, the loop must check both that it doesn't -overrun the vector (@code{SCM_SIMPLE_VECTOR_SET} does no range-checking) -and that it doesn't overrung the list (@code{SCM_CAR} and @code{SCM_CDR} -likewise do no type checking). - -It is safe to use @code{SCM_CAR} and @code{SCM_CDR} on the local -variable @var{list} once it is known that the variable contains a pair. -The contents of the pair might change spontaneously, but it will always -stay a valid pair (and a local variable will of course not spontaneously -point to a different Scheme object). - -Likewise, a simple vector such as the one returned by -@code{scm_make_vector} is guaranteed to always stay the same length so -that it is safe to only use SCM_SIMPLE_VECTOR_LENGTH once and store the -result. (In the example, @var{vector} is safe anyway since it is a -fresh object that no other thread can possibly know about until it is -returned from @code{my_list_to_vector}.) - -Of course the behavior of @code{my_list_to_vector} is suboptimal when -@var{list} does indeed gets asynchronously lengthened or shortened in -another thread. But it is robust: it will always return a valid vector. -That vector might be shorter than expected, or its last elements might -be unspecified, but it is a valid vector and if a program wants to rule -out these cases, it must avoid modifying the list asynchronously. - -Here is another version that is also correct: - -@example -SCM -my_pedantic_list_to_vector (SCM list) -@{ - SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED); - size_t len, i; - - len = SCM_SIMPLE_VECTOR_LENGTH (vector); - i = 0; - while (i < len) - @{ - SCM_SIMPLE_VECTOR_SET (vector, i, scm_car (list)); - list = scm_cdr (list); - i++; - @} - - return vector; -@} -@end example - -This version uses the type-checking and thread-robust functions -@code{scm_car} and @code{scm_cdr} instead of the faster, but less robust -macros @code{SCM_CAR} and @code{SCM_CDR}. When the list is shortened -(that is, when @var{list} holds a non-pair), @code{scm_car} will throw -an error. This might be preferable to just returning a half-initialized -vector. - -The API for accessing vectors and arrays of various kinds from C takes a -slightly different approach to thread-robustness. In order to get at -the raw memory that stores the elements of an array, you need to -@emph{reserve} that array as long as you need the raw memory. During -the time an array is reserved, its elements can still spontaneously -change their values, but the memory itself and other things like the -size of the array are guaranteed to stay fixed. Any operation that -would change these parameters of an array that is currently reserved -will signal an error. In order to avoid these errors, a program should -of course put suitable synchronization mechanisms in place. As you can -see, Guile itself is again only concerned about robustness, not about -correctness: without proper synchronization, your program will likely -not be correct, but the worst consequence is an error message. |