diff options
author | Greg Lewis <glewis@FreeBSD.org> | 2003-02-28 17:47:38 +0000 |
---|---|---|
committer | Greg Lewis <glewis@FreeBSD.org> | 2003-02-28 17:47:38 +0000 |
commit | dcef90030ba08cddeba45eb532b939f6a6b78fcd (patch) | |
tree | 1d3f9a43b7ebe250b2223214456a2cabeb6fccfb /java/jdk16 | |
parent | Bump PORTREVISION by updating japanese/eb. (diff) |
. Updated version of native threads for FreeBSD. This uses recently
committed enhancements to libc_r and is only suitable for very recent
versions of FreeBSD. The big benefit is that it removes almost all
the previous grovelling about in the pthreads internals.
The change only comes into effect when WITH_NATIVE_THREADS is set.
A separate Makefile commit will attempt to enforce appropriate
OSVERSION settings for using it.
Submitted by: fjoe
Notes
Notes:
svn path=/head/; revision=76662
Diffstat (limited to 'java/jdk16')
-rw-r--r-- | java/jdk16/files/patch-threads_bsd.c | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/java/jdk16/files/patch-threads_bsd.c b/java/jdk16/files/patch-threads_bsd.c new file mode 100644 index 000000000000..0549832f1833 --- /dev/null +++ b/java/jdk16/files/patch-threads_bsd.c @@ -0,0 +1,726 @@ +$FreeBSD$ + +--- ../src/solaris/hpi/native_threads/src/threads_bsd.c 7 Feb 2002 05:19:54 -0000 1.12 ++++ ../src/solaris/hpi/native_threads/src/threads_bsd.c 25 Feb 2003 16:31:54 -0000 +@@ -22,32 +22,23 @@ + #include "np.h" + + #include <pthread.h> ++#include <pthread_np.h> + + #if defined(__FreeBSD__) + +-#include <pthread_np.h> ++#include <assert.h> + +-/* Remove defines from pthread.h so pthread_private.h can be included */ +-#undef pthread_condattr_default +-#undef pthread_mutexattr_default + #undef pthread_attr_default ++#undef pthread_mutexattr_default ++#undef pthread_condattr_default + #include "pthread_private.h" + +-#include <assert.h> +-#include <ucontext.h> +-#include <machine/ucontext.h> +- +-#include <sys/exec.h> +-#include <vm/vm.h> +-#include <vm/pmap.h> +-#include <machine/pmap.h> +-#include <machine/vmparam.h> +- + #endif + + #include <string.h> + #include <signal.h> + #include <sys/signal.h> ++#include <sys/time.h> + #include <sys/resource.h> + #include <stdlib.h> + #include <string.h> +@@ -63,14 +54,9 @@ + /* Private functions used to implement native threading. --billh */ + + #ifdef DEBUG_BSD_NATIVE_THREADS +-void _pthread_suspend_all_np(void); +-void _pthread_resume_all_np(void); +-#endif +-void record_uc(sys_thread_t *, ucontext_t *); +-void record_gc_registers_of(sys_thread_t *); +- +-void dumpThreadStates(); + void dumpThreadLogStates(pthread_t); ++void dumpThreadStates(); ++#endif + + /* + * Suspend a thread. Used to implement java.lang.Thread.suspend(), +@@ -108,28 +94,24 @@ + int + np_stackinfo(void **addr, long *sizep) + { +- thread_t self = pthread_self(); +- int base; +- int size; +- +- if (!pthread_equal(self, _thread_initial)) { +- *addr = self->stack; +- *sizep = (long) PTHREAD_STACK_DEFAULT; +- +- } else { +- /* in main()'s thread */ +- struct rlimit r; +- +- if (getrlimit(RLIMIT_STACK, &r) == -1) +- return SYS_ERR; +- +- /* PS_STRINGS is also from sys/exec.h in FreeBSD, but as macro. --billh */ +- +- *addr = (void *) (PS_STRINGS +1); +- *sizep = (long)r.rlim_cur; +- } ++ pthread_attr_t attr; ++ size_t size; + ++ if ((errno = pthread_attr_init(&attr))) ++ return SYS_ERR; ++ if ((errno = pthread_attr_get_np(pthread_self(), &attr))) ++ goto err; ++ if ((errno = pthread_attr_getstackaddr(&attr, addr))) ++ goto err; ++ if ((errno = pthread_attr_getstacksize(&attr, &size))) ++ goto err; ++ *sizep = size; ++ pthread_attr_destroy(&attr); + return SYS_OK; ++ ++err: ++ pthread_attr_destroy(&attr); ++ return SYS_ERR; + } + + /* +@@ -177,7 +159,7 @@ + Do this for the FreeBSD implementation too, since this is a silly + function anyways. --billh + */ +- return TRUE; ++ return TRUE; + } + + +@@ -190,38 +172,54 @@ + static void + record_thread_regs() + { +- sys_thread_t *tid; ++ struct pthread *self = pthread_self(); ++ sys_thread_t *tid = ThreadQueue; + int i; +- int sp; + +- tid = ThreadQueue; +- for (i = 0; i < ActiveThreadCount && tid != 0; i++) { +- int i; +- +- if (tid->sys_thread != 0) { +-#ifdef __bsdi__ +- /* if thread has already been initialized */ +- if (pthread_getstackpointer_np(tid->sys_thread, &sp) == 0) +- tid->sp = sp; +- else +- tid->sp = 0; +-#elif __FreeBSD__ +-#endif +- tid->sp = tid->sys_thread->stack; +-//#endif //__FreeBSD__ +-/* Potential race here if the stack isn't setup before GC. --billh */ +- } else { ++ for (i = 0; i < ActiveThreadCount && tid != NULL; i++, tid = tid->next) { ++ struct pthread *thread = tid->sys_thread; ++ ++ if (thread == 0) { + /* + * thread is still in the process of being initalized. + * So GC should not care about this thread. Just + * set its sp to 0, and this will force GC to ignore it. + */ + tid->sp = 0; ++ continue; + } + +- record_gc_registers_of(tid); ++ tid->sp = thread->stack; ++/* Potential race here if the stack isn't setup before GC. --billh */ + +- tid = tid->next; ++ /* ++ * The thread that calls this function will alway be the JVM GC thread, ++ * so skip over it in the list of threads. ++ */ ++ if (thread != self && (thread->flags & PTHREAD_FLAGS_PRIVATE) == 0) { ++ register_t *regbase; ++ ++#ifdef DEBUG_BSD_NATIVE_THREADS ++ /* ++ * Got search candidate.. ++ */ ++ if (thread->state != PS_SUSPENDED) ++ dumpThreadLogStates(thread); ++#endif ++ ++ regbase = (register_t*) &thread->ctx.jb[0]; ++ tid->regs[0] = regbase[6]; /* eax */ ++ tid->regs[1] = 0; /* ecx (missing) */ ++ tid->regs[2] = 0; /* edx (missing) */ ++ tid->regs[3] = regbase[1]; /* ebx */ ++ tid->regs[4] = regbase[3]; /* ebp */ ++ tid->regs[5] = regbase[4]; /* esi */ ++ tid->regs[6] = regbase[5]; /* edi */ ++ ++#ifdef DEBUG_BSD_NATIVE_THREADS ++ dumpThreadStates(); ++#endif ++ } + } + + #ifdef DEBUG_BSD_NATIVE_THREADS +@@ -239,14 +237,7 @@ + { + sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf())); + +-#ifdef DEBUG_BSD_NATIVE_THREADS +- _pthread_suspend_all_np(); +-#else +- pthread_single_np(); +-#endif +- +-//usleep(100000 *3); +- ++ pthread_suspend_all_np(); + record_thread_regs(); + return SYS_OK; + } +@@ -259,42 +250,13 @@ + np_multi(void) + { + sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf())); +-#ifdef DEBUG_BSD_NATIVE_THREADS +- _pthread_resume_all_np(); +-#else +- pthread_multi_np(); +-#endif ++ pthread_resume_all_np(); + } + +- +- +- ++#ifdef DEBUG_BSD_NATIVE_THREADS + /* pthreads hackery begins --billh */ + +-#define ANALRETENTIVE (6 + 1) +- +-char SuspendList[ANALRETENTIVE][16] = +-{ +- "SUSP_NO", /* Not suspended. */ +- "SUSP_YES", /* Suspended. */ +- "SUSP_JOIN", /* Suspended, joining. */ +- "SUSP_NOWAIT", /* Suspended, was in a mutex or condition queue. */ +- "SUSP_MUTEX_WAIT", /* Suspended, still in a mutex queue. */ +- "SUSP_COND_WAIT", /* Suspended, still in a condition queue. */ +- "susp boundless" +-}; +- +-char *getSuspendStateString(enum pthread_susp suspendState) +-{ +- if (suspendState < ANALRETENTIVE) +- return &SuspendList[suspendState][0]; +- else +- return &SuspendList[ANALRETENTIVE-1][0]; +-} +- +-#define SATAN (21 + 1) /* for the error string at the end of the list */ +- +-char SignalList [SATAN][16] ++char SignalList [][16] + = + { + "PS_RUNNING", +@@ -316,18 +278,17 @@ + "PS_JOIN", + "PS_SUSPENDED", + "PS_DEAD", +- "PS_DEADLCK", ++ "PS_DEADLOCK", + "PS_STATE_MAX", +- "PS_REQUEST_WAITING_SUSPENDED", + "boundless" + }; + + char *getThreadStateString(enum pthread_state threadState) + { + if (threadState < SATAN) +- return &SignalList[threadState][0]; +- else +- return &SignalList[SATAN-1][0]; ++ return SignalList[threadState]; ++ else ++ return SignalList[SATAN-1]; + } + + void dumpThreadStates() +@@ -336,114 +297,29 @@ + struct pthread *thread; + struct pthread *self = pthread_self(); + +-#ifdef DEBUG_BSD_NATIVE_THREADS + _thread_kern_sig_defer(); + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread != self) { /* special case this --billh */ +- printf("\tthread %d\t%s\t%s\n", ++ printf("\tthread %d\t%s\n", + threadCount, +- getThreadStateString(thread->state), +- getSuspendStateString(thread->suspended)); ++ getThreadStateString(thread->state)); + + if (thread->state != PS_SUSPENDED) + dumpThreadLogStates(thread); +- } +- else +- { +- printf("\tgc thread %d\t%s\t%s\n", ++ } else { ++ printf("\tgc thread %d\t%s\n", + threadCount, +- getThreadStateString(thread->state), +- getSuspendStateString(thread->suspended)); ++ getThreadStateString(thread->state)) + } + ++threadCount; + } + _thread_kern_sig_undefer(); + printf("\n"); +-#endif +-} +- +- +-#ifdef DEBUG_BSD_NATIVE_THREADS +-extern void _pthread_suspend_np_by_pthread_common(pthread_t); +-extern void _pthread_resume_by_pthread_common(pthread_t, enum pthread_susp); +- +-void +-_pthread_suspend_all_np(void) +-{ +- struct pthread *thread; +- struct pthread *self = pthread_self(); +- +-fprintf(stderr, "pthread_suspend_all_np\n"); +- /* +- * Defer signals to protect the scheduling queues from +- * access by the signal handler: +- */ +- _thread_kern_sig_defer(); +- +- /* Suspend all threads other than the current thread: */ +- TAILQ_FOREACH(thread, &_thread_list, tle) { +- if (thread != self) { +- _pthread_suspend_np_by_pthread_common(thread); +- } +- } +- +- /* +- * Undefer and handle pending signals, yielding if necessary: +- */ +- _thread_kern_sig_undefer(); +-fprintf(stderr, "pthread_suspend_all_np END\n"); +-} +- +-/* Resume a thread: */ +-void +-_pthread_resume_all_np(void) +-{ +- enum pthread_susp old_suspended; +- struct pthread *thread; +- struct pthread *self = pthread_self(); +- +-fprintf(stderr, "pthread_resume_all_np\n"); +- _thread_kern_sig_defer(); +- +- /* +- Iterate through the thread list and resume suspended threads. +- this is copied from pthread_resume_np(). --billh +- */ +- +- TAILQ_FOREACH(thread, &_thread_list, tle) { +- if (thread != self) { +- /* Cancel any pending suspensions: */ +- +- old_suspended = thread->suspended; +- thread->suspended = SUSP_NO; +- +- _pthread_resume_by_pthread_common(thread, old_suspended); +- +- } // if !thread_self +- } // TAILQ_FOREACH +- +- /* +- * Undefer and handle pending signals, yielding if +- * necessary: +- */ +- _thread_kern_sig_undefer(); +-fprintf(stderr, "pthread_resume_all_np END\n"); + } +-#endif + + /* + [A snippet from Dan Eichen's email on the subject] + +- It uses _longjmp (non-signal-saving/restoring) for the most part. +- The only exception is when the process (currently running thread) is +- interrupted by a signal. So your context types are a jmp_buf and +- a ucontext_t (if interrupted by a signal). If thread->ctxtype is +- CTX_UC, the context is stored as a ucontext in thread->ctx.uc. +- Otherwise, the context is stored as a jmp_buf in thread->ctx.jb. +- We don't currently use CTX_JB and CTX_SJB, so don't even bother +- with those cases. Those should go away actually; all we need +- to know is if it is a ucontext_t or a jmp_buf. +- + You can also look at src/gnu/usr.bin/binutils/gdb/freebsd-uthread.c. + It knows how to iterate through all the threads and pull out + (and even set) thread contexts. +@@ -462,19 +338,8 @@ + --billh + */ + +-void clear_gc_registers(sys_thread_t * jthread) +-{ +-/* clear out x86 registers for the thread's "self" --billh */ +- +- jthread->regs[0] = 0; jthread->regs[1] = 0; +- jthread->regs[2] = 0; jthread->regs[3] = 0; +- jthread->regs[4] = 0; jthread->regs[5] = 0; +- jthread->regs[6] = 0; +-} +- + void dumpThreadLogStates(pthread_t thread) + { +-#ifdef DEBUG_BSD_NATIVE_THREADS + int i; + for(i=0; i < STATE_LOG_SIZE; ++i) + { +@@ -494,311 +359,5 @@ + } + } + printf("\t\t***XXX\n"); +-#endif +-} +- +-void record_gc_registers_of(sys_thread_t *javaThread) +-{ +-struct pthread *self = pthread_self(); +-struct pthread *thread = NULL; +- +- assert( javaThread != NULL ); +- assert( javaThread->sys_thread != NULL ); +- +- thread = javaThread->sys_thread; +- +- /* +- * The thread that calls this function will alway be the JVM GC thread, +- * so skip over it in the list of threads. +- */ +- if ( (thread == self) +- || ((thread->flags & PTHREAD_FLAGS_PRIVATE) != 1) +- ) +- { +- record_uc(javaThread, &thread->ctx.uc); +-#ifdef DEBUG_BSD_NATIVE_THREADS +- goto Terminate; // And do nothing with this pthread entry. +-#endif +- } +- +- /* +- * Got search candiate.. +- */ +- if (thread->state != PS_SUSPENDED) +- dumpThreadLogStates(thread); +- +- switch ((int)thread->ctxtype) +- { +- case CTX_JB_NOSIG: /* 0) jmp_buf context without signal mask for blocking IO, etc... */ +- case CTX_JB: /* 1) should never be CTX_JB */ +- case CTX_SJB: /* 2) should never be CTX_SJB */ +- clear_gc_registers(javaThread); +-#ifdef DEBUG_BSD_NATIVE_THREADS +- goto Terminate; +-#endif +- break; +- case CTX_UC: /* 3) */ +- /* context is a ucontext_t */ +- record_uc(javaThread, &thread->ctx.uc); +-#ifdef DEBUG_BSD_NATIVE_THREADS +- goto Terminate; +-#endif +- break; +- default: +-#ifdef DEBUG_BSD_NATIVE_THREADS +- fprintf(stderr, "ctxtype failed %d.\n", thread->ctxtype); +- goto TermFailed; +-#endif +- break; +- } +- +-#ifdef DEBUG_BSD_NATIVE_THREADS +-TermFailed: +- fprintf(stderr, "Failed to find pthread struct.\n"); fflush(stderr); +- assert(0); +- +-Terminate: +- dumpThreadStates(); +-#endif + } +- +-void record_uc(sys_thread_t *t, ucontext_t *uc) +-{ +- mcontext_t *mc = &(uc->uc_mcontext); +- +- t->regs[0] = mc->mc_eax; +- t->regs[1] = mc->mc_ecx; +- t->regs[2] = mc->mc_edx; +- t->regs[3] = mc->mc_ebx; +- t->regs[4] = mc->mc_ebp; +- t->regs[5] = mc->mc_esi; +- t->regs[6] = mc->mc_edi; +-} +- +-/* +-From /usr/src/lib/libc/i386/gen/_setjmp.S: +-ENTRY(_setjmp) +- movl 4(%esp),%eax +- movl 0(%esp),%edx +- movl %edx, 0(%eax) / * rta * / +- movl %ebx, 4(%eax) +- movl %esp, 8(%eax) +- movl %ebp,12(%eax) +- movl %esi,16(%eax) +- movl %edi,20(%eax) +- fnstcw 24(%eax) +- xorl %eax,%eax +- ret +- +-typedef JmpBufStruct +-{ +- int edx, // Accumulator for operands and results data. +- ebx, // Pointer to data in the DS segment. +- esp, // Stack pointer (in the SS segment). +- ebp, // Pointer to data on the stack (in the SS segment). +- esi, // Pointer to data in the segment pointer to by the DS register; source pointer for string operations. +- edi; // Pointer to data (or destination) in the segment pointer to by the ES register; destination pointer for string operations. +- +-} JmpBufStruct; +- +- +-void record_jb(sys_thread_t *t, JmpBufStruct *jb) +-{ +- t->regs[0] = jb->eax; // What about these two register ? they seem missing in jmp_buf. +- t->regs[1] = / *jb->ecx;* / 0; +- t->regs[2] = jb->edx; // The rest of these registers are defined... +- t->regs[3] = jb->ebx; +- t->regs[4] = jb->ebp; +- t->regs[5] = jb->esi; +- t->regs[6] = jb->edi; +-} +-*/ +- +-#if 0 +-static void +-finish_suspension(void *arg) +-{ +- if (_thread_run->suspended != SUSP_NO) +- _thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); +-} +- +-void _pthread_suspend_np_by_pthread_common(pthread_t thread) +-{ +-struct timeval tv; +-struct timespec current_ts; +- +- switch (thread->state) { +- case PS_RUNNING: +- /* +- * Remove the thread from the priority queue and +- * set the state to suspended: +- */ +- PTHREAD_PRIOQ_REMOVE(thread); +- PTHREAD_SET_STATE(thread, PS_SUSPENDED); +- break; +- +- case PS_SPINBLOCK: +- case PS_FDR_WAIT: +- case PS_FDW_WAIT: +- case PS_POLL_WAIT: +- case PS_SELECT_WAIT: +- /* +- * Remove these threads from the work queue +- * and mark the operation as interrupted: +- */ +- if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) +- PTHREAD_WORKQ_REMOVE(thread); +- _thread_seterrno(thread,EINTR); +- +- /* FALLTHROUGH */ +- case PS_SLEEP_WAIT: +- thread->interrupted = 1; +- +- /* FALLTHROUGH */ +- case PS_SIGTHREAD: +- case PS_WAIT_WAIT: +- case PS_SIGSUSPEND: +- case PS_SIGWAIT: +- /* +- * Remove these threads from the waiting queue and +- * set their state to suspended: +- */ +- PTHREAD_WAITQ_REMOVE(thread); +- PTHREAD_SET_STATE(thread, PS_SUSPENDED); +- break; +- +- case PS_MUTEX_WAIT: +- /* Mark the thread as suspended and still in a queue. */ +- thread->suspended = SUSP_MUTEX_WAIT; +- +- PTHREAD_SET_STATE(thread, PS_SUSPENDED); +- break; +- case PS_COND_WAIT: +-#if 0 +- /* This is for a pthreads_cond_timedwait() --billh */ +- if (thread->wakeup_time.tv_sec != -1) { +- /* (1) Use to restore the waiting-queue time that's left when the +- * thread is resumed. --billh +- */ +- _subtract_timespec3(thread, ¤t_ts, &thread->remaining_wakeup_time); +- +- /* (2) So that it's inserted at the end of the waiting queue and +- * not scanned by the uthreads_kern.c waiting queue logic. It also +- * means to make it wait forever. +- */ +- thread->wakeup_time.tv_sec = -1; +- thread->wakeup_time.tv_nsec = -1; +- +- /* (3) Remove and reinsert it at the end of waiting-queue +- * (automatic on the insertion attempt when (2)). +- */ +- PTHREAD_WORKQ_REMOVE(thread); +- PTHREAD_WORKQ_INSERT(thread); +- } +-#endif +- +- /* Mark the thread as suspended and still in a queue. */ +- thread->suspended = SUSP_COND_WAIT; +- +- PTHREAD_SET_STATE(thread, PS_SUSPENDED); +- break; +- case PS_JOIN: +- /* Mark the thread as suspended and joining: */ +- thread->suspended = SUSP_JOIN; +- +- PTHREAD_NEW_STATE(thread, PS_SUSPENDED); +- break; +- case PS_FDLR_WAIT: +- case PS_FDLW_WAIT: +- case PS_FILE_WAIT: +- /* Mark the thread as suspended: */ +- thread->suspended = SUSP_YES; +- +- /* +- * Threads in these states may be in queues. +- * In order to preserve queue integrity, the +- * cancelled thread must remove itself from the +- * queue. Mark the thread as interrupted and +- * set the state to running. When the thread +- * resumes, it will remove itself from the queue +- * and call the suspension completion routine. +- */ +- thread->interrupted = 1; +- _thread_seterrno(thread, EINTR); +- PTHREAD_NEW_STATE(thread, PS_RUNNING); +- thread->continuation = finish_suspension; +- break; +- +- case PS_DEAD: +- case PS_DEADLOCK: +- case PS_STATE_MAX: +- case PS_SUSPENDED: +- /* Nothing needs to be done: */ +- break; +- } +-} +- +-void _pthread_resume_by_pthread_common(pthread_t thread, enum pthread_susp old_suspended) +-{ +-struct timeval tv; +-struct timespec current_ts, +- remaining_spec; +- +- /* Is it currently suspended? */ +- if (thread->state == PS_SUSPENDED) { +- /* +- * Defer signals to protect the scheduling queues +- * from access by the signal handler: +- */ +- _thread_kern_sig_defer(); +- +- switch (old_suspended) { +- case SUSP_MUTEX_WAIT: +- /* Set the thread's state back. */ +- PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); +- break; +- case SUSP_COND_WAIT: +- /* For cases where it was doing a pthread_cond_timedwait() +- * Mark the remaining suspend time. +- * --billh +- */ +-#if 0 +- if (thread->remaining_wakeup_time.tv_sec != -1) { +- GET_CURRENT_TOD(tv); +- TIMEVAL_TO_TIMESPEC(&tv, ¤t_ts); +- +- _subtract_timespec3(remaining_spec, &thread->wakeup_time, ¤t_ts); +- _thread_kern_set_timeout_by_pthread_timespec(thread, &remaining_spec); +- } +-#endif +- +- /* Set the thread's state back. */ +- PTHREAD_SET_STATE(thread,PS_COND_WAIT); +- break; +- case SUSP_JOIN: +- /* Set the thread's state back. */ +- PTHREAD_SET_STATE(thread,PS_JOIN); +- break; +- case SUSP_NOWAIT: +- /* Allow the thread to run. */ +- PTHREAD_SET_STATE(thread,PS_RUNNING); +- PTHREAD_WAITQ_REMOVE(thread); +- PTHREAD_PRIOQ_INSERT_TAIL(thread); +- break; +- case SUSP_NO: +- case SUSP_YES: +- /* Allow the thread to run. */ +- PTHREAD_SET_STATE(thread,PS_RUNNING); +- PTHREAD_PRIOQ_INSERT_TAIL(thread); +- break; +- } +- +- /* +- * Undefer and handle pending signals, yielding if +- * necessary: +- */ +- _thread_kern_sig_undefer(); +- } +-} +- + #endif |