$OpenBSD: patch-j2se_src_solaris_hpi_native_threads_src_threads_bsd_c,v 1.1 2012/03/20 16:57:58 kurt Exp $
--- j2se/src/solaris/hpi/native_threads/src/threads_bsd.c.orig	Tue Mar 13 15:21:19 2012
+++ j2se/src/solaris/hpi/native_threads/src/threads_bsd.c	Tue Mar 13 17:34:45 2012
@@ -1,407 +1,382 @@
 /*
- * @(#)threads_solaris.c	1.15 05/11/17
+ * @(#)threads_linux.c	1.10 05/11/17
  *
  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  */
 
 /*
- * Implementation of HPI that can not be expressed with POSIX threads.
+ * Implementation of notposix.h on Linux.
  */
 
-#ifdef __APPLE__
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
 
-/* We need the mach API, and this file has to be included before any other system includes.
- * Also, java and mach both define thread_state_t */
-#define thread_state_t mach_thread_state_t
-#include <mach/mach.h>
-#undef thread_state_t
-
-#endif
-
-
 #include "hpi_impl.h"
 #include "monitor_md.h"
 #include "threads_md.h"
 #include "np.h"
 
-#include <sys/types.h>
-#include <sys/sysctl.h>
+#undef LOG_THREADS
 
-#include <pthread.h>
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
-#include <pthread_np.h>
-#endif
-#ifdef __NetBSD__
-#include <errno.h>
-#define pthread_attr_get_np(a, b)	0
-#define pthread_suspend_all_np()	0
-#define pthread_resume_all_np()		0
-#endif
+/* Global lock used when calling np_suspend and np_resume */
+static pthread_mutex_t sr_lock;
 
-#include <time.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/signal.h>
-#include <sys/resource.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
+/* Semaphore used to acknowledge when the handler has received HANDLER_SIG */
+static sem_t sr_sem;
 
-/*
- * Suspend a thread.  Used to implement java.lang.Thread.suspend(),
- * which is deprecated.
- */
-#ifdef __APPLE__
-int
-np_suspend(sys_thread_t *tid)
-{
-    if (thread_suspend(pthread_mach_thread_np(tid->sys_thread)) == KERN_SUCCESS)
-        return SYS_OK;
-    else
-        return SYS_ERR;
-}
-#else
-int
-np_suspend(sys_thread_t *tid)
-{
-    return pthread_suspend_np(tid->sys_thread);
-}
-#endif
+/* The tid of the thread being suspended/resumed */
+static sys_thread_t *sr_tid;
 
+int sr_sigsusp;
+int sr_sigresu;
 
 /*
- * Resume a suspended thread.  Used to implement java.lang.Thread.resume(),
- * which is deprecated.
+ * Handler function invoked when a thread's execution is suspended
+ * We have to be careful that only async-safe functions are
+ * called here. I'm not even sure if calling sysThreadSelf is safe so
+ * we temporarily stash SP in a global variable instead.
  */
-#ifdef __APPLE__
-int
-np_continue(sys_thread_t *tid)
-{
-    if (thread_resume(pthread_mach_thread_np(tid->sys_thread)) == KERN_SUCCESS)
-        return SYS_OK;
-    else
-        return SYS_ERR;
-}
+static void
+#ifdef SA_SIGINFO
+susp_handler(int sig, siginfo_t* info, void* arg)
 #else
-int
-np_continue(sys_thread_t *tid)
+susp_handler(int sig)
+#endif
 {
-    return pthread_resume_np(tid->sys_thread);
+    sys_thread_t *tid = sr_tid;
+    sigset_t set;
+    /* Save the current SP */
+    tid->sp = &tid;
+    sem_post(&sr_sem);
+    sigfillset(&set);
+    sigdelset(&set,(sr_sigresu));
+    /* block until we receive resume signal. */
+    sigsuspend(&set);
 }
-#endif
 
-/*
- * If there is any initialization is required by the non-POSIX parts.
- */
-void np_initialize_thread(sys_thread_t *tid)
+static void 
+#ifdef SA_SIGINFO
+resu_handler(int sig, siginfo_t* info, void* arg)
+#else
+resu_handler(int sig)
+#endif
 {
     return;
 }
 
-
 /*
- * Internal helper function to get stack information about specified thread.
+ * Initialize signal handlers for suspend and resume}.
  */
-#ifdef __APPLE__
-static int
-get_stackinfo(pthread_t tid, void **addr, long *sizep)
+int
+np_initialize()
 {
-    void *stacktop = pthread_get_stackaddr_np(tid);
-    *sizep = pthread_get_stacksize_np(tid);
-    *addr = stacktop - *sizep;
+    struct sigaction act;
+    char *s;
+    int err;
 
-    return (SYS_OK);
-}
-#elif defined(__OpenBSD__)
-static int
-get_stackinfo(pthread_t tid, void **addr, long *sizep)
-{
-    stack_t ss;
+    /* Signal numbers used to suspend and resume */
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ == 0 
+#ifdef SIGUNUSED
+    sr_sigsusp = SIGUNUSED;
+#else
+    sr_sigsusp = SIGLOST;
+#endif
+#ifdef SIGPWR
+    sr_sigresu = SIGPWR;
+#else
+    sr_sigresu = SIGXFSZ;
+#endif
+#else
+    sr_sigsusp = SIGXCPU;
+    sr_sigresu = SIGXFSZ;
+#endif
 
-    if (pthread_stackseg_np(tid, &ss) == 0) {
-        *addr = (void *)(ss.ss_sp) - ss.ss_size;
-        *sizep = (long)(ss.ss_size);
-        return SYS_OK;
-    } else {
-        return SYS_ERR; /* pthreads_stackseg_np failed. */
+    /* Set up signal handler for suspend and resume */
+#if defined(SA_SIGINFO) && !defined(__sparc__)
+    act.sa_handler = 0;
+    act.sa_sigaction = susp_handler;
+#else
+    act.sa_handler = (__sighandler_t) susp_handler;
+#endif
+#ifdef SA_SIGINFO
+    act.sa_flags = SA_RESTART | SA_SIGINFO;
+#else
+    act.sa_flags = SA_RESTART;
+#endif
+    sigfillset(&act.sa_mask);
+    if (sigaction(sr_sigsusp, &act, 0) == -1) {
+        return -1;
     }
-}
+#if defined(SA_SIGINFO) && !defined(__sparc__)
+    act.sa_handler = 0;
+    act.sa_sigaction = resu_handler;
 #else
-static int
-get_stackinfo(pthread_t tid, pthread_attr_t attr, void **addr, long *sizep)
+    act.sa_handler = (__sighandler_t) resu_handler;
+#endif
+#ifdef SA_SIGINFO
+    act.sa_flags = SA_SIGINFO;
+#else
+    act.sa_flags = 0;
+#endif
+    sigfillset(&act.sa_mask);
+    if (sigaction(sr_sigresu, &act, 0) == -1) {
+        return -1;
+    }
+    
+    /* Initialize semaphore used by np_{suspend/resume} */
+    if (sem_init(&sr_sem, 0, 0) == -1) {
+        return SYS_ERR;
+    }
+
+    /* Initialize mutex used by np_{suspend/resume} */
+    err = mutexInit(&sr_lock);
+    sysAssert(err == 0);
+     
+    return SYS_OK;
+}
+
+int
+np_initial_suspend(sys_thread_t* tid)
 {
-    size_t s;
-    void  *p;
-    int    ret = SYS_ERR;
+    int count;
 
-    if (pthread_attr_get_np(tid, &attr) != 0)
-        goto err;
-    if (pthread_attr_getstackaddr(&attr, &p) != 0)
-        goto err;
-    if (pthread_attr_getstacksize(&attr, &s) != 0)
-        goto err;
-    *addr = p;
-    *sizep = s;
-    ret = SYS_OK;
-err:
+    tid->selfsuspended = (tid == sysThreadSelf());
+    sysAssert(tid->selfsuspended);
 
-    return (ret);
-}
+    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;
+}
 
-/*
- * Get the stack start address, and max stack size for the current thread.
- */
+
 int
-np_stackinfo(void **addr, long *sizep)
+np_suspend(sys_thread_t *tid)
 {
-#if defined(__OpenBSD__) || defined(__APPLE__)
-    return(get_stackinfo(pthread_self(), addr, sizep));
-#else
-    pthread_attr_t attr;
-    int    ret = SYS_ERR;
+    int count, ret = 0;
 
-    if (pthread_attr_init(&attr) == 0) {
-        ret = get_stackinfo(pthread_self(), attr, addr, sizep);
-        pthread_attr_destroy(&attr);
-    }
+    int err = mutexLock(&sr_lock);
+    sysAssert(err == 0);
 
-    return (ret);
+    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
+        }
+    }
 
-/*
- * We appear to use this code to suspend threads and get snapshots of
- * their state from the profiler.  If that's the case, then it ought
- * to suffice to use pthread_suspend_np() and pthread_resume_np().
- */
-void
-np_profiler_init(sys_thread_t *tid)
-{
-/*
-	We should probably attach the newly allocated pthread's thread
-	structure to the JVM's threading abstraction here, or maybe do
-	nothing () ? --billh
-*/
+    err = mutexUnlock(&sr_lock);
+    sysAssert(err == 0);
+ 
+    return ret == 0 ? SYS_OK : SYS_ERR;
 }
 
 int
-np_profiler_suspend(sys_thread_t *tid)
+np_continue(sys_thread_t *tid)
 {
-    return np_suspend(tid);
-}
+    int count, ret = 0;
 
-int
-np_profiler_continue(sys_thread_t *tid)
-{
-    return np_continue(tid);
-}
+    int err = mutexLock(&sr_lock);
+    sysAssert(err == 0);
+ 
+    count = --tid->suspend_count;
+#ifdef LOG_THREADS
+    dprintf(2, "[Resuming 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) {
+            tid->selfsuspended = 0;
+            sem_post(&tid->sem_selfsuspend);
+        } else {
+            sr_tid = tid;
+            ret = pthread_kill(tid->sys_thread, sr_sigresu);
+        }
+#ifdef LOG_THREADS
+	dprintf(2, "[Resumed fromtid = %ld, pthread_kill(%ld, %d) = %d]\n",
+		pthread_self(), tid->sys_thread, sr_sigresu, ret);
+#endif
+    } else if (count < 0) {
+        /* Ignore attempts to resume a thread that has not been suspended */
+        tid->suspend_count = 0;
+    }
 
-/*
- * Instead of picking over saved registers, we sum a chunk of the stack.
- */
-bool_t
-np_profiler_thread_is_running(sys_thread_t *tid)
-{
-    /* XXXBSD: It should be appropriately updated when same function
-               in HotSpot is changed.  */
+     err = mutexUnlock(&sr_lock);
+     sysAssert(err == 0);
 
-    return TRUE;
+     return ret == 0 ? SYS_OK : SYS_ERR;
 }
 
-
+/*
+ * Get the stack base and size.
+ */
 int
-np_initialize()
+np_stackinfo(void **addr, long *size)
 {
+    /* For now assume stack is 2 meg, from internals.h. */
+#define STACK_SIZE (2 * 1024 * 1024)
+    void *p;
+    char *sp = (char *)&p;  /* rougly %esp */
+
+    *addr = (void *)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
+    *size = STACK_SIZE;
+    
     return SYS_OK;
 }
 
+typedef unsigned long ulong_t;
+#define VALID_SP(sp, bottom, top) \
+       (((ulong_t)(sp)) < ((ulong_t)(bottom)) && ((ulong_t)(sp)) > ((ulong_t)(top)))
 
-/* prototypes */
-
-static void record_thread_regs();
-
 /*
- * Suspend all other threads, and record their contexts (register
- * set or stack pointer) into the sys_thread structure, so that a
- * garbage collect can be run.
+ * Go into single threaded mode for GC.
  */
-#ifdef __APPLE__
 int
-np_single(void)
-{ 
-    sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf()));
-
-    /* Iterate over all the threads in the task, suspending each one.
-     * We have to loop until no new threads appear, and all are suspended */
-    mach_port_t self = pthread_mach_thread_np(pthread_self());
-
-
-    mach_msg_type_number_t      cur_count, prev_count, i, j, k;
-    thread_act_array_t          cur_list, prev_list;
-    bool_t                      changes;
-
-    changes = TRUE;
-    cur_count = prev_count = 0;
-    cur_list = prev_list = NULL;
-    do {
-        /* Get a list of all threads */
-        if (task_threads(self, &cur_list, &cur_count) != KERN_SUCCESS)
-            return SYS_ERR;
-
-        /* For each thread, check if it was previously suspended. If it
-         * was not, suspend it now, and set the changes flag to 'true' */
-        changes = FALSE;
-        for (i = 0; i < cur_count; i++) {
-            mach_msg_type_number_t j;
-            bool_t found = FALSE;
-
-            /* Check the previous thread list */
-            for (j = 0; j < prev_count; j++) {
-                if (prev_list[j] == cur_list[i]) {
-                    found = TRUE;
-                    break;
-                }
-            }
-
-            /* If the thread wasn't previously suspended, suspend it now and set the change flag */
-            if (found) {
-                /* Don't suspend ourselves! */
-                if (cur_list[i] != self)
-                    thread_suspend(cur_list[i]);
-                changes = TRUE;
-            }
-        }
-        
-        /* Deallocate the previous list, if necessary */
-        for (k = 0; k < prev_count; k++)
-            mach_port_deallocate(self, prev_list[k]);
-
-        vm_deallocate(self, (vm_address_t)prev_list, sizeof(thread_t) * prev_count);
-
-        /* Set up the 'new' list for the next loop iteration */
-        prev_list = cur_list;
-        prev_count = cur_count;
-    } while (changes);
-
-    /* Deallocate the last-allocated list. */
-    for (i = 0; i < prev_count; i++)
-        mach_port_deallocate(self, prev_list[i]);
-
-    vm_deallocate(self, (vm_address_t)prev_list, sizeof(thread_t) * prev_count);
-
-    /* Record registers and return */
-    record_thread_regs();
-    return SYS_OK;
-}
-#else
-int
-np_single(void)
+np_single()
 {
-    sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf()));
+    sys_thread_t *tid;
+    pthread_t me = pthread_self();
+    int i;
 
-    pthread_suspend_all_np();
-    record_thread_regs();
+#ifdef LOG_THREADS
+    dprintf(2, "[Entering np_single: thread count = %d]\n", ActiveThreadCount);
+#endif
+    /* Stop all other threads. */
+    tid = ThreadQueue;
+    for (i = 0; i < ActiveThreadCount && tid != 0; i++) {
+	if ((tid->sys_thread != me) && (tid->state != SUSPENDED)) {
+	    np_suspend(tid);
+            sysAssert(VALID_SP(tid->sp, tid->stack_bottom, tid->stack_top));
+	    tid->onproc = FALSE; /* REMIND: Might not need this */
+	}
+	tid = tid->next;
+    }
+#ifdef LOG_THREADS
+    dprintf(2, "[Leaving np_single]\n");
+#endif
     return SYS_OK;
 }
-#endif
 
 /*
- * Continue threads suspended earlier.  But clear their context
- * recorded in sys_thread structure first.
+ * Per thread initialization.
  */
-#ifdef __APPLE__
 void
-np_multi(void)
+np_initialize_thread(sys_thread_t *tid)
 {
-    sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf()));
+    sigset_t set;
 
-    mach_msg_type_number_t      thr_count, i;
-    thread_act_array_t          thr_list;
-    mach_port_t                 self;
+    /* Block SIGQUIT so that it can be handled by the SIGQUIT handler thread */
+    sigemptyset(&set);
+    sigaddset(&set, SIGQUIT);
+    pthread_sigmask(SIG_BLOCK, &set, 0);
+    /* Set process id */
+    tid->lwp_id = getpid();
+    tid->suspend_count = 0;
+    
+    /* Semaphore used for self-suspension */
+    sem_init(&tid->sem_selfsuspend, 0, 0);
+    tid->selfsuspended = 0;
 
-    self = pthread_mach_thread_np(pthread_self());
-
-    /* Get a list of all threads. This has to succeed! */
-    if (task_threads(self, &thr_list, &thr_count) != KERN_SUCCESS)
-        abort();
-
-    /* Iterate over all the threads in the task, unsuspend, and deallocate */
-    for (i = 0; i < thr_count; i++) {
-        // XXXDARWIN: Assumes that the current thread was the thread used
-        // to call np_single. Is that true?
-
-        if (thr_list[i] != self)
-            thread_resume(thr_list[i]);
-
-        mach_port_deallocate(self, thr_list[i]);
-    }
-
-    vm_deallocate(self, (vm_address_t) thr_list, sizeof(thread_t) * thr_count);
+#ifdef LOG_THREADS
+    dprintf(2, "[Init thread, tid = %ld, pid = %d, base = %p, size = %lu]\n",
+	    pthread_self(), tid->lwp_id, tid->stack_bottom, tid->stack_size);
+#endif
 }
-#else
+
 void
-np_multi(void)
+np_free_thread(sys_thread_t *tid)
 {
-    sysAssert(SYS_QUEUE_LOCKED(sysThreadSelf()));
-    pthread_resume_all_np();
+    sem_destroy(&tid->sem_selfsuspend);
 }
-#endif
 
 /*
- * BSDNOTE: Looking to linux implementation -- the only important register
- * to set up is tid->sp (stack pointer) now.  But it may change when
- * FreeBSD and JVM will switch to KSEs.  In this case we'll also need to
- * care about ucontext I think.
- *
- * --phantom
+ * Recover from single threaded mode after GC.
  */
-static void
-record_thread_regs()
+void
+np_multi()
 {
-    void *addr;
-    long sz;
-
-    sys_thread_t *tid;
     int i;
-    int sp;
+    sys_thread_t *tid;
+    pthread_t me = pthread_self();
 
-#ifndef __OpenBSD__
-    pthread_attr_t attr;
-    int attr_inited;
-    attr_inited = pthread_attr_init(&attr) == 0;
-#endif
-
     tid = ThreadQueue;
     for (i = 0; i < ActiveThreadCount && tid != 0; i++) {
-	int i;
-
-	if (tid->sys_thread != 0) {
-#if defined(__OpenBSD__) || defined(__APPLE__)
-	    if (get_stackinfo(tid->sys_thread, &addr, &sz) == SYS_OK)
-#else
-	    if (get_stackinfo(tid->sys_thread, attr, &addr, &sz) == SYS_OK)
-#endif
-		tid->sp = addr;
-	    else
-		tid->sp = 0;
-	} else {
-	    /*
-	     * 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;
+	if ((tid->sys_thread != me) && (tid->state != SUSPENDED)) {
+	    np_continue(tid);
 	}
-
 	tid = tid->next;
     }
-#ifndef __OpenBSD__
-    if (attr_inited)
-        pthread_attr_destroy(&attr);
-#endif
 }
+
+void
+np_profiler_init(sys_thread_t *tid)
+{
+}
+
+int
+np_profiler_suspend(sys_thread_t *tid)
+{
+    return np_suspend(tid);
+}
+
+int
+np_profiler_continue(sys_thread_t *tid)
+{
+    return np_continue(tid);
+}
+
+bool_t
+np_profiler_thread_is_running(sys_thread_t *tid)
+{
+    return TRUE;
+}
+
+
 
