Fixed deadlock in pause enable/disable
[mirrors/Programs.git] / c / pthread_extra / pthread_pause.c
index a9ce5dce3c487e87613fff24d90c39fe045f5741..f8fb296fdc7b79be4c0baa0241959d917d5e5ed0 100644 (file)
@@ -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,49 @@ int pthread_extra_yield() {
        return pthread_yield();
 }
 
+///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();
+       //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();
+       //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());
+       if(!pthread_equal(pthread_pause_holder,PTHREAD_XNULL)) assert(pthread_equal(pthread_pause_holder, pthread_self()));
        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");
+       if(!pthread_equal(pthread_pause_holder,PTHREAD_XNULL)) assert(pthread_equal(pthread_pause_holder, pthread_self()));
        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 +210,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());
This page took 0.160943 seconds and 4 git commands to generate.