Skip to content

Commit

Permalink
libc: support sigwait - WiP
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-ab committed Sep 26, 2024
1 parent abadc39 commit f2a0e50
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 8 deletions.
1 change: 1 addition & 0 deletions repos/libports/lib/symbols/libc
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ sigsetjmp T
sigsetmask T
sigsuspend W
sigvec T
sigwait T
sl_add T
sl_find T
sl_free T
Expand Down
1 change: 0 additions & 1 deletion repos/libports/src/lib/libc/dummies.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ DUMMY(int, -1, thr_kill2, (pid_t pid, long id, int sig));
__SYS_DUMMY(int, -1, sigsuspend, (const sigset_t *))
__SYS_DUMMY(int, -1, sigtimedwait, (const sigset_t *, siginfo_t *, const struct timespec *));
__SYS_DUMMY(int, -1, sigwaitinfo, (const sigset_t *, siginfo_t *));
__SYS_DUMMY(int, -1, sigwait, (const sigset_t *, int *));
__SYS_DUMMY(int, -1, thr_kill, (long id, int sig));


Expand Down
2 changes: 1 addition & 1 deletion repos/libports/src/lib/libc/internal/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ namespace Libc {
/**
* Signal handling
*/
void init_signal(Signal &);
void init_signal(Signal &, Monitor &);

/**
* Atexit handling
Expand Down
4 changes: 3 additions & 1 deletion repos/libports/src/lib/libc/internal/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ struct Libc::Signal : Noncopyable
{
public:

struct sigaction signal_action[NSIG + 1] { };
struct sigaction signal_action [NSIG + 1] { };
unsigned signal_count [NSIG + 1] { };
bool signal_sigwait[NSIG + 1] { };

private:

Expand Down
2 changes: 1 addition & 1 deletion repos/libports/src/lib/libc/kernel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap)
init_select(*this);
init_socket_fs(*this, *this);
init_passwd(_passwd_config());
init_signal(_signal);
init_signal(_signal, *this);

_init_file_descriptors();

Expand Down
84 changes: 80 additions & 4 deletions repos/libports/src/lib/libc/signal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

/*
* Copyright (C) 2006-2019 Genode Labs GmbH
* Copyright (C) 2006-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
Expand All @@ -26,21 +26,30 @@ extern "C" {
#include <internal/init.h>
#include <internal/signal.h>
#include <internal/errno.h>
#include <internal/monitor.h>

using namespace Libc;


static Libc::Signal *_signal_ptr;
static Monitor *_monitor_ptr;


void Libc::init_signal(Signal &signal)
void Libc::init_signal(Signal &signal, Monitor &monitor)
{
_signal_ptr = &signal;
_signal_ptr = &signal;
_monitor_ptr = &monitor;
}


void Libc::Signal::_execute_signal_handler(unsigned n)
void Libc::Signal::_execute_signal_handler(unsigned const n)
{
signal_count[n] ++;

if (signal_sigwait[n])
/* the blocked thread is woken by sigwait() in monitor() */
return;

if (signal_action[n].sa_flags & SA_SIGINFO) {
signal_action[n].sa_sigaction(n, 0, 0);
return;
Expand Down Expand Up @@ -266,3 +275,70 @@ extern "C" int sigaltstack(stack_t const * const ss, stack_t * const old_ss)

return 0;
}


extern "C" int __libc_sigwait(const sigset_t *, int *) __attribute__((weak, alias("sigwait")));

extern "C" int sigwait(const sigset_t *set, int *sig)
{
if (!set || !sig)
return EINVAL;

if (!_signal_ptr || !_monitor_ptr)
return EINVAL;

auto &signals = *_signal_ptr;

auto for_each_signal_of_set = [&](sigset_t const &set, auto const &fn) {
for (unsigned word = 0; word < _SIG_WORDS; word++) {
if (!set.__bits[word])
continue;

unsigned signals = set.__bits[word];

/* invoke functor for all signals of set */
while (signals) {
unsigned const pos = __builtin_ctz(signals);
unsigned const signal = word * 32 + pos + 1;

signals &= ~(1u << pos);

fn(signal);
}
}
};

unsigned signal_count_before[NSIG + 1] { };

/* mark signals to wait for */
for_each_signal_of_set(*set, [&](auto const signal) {
signals.signal_sigwait[signal] = true;
signal_count_before[signal] = signals.signal_count[signal];
});

/* block as long none of the monitored signals are pending */
_monitor_ptr->monitor([&]() {
bool triggered = false;

for_each_signal_of_set(*set, [&](auto const signal) {
if (triggered)
return;

triggered = signals.signal_count[signal] !=
signal_count_before[signal];

if (triggered)
*sig = signal;
});

return triggered ? Monitor::Function_result::COMPLETE
: Monitor::Function_result::INCOMPLETE;
});

/* de-mark signals we had wait for */
for_each_signal_of_set(*set, [&](auto const signal) {
signals.signal_sigwait[signal] = false;
});

return 0;
}
40 changes: 40 additions & 0 deletions repos/libports/src/test/libc/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extern "C" {
}

static void test_sigalt();
static void test_sigwait();

int main(int argc, char **argv)
{
Expand Down Expand Up @@ -269,6 +270,7 @@ int main(int argc, char **argv)
} while (0);

test_sigalt();
test_sigwait();

exit(error_count);
}
Expand Down Expand Up @@ -357,3 +359,41 @@ static void test_sigalt()

printf("%s done\n", __func__);
}


static void * test_sigwait_pthread(void *arg)
{
sigset_t set { };
int triggered_signal { };

sigemptyset(&set);
sigaddset (&set, SIGBUS);

int result = sigwait(&set, &triggered_signal);

if (result)
abort();

return arg;
}


static void test_sigwait()
{
pthread_t t;

if (pthread_create(&t, 0, test_sigwait_pthread, NULL)) {
printf("error: pthread_create() failed\n");
exit(-1);
}

/* wait for pthread to invoke sigwait */
sleep(3);

/* send signal to pthread */
kill(getpid(), SIGBUS);

pthread_join(t, NULL);

printf("%s done\n", __func__);
}

0 comments on commit f2a0e50

Please sign in to comment.