Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 10
0
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);
}