mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Deprecate critical sections
* NEWS: Deprecate critical sections. * doc/ref/api-scheduling.texi (Critical Sections): Remove. * libguile/async.c: * libguile/async.h: * libguile/deprecated.c: * libguile/deprecated.h: * libguile/threads.c: * libguile/threads.h: Deprecate critical section API.
This commit is contained in:
parent
4b78b001d8
commit
fcc6a7ba20
8 changed files with 58 additions and 89 deletions
8
NEWS
8
NEWS
|
@ -43,6 +43,14 @@ trivial unused data structure. Now that we have deprecated the old
|
||||||
"user async" facility, we have been able to clarify our documentation to
|
"user async" facility, we have been able to clarify our documentation to
|
||||||
only refer to "asyncs".
|
only refer to "asyncs".
|
||||||
|
|
||||||
|
** Critical sections deprecated
|
||||||
|
|
||||||
|
Critical sections have long been just a fancy way to lock a mutex and
|
||||||
|
defer asynchronous interrupts. Instead of SCM_CRITICAL_SECTION_START,
|
||||||
|
make sure you're in a "scm_dynwind_begin (0)" and use
|
||||||
|
scm_dynwind_pthread_mutex_lock instead, possibly also with
|
||||||
|
scm_dynwind_block_asyncs.
|
||||||
|
|
||||||
* Bug fixes
|
* Bug fixes
|
||||||
** cancel-thread uses asynchronous interrupts, not pthread_cancel
|
** cancel-thread uses asynchronous interrupts, not pthread_cancel
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
* Atomics:: Atomic references.
|
* Atomics:: Atomic references.
|
||||||
* Mutexes and Condition Variables:: Synchronization primitives.
|
* Mutexes and Condition Variables:: Synchronization primitives.
|
||||||
* Blocking:: How to block properly in guile mode.
|
* Blocking:: How to block properly in guile mode.
|
||||||
* Critical Sections:: Avoiding concurrency and reentries.
|
|
||||||
* Fluids and Dynamic States:: Thread-local variables, etc.
|
* Fluids and Dynamic States:: Thread-local variables, etc.
|
||||||
* Parameters:: Dynamic scoping in Scheme.
|
* Parameters:: Dynamic scoping in Scheme.
|
||||||
* Futures:: Fine-grain parallelism.
|
* Futures:: Fine-grain parallelism.
|
||||||
|
@ -619,51 +618,6 @@ delivery of an async causes this function to be interrupted.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
|
|
||||||
@node Critical Sections
|
|
||||||
@subsection Critical Sections
|
|
||||||
|
|
||||||
@deffn {C Macro} SCM_CRITICAL_SECTION_START
|
|
||||||
@deffnx {C Macro} SCM_CRITICAL_SECTION_END
|
|
||||||
These two macros can be used to delimit a critical section.
|
|
||||||
Syntactically, they are both statements and need to be followed
|
|
||||||
immediately by a semicolon.
|
|
||||||
|
|
||||||
Executing @code{SCM_CRITICAL_SECTION_START} will lock a recursive mutex
|
|
||||||
and block the executing of asyncs. Executing
|
|
||||||
@code{SCM_CRITICAL_SECTION_END} will unblock the execution of system
|
|
||||||
asyncs and unlock the mutex. Thus, the code that executes between these
|
|
||||||
two macros can only be executed in one thread at any one time and no
|
|
||||||
asyncs will run. However, because the mutex is a recursive one, the
|
|
||||||
code might still be reentered by the same thread. You must either allow
|
|
||||||
for this or avoid it, both by careful coding.
|
|
||||||
|
|
||||||
On the other hand, critical sections delimited with these macros can
|
|
||||||
be nested since the mutex is recursive.
|
|
||||||
|
|
||||||
You must make sure that for each @code{SCM_CRITICAL_SECTION_START},
|
|
||||||
the corresponding @code{SCM_CRITICAL_SECTION_END} is always executed.
|
|
||||||
This means that no non-local exit (such as a signalled error) might
|
|
||||||
happen, for example.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_dynwind_critical_section (SCM mutex)
|
|
||||||
Call @code{scm_dynwind_lock_mutex} on @var{mutex} and call
|
|
||||||
@code{scm_dynwind_block_asyncs}. When @var{mutex} is false, a recursive
|
|
||||||
mutex provided by Guile is used instead.
|
|
||||||
|
|
||||||
The effect of a call to @code{scm_dynwind_critical_section} is that
|
|
||||||
the current dynwind context (@pxref{Dynamic Wind}) turns into a
|
|
||||||
critical section. Because of the locked mutex, no second thread can
|
|
||||||
enter it concurrently and because of the blocked asyncs, no system
|
|
||||||
async can reenter it from the current thread.
|
|
||||||
|
|
||||||
When the current thread reenters the critical section anyway, the kind
|
|
||||||
of @var{mutex} determines what happens: When @var{mutex} is recursive,
|
|
||||||
the reentry is allowed. When it is a normal mutex, an error is
|
|
||||||
signalled.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
|
|
||||||
@node Fluids and Dynamic States
|
@node Fluids and Dynamic States
|
||||||
@subsection Fluids and Dynamic States
|
@subsection Fluids and Dynamic States
|
||||||
|
|
||||||
|
|
|
@ -298,31 +298,11 @@ scm_c_call_with_unblocked_asyncs (void *(*proc) (void *data), void *data)
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static scm_i_pthread_mutex_t critical_section_mutex;
|
|
||||||
|
|
||||||
void
|
|
||||||
scm_critical_section_start (void)
|
|
||||||
{
|
|
||||||
scm_i_pthread_mutex_lock (&critical_section_mutex);
|
|
||||||
SCM_I_CURRENT_THREAD->block_asyncs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
scm_critical_section_end (void)
|
|
||||||
{
|
|
||||||
SCM_I_CURRENT_THREAD->block_asyncs--;
|
|
||||||
scm_i_pthread_mutex_unlock (&critical_section_mutex);
|
|
||||||
scm_async_tick ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_init_async ()
|
scm_init_async ()
|
||||||
{
|
{
|
||||||
scm_i_pthread_mutex_init (&critical_section_mutex,
|
|
||||||
scm_i_pthread_mutexattr_recursive);
|
|
||||||
#include "libguile/async.x"
|
#include "libguile/async.x"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,14 +46,6 @@ SCM_API void *scm_c_call_with_unblocked_asyncs (void *(*p) (void *d), void *d);
|
||||||
SCM_API void scm_dynwind_block_asyncs (void);
|
SCM_API void scm_dynwind_block_asyncs (void);
|
||||||
SCM_API void scm_dynwind_unblock_asyncs (void);
|
SCM_API void scm_dynwind_unblock_asyncs (void);
|
||||||
|
|
||||||
/* Critical sections */
|
|
||||||
|
|
||||||
SCM_API void scm_critical_section_start (void);
|
|
||||||
SCM_API void scm_critical_section_end (void);
|
|
||||||
|
|
||||||
#define SCM_CRITICAL_SECTION_START scm_critical_section_start ()
|
|
||||||
#define SCM_CRITICAL_SECTION_END scm_critical_section_end ()
|
|
||||||
|
|
||||||
SCM_INTERNAL void scm_init_async (void);
|
SCM_INTERNAL void scm_init_async (void);
|
||||||
|
|
||||||
#endif /* SCM_ASYNC_H */
|
#endif /* SCM_ASYNC_H */
|
||||||
|
|
|
@ -639,6 +639,44 @@ SCM_DEFINE (scm_run_asyncs, "run-asyncs", 1, 0, 0,
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
|
||||||
|
static scm_i_pthread_mutex_t critical_section_mutex;
|
||||||
|
static SCM dynwind_critical_section_mutex;
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_critical_section_start (void)
|
||||||
|
{
|
||||||
|
scm_c_issue_deprecation_warning
|
||||||
|
("Critical sections are deprecated. Instead use dynwinds and "
|
||||||
|
"\"scm_dynwind_pthread_mutex_lock\" together with "
|
||||||
|
"\"scm_dynwind_block_asyncs\" if appropriate.");
|
||||||
|
|
||||||
|
scm_i_pthread_mutex_lock (&critical_section_mutex);
|
||||||
|
SCM_I_CURRENT_THREAD->block_asyncs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_critical_section_end (void)
|
||||||
|
{
|
||||||
|
SCM_I_CURRENT_THREAD->block_asyncs--;
|
||||||
|
scm_i_pthread_mutex_unlock (&critical_section_mutex);
|
||||||
|
scm_async_tick ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_dynwind_critical_section (SCM mutex)
|
||||||
|
{
|
||||||
|
scm_c_issue_deprecation_warning
|
||||||
|
("Critical sections are deprecated. Instead use dynwinds and "
|
||||||
|
"\"scm_dynwind_pthread_mutex_lock\" together with "
|
||||||
|
"\"scm_dynwind_block_asyncs\" if appropriate.");
|
||||||
|
|
||||||
|
if (scm_is_false (mutex))
|
||||||
|
mutex = dynwind_critical_section_mutex;
|
||||||
|
scm_dynwind_lock_mutex (mutex);
|
||||||
|
scm_dynwind_block_asyncs ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -648,6 +686,9 @@ scm_i_init_deprecated ()
|
||||||
scm_tc16_arbiter = scm_make_smob_type ("arbiter", 0);
|
scm_tc16_arbiter = scm_make_smob_type ("arbiter", 0);
|
||||||
scm_set_smob_print (scm_tc16_arbiter, arbiter_print);
|
scm_set_smob_print (scm_tc16_arbiter, arbiter_print);
|
||||||
tc16_async = scm_make_smob_type ("async", 0);
|
tc16_async = scm_make_smob_type ("async", 0);
|
||||||
|
scm_i_pthread_mutex_init (&critical_section_mutex,
|
||||||
|
scm_i_pthread_mutexattr_recursive);
|
||||||
|
dynwind_critical_section_mutex = scm_make_recursive_mutex ();
|
||||||
#include "libguile/deprecated.x"
|
#include "libguile/deprecated.x"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,15 @@ SCM_DEPRECATED SCM scm_run_asyncs (SCM list_of_a);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SCM_DEPRECATED void scm_critical_section_start (void);
|
||||||
|
SCM_DEPRECATED void scm_critical_section_end (void);
|
||||||
|
SCM_DEPRECATED void scm_dynwind_critical_section (SCM mutex);
|
||||||
|
|
||||||
|
#define SCM_CRITICAL_SECTION_START scm_critical_section_start ()
|
||||||
|
#define SCM_CRITICAL_SECTION_END scm_critical_section_end ()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void scm_i_init_deprecated (void);
|
void scm_i_init_deprecated (void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1938,17 +1938,6 @@ static scm_i_pthread_cond_t wake_up_cond;
|
||||||
static int threads_initialized_p = 0;
|
static int threads_initialized_p = 0;
|
||||||
|
|
||||||
|
|
||||||
static SCM dynwind_critical_section_mutex;
|
|
||||||
|
|
||||||
void
|
|
||||||
scm_dynwind_critical_section (SCM mutex)
|
|
||||||
{
|
|
||||||
if (scm_is_false (mutex))
|
|
||||||
mutex = dynwind_critical_section_mutex;
|
|
||||||
scm_dynwind_lock_mutex (mutex);
|
|
||||||
scm_dynwind_block_asyncs ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** Initialization */
|
/*** Initialization */
|
||||||
|
|
||||||
scm_i_pthread_mutex_t scm_i_misc_mutex;
|
scm_i_pthread_mutex_t scm_i_misc_mutex;
|
||||||
|
@ -2011,8 +2000,6 @@ scm_init_threads ()
|
||||||
guilify_self_2 (SCM_BOOL_F);
|
guilify_self_2 (SCM_BOOL_F);
|
||||||
threads_initialized_p = 1;
|
threads_initialized_p = 1;
|
||||||
|
|
||||||
dynwind_critical_section_mutex = scm_make_recursive_mutex ();
|
|
||||||
|
|
||||||
scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
|
scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
|
||||||
"scm_init_ice_9_threads",
|
"scm_init_ice_9_threads",
|
||||||
scm_init_ice_9_threads, NULL);
|
scm_init_ice_9_threads, NULL);
|
||||||
|
|
|
@ -178,8 +178,6 @@ SCM_API SCM scm_all_threads (void);
|
||||||
SCM_API int scm_c_thread_exited_p (SCM thread);
|
SCM_API int scm_c_thread_exited_p (SCM thread);
|
||||||
SCM_API SCM scm_thread_exited_p (SCM thread);
|
SCM_API SCM scm_thread_exited_p (SCM thread);
|
||||||
|
|
||||||
SCM_API void scm_dynwind_critical_section (SCM mutex);
|
|
||||||
|
|
||||||
#ifdef BUILDING_LIBGUILE
|
#ifdef BUILDING_LIBGUILE
|
||||||
|
|
||||||
/* Though we don't need the key for SCM_I_CURRENT_THREAD if we have TLS,
|
/* Though we don't need the key for SCM_I_CURRENT_THREAD if we have TLS,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue