1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 03:30:27 +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:
Andy Wingo 2016-11-01 23:48:42 +01:00
parent 4b78b001d8
commit fcc6a7ba20
8 changed files with 58 additions and 89 deletions

8
NEWS
View file

@ -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
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
** cancel-thread uses asynchronous interrupts, not pthread_cancel

View file

@ -13,7 +13,6 @@
* Atomics:: Atomic references.
* Mutexes and Condition Variables:: Synchronization primitives.
* Blocking:: How to block properly in guile mode.
* Critical Sections:: Avoiding concurrency and reentries.
* Fluids and Dynamic States:: Thread-local variables, etc.
* Parameters:: Dynamic scoping in Scheme.
* Futures:: Fine-grain parallelism.
@ -619,51 +618,6 @@ delivery of an async causes this function to be interrupted.
@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
@subsection Fluids and Dynamic States

View file

@ -298,31 +298,11 @@ scm_c_call_with_unblocked_asyncs (void *(*proc) (void *data), void *data)
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
scm_init_async ()
{
scm_i_pthread_mutex_init (&critical_section_mutex,
scm_i_pthread_mutexattr_recursive);
#include "libguile/async.x"
}

View file

@ -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_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);
#endif /* SCM_ASYNC_H */

View file

@ -639,6 +639,44 @@ SCM_DEFINE (scm_run_asyncs, "run-asyncs", 1, 0, 0,
}
#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_set_smob_print (scm_tc16_arbiter, arbiter_print);
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"
}

View file

@ -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);
#endif

View file

@ -1938,17 +1938,6 @@ static scm_i_pthread_cond_t wake_up_cond;
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 */
scm_i_pthread_mutex_t scm_i_misc_mutex;
@ -2011,8 +2000,6 @@ scm_init_threads ()
guilify_self_2 (SCM_BOOL_F);
threads_initialized_p = 1;
dynwind_critical_section_mutex = scm_make_recursive_mutex ();
scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
"scm_init_ice_9_threads",
scm_init_ice_9_threads, NULL);

View file

@ -178,8 +178,6 @@ SCM_API SCM scm_all_threads (void);
SCM_API int scm_c_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
/* Though we don't need the key for SCM_I_CURRENT_THREAD if we have TLS,