}
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:
//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);
.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();
}
/*
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
//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);
//Wait for signal to be delivered
sem_wait(&pthread_pause_sem);
sem_post(&pthread_pause_sem);
+ pthread_user_data_unlock();
return 0;
}
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;
}
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());