From: Tomas Mudrunka Date: Fri, 2 Jul 2021 14:33:11 +0000 (+0200) Subject: Priprava na semafor, zatim obsahuje ZAVAZNY DEADLOCK X-Git-Url: http://git.harvie.cz/?p=mirrors%2FPrograms.git;a=commitdiff_plain;h=3109d0d18e330e166a45042a2d363ec1b285c493 Priprava na semafor, zatim obsahuje ZAVAZNY DEADLOCK --- diff --git a/c/pthread_extra/Makefile b/c/pthread_extra/Makefile index 35fac9c..0022774 100644 --- a/c/pthread_extra/Makefile +++ b/c/pthread_extra/Makefile @@ -18,7 +18,7 @@ $(BIN): $(OBJ) $(CXX) -o $(BIN) $(OBJ) $(LDFLAGS) strip --strip-unneeded $(BIN) - gcc -lpthread -I . test_pause.c pthread_user_data.o pthread_pause.o -o test_pause + gcc -lpthread -I . test_pause.c pthread_user_data.o pthread_pause.o pthread_sleep.o -o test_pause clean: rm -f $(BIN) $(OBJ) $(DEPS) diff --git a/c/pthread_extra/pthread_pause.c b/c/pthread_extra/pthread_pause.c index 103283d..a9ce5dc 100644 --- a/c/pthread_extra/pthread_pause.c +++ b/c/pthread_extra/pthread_pause.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -12,8 +13,20 @@ #include //#include +//Mutex that ensures proper serialization of (un)pause calls +//pthread_mutex_t pthread_pause_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + +//Semaphore that ensures proper serialization of (un)pause signals +sem_t pthread_pause_sem; +//Once control to init the semaphore (and possibly other stuff) +pthread_once_t pthread_pause_once_ctrl = PTHREAD_ONCE_INIT; +void pthread_pause_once(void) { + sem_init(&pthread_pause_sem, 0, 1); +} +void pthread_pause_init() { pthread_once(&pthread_pause_once_ctrl, &pthread_pause_once); } + ///When this variable is nonzero, only referenced thread is allowed to run -///Access has to be protected by pthread_user_data_lock() +///Access has to be protected by pthread_user_data_lock() and pthread_pause_sem; pthread_t pthread_pause_holder = PTHREAD_XNULL; void pthread_pause_handler(const int signal, siginfo_t *info, void *ptr) { @@ -21,20 +34,14 @@ void pthread_pause_handler(const int signal, siginfo_t *info, void *ptr) { int run = info->si_value.sival_int; //(void)td; - //Do nothing when there are more signals pending (to cleanup the queue) - sigset_t pending; - sigpending(&pending); - if(sigismember(&pending, PTHREAD_XSIG_STOP)) return; + //Post semaphore to confirm that signal is handled + sem_post(&pthread_pause_sem); //Keep waiting for signals until we are supposed to be running - sigset_t sigset; - sigfillset(&sigset); - sigdelset(&sigset, PTHREAD_XSIG_STOP); - - //printf("RCV: %p = %p\n", (void *)pthread_user_data_internal(pthread_self()), (void *)td); - - //if(!pthread_user_data_internal(pthread_self())->running) { if(!run) { + sigset_t sigset; + sigfillset(&sigset); + sigdelset(&sigset, PTHREAD_XSIG_STOP); sigsuspend(&sigset); } } @@ -46,8 +53,10 @@ void pthread_pause_enable() { //Nesting signals too deep is not good for stack //You can get runtime stats using following command: //grep -i sig /proc/$(pgrep binary)/status - struct rlimit sigq = {.rlim_cur = 32, .rlim_max=32}; - setrlimit(RLIMIT_SIGPENDING, &sigq); + //struct rlimit sigq = {.rlim_cur = 32, .rlim_max=32}; + //setrlimit(RLIMIT_SIGPENDING, &sigq); + + pthread_pause_init(); //Make sure semaphore is init'd //Prepare signal mask sigset_t sigset; @@ -72,11 +81,17 @@ void pthread_pause_disable() { //Add thread to internal registry //pthread_user_data_internal(pthread_self()); + pthread_pause_init(); //Make sure semaphore is init'd + //Block signal sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, PTHREAD_XSIG_STOP); + + //Make sure all signals are dispatched before we block them + sem_wait(&pthread_pause_sem); pthread_sigmask(SIG_BLOCK, &sigset, NULL); + sem_post(&pthread_pause_sem); } /* @@ -92,7 +107,14 @@ int pthread_pause_reschedule(pthread_t thread) { */ int pthread_pause_reschedule(pthread_t thread) { - //Decide if the thread should run + //Decide if the thread should run and signal it + + //Wait for semaphore which means signal queue is empty + pthread_pause_init(); //Make sure semaphore is init'd + sem_wait(&pthread_pause_sem); + + //Only call this if you already acquired pthread_pause_sem semaphore!!!! + //Otherwise call pthread_pause_reschedule() pthread_user_data_lock(); //Check if thread has running flag @@ -108,6 +130,11 @@ int pthread_pause_reschedule(pthread_t thread) { while(pthread_sigqueue(thread, PTHREAD_XSIG_STOP, (const union sigval){.sival_int=run} ) == EAGAIN) usleep(1000); + + //Wait for signal to be delivered + sem_wait(&pthread_pause_sem); + sem_post(&pthread_pause_sem); + return 0; } @@ -121,8 +148,8 @@ int pthread_pause(pthread_t thread) { //Set thread as paused and notify it via signal (wait when queue full) pthread_user_data_lock(); pthread_user_data_internal(thread)->running = 0; - pthread_user_data_unlock(); pthread_pause_reschedule(thread); + pthread_user_data_unlock(); return 0; } @@ -130,8 +157,8 @@ int pthread_unpause(pthread_t thread) { //Set thread as running and notify it via signal (wait when queue full) pthread_user_data_lock(); pthread_user_data_internal(thread)->running = 1; - pthread_user_data_unlock(); pthread_pause_reschedule(thread); + pthread_user_data_unlock(); return 0; } @@ -139,8 +166,8 @@ int pthread_pause_all() { pthread_user_data_lock(); if(pthread_pause_holder!=PTHREAD_XNULL) assert(pthread_equal(pthread_pause_holder, pthread_self())); pthread_pause_holder = pthread_self(); - pthread_user_data_unlock(); pthread_user_data_internal_iterate(&pthread_pause_reschedule, NULL); + pthread_user_data_unlock(); return 0; } @@ -148,8 +175,8 @@ int pthread_unpause_all() { pthread_user_data_lock(); if(pthread_pause_holder!=PTHREAD_XNULL) assert(pthread_equal(pthread_pause_holder, pthread_self())); pthread_pause_holder = PTHREAD_XNULL; - pthread_user_data_unlock(); pthread_user_data_internal_iterate(&pthread_pause_reschedule, NULL); + pthread_user_data_unlock(); return 0; } diff --git a/c/pthread_extra/test_pause.c b/c/pthread_extra/test_pause.c index ed60fcc..439c6d8 100644 --- a/c/pthread_extra/test_pause.c +++ b/c/pthread_extra/test_pause.c @@ -6,23 +6,31 @@ #include #include +pthread_t main_thread; + void *thread_test(void *arg) { //Whole process dies if you kill thread immediately before it is pausable //pthread_pause_enable(); while(1) { - usleep(1000*300); + pthread_nsleep(0, 1000*1000*300); + //pthread_pause_all(); + pthread_pause(main_thread); printf("Running%s!\n", (char *)arg); + //pthread_unpause_all(); + pthread_unpause(main_thread); } } int main() { + main_thread = pthread_self(); + pthread_t a, b; pthread_pause_enable(); //Will get inherited by all threads from now on //That way you can be sure it is pausable immediately pthread_extra_create(&a, NULL, thread_test, " A"); pthread_extra_create(&b, NULL, thread_test, " B"); - //sleep(1); + //pthread_sleep(1); //printf("OK\n"); /* @@ -43,24 +51,24 @@ int main() { pthread_pause(b); pthread_unpause(a); printf("SWITCH A:\n"); - sleep(2); + pthread_sleep(2); printf("SWITCH B:\n"); pthread_pause(a); pthread_unpause(b); - sleep(2); + pthread_sleep(2); printf("SWITCH A+B:\n"); pthread_unpause(a); pthread_unpause(b); - sleep(1); + pthread_sleep(1); printf("SWITCH MAIN ONLY:\n"); pthread_pause_all(); - sleep(1); + pthread_sleep(1); printf("SWITCH MAIN A+B:\n"); pthread_unpause_all(); - sleep(1); + pthread_sleep(1); } pthread_join(a, NULL);