diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile index b559251788..32dd64bd39 100644 --- a/src/tests/system/libroot/posix/Jamfile +++ b/src/tests/system/libroot/posix/Jamfile @@ -17,6 +17,7 @@ SimpleTest getsubopt_test : getsubopt_test.cpp ; SimpleTest locale_test : locale_test.cpp ; SimpleTest memalign_test : memalign_test.cpp ; SimpleTest mprotect_test : mprotect_test.cpp ; +SimpleTest pthread_signal_test : pthread_signal_test.cpp ; SimpleTest realtime_sem_test1 : realtime_sem_test1.cpp ; SimpleTest seek_and_write_test : seek_and_write_test.cpp ; SimpleTest setpgid_test : setpgid_test.cpp ; diff --git a/src/tests/system/libroot/posix/pthread_signal_test.cpp b/src/tests/system/libroot/posix/pthread_signal_test.cpp new file mode 100644 index 0000000000..1427212e49 --- /dev/null +++ b/src/tests/system/libroot/posix/pthread_signal_test.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +static pthread_attr_t attributes; +static pthread_t tid[4]; +static bool state[4]; +static bool blocking[4]; +static pthread_key_t self; + + +static void suspendLoop(int *i) { + sigjmp_buf env; + sigset_t mask; + + sigsetjmp(env, false); + + state[*i] = false; + + sigfillset(&mask); + sigdelset(&mask, SIGUSR1); + sigdelset(&mask, SIGTERM); + + while(state[*i] == false && blocking[*i] == false) + sigsuspend(&mask); + + state[*i] = true; +} + + +static void suspendHandler(int sig) { + int *i = (int*)pthread_getspecific(self); + suspendLoop(i); +} + +static void initialiseSignals() +{ + struct sigaction act; + sigset_t mask; + + act.sa_handler = suspendHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGUSR1, &act, NULL); + + sigemptyset(&mask); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGPIPE); + sigprocmask(SIG_BLOCK, &mask, NULL); +} + + +static void self_suspend(int* i) +{ + sigset_t mask; + + blocking[*i] = false; + + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + + printf("thread %d suspending\n", *i); + + suspendLoop(i); + + printf("thread %d suspend ended\n", *i); + + pthread_sigmask(SIG_UNBLOCK, &mask, NULL); +} + + +void *threadStart(void *arg) { + int *i = (int*)arg; + pthread_setspecific(self, i); + + state[*i] = true; + blocking[*i] = true; + + for (int j = 0; j < 10; j++) { + self_suspend(i); + usleep(10000); + } + + printf("quitting %d\n", *i); + return NULL; +} + + +/*void suspendAllThreads() +{ + for (int i = 0; i < 4; i++) { + blocking[i] = false; + if (state[i] == true) + pthread_kill(tid[i], SIGUSR1); + } + + for (int i = 0; i < 4; i++) { + while(state[i] == true) { + sched_yield(); + } + } +}*/ + + + +void resumeAllThreads() +{ + for (int i = 0; i < 4; i++) { + blocking[i] = true; + if (state[i] == false) { + printf("thread %d signaled for resume\n", i); + pthread_kill(tid[i], SIGUSR1); + } + } + + for (int i = 0; i < 4; i++) { + while(state[i] == false) { + printf("thread %d still suspended, yielding\n", i); + sched_yield(); + } + } +} + + +int main(int argc, char **argv) +{ + initialiseSignals(); + + pthread_key_create(&self, NULL); + + pthread_attr_init(&attributes); + pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); + + for (int i = 0; i < 4; i++) { + if (pthread_create(&tid[i], &attributes, threadStart, &i) != 0) + fprintf(stderr, "couldn't create thread %d\n", i); + printf("thread %d created\n", i); + } + + /*suspendAllThreads();*/ + printf("snoozing\n"); + usleep(2000000); + printf("resuming all threads\n"); + resumeAllThreads(); + printf("resuming all threads done\n"); +}