X-Git-Url: https://git.harvie.cz/?a=blobdiff_plain;f=c%2Fpthread_extra%2Fpthread_pause.c;h=950d6fa26954ffdbf5d42ad9fcec3a27fd3e860b;hb=30d358cd5a66ea85b06729df8fa13a068ac21d51;hp=a9ce5dce3c487e87613fff24d90c39fe045f5741;hpb=3109d0d18e330e166a45042a2d363ec1b285c493;p=mirrors%2FPrograms.git diff --git a/c/pthread_extra/pthread_pause.c b/c/pthread_extra/pthread_pause.c index a9ce5dc..950d6fa 100644 --- a/c/pthread_extra/pthread_pause.c +++ b/c/pthread_extra/pthread_pause.c @@ -47,8 +47,7 @@ void pthread_pause_handler(const int signal, siginfo_t *info, void *ptr) { } void pthread_pause_enable() { - //Add thread to internal registry - //pthread_user_data_internal(pthread_self()); + pthread_pause_init(); //Make sure semaphore is init'd //Nesting signals too deep is not good for stack //You can get runtime stats using following command: @@ -56,8 +55,6 @@ void pthread_pause_enable() { //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; sigemptyset(&sigset); @@ -71,27 +68,35 @@ void pthread_pause_enable() { .sa_flags = SA_SIGINFO | SA_RESTART, .sa_restorer = NULL }; + sigaction(PTHREAD_XSIG_STOP, &pause_sa, NULL); //Unblock signal pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); -} -void pthread_pause_disable() { //Add thread to internal registry - //pthread_user_data_internal(pthread_self()); + pthread_user_data_internal(pthread_self()); //Only now, when signals are unblocked! +} +void pthread_pause_disable() { + //pthread_user_data_lock(); pthread_pause_init(); //Make sure semaphore is init'd + //Add thread to internal registry + //pthread_user_data_internal(pthread_self()); //DEADLOCKS! + //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); + //Maybe not a good idea, causes DEADLOCKS! + //sem_wait(&pthread_pause_sem); pthread_sigmask(SIG_BLOCK, &sigset, NULL); - sem_post(&pthread_pause_sem); + //sem_post(&pthread_pause_sem); + + //pthread_user_data_unlock(); } /* @@ -108,6 +113,7 @@ int pthread_pause_reschedule(pthread_t thread) { int pthread_pause_reschedule(pthread_t thread) { //Decide if the thread should run and signal it + pthread_user_data_lock(); //Wait for semaphore which means signal queue is empty pthread_pause_init(); //Make sure semaphore is init'd @@ -116,17 +122,16 @@ int pthread_pause_reschedule(pthread_t thread) { //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 int run = (pthread_user_data_internal(thread)->running); //Check if privileged (single thread) mode is active - if((pthread_pause_holder != PTHREAD_XNULL) && !pthread_equal(pthread_pause_holder, thread)) { + if(!pthread_equal(pthread_pause_holder, PTHREAD_XNULL) && !pthread_equal(pthread_pause_holder, thread)) { run = 0; } - pthread_user_data_unlock(); //Send signal to initiate pause handler (keep trying while SigQueue is full) //while(pthread_kill(thread, PTHREAD_XSIG_STOP) == EAGAIN) usleep(1000); + //printf("Sched %lu = %d (self: %lu, lck: %lu)\n", thread, run, pthread_self(), pthread_pause_holder); while(pthread_sigqueue(thread, PTHREAD_XSIG_STOP, (const union sigval){.sival_int=run} ) == EAGAIN) usleep(1000); @@ -134,6 +139,7 @@ int pthread_pause_reschedule(pthread_t thread) { //Wait for signal to be delivered sem_wait(&pthread_pause_sem); sem_post(&pthread_pause_sem); + pthread_user_data_unlock(); return 0; } @@ -144,38 +150,58 @@ int pthread_extra_yield() { return pthread_yield(); } +///Sanity check to be sure there are no race conditions +inline void pthread_pause_assert_owner() { + if(!pthread_equal(pthread_pause_holder,PTHREAD_XNULL)) + assert(pthread_equal(pthread_pause_holder, pthread_self())); +} + +///Pause specified thread (block until it is paused) int pthread_pause(pthread_t thread) { - //Set thread as paused and notify it via signal (wait when queue full) pthread_user_data_lock(); + pthread_pause_assert_owner(); + //if(!pthread_equal(pthread_pause_holder,PTHREAD_XNULL)) assert(pthread_equal(pthread_pause_holder, pthread_self())); + //Set thread as paused and notify it via signal (wait when queue full) pthread_user_data_internal(thread)->running = 0; pthread_pause_reschedule(thread); pthread_user_data_unlock(); return 0; } +///UnPause specified thread (block until it is unpaused) int pthread_unpause(pthread_t thread) { - //Set thread as running and notify it via signal (wait when queue full) pthread_user_data_lock(); + pthread_pause_assert_owner(); + //Set thread as running and notify it via signal (wait when queue full) pthread_user_data_internal(thread)->running = 1; pthread_pause_reschedule(thread); pthread_user_data_unlock(); return 0; } +///Enter exclusive mode by pausing everyone else int pthread_pause_all() { + //printf("Pause ALL\n"); pthread_user_data_lock(); - if(pthread_pause_holder!=PTHREAD_XNULL) assert(pthread_equal(pthread_pause_holder, pthread_self())); + //printf("Pause ALL+\n"); + //printf("Pause %p == %p\n", (void *)pthread_pause_holder, (void *)pthread_self()); + pthread_pause_assert_owner(); pthread_pause_holder = pthread_self(); pthread_user_data_internal_iterate(&pthread_pause_reschedule, NULL); + //printf("Pause ALL!\n"); pthread_user_data_unlock(); return 0; } +///Leave exclusive mode by unpausing everyone else int pthread_unpause_all() { + //printf("UnPause ALL\n"); pthread_user_data_lock(); - if(pthread_pause_holder!=PTHREAD_XNULL) assert(pthread_equal(pthread_pause_holder, pthread_self())); + //printf("UnPause ALL+\n"); + pthread_pause_assert_owner(); pthread_pause_holder = PTHREAD_XNULL; pthread_user_data_internal_iterate(&pthread_pause_reschedule, NULL); + //printf("UnPause ALL!\n"); pthread_user_data_unlock(); return 0; } @@ -193,8 +219,10 @@ void *pthread_extra_thread_wrapper(void *arg) { pthread_extra_wrapper_t task = *((pthread_extra_wrapper_t*)arg); free(arg); + pthread_pause_enable(); + //Register new thread to user data structure - pthread_user_data_internal(pthread_self()); + //pthread_user_data_internal(pthread_self()); //Perhaps already done in pthread_extra_yield() and pthread_pause_enable()?? //TODO: user_data should do this automaticaly? pthread_cleanup_push(pthread_user_data_cleanup, (void *)pthread_self());