* __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:
parent
fc85d09560
commit
9bc4701cd3
19 changed files with 995 additions and 491 deletions
|
|
@ -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.
|
||||
|
|
|
|||
10
configure.in
10
configure.in
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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}:
|
||||
|
|
|
|||
128
libguile/__scm.h
128
libguile/__scm.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue