void * sysLoadLibrary(const char *name, char *err_buf, int err_buflen) { void * result; #ifdef NEED_DL_LOCK sysMonitorEnter(sysThreadSelf(), &_dl_lock); result = dlopen(name, RTLD_NOW); sysMonitorExit(sysThreadSelf(), &_dl_lock); #else result = dlopen(name, RTLD_LAZY); #endif /* * This is a bit of bulletproofing to catch the commonly occurring * problem of people loading a library which depends on libthread into * the VM. thr_main() should always return -1 which means that libthread * isn't loaded. */ #ifndef NATIVE if (thr_main() != -1) { VM_CALL(panic)("libthread loaded into green threads"); } #endif if (result == NULL) { strncpy(err_buf, dlerror(), err_buflen-2); err_buf[err_buflen-1] = '\0'; } return result; }
void sysUnloadLibrary(void *handle) { #ifdef NEED_DL_LOCK sysMonitorEnter(sysThreadSelf(), &_dl_lock); dlclose(handle); sysMonitorExit(sysThreadSelf(), &_dl_lock); #else dlclose(handle); #endif }
/* * Add thread to queue of active threads. */ static void queueInsert(sys_thread_t *tid) { if (ThreadsInitialized) SYS_QUEUE_LOCK(sysThreadSelf()); ActiveThreadCount++; tid->next = ThreadQueue; ThreadQueue = tid; if (ThreadsInitialized) SYS_QUEUE_UNLOCK(sysThreadSelf()); else ThreadsInitialized = TRUE; }
void * sysFindLibraryEntry(void *handle, const char *name) { void *sym; #ifdef NEED_DL_LOCK sysMonitorEnter(sysThreadSelf(), &_dl_lock); sym = dlsym(handle, name); sysMonitorExit(sysThreadSelf(), &_dl_lock); #else sym = dlsym(handle, name); #endif return sym; }
/* * Enumerate over all threads in active queue calling a function for * each one. Expects the caller to lock _queue_lock */ int sysThreadEnumerateOver(int (*func)(sys_thread_t *, void *), void *arg) { sys_thread_t *tid; int ret = SYS_OK; sys_thread_t *self = sysThreadSelf(); sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf())); for (tid = ThreadQueue; tid != 0; tid = tid->next) { if ((ret = (*func)(tid, arg)) != SYS_OK) { break; } } return ret; }
/* * Free a system thread block. * Remove from the thread queue. */ int sysThreadFree() { sys_thread_t *tid = sysThreadSelf(); /* * remove ourselves from the thread queue. This must be done after * the notify above since monitor operations aren't really safe if * your thread isn't on the thread queue. (This isn't true of * the sysMonitor* functions, only monitor*) */ SYS_QUEUE_LOCK(tid); removefromActiveQ(tid); SYS_QUEUE_UNLOCK(tid); /* For invocation API: later sysThreadSelf() calls will return 0 */ TlsSetValue(tls_index, 0); /* * Close the thread and interrupt event handles, and free the * sys_thread_t structure. */ CloseHandle(tid->handle); CloseHandle(tid->interrupt_event); freeThreadBlock(tid); return SYS_OK; }
int np_suspend(sys_thread_t *tid) { int count, ret = 0; int err = mutexLock(&sr_lock); sysAssert(err == 0); tid->selfsuspended = (tid == sysThreadSelf()); count = tid->suspend_count++; #ifdef LOG_THREADS dprintf(2, "[Suspending fromtid = %ld, tid = %ld, pid = %d, count = %d]\n", pthread_self(), tid->sys_thread, tid->lwp_id, count); #endif if (count == 0) { if (tid->selfsuspended) { #ifdef LOG_THREADS dprintf(2, "[Self-suspending [tid = %ld, sys_thread = %ld]\n", pthread_self(), tid->sys_thread); #endif mutexUnlock(&sr_lock); do { sem_wait(&tid->sem_selfsuspend); } while (tid->selfsuspended); /* [jk] What is the correct return value here? There was no error, but when we return the thread has already been resumed. */ return SYS_OK; } else { sr_tid = tid; ret = pthread_kill(tid->sys_thread, sr_sigsusp); if (ret == 0) { sem_wait(&sr_sem); } #ifdef LOG_THREADS dprintf(2, "[Suspended fromtid = %ld, pthread_kill(%ld, %d) = %d]\n", pthread_self(), tid->sys_thread, sr_sigsusp, ret); #endif } } err = mutexUnlock(&sr_lock); sysAssert(err == 0); return ret == 0 ? SYS_OK : SYS_ERR; }
/* * Remove thread from queue of active threads. */ static void removefromActiveQ(sys_thread_t *tid) { sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf())); --ActiveThreadCount; if (ThreadQueue == tid) { ThreadQueue = tid->next; } else { sys_thread_t *p; for (p = ThreadQueue; p->next != 0; p = p->next) { if (p->next == tid) { p->next = tid->next; break; } } } }
/* * Suspend execution of the specified thread. */ int sysThreadSuspend(sys_thread_t *tid) { /* REMIND: Fix for Win95 */ /* Set state first so state is reflected before this thread */ /* returns. Fix suggested by ARB of SAS */ thread_state_t oldstate = tid->state; sys_thread_t *self = sysThreadSelf(); if (tid == self) { self->state = SUSPENDED; } else { switch(tid->state) { case RUNNABLE: tid->state = SUSPENDED; break; case MONITOR_WAIT: tid->state = SUSPENDED; tid->suspend_flags |= MONITOR_WAIT_SUSPENDED; break; case CONDVAR_WAIT: tid->state = SUSPENDED; tid->suspend_flags |= CONDVAR_WAIT_SUSPENDED; break; case SUSPENDED: case MONITOR_SUSPENDED: default: return SYS_ERR; } } if (SuspendThread(tid->handle) == 0xffffffffUL) { tid->state = oldstate; tid->suspend_flags = 0; return SYS_ERR; } return SYS_OK; }
int np_initial_suspend(sys_thread_t* tid) { int count; tid->selfsuspended = (tid == sysThreadSelf()); sysAssert(tid->selfsuspended); count = tid->suspend_count++; sysAssert(count == 0); #ifdef LOG_THREADS dprintf(2, "[Initial self-suspend [tid = %ld, sys_thread = %ld]\n", pthread_self(), tid->sys_thread); #endif /* Order should not matter but doing the post first should be faster */ sem_post(&tid->sem_suspended); do { sem_wait(&tid->sem_selfsuspend); } while (tid->selfsuspended); /* paranoid */ return 0; }
void * sysThreadInterruptEvent() { return sysThreadSelf()->interrupt_event; }
/* * Wakes up each thread in active thread queue except for the calling * thread. The mechanism uses thread suspension, and will not wake a * thread that was already suspended. Must be matched 1-1 with calls * to sysThreadSingle(). Returns SYS_ERR if not all threads could be * woken up. */ void sysThreadMulti(void) { sysThreadEnumerateOver(threadMultiHelper, sysThreadSelf()); }
/* * Puts each thread in the active thread queue to sleep except for the * calling thread. The threads must be later woken up with a corresponding * call to 'sysThreadMulti'. Returns SYS_OK on success, or SYS_ERR if any * of the threads could not be suspended. */ int sysThreadSingle(void) { return sysThreadEnumerateOver(threadSingleHelper, sysThreadSelf()); }
int condvarWait(condvar_t *condvar, mutex_t *mutex, thread_state_t wtype) { sigjmp_buf jmpbuf; int err; sys_thread_t *self = sysThreadSelf(); /* * There is no threads interface to get a thread's state. So, instead, * we use this hack so that the debugger agent can get at this thread's * state. Of course, this is not very reliable, but when a thread goes * to sleep, it *will* be reported as sleeping. During the transition * from running to sleep, it may be incorrectly reported, since the * setting of the state here is not atomic with the voluntary sleep. * The better fix is to extend the Solaris threads interface and have * the debugger agent call this interface OR to use libthread_db for * intra-process state reporting. * * Now, condition variables are used either for waiting to enter a * monitor (MONITOR_WAIT) or to execute a "wait()" method when already * holding a monitor (CONDVAR_WAIT). So, when condvarWait() is called * it could be to wait for a monitor or for a condition within a * monitor. This is indicated by the "wtype" argument to condvarWait(). * This type is set in the thread state before going to sleep. */ self->state = wtype; #ifdef __linux__ /* * Register our intrHandler as a cleanup handler. If we get * interrupted (i.e. canceled), we longjmp out of this handler. */ pthread_cleanup_push(intrHandler, NULL); if (setjmp(jmpbuf) == 0) { /* * Set the jmp buf and enable cancellation. */ thr_setspecific(intrJmpbufkey, &jmpbuf); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); /* * Note: pthread_cond_wait is _not_ interruptible on Linux */ #else thr_setspecific(sigusr1Jmpbufkey, &jmpbuf); if (sigsetjmp(jmpbuf, 1) == 0) { sigset_t osigset; thr_sigsetmask(SIG_UNBLOCK, &sigusr1Mask, &osigset); again: #endif err = cond_wait((cond_t *) condvar, (mutex_t *) mutex); switch(err) { case 0: err = SYS_OK; break; #ifndef __linux__ case EINTR: /* Signals other than USR1 were received. */ goto again; #endif default: err = SYS_ERR; } #ifdef __linux__ /* * Disable cancellation and clear the jump buf. */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); thr_setspecific(intrJmpbufkey, NULL); #else thr_sigsetmask(SIG_SETMASK, &osigset, NULL); #endif } else { /* * we've received a SIGUSR1 to interrupt our wait. We just return * and something above use notices the change. * clear the jump buf just to be paranoid. */ #ifndef __linux__ thr_setspecific(sigusr1Jmpbufkey, NULL); #endif err = SYS_INTRPT; } #ifdef __linux__ pthread_cleanup_pop(0); #endif /* * After having woken up, change the thread state to RUNNABLE, since * it is now runnable. */ self->state = RUNNABLE; return err; } /* * Returns 0 if condition variable became true before timeout expired. * Returns 1 if timeout expired first. * Returns <0 if wait fails for any other reason. */ int condvarTimedWait(condvar_t *condvar, mutex_t *mutex, jlong millis, thread_state_t wtype) { #ifdef __linux__ jmp_buf jmpbuf; #else sigjmp_buf jmpbuf; #endif int err; struct timespec timeout; sys_thread_t *self; jlong end_time; if (millis < 0) return SYS_ERR; if (millis > (jlong)INT_MAX) { return condvarWait(condvar, mutex, wtype); } end_time = sysTimeMillis() + millis; self = sysThreadSelf(); self->state = wtype; #ifdef __linux__ /* * Register our intrHandler as a cleanup handler. If we get * interrupted (i.e. canceled), we longjmp out of this handler. */ pthread_cleanup_push(intrHandler, NULL); if (setjmp(jmpbuf) == 0) { /* * Set the jmp buf and enable cancellation. */ thr_setspecific(intrJmpbufkey, &jmpbuf); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); /* * Calculate an absolute timeout value. */ timeout.tv_sec = end_time / 1000; timeout.tv_nsec = (end_time % 1000) * 1000000; again: #else thr_setspecific(sigusr1Jmpbufkey, &jmpbuf); if (sigsetjmp(jmpbuf, 1) == 0) { sigset_t osigset; thr_sigsetmask(SIG_UNBLOCK, &sigusr1Mask, &osigset); again: timeout.tv_sec = end_time / 1000; timeout.tv_nsec = (end_time % 1000) * 1000000; #endif err = cond_timedwait((cond_t *)condvar, (mutex_t *)mutex, &timeout); switch(err) { case 0: err = SYS_OK; break; case EINTR: /* Signals other than USR1 were received. */ if (sysTimeMillis() < end_time) { goto again; } /*FALLTHRU*/ #ifdef USE_PTHREADS case ETIMEDOUT: #else case ETIME: #endif err = SYS_TIMEOUT; break; default: err = SYS_ERR; } #ifdef __linux__ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); thr_setspecific(intrJmpbufkey, NULL); #else thr_sigsetmask(SIG_SETMASK, &osigset, NULL); #endif } else { /* * we've received a SIGUSR1 to interrupt our wait. We just return * and something above use notices the change. * clear the jump buf just to be paranoid. */ #ifndef __linux__ thr_setspecific(sigusr1Jmpbufkey, NULL); #endif err = SYS_INTRPT; } #ifdef __linux__ /* Remove intrHandler without calling it. */ pthread_cleanup_pop(0); sysAssert(pthread_mutex_trylock(mutex) == EBUSY); /* * After having woken up, change the thread state to RUNNABLE, since * it is now runnable. */ #endif self->state = RUNNABLE; return err; } int condvarSignal(condvar_t *condvar) { int err; err = cond_signal((cond_t *) condvar); condvar->counter++; return (err == 0 ? SYS_OK : SYS_ERR); }