mirror of
https://https.git.savannah.gnu.org/git/gnulib.git
synced 2026-04-28 06:33:36 +00:00
Suggested by Paul Eggert. * lib/asyncsafe-spin.c (asyncsafe_spin_lock, asyncsafe_spin_unlock): Use pthread_sigmask instead of sigprocmask. * modules/asyncsafe-spin (Depends-on): Add pthread_sigmask. Remove sigprocmask. (Link): New section. * modules/asyncsafe-spin-tests (Makefile.am): Link test-asyncsafe-spin1 with $(PTHREAD_SIGMASK_LIB). * modules/jit/cache-tests (Makefile.am): Link test-cache with $(PTHREAD_SIGMASK_LIB).
81 lines
2.8 KiB
C
81 lines
2.8 KiB
C
/* Spin locks for communication between threads and signal handlers.
|
|
Copyright (C) 2020-2026 Free Software Foundation, Inc.
|
|
|
|
This file is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as
|
|
published by the Free Software Foundation; either version 2.1 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This file is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
/* Written by Bruno Haible <bruno@clisp.org>, 2020. */
|
|
|
|
#include <config.h>
|
|
|
|
/* Specification. */
|
|
#include "asyncsafe-spin.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
void
|
|
asyncsafe_spin_init (asyncsafe_spinlock_t *lock)
|
|
{
|
|
glthread_spinlock_init (lock);
|
|
}
|
|
|
|
void
|
|
asyncsafe_spin_lock (asyncsafe_spinlock_t *lock,
|
|
bool from_signal_handler,
|
|
const sigset_t *mask, sigset_t *saved_mask)
|
|
{
|
|
/* On all platforms, when not running in a signal handler, we need to block
|
|
the signals until the corresponding asyncsafe_spin_unlock() invocation.
|
|
This is needed because if, during that period, a signal occurred and it
|
|
happened to run in the current thread and it were to wait on this spin
|
|
lock, it would hang.
|
|
On platforms other than native Windows, it is useful to do the same
|
|
thing also within a signal handler, since signals may remain enabled
|
|
while a signal handler runs. It is possible to do this because
|
|
pthread_sigmask() is safe to call from within a signal handler, see
|
|
POSIX section "Signal Actions"
|
|
<https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_04_03>.
|
|
(In other words, pthread_sigmask() is atomic, because it is implemented as a
|
|
system call.)
|
|
Whereas on native Windows, pthread_sigmask() = sigprocmask() is not atomic,
|
|
because it manipulates global variables. Therefore in this case, we are
|
|
*not* allowed to call it from within a signal handler. */
|
|
|
|
#if defined _WIN32 && !defined __CYGWIN__
|
|
if (!from_signal_handler)
|
|
#endif
|
|
pthread_sigmask (SIG_BLOCK, mask, saved_mask);
|
|
|
|
glthread_spinlock_lock (lock);
|
|
}
|
|
|
|
void
|
|
asyncsafe_spin_unlock (asyncsafe_spinlock_t *lock,
|
|
bool from_signal_handler,
|
|
const sigset_t *saved_mask)
|
|
{
|
|
if (glthread_spinlock_unlock (lock))
|
|
abort ();
|
|
|
|
#if defined _WIN32 && !defined __CYGWIN__
|
|
if (!from_signal_handler)
|
|
#endif
|
|
pthread_sigmask (SIG_SETMASK, saved_mask, NULL);
|
|
}
|
|
|
|
void
|
|
asyncsafe_spin_destroy (asyncsafe_spinlock_t *lock)
|
|
{
|
|
glthread_spinlock_destroy (lock);
|
|
}
|