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:
Jérôme Duval
2024-05-02 18:07:23 +00:00
committed by waddlesplash
parent 7866929cf9
commit f758e73fe6
6 changed files with 149 additions and 2 deletions
+1
View File
@@ -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
}
+1 -1
View File
@@ -7,7 +7,7 @@
#include_next <pthread.h>
#include <features.h>
#ifdef _GNU_SOURCE
+1 -1
View File
@@ -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 ;
+25
View File
@@ -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);
}
+1
View File
@@ -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();
}