* __scm.h (SCM_ALLOW_INTS_ONLY): Removed.

(SCM_NONREC_CRITICAL_SECTION_START,
SCM_NONREC_CRITICAL_SECTION_END, SCM_REC_CRITICAL_SECTION_START,
SCM_REC_CRITICAL_SECTION_END): New macros.
(SCM_CRITICAL_SECTION_START/END): Defined here.

* eval.c: Insert SOURCE_SECTION_START / SOURCE_SECTION_END around
the three calls to scm_m_expand_body.

* gc.h: #include "libguile/pthread-threads.h";
(SCM_FREELIST_CREATE, SCM_FREELIST_LOC): New macros.

* gc.c (scm_i_freelist, scm_i_freelist2): Defined to be of type
scm_t_key;

* gc.c, gc-freelist.c, inline.h: Use SCM_FREELIST_LOC for freelist
access.

* gc-freelist.c (scm_gc_init_freelist): Create freelist keys.

* gc-freelist.c, threads.c (really_launch): Use
SCM_FREELIST_CREATE.

* gc-malloc.c (scm_realloc, scm_gc_register_collectable_memory):

* gc.c (scm_i_expensive_validation_check, scm_gc,
scm_gc_for_newcell): Put threads to sleep before doing GC-related
heap administration so that those pieces of code are executed
single-threaded.  We might consider rewriting these code sections
in terms of a "call_gc_code_singly_threaded" construct instead of
calling the pair of scm_i_thread_put_to_sleep () and
scm_i_thread_wake_up ().  Also, we would want to have as many of
these sections eleminated.

* init.c (scm_init_guile_1): Call scm_threads_prehistory.

* inline.h: #include "libguile/threads.h"

* pthread-threads.h: Macros now conform more closely to the
pthreads interface.  Some of them now take a second argument.

* threads.c, threads.h: Many changes.

* configure.in: Temporarily replaced "copt" threads option with new
option "pthreads".
(USE_PTHREAD_THREADS): Define if pthreads configured.
This commit is contained in:
Mikael Djurfeldt 2002-12-09 13:42:58 +00:00
commit 9bc4701cd3
19 changed files with 995 additions and 491 deletions

View file

@ -1,3 +1,9 @@
2002-12-09 Mikael Djurfeldt <djurfeldt@nada.kth.se>
* configure.in: Temporarily replaced "copt" threads option with new
option "pthreads".
(USE_PTHREAD_THREADS): Define if pthreads configured.
2002-12-08 Rob Browning <rlb@defaultvalue.org>
* configure.in (GUILE_EFFECTIVE_VERSION): AC_SUBST it.

View file

@ -642,18 +642,18 @@ AC_ARG_WITH(threads, [ --with-threads thread interface],
, with_threads=yes)
case "$with_threads" in
"yes" | "coop-pthread" | "copt" | "coop" | "")
"yes" | "pthread" | "pthreads" | "pthread-threads" | "")
AC_CHECK_LIB(pthread, main,
LIBS="-lpthread $LIBS"
AC_DEFINE(USE_COPT_THREADS, 1,
[Define if using coop-pthread multithreading.])
with_threads="coop-pthreads",
AC_DEFINE(USE_PTHREAD_THREADS, 1,
[Define if using pthread multithreading.])
with_threads="pthreads",
with_threads="null")
;;
esac
case "$with_threads" in
"coop-pthreads")
"pthreads")
;;
"no" | "null")
AC_DEFINE(USE_NULL_THREADS, 1,

View file

@ -1,3 +1,61 @@
2002-12-09 Mikael Djurfeldt <djurfeldt@nada.kth.se>
These changes are the start of support for preemptive
multithreading. Marius and I have agreed that I commit this code
into the repository although it isn't thoroughly tested and surely
introduces many bugs. The bugs should only be exposed when using
threads, though. Signalling and error handling for threads is
very likely broken. Work on making the implementation cleaner and
more efficient is needed.
* __scm.h (SCM_ALLOW_INTS_ONLY): Removed.
(SCM_NONREC_CRITICAL_SECTION_START,
SCM_NONREC_CRITICAL_SECTION_END, SCM_REC_CRITICAL_SECTION_START,
SCM_REC_CRITICAL_SECTION_END): New macros.
(SCM_CRITICAL_SECTION_START/END): Defined here.
* eval.c: Insert SOURCE_SECTION_START / SOURCE_SECTION_END around
the three calls to scm_m_expand_body.
* gc.h: #include "libguile/pthread-threads.h";
(SCM_FREELIST_CREATE, SCM_FREELIST_LOC): New macros.
* gc.c (scm_i_freelist, scm_i_freelist2): Defined to be of type
scm_t_key;
* gc.c, gc-freelist.c, inline.h: Use SCM_FREELIST_LOC for freelist
access.
* gc-freelist.c (scm_gc_init_freelist): Create freelist keys.
* gc-freelist.c, threads.c (really_launch): Use
SCM_FREELIST_CREATE.
* gc-malloc.c (scm_realloc, scm_gc_register_collectable_memory):
* gc.c (scm_i_expensive_validation_check, scm_gc,
scm_gc_for_newcell): Put threads to sleep before doing GC-related
heap administration so that those pieces of code are executed
single-threaded. We might consider rewriting these code sections
in terms of a "call_gc_code_singly_threaded" construct instead of
calling the pair of scm_i_thread_put_to_sleep () and
scm_i_thread_wake_up (). Also, we would want to have as many of
these sections eleminated.
* init.c (scm_init_guile_1): Call scm_threads_prehistory.
* inline.h: #include "libguile/threads.h"
* pthread-threads.h: Macros now conform more closely to the
pthreads interface. Some of them now take a second argument.
* threads.c, threads.h: Many changes.
2002-12-09 Mikael Djurfeldt <djurfeldt@nada.kth.se>
* Makefile.am (version.h): Changed $^ --> $< in rule for
version.h.
2002-12-08 Rob Browning <rlb@defaultvalue.org>
* version.h.in (SCM_MICRO_VERSION): use @--@ substitution now.

View file

@ -181,7 +181,7 @@ EXTRA_DIST = ChangeLog-gh ChangeLog-scm ChangeLog-threads \
## usual @...@, so autoconf doesn't go and substitute the values
## directly into the left-hand sides of the sed substitutions. *sigh*
version.h: version.h.in
sed < $^ > $@.tmp \
sed < $< > $@.tmp \
-e s:@-GUILE_MAJOR_VERSION-@:${GUILE_MAJOR_VERSION}: \
-e s:@-GUILE_MINOR_VERSION-@:${GUILE_MINOR_VERSION}: \
-e s:@-GUILE_MICRO_VERSION-@:${GUILE_MICRO_VERSION}:

View file

@ -446,53 +446,46 @@ do { \
#define SCM_FENCE
#endif
#define SCM_DEFER_INTS \
do { \
SCM_FENCE; \
SCM_CHECK_NOT_DISABLED; \
SCM_CRITICAL_SECTION_START; \
SCM_FENCE; \
scm_ints_disabled = 1; \
SCM_FENCE; \
#define SCM_DEFER_INTS \
do { \
SCM_FENCE; \
SCM_CHECK_NOT_DISABLED; \
SCM_REC_CRITICAL_SECTION_START (scm_i_defer); \
SCM_FENCE; \
scm_ints_disabled = 1; \
SCM_FENCE; \
} while (0)
#define SCM_ALLOW_INTS_ONLY \
do { \
SCM_CRITICAL_SECTION_END; \
scm_ints_disabled = 0; \
#define SCM_ALLOW_INTS \
do { \
SCM_FENCE; \
SCM_CHECK_NOT_ENABLED; \
SCM_REC_CRITICAL_SECTION_END (scm_i_defer); \
SCM_FENCE; \
scm_ints_disabled = 0; \
SCM_FENCE; \
SCM_THREAD_SWITCHING_CODE; \
SCM_FENCE; \
} while (0)
#define SCM_ALLOW_INTS \
do { \
SCM_FENCE; \
SCM_CHECK_NOT_ENABLED; \
SCM_CRITICAL_SECTION_END; \
SCM_FENCE; \
scm_ints_disabled = 0; \
SCM_FENCE; \
SCM_THREAD_SWITCHING_CODE; \
SCM_FENCE; \
#define SCM_REDEFER_INTS \
do { \
SCM_FENCE; \
SCM_REC_CRITICAL_SECTION_START (scm_i_defer); \
++scm_ints_disabled; \
SCM_FENCE; \
} while (0)
#define SCM_REDEFER_INTS \
do { \
SCM_FENCE; \
SCM_CRITICAL_SECTION_START; \
++scm_ints_disabled; \
SCM_FENCE; \
} while (0)
#define SCM_REALLOW_INTS \
do { \
SCM_FENCE; \
SCM_CRITICAL_SECTION_END; \
SCM_FENCE; \
--scm_ints_disabled; \
SCM_FENCE; \
#define SCM_REALLOW_INTS \
do { \
SCM_FENCE; \
SCM_REC_CRITICAL_SECTION_END (scm_i_defer); \
SCM_FENCE; \
--scm_ints_disabled; \
SCM_FENCE; \
} while (0)
@ -504,6 +497,65 @@ do { \
/* Critical sections */
#define SCM_DECLARE_NONREC_CRITICAL_SECTION(prefix) \
extern scm_t_mutex prefix ## _mutex
#define SCM_NONREC_CRITICAL_SECTION_START(prefix) \
do { scm_thread *t = scm_i_leave_guile (); \
scm_i_plugin_mutex_lock (&prefix ## _mutex); \
scm_i_enter_guile (t); \
} while (0)
#define SCM_NONREC_CRITICAL_SECTION_END(prefix) \
do { scm_i_plugin_mutex_unlock (&prefix ## _mutex); \
} while (0)
/* This could be replaced by a single call to scm_i_plugin_mutex_lock
on systems which support recursive mutecis (like LinuxThreads).
We should test for the presence of recursive mutecis in
configure.in.
Also, it is probably possible to replace recursive sections with
non-recursive ones, so don't worry about the complexity.
*/
#define SCM_DECLARE_REC_CRITICAL_SECTION(prefix) \
extern scm_t_mutex prefix ## _mutex; \
extern int prefix ## _count; \
extern scm_thread *prefix ## _owner
#define SCM_REC_CRITICAL_SECTION_START(prefix) \
do { scm_i_plugin_mutex_lock (&scm_i_section_mutex); \
if (prefix ## _count && prefix ## _owner == SCM_CURRENT_THREAD) \
{ \
++prefix ## _count; \
scm_i_plugin_mutex_unlock (&scm_i_section_mutex); \
} \
else \
{ \
scm_thread *t = scm_i_leave_guile (); \
scm_i_plugin_mutex_unlock (&scm_i_section_mutex); \
scm_i_plugin_mutex_lock (&prefix ## _mutex); \
prefix ## _count = 1; \
prefix ## _owner = t; \
scm_i_enter_guile (t); \
} \
} while (0)
#define SCM_REC_CRITICAL_SECTION_END(prefix) \
do { scm_i_plugin_mutex_lock (&scm_i_section_mutex); \
if (!--prefix ## _count) \
{ \
prefix ## _owner = 0; \
scm_i_plugin_mutex_unlock (&prefix ## _mutex); \
} \
scm_i_plugin_mutex_unlock (&scm_i_section_mutex); \
} while (0)
/* Note: The following needs updating. */
/* Classification of critical sections
*
* When Guile moves to POSIX threads, it won't be possible to prevent

View file

@ -88,7 +88,7 @@
*/
#ifdef HAVE_RESTARTABLE_SYSCALLS
#ifndef USE_COPT_THREADS /* However, don't assume SA_RESTART
#ifndef USE_PTHREAD_THREADS /* However, don't assume SA_RESTART
works with pthreads... */
#define SCM_SYSCALL(line) line
#endif

View file

@ -152,6 +152,10 @@ char *alloca ();
#define EXTEND_ENV SCM_EXTEND_ENV
SCM_REC_CRITICAL_SECTION (source);
#define SOURCE_SECTION_START SCM_REC_CRITICAL_SECTION_START (source);
#define SOURCE_SECTION_END SCM_REC_CRITICAL_SECTION_END (source);
SCM *
scm_ilookup (SCM iloc, SCM env)
{
@ -1580,7 +1584,11 @@ scm_eval_body (SCM code, SCM env)
{
if (SCM_ISYMP (SCM_CAR (code)))
{
code = scm_m_expand_body (code, env);
SOURCE_SECTION_START;
/* check for race condition */
if (SCM_ISYMP (SCM_CAR (code)))
code = scm_m_expand_body (code, env);
SOURCE_SECTION_END;
goto again;
}
}
@ -1979,7 +1987,11 @@ dispatch:
{
if (SCM_ISYMP (form))
{
x = scm_m_expand_body (x, env);
SOURCE_SECTION_START;
/* check for race condition */
if (SCM_ISYMP (SCM_CAR (x)))
x = scm_m_expand_body (x, env);
SOURCE_SECTION_END;
goto nontoplevel_begin;
}
else
@ -3634,7 +3646,11 @@ tail:
{
if (SCM_ISYMP (SCM_CAR (proc)))
{
proc = scm_m_expand_body (proc, args);
SOURCE_SECTION_START;
/* check for race condition */
if (SCM_ISYMP (SCM_CAR (proc)))
proc = scm_m_expand_body (proc, args);
SOURCE_SECTION_END;
goto again;
}
else

View file

@ -168,8 +168,11 @@ scm_gc_init_freelist (void)
int init_heap_size_2
= scm_getenv_int ("GUILE_INIT_SEGMENT_SIZE_2", SCM_DEFAULT_INIT_HEAP_SIZE_2);
scm_i_freelist = SCM_EOL;
scm_i_freelist2 = SCM_EOL;
/* These are the thread-local freelists. */
scm_key_create (&scm_i_freelist, free);
scm_key_create (&scm_i_freelist2, free);
SCM_FREELIST_CREATE (scm_i_freelist);
SCM_FREELIST_CREATE (scm_i_freelist2);
scm_init_freelist (&scm_i_master_freelist2, 2,
scm_getenv_int ("GUILE_MIN_YIELD_2", SCM_DEFAULT_MIN_YIELD_2));

View file

@ -130,15 +130,22 @@ scm_realloc (void *mem, size_t size)
if (ptr)
return ptr;
scm_i_thread_put_to_sleep ();
scm_i_sweep_all_segments ("realloc");
SCM_SYSCALL (ptr = realloc (mem, size));
if (ptr)
return ptr;
{
scm_i_thread_wake_up ();
return ptr;
}
scm_igc ("realloc");
scm_i_sweep_all_segments ("realloc");
scm_i_thread_wake_up ();
SCM_SYSCALL (ptr = realloc (mem, size));
if (ptr)
return ptr;
@ -208,11 +215,14 @@ scm_gc_register_collectable_memory (void *mem, size_t size, const char *what)
*/
if (scm_mallocated > scm_mtrigger)
{
unsigned long prev_alloced = scm_mallocated;
unsigned long prev_alloced;
float yield;
scm_i_thread_put_to_sleep ();
prev_alloced = scm_mallocated;
scm_igc (what);
scm_i_sweep_all_segments("mtrigger");
scm_i_sweep_all_segments ("mtrigger");
yield = ((float)prev_alloced - (float) scm_mallocated)
/ (float) prev_alloced;
@ -243,6 +253,8 @@ scm_gc_register_collectable_memory (void *mem, size_t size, const char *what)
fprintf (stderr, "Mtrigger sweep: ineffective. New trigger %d\n", scm_mtrigger);
#endif
}
scm_i_thread_wake_up ();
}
#ifdef GUILE_DEBUG_MALLOC

View file

@ -144,7 +144,9 @@ scm_i_expensive_validation_check (SCM cell)
else
{
counter = scm_debug_cells_gc_interval;
scm_i_thread_put_to_sleep ();
scm_igc ("scm_assert_cell_valid");
scm_i_thread_wake_up ();
}
}
}
@ -249,8 +251,8 @@ SCM_DEFINE (scm_set_debug_cell_accesses_x, "set-debug-cell-accesses!", 1, 0, 0,
SCM scm_i_freelist = SCM_EOL;
SCM scm_i_freelist2 = SCM_EOL;
scm_t_key scm_i_freelist;
scm_t_key scm_i_freelist2;
/* scm_mtrigger
@ -457,7 +459,9 @@ SCM_DEFINE (scm_gc, "gc", 0, 0, 0,
#define FUNC_NAME s_scm_gc
{
SCM_DEFER_INTS;
scm_i_thread_put_to_sleep ();
scm_igc ("call");
scm_i_thread_wake_up ();
SCM_ALLOW_INTS;
return SCM_UNSPECIFIED;
}
@ -475,6 +479,8 @@ scm_gc_for_newcell (scm_t_cell_type_statistics *freelist, SCM *free_cells)
{
SCM cell;
scm_i_thread_put_to_sleep ();
++scm_ints_disabled;
*free_cells = scm_i_sweep_some_segments (freelist);
@ -519,6 +525,7 @@ scm_gc_for_newcell (scm_t_cell_type_statistics *freelist, SCM *free_cells)
*free_cells = SCM_FREE_CELL_CDR (cell);
scm_i_thread_wake_up ();
return cell;
}
@ -540,13 +547,17 @@ scm_igc (const char *what)
fprintf (stderr,"gc reason %s\n", what);
fprintf (stderr,
SCM_NULLP (scm_i_freelist)
SCM_NULLP (*SCM_FREELIST_LOC (scm_i_freelist))
? "*"
: (SCM_NULLP (scm_i_freelist2) ? "o" : "m"));
: (SCM_NULLP (*SCM_FREELIST_LOC (scm_i_freelist2)) ? "o" : "m"));
#endif
/* During the critical section, only the current thread may run. */
#if 0 /* MDJ 021207 <djurfeldt@nada.kth.se>
Currently, a much larger piece of the GC is single threaded.
Can we shrink it again? */
SCM_CRITICAL_SECTION_START;
#endif
if (!scm_root || !scm_stack_base || scm_block_gc)
{
@ -610,7 +621,9 @@ scm_igc (const char *what)
scm_c_hook_run (&scm_after_sweep_c_hook, 0);
gc_end_stats ();
#if 0 /* MDJ 021207 <djurfeldt@nada.kth.se> */
SCM_CRITICAL_SECTION_END;
#endif
/*
See above.
@ -1011,8 +1024,8 @@ scm_gc_sweep (void)
/* When we move to POSIX threads private freelists should probably
be GC-protected instead. */
scm_i_freelist = SCM_EOL;
scm_i_freelist2 = SCM_EOL;
*SCM_FREELIST_LOC (scm_i_freelist) = SCM_EOL;
*SCM_FREELIST_LOC (scm_i_freelist2) = SCM_EOL;
}
#undef FUNC_NAME

View file

@ -3,7 +3,7 @@
#ifndef SCM_GC_H
#define SCM_GC_H
/* Copyright (C) 1995,1996,1998,1999,2000,2001 Free Software Foundation, Inc.
/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2002 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -50,6 +50,12 @@
#include "libguile/hooks.h"
#ifdef USE_PTHREAD_THREADS
#include "libguile/pthread-threads.h"
#else
#include "libguile/null-threads.h"
#endif
typedef struct scm_t_cell
@ -276,13 +282,14 @@ SCM_API size_t scm_default_max_segment_size;
SCM_API size_t scm_max_segment_size;
/*
Deprecated scm_freelist, scm_master_freelist.
No warning; this is not a user serviceable part.
*/
extern SCM scm_i_freelist;
#define SCM_FREELIST_CREATE(key) \
do { SCM *ls = (SCM *) malloc (sizeof (SCM)); \
*ls = SCM_EOL; \
scm_setspecific ((key), ls); } while (0)
#define SCM_FREELIST_LOC(key) ((SCM *) scm_getspecific (key))
extern scm_t_key scm_i_freelist;
extern scm_t_key scm_i_freelist2;
extern struct scm_t_cell_type_statistics scm_i_master_freelist;
extern SCM scm_i_freelist2;
extern struct scm_t_cell_type_statistics scm_i_master_freelist2;

View file

@ -445,13 +445,14 @@ scm_init_guile_1 (SCM_STACKITEM *base)
scm_ints_disabled = 1;
scm_block_gc = 1;
scm_threads_prehistory ();
scm_ports_prehistory ();
scm_smob_prehistory ();
scm_tables_prehistory ();
#ifdef GUILE_DEBUG_MALLOC
scm_debug_malloc_prehistory ();
#endif
if (scm_init_storage ()) /* requires smob_prehistory */
if (scm_init_storage ()) /* requires threads and smob_prehistory */
abort ();
scm_struct_prehistory (); /* requires storage */

View file

@ -57,6 +57,7 @@
#include "libguile/pairs.h"
#include "libguile/gc.h"
#include "libguile/threads.h"
SCM_API SCM scm_cell (scm_t_bits car, scm_t_bits cdr);
@ -79,15 +80,23 @@ SCM
scm_cell (scm_t_bits car, scm_t_bits cdr)
{
SCM z;
/* We retrieve the SCM pointer only once since the call to
SCM_FREELIST_LOC will be slightly expensive when we support
preemptive multithreading. SCM_FREELIST_DOC will then retrieve
the thread specific freelist.
if (SCM_NULLP (scm_i_freelist))
{
z = scm_gc_for_newcell (&scm_i_master_freelist, &scm_i_freelist);
}
Until then, SCM_FREELIST_DOC expands to (&scm_i_freelist) and the
following code will compile to the same as if we had worked
directly on the scm_i_freelist variable.
*/
SCM *freelist = SCM_FREELIST_LOC (scm_i_freelist);
if (SCM_NULLP (*freelist))
z = scm_gc_for_newcell (&scm_i_master_freelist, freelist);
else
{
z = scm_i_freelist;
scm_i_freelist = SCM_FREE_CELL_CDR (scm_i_freelist);
z = *freelist;
*freelist = SCM_FREE_CELL_CDR (*freelist);
}
/*
@ -136,6 +145,7 @@ scm_cell (scm_t_bits car, scm_t_bits cdr)
SCM_GC_SET_CELL_WORD (z, 1, cdr);
SCM_GC_SET_CELL_WORD (z, 0, car);
#if 0 /*fixme* Hmm... let's consider this later. */
#if !defined(USE_COOP_THREADS) && !defined(USE_NULL_THREADS) && !defined(USE_COPT_THREADS)
/* When we are using preemtive threads, we might need to make
sure that the initial values for the slots are protected until
@ -144,7 +154,7 @@ scm_cell (scm_t_bits car, scm_t_bits cdr)
#error review me
scm_remember_upto_here_1 (SCM_PACK (cdr));
#endif
#endif
#if (SCM_DEBUG_CELL_ACCESSES == 1)
if (scm_expensive_debug_cell_accesses_p )
@ -160,16 +170,14 @@ scm_double_cell (scm_t_bits car, scm_t_bits cbr,
scm_t_bits ccr, scm_t_bits cdr)
{
SCM z;
SCM *freelist = SCM_FREELIST_LOC (scm_i_freelist2);
if (SCM_NULLP (scm_i_freelist2))
{
z = scm_gc_for_newcell (&scm_i_master_freelist2, &scm_i_freelist2);
}
if (SCM_NULLP (*freelist))
z = scm_gc_for_newcell (&scm_i_master_freelist2, freelist);
else
{
z = scm_i_freelist2;
scm_i_freelist2 = SCM_FREE_CELL_CDR (scm_i_freelist2);
z = *freelist;
*freelist = SCM_FREE_CELL_CDR (*freelist);
}
scm_cells_allocated += 2;
@ -185,6 +193,7 @@ scm_double_cell (scm_t_bits car, scm_t_bits cbr,
SCM_GC_SET_CELL_WORD (z, 3, cdr);
SCM_GC_SET_CELL_WORD (z, 0, car);
#if 0 /*fixme* Hmm... let's consider this later. */
#if !defined(USE_COOP_THREADS) && !defined(USE_NULL_THREADS) && !defined(USE_COPT_THREADS)
/* When we are using non-cooperating threads, we might need to make
sure that the initial values for the slots are protected until
@ -193,6 +202,7 @@ scm_double_cell (scm_t_bits car, scm_t_bits cbr,
#error review me
scm_remember_upto_here_3 (SCM_PACK (cbr), SCM_PACK (ccr), SCM_PACK (cdr));
#endif
#endif
#if (SCM_DEBUG_CELL_ACCESSES == 1)

View file

@ -50,6 +50,8 @@
no new threads can be created.
*/
#error temporarily broken, compile with threads enabled (default option)
/* We can't switch so don't bother trying.
*/
#undef SCM_THREAD_SWITCHING_CODE

View file

@ -46,49 +46,52 @@
/* The pthreads-threads implementation. This is a very simple mapping.
/* The pthreads-threads implementation. This is a direct mapping.
*/
/* This is an interface between Guile and the pthreads thread package. */
#include <pthread.h>
#define scm_t_thread pthread_t
/* MDJ 021209 <djurfeldt@nada.kth.se>:
The separation of the plugin interface and the low-level C API
(currently in threads.h) needs to be completed in a sensible way.
*/
#define scm_thread_create(th,proc,data) \
pthread_create ((th), NULL, (void *(*)(void *))(proc), (data))
/* The scm_t_ types are temporarily used both in plugin and low-level API */
#define scm_t_thread pthread_t
#define scm_thread_join(th) pthread_join (th, NULL)
#define scm_thread_detach(th) pthread_detach (th)
#define scm_thread_self() pthread_self ()
#define scm_i_plugin_thread_create pthread_create
#define scm_t_mutex pthread_mutex_t
#define scm_i_plugin_thread_join pthread_join
#define scm_i_plugin_thread_detach pthread_detach
#define scm_i_plugin_thread_self pthread_self
#define scm_mutex_init(mx) pthread_mutex_init (mx, NULL)
#define scm_mutex_destroy(mx) pthread_mutex_destroy (mx)
#define scm_mutex_lock(mx) pthread_mutex_lock (mx)
#define scm_mutex_trylock(mx) pthread_mutex_trylock (mx)
#define scm_mutex_unlock(mx) pthread_mutex_unlock (mx)
#define scm_t_mutex pthread_mutex_t
#define scm_t_cond pthread_cond_t
#define scm_i_plugin_mutex_init pthread_mutex_init
#define scm_i_plugin_mutex_destroy pthread_mutex_destroy
#define scm_i_plugin_mutex_lock pthread_mutex_lock
#define scm_i_plugin_mutex_trylock pthread_mutex_trylock
#define scm_i_plugin_mutex_unlock pthread_mutex_unlock
#define scm_cond_init(cv) pthread_cond_init (cv, NULL)
#define scm_cond_destroy(cv) pthread_cond_destroy (cv)
#define scm_cond_wait(cv,mx) pthread_cond_wait (cv, mx)
#define scm_cond_timedwait(cv,mx,at) \
pthread_cond_timedwait (cv, mx, at)
#define scm_cond_signal(cv) pthread_cond_signal (cv)
#define scm_cond_broadcast(cv) \
pthread_cond_broadcast (cv)
#define scm_t_cond pthread_cond_t
#define scm_t_key pthread_key_t
#define scm_i_plugin_cond_init pthread_cond_init
#define scm_i_plugin_cond_destroy pthread_cond_destroy
#define scm_i_plugin_cond_wait pthread_cond_wait
#define scm_i_plugin_cond_timedwait pthread_cond_timedwait
#define scm_i_plugin_cond_signal pthread_cond_signal
#define scm_i_plugin_cond_broadcast pthread_cond_broadcast
#define scm_key_create(keyp) pthread_key_create (keyp, NULL)
#define scm_key_delete(key) pthread_key_delete (key)
#define scm_key_setspecific(key, value) \
pthread_setspecific (key, value)
#define scm_key_getspecific(key) \
pthread_getspecific (key)
#define scm_t_key pthread_key_t
#define scm_thread_select select
#define scm_i_plugin_key_create pthread_key_create
#define scm_i_plugin_key_delete pthread_key_delete
#define scm_i_plugin_setspecific pthread_setspecific
#define scm_i_plugin_getspecific pthread_getspecific
#define scm_i_plugin_select select
#endif /* SCM_THREADS_NULL_H */

View file

@ -203,6 +203,34 @@ SCM_SNARF_INIT(c_name = scm_permanent_object (scm_c_define (scheme_name, init_va
SCM_SNARF_HERE(SCM c_name) \
SCM_SNARF_INIT(c_name = scm_permanent_object (scm_c_define (scheme_name, init_val));)
#define SCM_NONREC_CRITICAL_SECTION(prefix) \
SCM_SNARF_HERE(static scm_t_mutex prefix ## _mutex) \
SCM_SNARF_INIT(scm_i_plugin_mutex_init (&prefix ## _mutex, 0))
#define SCM_GLOBAL_NONREC_CRITICAL_SECTION(prefix) \
SCM_SNARF_HERE(scm_t_mutex prefix ## _mutex) \
SCM_SNARF_INIT(scm_i_plugin_mutex_init (&prefix ## _mutex, 0))
#define SCM_REC_CRITICAL_SECTION(prefix) \
SCM_SNARF_HERE(\
static scm_t_mutex prefix ## _mutex; \
static int prefix ## _count; \
static scm_thread *prefix ## _owner\
)SCM_SNARF_INIT(\
scm_i_plugin_mutex_init (&prefix ## _mutex, 0)\
)
#define SCM_GLOBAL_REC_CRITICAL_SECTION(prefix) \
SCM_SNARF_HERE(\
scm_t_mutex prefix ## _mutex; \
int prefix ## _count; \
scm_thread *prefix ## _owner\
)SCM_SNARF_INIT(\
scm_i_plugin_mutex_init (&prefix ## _mutex, 0); \
prefix ## _count = 0; \
prefix ## _owner = 0\
)
#ifdef SCM_MAGIC_SNARF_DOCS
#undef SCM_ASSERT
#define SCM_ASSERT(_cond, _arg, _pos, _subr) ^^ argpos _arg _pos __LINE__ ^^

File diff suppressed because it is too large Load diff

View file

@ -56,72 +56,152 @@
/* smob tags for the thread datatypes */
SCM_API scm_t_bits scm_tc16_thread;
SCM_API scm_t_bits scm_tc16_mutex;
SCM_API scm_t_bits scm_tc16_fair_mutex;
SCM_API scm_t_bits scm_tc16_condvar;
SCM_API scm_t_bits scm_tc16_fair_condvar;
#define SCM_THREADP(x) SCM_TYP16_PREDICATE (scm_tc16_thread, x)
#define SCM_THREAD_DATA(x) ((void *) SCM_CELL_WORD_1 (x))
#define SCM_THREADP(x) SCM_TYP16_PREDICATE (scm_tc16_thread, x)
#define SCM_THREAD_DATA(x) ((scm_thread *) SCM_CELL_WORD_1 (x))
#define SCM_MUTEXP(x) SCM_TYP16_PREDICATE (scm_tc16_mutex, x)
#define SCM_MUTEX_DATA(x) ((void *) SCM_CELL_WORD_1 (x))
#define SCM_MUTEXP(x) SCM_TYP16_PREDICATE (scm_tc16_mutex, x)
#define SCM_FAIR_MUTEX_P(x) SCM_TYP16_PREDICATE (scm_tc16_fair_mutex, x)
#define SCM_MUTEX_DATA(x) ((void *) SCM_CELL_WORD_1 (x))
#define SCM_CONDVARP(x) SCM_TYP16_PREDICATE (scm_tc16_condvar, x)
#define SCM_CONDVAR_DATA(x) ((void *) SCM_CELL_WORD_1 (x))
#define SCM_CONDVARP(x) SCM_TYP16_PREDICATE (scm_tc16_condvar, x)
#define SCM_FAIR_CONDVAR_P(x) SCM_TYP16_PREDICATE (scm_tc16_fair_condvar, x)
#define SCM_CONDVAR_DATA(x) ((void *) SCM_CELL_WORD_1 (x))
#define SCM_VALIDATE_THREAD(pos, a) \
SCM_MAKE_VALIDATE_MSG (pos, a, THREADP, "thread")
#define SCM_VALIDATE_MUTEX(pos, a) \
SCM_MAKE_VALIDATE_MSG (pos, a, MUTEXP, "mutex")
SCM_ASSERT_TYPE (SCM_MUTEXP (a) || SCM_FAIR_MUTEX_P (a), \
a, pos, FUNC_NAME, "mutex");
#define SCM_VALIDATE_CONDVAR(pos, a) \
SCM_MAKE_VALIDATE_MSG (pos, a, CONDVARP, "condition variable")
SCM_ASSERT_TYPE (SCM_CONDVARP (a) || SCM_FAIR_CONDVAR_P (a), \
a, pos, FUNC_NAME, "condition variable");
SCM_API void scm_threads_mark_stacks (void);
SCM_API void scm_init_threads (SCM_STACKITEM *);
SCM_API void scm_init_thread_procs (void);
/*----------------------------------------------------------------------*/
/* Low-level C API */
/* The purpose of this API is seamless, simple and thread package
independent interaction with Guile threads from the application.
*/
/* MDJ 021209 <djurfeldt@nada.kth.se>:
The separation of the plugin interface (currently in
pthread-threads.h and null-threads.h) and the low-level C API needs
to be completed in a sensible way.
*/
/* Deprecate this name and rename to scm_thread_create?
Introduce the other two arguments in pthread_create to prepare for
the future?
*/
SCM_API SCM scm_spawn_thread (scm_t_catch_body body, void *body_data,
scm_t_catch_handler handler, void *handler_data);
#define scm_thread_join scm_i_plugin_thread_join
#define scm_thread_detach scm_i_plugin_thread_detach
#define scm_thread_self scm_i_plugin_thread_self
#define scm_mutex_init scm_i_plugin_mutex_init
#define scm_mutex_destroy scm_i_plugin_mutex_destroy
SCM_API int scm_mutex_lock (scm_t_mutex *m);
#define scm_mutex_trylock scm_i_plugin_mutex_trylock
#define scm_mutex_unlock scm_i_plugin_mutex_unlock
#define scm_cond_init scm_i_plugin_cond_init
#define scm_cond_destroy scm_i_plugin_cond_destroy
SCM_API int scm_cond_wait (scm_t_cond *c, scm_t_mutex *m);
SCM_API int scm_cond_timedwait (scm_t_cond *c,
scm_t_mutex *m,
const struct timespec *t);
#define scm_cond_signal scm_i_plugin_cond_signal
#define scm_cond_broadcast scm_i_plugin_cond_broadcast
#define scm_key_create scm_i_plugin_key_create
#define scm_key_delete scm_i_plugin_key_delete
#define scm_setspecific scm_i_plugin_setspecific
#define scm_getspecific scm_i_plugin_getspecific
#define scm_thread_select scm_internal_select
/* The application must scm_leave_guile() before entering any piece of
code which can
1. block, or
2. execute for any longer period of time without calling SCM_TICK
Note, though, that it is *not* necessary to use these calls
together with any call in this API.
*/
SCM_API void scm_enter_guile (void);
SCM_API void scm_leave_guile (void);
/* Better versions (although we need the former ones also in order to
avoid forcing code restructuring in existing applications): */
/*fixme* Not implemented yet! */
SCM_API void *scm_in_guile (void (*func) (void*), void *data);
SCM_API void *scm_outside_guile (void (*func) (void*), void *data);
/* These are versions of the ordinary sleep and usleep functions
that play nicely with the thread system. */
SCM_API unsigned long scm_thread_sleep (unsigned long);
SCM_API unsigned long scm_thread_usleep (unsigned long);
/* End of low-level C API */
/*----------------------------------------------------------------------*/
typedef struct scm_thread scm_thread;
SCM_API void scm_i_enter_guile (scm_thread *t);
SCM_API scm_thread *scm_i_leave_guile (void);
/* Critical sections */
/* Since only one thread can be active anyway, we don't need to do
anything special around critical sections. In fact, that's the
reason we do only support cooperative threading: Guile's critical
regions have not been completely identified yet. (I think.) */
SCM_API scm_t_mutex scm_i_section_mutex;
#define SCM_CRITICAL_SECTION_START
#define SCM_CRITICAL_SECTION_END
/* This is the generic critical section for places where we are too
lazy to allocate a specific mutex. */
SCM_DECLARE_NONREC_CRITICAL_SECTION (scm_i_critical_section);
#define SCM_CRITICAL_SECTION_START \
SCM_NONREC_CRITICAL_SECTION_START (scm_i_critical_section)
#define SCM_CRITICAL_SECTION_END \
SCM_NONREC_CRITICAL_SECTION_END (scm_i_critical_section)
/* Switching */
/* This is the temporary support for the old ALLOW/DEFER ints sections */
SCM_DECLARE_REC_CRITICAL_SECTION (scm_i_defer);
SCM_API int scm_i_switch_counter;
#define SCM_I_THREAD_SWITCH_COUNT 50
extern int scm_i_thread_go_to_sleep;
void scm_i_thread_put_to_sleep (void);
void scm_i_thread_wake_up (void);
void scm_i_thread_sleep_for_gc (void);
void scm_threads_prehistory (void);
void scm_threads_init_first_thread (void);
#define SCM_THREAD_SWITCHING_CODE \
do { \
scm_i_switch_counter--; \
if (scm_i_switch_counter == 0) \
{ \
scm_i_switch_counter = SCM_I_THREAD_SWITCH_COUNT; \
scm_yield(); \
} \
if (scm_i_thread_go_to_sleep) \
scm_i_thread_sleep_for_gc (); \
} while (0)
/* The C versions of the Scheme-visible thread functions. */
SCM_API SCM scm_yield (void);
SCM_API SCM scm_call_with_new_thread (SCM thunk, SCM handler);
SCM_API SCM scm_join_thread (SCM t);
SCM_API SCM scm_make_mutex (void);
SCM_API SCM scm_make_fair_mutex (void);
SCM_API SCM scm_lock_mutex (SCM m);
SCM_API SCM scm_try_mutex (SCM m);
SCM_API SCM scm_unlock_mutex (SCM m);
SCM_API SCM scm_make_condition_variable (void);
SCM_API SCM scm_make_fair_condition_variable (void);
SCM_API SCM scm_wait_condition_variable (SCM cond, SCM mutex);
SCM_API SCM scm_timed_wait_condition_variable (SCM cond, SCM mutex,
SCM abstime);
@ -136,10 +216,16 @@ SCM_API SCM scm_thread_exited_p (SCM thread);
SCM_API scm_root_state *scm_i_thread_root (SCM thread);
SCM_API void *scm_i_thread_data;
SCM_API void scm_i_set_thread_data (void *);
#define SCM_THREAD_LOCAL_DATA scm_i_thread_data
#define SCM_CURRENT_THREAD \
((scm_thread *) scm_i_plugin_getspecific (scm_i_thread_key))
extern scm_t_key scm_i_thread_key;
/* These macros have confusing names.
They really refer to the root state of the running thread. */
#define SCM_THREAD_LOCAL_DATA (scm_i_plugin_getspecific (scm_i_root_state_key))
#define SCM_SET_THREAD_LOCAL_DATA(x) scm_i_set_thread_data(x)
extern scm_t_key scm_i_root_state_key;
SCM_API void scm_i_set_thread_data (void *);
#ifndef HAVE_STRUCT_TIMESPEC
/* POSIX.4 structure for a time value. This is like a `struct timeval' but
@ -151,7 +237,7 @@ struct timespec
};
#endif
#ifdef USE_COPT_THREADS
#ifdef USE_PTHREAD_THREADS
#include "libguile/pthread-threads.h"
#else
#include "libguile/null-threads.h"

View file

@ -59,7 +59,7 @@ SCM_DEFINE (scm_major_version, "major-version", 0, 0, 0,
"E.g., the 1 in \"1.6.5\".")
#define FUNC_NAME s_scm_major_version
{
return scm_number_to_string (SCM_MAKINUM(SCM_MAJOR_VERSION),
return scm_number_to_string (SCM_MAKINUM(1),
SCM_MAKINUM(10));
}
#undef FUNC_NAME
@ -72,7 +72,7 @@ SCM_DEFINE (scm_minor_version, "minor-version", 0, 0, 0,
"E.g., the 6 in \"1.6.5\".")
#define FUNC_NAME s_scm_minor_version
{
return scm_number_to_string (SCM_MAKINUM(SCM_MINOR_VERSION),
return scm_number_to_string (SCM_MAKINUM(7),
SCM_MAKINUM(10));
}
#undef FUNC_NAME
@ -85,7 +85,7 @@ SCM_DEFINE (scm_micro_version, "micro-version", 0, 0, 0,
"E.g., the 5 in \"1.6.5\".")
#define FUNC_NAME s_scm_micro_version
{
return scm_number_to_string (SCM_MAKINUM(SCM_MICRO_VERSION),
return scm_number_to_string (SCM_MAKINUM(0),
SCM_MAKINUM(10));
}
#undef FUNC_NAME
@ -110,15 +110,17 @@ SCM_DEFINE (scm_version, "version", 0, 0, 0,
char version_str[3 * 4 + 3];
#if 0
#if SCM_MAJOR_VERSION > 9999 \
|| SCM_MINOR_VERSION > 9999 \
|| SCM_MICRO_VERSION > 9999
# error version string may overflow buffer
#endif
#endif
sprintf (version_str, "%d.%d.%d",
SCM_MAJOR_VERSION,
SCM_MINOR_VERSION,
SCM_MICRO_VERSION);
1,
7,
0);
return scm_makfrom0str (version_str);
}
#undef FUNC_NAME
@ -140,10 +142,12 @@ SCM_DEFINE (scm_effective_version, "effective-version", 0, 0, 0,
char version_str[2 * 4 + 3];
#if 0
#if (SCM_MAJOR_VERSION > 9999 || SCM_MINOR_VERSION > 9999)
# error version string may overflow buffer
#endif
sprintf (version_str, "%d.%d", SCM_MAJOR_VERSION, SCM_MINOR_VERSION);
#endif
sprintf (version_str, "%d.%d", 1, 7);
return scm_makfrom0str (version_str);
}
#undef FUNC_NAME