libbsd: add pthread_sigqueue()
* like sigqueue() but for threads. was added recently to FreeBSD, long before to glibc. * also include features.h in gnu/pthread.h Change-Id: I73bca666e2c67d7ff05f341bf85d71df9ccccbe5 Reviewed-on: https://review.haiku-os.org/c/haiku/+/7659 Reviewed-by: waddlesplash <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
7866929cf9
commit
f758e73fe6
@@ -22,6 +22,7 @@ extern "C" {
|
||||
|
||||
int sigsetmask(int mask);
|
||||
int sigblock(int mask);
|
||||
int pthread_sigqueue(pthread_t thread, int sig, const union sigval value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
|
||||
#include_next <pthread.h>
|
||||
|
||||
#include <features.h>
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SubDir HAIKU_TOP src libs bsd ;
|
||||
|
||||
UsePrivateHeaders system ;
|
||||
UsePrivateHeaders libroot shared system ;
|
||||
UsePrivateHeaders [ FDirName system arch $(TARGET_ARCH) ] ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <pthread_private.h>
|
||||
#include <signal_defs.h>
|
||||
#include <syscalls.h>
|
||||
#include <syscall_utils.h>
|
||||
|
||||
|
||||
int
|
||||
sigsetmask(int mask)
|
||||
@@ -35,3 +42,21 @@ sigblock(int mask)
|
||||
return (int)oset;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pthread_sigqueue(pthread_t thread, int sig, const union sigval userValue)
|
||||
{
|
||||
status_t error;
|
||||
if (signal < 0)
|
||||
RETURN_AND_SET_ERRNO(EINVAL);
|
||||
|
||||
error = _kern_send_signal(thread->id, sig, &userValue,
|
||||
SIGNAL_FLAG_SEND_TO_THREAD | SIGNAL_FLAG_QUEUING_REQUIRED);
|
||||
if (error != B_OK) {
|
||||
// translate B_BAD_THREAD_ID/B_BAD_TEAM_ID to ESRCH
|
||||
if (error == B_BAD_THREAD_ID || error == B_BAD_TEAM_ID)
|
||||
error = ESRCH;
|
||||
}
|
||||
|
||||
RETURN_AND_SET_ERRNO(error);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ SimpleTest tst-wscanf : tst-wscanf.c ;
|
||||
SimpleTest test_wcfuncs : test_wcfuncs.c ;
|
||||
SimpleTest test_wctype : test_wctype.c ;
|
||||
SimpleTest wcs_test : wcs_test.cpp ;
|
||||
SimpleTest pthread_sigqueue : pthread_sigqueue.cpp : [ TargetLibstdc++ ] libbsd.so ;
|
||||
|
||||
UnitTestLib librootposixtest.so :
|
||||
LibRootPosix.cpp
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2024, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Jérôme Duval, [email protected]
|
||||
* Inspired from Android signal_test.cpp
|
||||
*/
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define ASSERT_EQ(x,y) { if (x != y) { fprintf(stderr, "assert failed %s %s\n", #x, #y); exit(1); }}
|
||||
#define ASSERT_ERRNO(x) ASSERT_EQ(errno, x)
|
||||
|
||||
|
||||
class ScopedSignalHandler
|
||||
{
|
||||
public:
|
||||
ScopedSignalHandler(int signal, void (*handler)(int, siginfo_t*, void*))
|
||||
: signalNumber(signal)
|
||||
{
|
||||
sigemptyset(&action.sa_mask);
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
action.sa_sigaction = handler;
|
||||
sigaction(signalNumber, &action, &oldAction);
|
||||
}
|
||||
~ScopedSignalHandler()
|
||||
{
|
||||
sigaction(signalNumber, &oldAction, NULL);
|
||||
}
|
||||
private:
|
||||
struct sigaction action;
|
||||
struct sigaction oldAction;
|
||||
const int signalNumber;
|
||||
};
|
||||
|
||||
static int gSigqueueSignalHandlerCallCount = 0;
|
||||
|
||||
static void
|
||||
SigqueueSignalHandler(int signum, siginfo_t* info, void*)
|
||||
{
|
||||
ASSERT_EQ(SIGALRM, signum);
|
||||
ASSERT_EQ(SIGALRM, info->si_signo);
|
||||
ASSERT_EQ(SI_QUEUE, info->si_code);
|
||||
ASSERT_EQ(1, info->si_value.sival_int);
|
||||
++gSigqueueSignalHandlerCallCount;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
signal_sigqueue()
|
||||
{
|
||||
gSigqueueSignalHandlerCallCount = 0;
|
||||
ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler);
|
||||
sigval sigval = {.sival_int = 1};
|
||||
errno = 0;
|
||||
ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
|
||||
ASSERT_ERRNO(0);
|
||||
ASSERT_EQ(1, gSigqueueSignalHandlerCallCount);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
signal_pthread_sigqueue_self()
|
||||
{
|
||||
gSigqueueSignalHandlerCallCount = 0;
|
||||
ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler);
|
||||
sigval sigval = {.sival_int = 1};
|
||||
errno = 0;
|
||||
ASSERT_EQ(0, pthread_sigqueue(pthread_self(), SIGALRM, sigval));
|
||||
ASSERT_ERRNO(0);
|
||||
ASSERT_EQ(1, gSigqueueSignalHandlerCallCount);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
signal_pthread_sigqueue_other()
|
||||
{
|
||||
gSigqueueSignalHandlerCallCount = 0;
|
||||
ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler);
|
||||
sigval sigval = {.sival_int = 1};
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
pthread_sigmask(SIG_SETMASK, &mask, nullptr);
|
||||
pthread_t thread;
|
||||
int rc = pthread_create(&thread, nullptr,
|
||||
[](void*) -> void* {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigsuspend(&mask);
|
||||
return nullptr;
|
||||
}, nullptr);
|
||||
ASSERT_EQ(0, rc);
|
||||
errno = 0;
|
||||
ASSERT_EQ(0, pthread_sigqueue(thread, SIGALRM, sigval));
|
||||
ASSERT_ERRNO(0);
|
||||
pthread_join(thread, nullptr);
|
||||
ASSERT_EQ(1, gSigqueueSignalHandlerCallCount);
|
||||
}
|
||||
|
||||
|
||||
extern "C" int
|
||||
main()
|
||||
{
|
||||
printf("signal_sigqueue\n");
|
||||
signal_sigqueue();
|
||||
printf("signal_pthread_sigqueue_self\n");
|
||||
signal_pthread_sigqueue_self();
|
||||
printf("signal_pthread_sigqueue_other\n");
|
||||
signal_pthread_sigqueue_other();
|
||||
}
|
||||
Reference in New Issue
Block a user