You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/12/01 07:04:00 UTC
svn commit: r350181 [165/198] - in
/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core: ./ depends/
depends/files/ depends/jars/ depends/libs/ depends/libs/linux.IA32/
depends/libs/win.IA32/ depends/oss/ depends/oss/linux.IA32/
depends/oss/win....
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/native-src/linux.IA32/thread/hythread.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/native-src/linux.IA32/thread/hythread.c?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/native-src/linux.IA32/thread/hythread.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/native-src/linux.IA32/thread/hythread.c Wed Nov 30 21:29:27 2005
@@ -0,0 +1,3682 @@
+/* Copyright 1991, 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * @ingroup Thread
+ * @brief Threading and synchronization support
+ */
+
+#include "threaddef.h"
+#include <stdlib.h>
+
+#define CDEV_CURRENT_FUNCTION _prototypes_private
+static hythread_t allocate_thread PROTOTYPE ((int globalIsLocked));
+static void free_thread
+PROTOTYPE ((hythread_t thread, int globalAlreadyLocked));
+static IDATA interrupt_waiting_thread
+PROTOTYPE ((hythread_t self, hythread_t threadToInterrupt));
+static void remove_from_queue
+PROTOTYPE ((hythread_t volatile *queue, hythread_t thread));
+static IDATA destroy_thread
+PROTOTYPE ((hythread_t thread, int globalAlreadyLocked));
+void VMCALL hythread_shutdown PROTOTYPE ((void));
+static void HYTHREAD_PROC tls_null_finalizer PROTOTYPE ((void *entry));
+static I_32 HYTHREAD_PROC interruptServer PROTOTYPE ((void *entryArg));
+static hythread_monitor_t VMCALL hythread_monitor_acquire
+PROTOTYPE ((hythread_t self, IDATA policy, IDATA policyData));
+void VMCALL hythread_init PROTOTYPE ((hythread_library_t lib));
+static IDATA init_global_monitor PROTOTYPE ((hythread_library_t lib));
+static void tls_finalize PROTOTYPE ((hythread_t thread));
+static void free_monitor_pools PROTOTYPE ((void));
+static void *VMCALL thread_malloc PROTOTYPE ((void *unused, U_32 size));
+static void NORETURN internal_exit PROTOTYPE ((void));
+static IDATA monitor_wait
+PROTOTYPE ((hythread_monitor_t monitor, I_64 millis, IDATA nanos,
+ IDATA interruptable));
+static IDATA monitor_enter
+PROTOTYPE ((hythread_t self, hythread_monitor_t monitor));
+static UDATA init_monitor
+PROTOTYPE ((hythread_monitor_t monitor, UDATA flags));
+
+static IDATA monitor_enter_three_tier
+PROTOTYPE ((hythread_t self, hythread_monitor_t monitor));
+
+static hytime_t getCurrentCycles PROTOTYPE ((void));
+static hythread_monitor_pool_t allocate_monitor_pool PROTOTYPE ((void));
+static IDATA create_thread
+PROTOTYPE ((hythread_t * handle, UDATA stacksize, UDATA priority,
+ UDATA suspend, hythread_entrypoint_t entrypoint, void *entryarg,
+ int globalIsLocked));
+static void interrupt_thread
+PROTOTYPE ((hythread_t thread, UDATA interruptFlag));
+
+static void unblock_spinlock_threads
+PROTOTYPE ((hythread_t self, hythread_monitor_t monitor));
+
+static void notify_thread
+PROTOTYPE ((hythread_t threadToNotify, int setNotifiedFlag));
+static IDATA monitor_exit
+PROTOTYPE ((hythread_t self, hythread_monitor_t monitor));
+static WRAPPER_TYPE thread_wrapper PROTOTYPE ((WRAPPER_ARG arg));
+static void VMCALL thread_free PROTOTYPE ((void *unused, void *ptr));
+static void enqueue_thread
+PROTOTYPE ((hythread_t * queue, hythread_t thread));
+static IDATA monitor_notify_one_or_all
+PROTOTYPE ((hythread_monitor_t monitor, int notifyall));
+
+#undef CDEV_CURRENT_FUNCTION
+
+#if defined(THREAD_ASSERTS)
+/*
+ * Helper variable for asserts.
+ * We use this to keep track of when the global lock is owned.
+ * We don't want to do a re-entrant enter on the global lock
+ */
+hythread_t global_lock_owner = UNOWNED;
+#endif
+
+#define BOUNDED_I64_TO_IDATA(longValue) ((longValue) > 0x7FFFFFFF ? 0x7FFFFFFF : (IDATA)(longValue))
+
+#define HYTHREAD_MAX_TLS_KEYS (sizeof( ((HyThreadLibrary*)NULL)->tls_finalizers ) / sizeof( ((HyThreadLibrary*)NULL)->tls_finalizers[0] ))
+
+#define CDEV_CURRENT_FUNCTION hythread_init
+/**
+ * Initialize a Hy threading library.
+ *
+ * @note This must only be called once.
+ *
+ * If any OS threads were created before calling this function, they must be attached using
+ * hythread_attach before accessing any Hy thread library functions.
+ *
+ * @param[in] lib pointer to the Hy thread library to be initialized (non-NULL)
+ * @return The Hy thread library's initStatus will be set to 0 on success or
+ * a negative value on failure.
+ *
+ * @see hythread_attach, hythread_shutdown
+ */
+void VMCALL
+hythread_init (hythread_library_t lib)
+{
+ ASSERT (lib);
+
+ lib->spinlock = 0;
+ lib->threadCount = 0;
+ lib->globals = NULL;
+ lib->stack_usage = 0;
+
+ /* set all TLS finalizers to NULL. This indicates that the key is unused */
+ memset (lib->tls_finalizers, 0, sizeof (lib->tls_finalizers));
+
+ STATIC_ASSERT (CALLER_LAST_INDEX <= MAX_CALLER_INDEX);
+
+ if (TLS_ALLOC (lib->self_ptr))
+ goto init_cleanup1;
+
+ lib->monitor_pool = allocate_monitor_pool ();
+ if (lib->monitor_pool == NULL)
+ goto init_cleanup2;
+
+ if (!MUTEX_INIT (lib->monitor_mutex))
+ goto init_cleanup3;
+ if (!MUTEX_INIT (lib->tls_mutex))
+ goto init_cleanup4;
+ if (!MUTEX_INIT (lib->global_mutex))
+ goto init_cleanup5;
+
+ lib->thread_pool =
+ pool_new (sizeof (HyThread), 0, 0, 0, thread_malloc, thread_free, NULL);
+ if (lib->thread_pool == NULL)
+ goto init_cleanup6;
+
+ lib->global_pool =
+ pool_new (sizeof (HyThreadGlobal), 0, 0, 0, thread_malloc, thread_free,
+ NULL);
+ if (lib->global_pool == NULL)
+ goto init_cleanup7;
+
+ if (init_global_monitor (lib))
+ goto init_cleanup8;
+
+ lib->initStatus = 1;
+ return;
+
+init_cleanup8:pool_kill (lib->global_pool);
+init_cleanup7:pool_kill (lib->thread_pool);
+init_cleanup6:MUTEX_DESTROY (lib->global_mutex);
+init_cleanup5:MUTEX_DESTROY (lib->tls_mutex);
+init_cleanup4:MUTEX_DESTROY (lib->monitor_mutex);
+init_cleanup3:free_monitor_pools ();
+init_cleanup2:TLS_DESTROY (lib->self_ptr);
+init_cleanup1:lib->initStatus = -1;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_self
+/**
+ * Return the hythread_t for the current thread.
+ *
+ * @note Must be called only by an attached thread
+ *
+ * @return hythread_t for the current thread
+ *
+ * @see hythread_attach
+ *
+ */
+hythread_t VMCALL
+hythread_self (void)
+{
+ return MACRO_SELF ();
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_create
+/**
+ * Create a new OS thread.
+ *
+ * The created thread is attached to the threading library.<br>
+ * <br>
+ * Unlike POSIX, this doesn't require an attributes structure.
+ * Instead, any interesting attributes (e.g. stacksize) are
+ * passed in with the arguments.
+ *
+ * @param[out] handle a pointer to a hythread_t which will point to the thread (if successfully created)
+ * @param[in] stacksize the size of the new thread's stack (bytes)<br>
+ * 0 indicates use default size
+ * @param[in] priority priorities range from HYTHREAD_PRIORITY_MIN to HYTHREAD_PRIORITY_MAX (inclusive)
+ * @param[in] suspend set to non-zero to create the thread in a suspended state.
+ * @param[in] entrypoint pointer to the function which the thread will run
+ * @param[in] entryarg a value to pass to the entrypoint function
+ *
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_exit, hythread_resume
+ */
+IDATA VMCALL
+hythread_create (hythread_t * handle, UDATA stacksize, UDATA priority,
+ UDATA suspend, hythread_entrypoint_t entrypoint,
+ void *entryarg)
+{
+ return create_thread (handle, stacksize, priority, suspend, entrypoint,
+ entryarg, GLOBAL_NOT_LOCKED);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION create_thread
+/*
+ * Create a new OS thread and attach it.
+ */
+static IDATA
+create_thread (hythread_t * handle, UDATA stacksize, UDATA priority,
+ UDATA suspend, hythread_entrypoint_t entrypoint,
+ void *entryarg, int globalIsLocked)
+{
+ hythread_t thread;
+ hythread_library_t lib = GLOBAL_DATA (default_library);
+
+ ASSERT (lib->initStatus);
+
+ if (priority > HYTHREAD_PRIORITY_MAX)
+ {
+ goto cleanup0;
+ }
+
+ if (stacksize == 0)
+ {
+ stacksize = STACK_DEFAULT_SIZE;
+ }
+
+ thread = allocate_thread (globalIsLocked);
+ if (!thread)
+ {
+ goto cleanup0;
+ }
+ if (handle)
+ {
+ *handle = thread;
+ }
+ thread->library = lib;
+ thread->priority = priority;
+ thread->attachcount = 0;
+ thread->stacksize = stacksize;
+
+ memset (thread->tls, 0, sizeof (thread->tls));
+
+ thread->interrupter = NULL;
+
+ if (!COND_INIT (thread->condition))
+ {
+ goto cleanup1;
+ }
+ if (!MUTEX_INIT (thread->mutex))
+ {
+ goto cleanup2;
+ }
+
+ thread->flags = suspend ? HYTHREAD_FLAG_SUSPENDED : 0;
+ thread->entrypoint = entrypoint;
+ thread->entryarg = entryarg;
+
+ if (IS_JLM_ENABLED (thread))
+ {
+ hythread_jlm_thread_init (thread);
+ }
+
+#if defined(LINUX)
+ thread->jumpBuffer = NULL;
+#endif
+
+ if (!THREAD_CREATE (thread, stacksize, priority, thread_wrapper, thread))
+ {
+ goto cleanup3;
+ }
+
+ return 0;
+
+/* Cleanup points */
+cleanup3:MUTEX_DESTROY (thread->mutex);
+cleanup2:COND_DESTROY (thread->condition);
+cleanup1:free_thread (thread, GLOBAL_NOT_LOCKED);
+cleanup0:if (handle)
+ *handle = NULL;
+ return -1;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_attach
+/**
+ * Attach an OS thread to the threading library.
+ *
+ * Create a new hythread_t to represent the existing OS thread.
+ * Attaching a thread is required when a thread was created
+ * outside of the Hy threading library wants to use any of the
+ * Hy threading library functionality.
+ *
+ * If the OS thread is already attached, handle is set to point
+ * to the existing hythread_t.
+ *
+ * @param[out] handle pointer to a hythread_t to be set (will be ignored if null)
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_detach
+ */
+IDATA VMCALL
+hythread_attach (hythread_t * handle)
+{
+ hythread_t thread;
+
+ if (init_thread_library ())
+ {
+ goto cleanup0;
+ }
+
+ if ((thread = MACRO_SELF ()) != NULL)
+ {
+ if (handle)
+ {
+ *handle = thread;
+ }
+ THREAD_LOCK (thread, thread, CALLER_ATTACH);
+ thread->attachcount++;
+ THREAD_UNLOCK (thread, thread);
+ return 0;
+ }
+
+ thread = allocate_thread (GLOBAL_NOT_LOCKED);
+ if (!thread)
+ {
+ goto cleanup0;
+ }
+
+ thread->library = GLOBAL_DATA (default_library);
+ thread->attachcount = 1;
+ thread->priority = HYTHREAD_PRIORITY_NORMAL;
+ thread->flags = HYTHREAD_FLAG_ATTACHED;
+
+ if (!COND_INIT (thread->condition))
+ {
+ goto cleanup1;
+ }
+
+ if (!MUTEX_INIT (thread->mutex))
+ {
+ goto cleanup2;
+ }
+
+#if defined(WIN32)
+ {
+ DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+ GetCurrentProcess (), &thread->handle, 0, TRUE,
+ DUPLICATE_SAME_ACCESS);
+ }
+#else
+ thread->handle = THREAD_SELF ();
+#endif
+
+ initialize_thread_priority (thread);
+
+ TLS_SET (thread->library->self_ptr, thread);
+
+ thread->tid = RAS_THREAD_ID ();
+
+ if (handle)
+ {
+ *handle = thread;
+ }
+ return 0;
+
+/* failure points */
+cleanup2:COND_DESTROY (thread->condition);
+cleanup1:free_thread (thread, GLOBAL_NOT_LOCKED);
+cleanup0:return -1;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_suspend
+/**
+ * Suspend the current thread.
+ *
+ * Stop the current thread from executing until it is resumed.
+ *
+ * @return none
+ *
+ * @see hythread_resume
+ */
+void VMCALL
+hythread_suspend (void)
+{
+ hythread_t self = MACRO_SELF ();
+ ASSERT (self);
+
+ THREAD_LOCK (self, self, CALLER_SUSPEND);
+ self->flags |= HYTHREAD_FLAG_SUSPENDED;
+
+ COND_WAIT (self->condition, self->mutex);
+ if ((self->flags & HYTHREAD_FLAG_SUSPENDED) == 0)
+ break;
+ COND_WAIT_LOOP ();
+
+ THREAD_UNLOCK (self, self);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_resume
+/**
+ * Resume a thread.
+ *
+ * Take a threads out of the suspended state.
+ *
+ * If the thread is not suspended, no action is taken.
+ *
+ * @param[in] thread a thread to be resumed
+ * @return none
+ *
+ * @see hythread_create, hythread_suspend
+ */
+void VMCALL
+hythread_resume (hythread_t thread)
+{
+ hythread_t self;
+
+ ASSERT (thread);
+
+ if ((thread->flags & HYTHREAD_FLAG_SUSPENDED) == 0)
+ {
+ /* it wasn't suspended! */
+ return;
+ }
+
+ self = MACRO_SELF ();
+ ASSERT (self);
+
+ THREAD_LOCK (self, thread, CALLER_RESUME);
+
+ /*
+ * The thread _should_ only be OS suspended once, but
+ * handle the case where it's suspended more than once anyway.
+ */
+ COND_NOTIFY_ALL (thread->condition);
+ thread->flags &= ~HYTHREAD_FLAG_SUSPENDED;
+
+ THREAD_UNLOCK (self, thread);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_yield
+/**
+ * Yield the processor.
+ *
+ * @return none
+ */
+void VMCALL
+hythread_yield (void)
+{
+ THREAD_YIELD ();
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_init
+/*
+ * Acquire and initialize a new monitor from the threading library.
+ *
+ * @param[out] handle pointer to a hythread_monitor_t to be set to point to the new monitor
+ * @param[in] flags initial flag values for the monitor
+ * @return 0 on success, negative value on failure
+ *
+ * @deprecated This has been replaced by hythread_monitor_init_with_name
+ * @see hythread_monitor_init_with_name
+ */
+IDATA VMCALL
+hythread_monitor_init (hythread_monitor_t * handle, UDATA flags)
+{
+ IDATA rc;
+
+ /* Initialize monitor with default locking policy */
+ rc =
+ hythread_monitor_init_policy (handle, flags, HYTHREAD_LOCKING_DEFAULT,
+ HYTHREAD_LOCKING_NO_DATA);
+ return rc;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_init_policy
+/*
+ * Acquire and initialize a new monitor with given locking policy from the threading library.
+ *
+ * @param[out] handle pointer to a hythread_monitor_t to be set to point to the new monitor
+ * @param[in] flags initial flag values for the monitor
+ * @param[in] locking policy for the monitor
+ * @param[in] data associated with locking policy or HYTHREAD_LOCKING_NO_DATA
+ * @return 0 on success, negative value on failure
+ *
+ */
+IDATA VMCALL
+hythread_monitor_init_policy (hythread_monitor_t * handle, UDATA flags,
+ IDATA policy, IDATA policyData)
+{
+ hythread_monitor_t monitor;
+
+ hythread_t self = MACRO_SELF ();
+ ASSERT (self);
+ ASSERT (handle);
+
+ monitor = hythread_monitor_acquire (self, policy, policyData);
+ if (NULL == monitor)
+ {
+ return -1;
+ }
+
+ if (init_monitor (monitor, flags) != 0)
+ {
+ return -1;
+ }
+
+ if (IS_JLM_ENABLED (self))
+ {
+ hythread_jlm_monitor_init (monitor);
+ }
+
+ *handle = monitor;
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_destroy
+/**
+ * Destroy a monitor.
+ *
+ * Destroying a monitor frees the internal resources associated
+ * with it.
+ *
+ * @note A monitor must NOT be destroyed if threads are waiting on
+ * it, or if it is currently owned.
+ *
+ * @param[in] monitor a monitor to be destroyed
+ * @return 0 on success or non-0 on failure (the monitor is in use)
+ *
+ * @see hythread_monitor_init_with_name
+ */
+IDATA VMCALL
+hythread_monitor_destroy (hythread_monitor_t monitor)
+{
+ hythread_t self = MACRO_SELF ();
+
+ ASSERT (self);
+ ASSERT (monitor);
+
+ GLOBAL_LOCK (self, CALLER_MONITOR_DESTROY);
+
+ if (monitor->owner || monitor->waiting)
+ {
+ /* This monitor is in use! It was probably abandoned when a thread was cancelled.
+ * There's actually a very small timing hole here -- if the thread had just locked the
+ * mutex and not yet set the owner field when it was cancelled, we have no way of
+ * knowing that the mutex may be in an invalid state. The same thing can happen
+ * if the thread has just cleared the field and is about to unlock the mutex.
+ * Hopefully the OS takes care of this for us, but it might not.
+ */
+ GLOBAL_UNLOCK (self);
+ return HYTHREAD_ILLEGAL_MONITOR_STATE;
+ }
+
+ monitor->owner = (hythread_t) self->library->monitor_pool->next_free;
+ monitor->count = FREE_TAG;
+ monitor->userData = 0;
+ self->library->monitor_pool->next_free = monitor;
+
+ GLOBAL_UNLOCK (self);
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_enter
+/**
+ * Enter a monitor.
+ *
+ * A thread may re-enter a monitor it owns multiple times, but must
+ * exit the monitor the same number of times before any other thread
+ * wanting to enter the monitor is permitted to continue.
+ *
+ * @param[in] monitor a monitor to be entered
+ * @return 0 on success<br>
+ * HYTHREAD_PRIORITY_INTERRUPTED if the thread was priority interrupted while blocked
+ *
+ * @see hythread_monitor_enter_using_threadId, hythread_monitor_exit, hythread_monitor_exit_using_threadId
+ */
+IDATA VMCALL
+hythread_monitor_enter (hythread_monitor_t monitor)
+{
+ hythread_t self = MACRO_SELF ();
+
+ ASSERT (self);
+ ASSERT (monitor);
+ ASSERT (FREE_TAG != monitor->count);
+
+ if (monitor->owner == self)
+ {
+ ASSERT (monitor->count >= 1);
+ monitor->count++;
+
+ if (IS_JLM_ENABLED (self))
+ {
+ ASSERT (monitor->tracing);
+ monitor->tracing->recursive_count++;
+ monitor->tracing->enter_count++;
+ } /* if (IS_JLM_ENABLED(self)) */
+
+ return 0;
+ }
+
+ return monitor_enter (self, monitor);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_exit
+/**
+ * Exit a monitor.
+ *
+ * Exit a monitor, and if the owning count is zero, release it.
+ *
+ * @param[in] monitor a monitor to be exited
+ * @return 0 on success, <br>HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not own the monitor
+ *
+ * @see hythread_monitor_exit_using_threadId, hythread_monitor_enter, hythread_monitor_enter_using_threadId
+ */
+IDATA VMCALL
+hythread_monitor_exit (hythread_monitor_t monitor)
+{
+ hythread_t self = MACRO_SELF ();
+
+ ASSERT (self);
+ ASSERT (monitor);
+ ASSERT (FREE_TAG != monitor->count);
+
+ if (monitor->owner != self)
+ {
+ return HYTHREAD_ILLEGAL_MONITOR_STATE;
+ }
+
+ return monitor_exit (self, monitor);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_wait
+/**
+ * Wait on a monitor until notified.
+ *
+ * Release the monitor, wait for a signal (notification), then re-acquire the monitor.
+ *
+ * @param[in] monitor a monitor to be waited on
+ * @return 0 if the monitor has been waited on, notified, and reobtained<br>
+ * HYTHREAD_INVALID_ARGUMENT if millis or nanos is out of range (millis or nanos < 0, or nanos >= 1E6)<br>
+ * HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not own the monitor
+ *
+ * @see hythread_monitor_wait_interruptable, hythread_monitor_wait_timed, hythread_monitor_enter
+ *
+ */
+IDATA VMCALL
+hythread_monitor_wait (hythread_monitor_t monitor)
+{
+ return monitor_wait (monitor, 0, 0, WAIT_UNINTERRUPTABLE);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_notify
+/**
+ * Notify a single thread waiting on a monitor.
+ *
+ * A thread is considered to be waiting on the monitor if
+ * it is currently blocked while executing hythread_monitor_wait on the monitor.
+ *
+ * If no threads are waiting, no action is taken.
+ *
+ * @param[in] monitor a monitor to be signaled
+ * @return 0 once the monitor has been signaled<br>HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not own the monitor
+ *
+ * @see hythread_monitor_notify_all, hythread_monitor_enter, hythread_monitor_wait
+ */
+IDATA VMCALL
+hythread_monitor_notify (hythread_monitor_t monitor)
+{
+ return monitor_notify_one_or_all (monitor, NOTIFY_ONE);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_notify_all
+/**
+ * Notify all threads waiting on a monitor.
+ *
+ * A thread is considered to be waiting on the monitor if
+ * it is currently blocked while executing hythread_monitor_wait on the monitor.
+ *
+ * If no threads are waiting, no action is taken.
+ *
+ *
+ * @param[in] monitor a monitor to be signaled
+ * @return 0 once the monitor has been signaled<br>HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not own the monitor
+ *
+ * @see hythread_monitor_notify, hythread_monitor_enter, hythread_monitor_wait
+ */
+IDATA VMCALL
+hythread_monitor_notify_all (hythread_monitor_t monitor)
+{
+ return monitor_notify_one_or_all (monitor, NOTIFY_ALL);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_tls_alloc
+/**
+ * Allocate a thread local storage (TLS) key.
+ *
+ * Create and return a new, unique key for thread local storage.
+ *
+ * @note The hande returned will be >=0, so it is safe to test the handle against 0 to see if it's been
+ * allocated yet.
+ *
+ * @param[out] handle pointer to a key to be initialized with a key value
+ * @return 0 on success or negative value if a key could not be allocated (i.e. all TLS has been allocated)
+ *
+ * @see hythread_tls_free, hythread_tls_set
+ */
+IDATA VMCALL
+hythread_tls_alloc (hythread_tls_key_t * handle)
+{
+ return hythread_tls_alloc_with_finalizer (handle, tls_null_finalizer);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_tls_free
+/**
+ * Release a TLS key.
+ *
+ * Release a TLS key previously allocated by hythread_tls_alloc.
+ *
+ * @param[in] key TLS key to be freed
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_tls_alloc, hythread_tls_set
+ *
+ */
+IDATA VMCALL
+hythread_tls_free (hythread_tls_key_t key)
+{
+ HyPoolState state;
+ hythread_t each;
+ hythread_library_t lib = GLOBAL_DATA (default_library);
+ ASSERT (lib);
+
+ /* clear the TLS in every existing thread */
+ GLOBAL_LOCK_SIMPLE (lib);
+ each = pool_startDo (lib->thread_pool, &state);
+ while (each)
+ {
+ each->tls[key - 1] = NULL;
+ each = pool_nextDo (&state);
+ }
+ GLOBAL_UNLOCK_SIMPLE (lib);
+
+ /* now return the key to the free set */
+ MUTEX_ENTER (lib->tls_mutex);
+ lib->tls_finalizers[key - 1] = NULL;
+ MUTEX_EXIT (lib->tls_mutex);
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_tls_set
+/**
+ * Set a thread's TLS value.
+ *
+ * @param[in] thread a thread
+ * @param[in] key key to have TLS value set (any value returned by hythread_alloc)
+ * @param[in] value value to be stored in TLS
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_tls_alloc, hythread_tls_free, hythread_tls_get
+ */
+IDATA VMCALL
+hythread_tls_set (hythread_t thread, hythread_tls_key_t key, void *value)
+{
+ thread->tls[key - 1] = value;
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_set_priority
+/**
+ * Set a thread's execution priority.
+ *
+ * @param[in] thread a thread
+ * @param[in] priority
+ * Use the following symbolic constants for priorities:<br>
+ * HYTHREAD_PRIORITY_MAX<br>
+ * HYTHREAD_PRIORITY_USER_MAX<br>
+ * HYTHREAD_PRIORITY_NORMAL<br>
+ * HYTHREAD_PRIORITY_USER_MIN<br>
+ * HYTHREAD_PRIORITY_MIN<br>
+ *
+ * @returns 0 on success or negative value on failure (priority wasn't changed)
+ *
+ *
+ */
+IDATA VMCALL
+hythread_set_priority (hythread_t thread, UDATA priority)
+{
+ ASSERT (thread);
+
+ if (priority > HYTHREAD_PRIORITY_MAX)
+ {
+ return -1;
+ }
+
+ if (THREAD_SET_PRIORITY (thread->handle, priority_map[priority]))
+ {
+ return -1;
+ }
+
+ thread->priority = priority;
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_interrupt
+/**
+ * Interrupt a thread.
+ *
+ * If the thread is currently blocked (i.e. waiting on a monitor_wait or sleeping)
+ * resume the thread and cause it to return from the blocking function with
+ * HYTHREAD_INTERRUPTED.
+ *
+ * @param[in] thread a thead to be interrupted
+ * @return none
+ */
+void VMCALL
+hythread_interrupt (hythread_t thread)
+{
+ interrupt_thread (thread, HYTHREAD_FLAG_INTERRUPTED);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_interrupted
+/**
+ * Return the value of a thread's interrupted flag.
+ *
+ * @param[in] thread thread to be queried
+ * @return 0 if not interrupted, non-zero if interrupted
+ */
+UDATA VMCALL
+hythread_interrupted (hythread_t thread)
+{
+ ASSERT (thread);
+ return (thread->flags & HYTHREAD_FLAG_INTERRUPTED) != 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_clear_interrupted
+/**
+ * Clear the interrupted flag of the current thread and return its previous value.
+ *
+ * @return previous value of interrupted flag: non-zero if the thread had been interrupted.
+ */
+UDATA VMCALL
+hythread_clear_interrupted (void)
+{
+ UDATA oldFlags;
+ hythread_t self = MACRO_SELF ();
+ ASSERT (self);
+
+ THREAD_LOCK (self, self, CALLER_CLEAR_INTERRUPTED);
+ oldFlags = self->flags;
+ self->flags = oldFlags & ~HYTHREAD_FLAG_INTERRUPTED;
+ THREAD_UNLOCK (self, self);
+
+ return (oldFlags & HYTHREAD_FLAG_INTERRUPTED) != 0;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION remove_from_queue
+/*
+ * Remove a thread from a monitor's queue.
+ *
+ * @param[in] queue head of a monitor's queue
+ * @param[in] thread thread to be removed from queue
+ * @return none
+ */
+static void
+remove_from_queue (hythread_t volatile *queue, hythread_t thread)
+{
+ hythread_t queued, next;
+
+ ASSERT (thread);
+
+ if ((queued = *queue) == NULL)
+ return;
+
+ if (queued == thread)
+ {
+ *queue = thread->next;
+ thread->next = NULL;
+ }
+ else
+ {
+ while ((next = queued->next) != NULL && next != thread)
+ {
+ queued = next;
+ }
+ if (next != NULL)
+ {
+ queued->next = thread->next;
+ thread->next = NULL;
+ }
+ }
+
+ ASSERT (NULL == thread->next);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION allocate_monitor_pool
+/*
+ * Create and initialize a pool of monitors.
+ *
+ * @return pointer to a new monitor pool on success, NULL on failure
+ *
+ */
+static hythread_monitor_pool_t
+allocate_monitor_pool (void)
+{
+ int i;
+ hythread_monitor_t entry;
+ hythread_monitor_pool_t pool =
+ (hythread_monitor_pool_t) malloc (sizeof (HyThreadMonitorPool));
+ if (pool == NULL)
+ {
+ return NULL;
+ }
+ memset (pool, 0, sizeof (HyThreadMonitorPool));
+
+ pool->next_free = entry = &pool->entries[0];
+ for (i = 0; i < MONITOR_POOL_SIZE - 1; i++, entry++)
+ {
+ entry->count = FREE_TAG;
+ entry->owner = (hythread_t) (entry + 1);
+ /* entry->waiting = entry->blocked = NULL; *//* (unnecessary) */
+ entry->flags = HYTHREAD_MONITOR_MUTEX_UNINITIALIZED;
+ }
+ /* initialize the last monitor */
+ entry->count = FREE_TAG;
+ entry->flags = HYTHREAD_MONITOR_MUTEX_UNINITIALIZED;
+
+ return pool;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION thread_wrapper
+/*
+ * Function we pass to the OS for new threads.
+ *
+ * @param arg pointer to the hythread_t for the new thread
+ * @return none
+ */
+static WRAPPER_TYPE
+thread_wrapper (WRAPPER_ARG arg)
+{
+ hythread_t thread = (hythread_t) arg;
+ hythread_library_t lib = thread->library;
+ UDATA flags;
+
+ ASSERT (thread);
+ ASSERT (lib);
+
+ thread->tid = RAS_THREAD_ID ();
+
+ TLS_SET (lib->self_ptr, thread);
+
+ if (lib->stack_usage)
+ {
+ paint_stack (thread);
+ }
+
+ if (thread->flags & HYTHREAD_FLAG_CANCELED)
+ {
+ internal_exit ();
+ }
+
+ /* Handle the create-suspended case */
+ /* (This code is basically the same as hythread_suspend, but we need to
+ test the condition under mutex or else there's a timing hole) */
+ THREAD_LOCK (thread, thread, CALLER_THREAD_WRAPPER);
+ if (thread->flags & HYTHREAD_FLAG_SUSPENDED)
+ {
+ COND_WAIT (thread->condition, thread->mutex);
+ if ((thread->flags & HYTHREAD_FLAG_SUSPENDED) == 0)
+ break;
+ COND_WAIT_LOOP ();
+ }
+ thread->flags |= HYTHREAD_FLAG_STARTED;
+ flags = thread->flags;
+ THREAD_UNLOCK (thread, thread);
+
+ if (thread->flags & HYTHREAD_FLAG_CANCELED)
+ {
+ internal_exit ();
+ }
+
+#if defined(LINUX)
+ /* Workaround for NPTL bug on Linux. See hythread_exit() */
+ {
+ jmp_buf jumpBuffer;
+ if (0 == setjmp (jumpBuffer))
+ {
+ thread->jumpBuffer = &jumpBuffer;
+ thread->entrypoint (thread->entryarg);
+ }
+ thread->jumpBuffer = NULL;
+ }
+#else
+ thread->entrypoint (thread->entryarg);
+#endif
+
+ internal_exit ();
+ /* UNREACHABLE */
+ WRAPPER_RETURN ();
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION monitor_notify_one_or_all
+/*
+ * Signal one or all threads waiting on the monitor.
+ *
+ * If no threads are waiting, this does nothing.
+ *
+ * @param[in] monitor monitor to be notified on
+ * @param[in] notifyall 0 to notify one, non-zero to notify all
+ * @return 0 once the monitor has been signalled<br>
+ * HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not
+ * own the monitor
+ *
+ */
+static IDATA
+monitor_notify_one_or_all (hythread_monitor_t monitor, int notifyall)
+{
+
+ hythread_t self = MACRO_SELF ();
+ hythread_t queue, next;
+ int someoneNotified = 0;
+
+ ASSERT (self);
+ ASSERT (monitor);
+
+ if (monitor->owner != self)
+ {
+ ASSERT_DEBUG (0);
+ return HYTHREAD_ILLEGAL_MONITOR_STATE;
+ }
+
+ MONITOR_LOCK (self, monitor, CALLER_NOTIFY_ONE_OR_ALL);
+
+ next = monitor->waiting;
+
+ while (next)
+ {
+ queue = next;
+ next = queue->next;
+ THREAD_LOCK (self, queue, CALLER_NOTIFY_ONE_OR_ALL);
+ if (queue->flags & HYTHREAD_FLAG_WAITING)
+ {
+ notify_thread (queue, SET_NOTIFIED_FLAG);
+ someoneNotified = 1;
+ }
+ THREAD_UNLOCK (self, queue);
+
+ if ((someoneNotified) && (!notifyall))
+ {
+ break;
+ }
+ }
+
+ MONITOR_UNLOCK (self, monitor);
+
+ return 0;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION notify_thread
+/*
+ * Notify a thread.
+ *
+ * Helper routine because we notify a thread in
+ * a couple of places.
+ * @note: assumes the caller has THREAD_LOCK'd the
+ * thread being notified (and owns the monitor being notified on)
+ * @param[in] threadToNotify thread to notify
+ * @param[in] setNotifiedFlag indicates whether to set the notified thread's notified flag.
+ * @return none
+ */
+static void
+notify_thread (hythread_t threadToNotify, int setNotifiedFlag)
+{
+ ASSERT (threadToNotify);
+ ASSERT (threadToNotify->flags & HYTHREAD_FLAG_WAITING);
+
+ threadToNotify->flags &= ~HYTHREAD_FLAG_WAITING;
+ threadToNotify->flags |= HYTHREAD_FLAG_BLOCKED;
+ if (setNotifiedFlag)
+ {
+ threadToNotify->flags |= HYTHREAD_FLAG_NOTIFIED;
+ }
+ COND_NOTIFY_ALL (threadToNotify->condition);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_sleep_interruptable
+/**
+ * Suspend the current thread from executing
+ * for at least the specified time.
+ *
+ * @param[in] millis
+ * @param[in] nanos
+ * @return 0 on success<br>
+ * HYTHREAD_INVALID_ARGUMENT if the arguments are invalid<br>
+ * HYTHREAD_INTERRUPTED if the sleep was interrupted
+ *
+ * @see hythread_sleep
+ */
+IDATA VMCALL
+hythread_sleep_interruptable (I_64 millis, IDATA nanos)
+{
+ hythread_t self = MACRO_SELF ();
+ IDATA boundedMillis = BOUNDED_I64_TO_IDATA (millis);
+
+ ASSERT (self);
+
+ if ((millis < 0) || (nanos < 0) || (nanos >= 1000000))
+ {
+ return HYTHREAD_INVALID_ARGUMENT;
+ }
+
+ THREAD_LOCK (self, self, CALLER_SLEEP_INTERRUPTABLE);
+
+ if (self->flags & HYTHREAD_FLAG_INTERRUPTED)
+ {
+ self->flags &= ~HYTHREAD_FLAG_INTERRUPTED;
+ THREAD_UNLOCK (self, self);
+ return HYTHREAD_INTERRUPTED;
+ }
+
+ if (self->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED)
+ {
+ self->flags &= ~HYTHREAD_FLAG_PRIORITY_INTERRUPTED;
+ THREAD_UNLOCK (self, self);
+ return HYTHREAD_PRIORITY_INTERRUPTED;
+ }
+
+ self->flags |=
+ HYTHREAD_FLAG_SLEEPING | HYTHREAD_FLAG_INTERRUPTABLE |
+ HYTHREAD_FLAG_TIMER_SET;
+
+ COND_WAIT_IF_TIMEDOUT (self->condition, self->mutex, boundedMillis, nanos)
+ {
+ break;
+ }
+ else
+ {
+ if (self->flags & HYTHREAD_FLAG_INTERRUPTED)
+ {
+ self->flags &=
+ ~(HYTHREAD_FLAG_INTERRUPTED | HYTHREAD_FLAG_SLEEPING |
+ HYTHREAD_FLAG_INTERRUPTABLE | HYTHREAD_FLAG_TIMER_SET);
+ THREAD_UNLOCK (self, self);
+ return HYTHREAD_INTERRUPTED;
+ }
+ if (self->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED)
+ {
+ self->flags &=
+ ~(HYTHREAD_FLAG_PRIORITY_INTERRUPTED | HYTHREAD_FLAG_SLEEPING |
+ HYTHREAD_FLAG_INTERRUPTABLE | HYTHREAD_FLAG_TIMER_SET);
+ THREAD_UNLOCK (self, self);
+ return HYTHREAD_PRIORITY_INTERRUPTED;
+ }
+ }
+ COND_WAIT_TIMED_LOOP ();
+
+ self->flags &=
+ ~(HYTHREAD_FLAG_SLEEPING | HYTHREAD_FLAG_INTERRUPTABLE |
+ HYTHREAD_FLAG_TIMER_SET);
+ THREAD_UNLOCK (self, self);
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_sleep
+/**
+ * Suspend the current thread from executing
+ * for at least the specified time.
+ *
+ * @param[in] millis minimum number of milliseconds to sleep
+ * @return 0 on success<br> HYTHREAD_INVALID_ARGUMENT if millis < 0
+ *
+ * @see hythread_sleep_interruptable
+ */
+IDATA VMCALL
+hythread_sleep (I_64 millis)
+{
+ hythread_t self = MACRO_SELF ();
+
+ IDATA boundedMillis = (millis > 0x7FFFFFFF ? 0x7FFFFFFF : (IDATA) millis);
+
+ ASSERT (self);
+
+ if (millis < 0)
+ {
+ return HYTHREAD_INVALID_ARGUMENT;
+ }
+
+ THREAD_LOCK (self, self, CALLER_SLEEP);
+
+ self->flags |= HYTHREAD_FLAG_SLEEPING | HYTHREAD_FLAG_TIMER_SET;
+
+ COND_WAIT_IF_TIMEDOUT (self->condition, self->mutex, boundedMillis, 0)
+ {
+ break;
+ }
+ COND_WAIT_TIMED_LOOP ();
+
+ self->flags &= ~(HYTHREAD_FLAG_SLEEPING | HYTHREAD_FLAG_TIMER_SET);
+ THREAD_UNLOCK (self, self);
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_lock
+/*
+ * Acquire the threading library's global lock.
+ *
+ * @param[in] self hythread_t for the current thread
+ * @param[in] monitor must be NULL
+ * @return none
+ *
+ * @deprecated This has been replaced by hythread_lib_lock.
+ * @see hythread_lib_lock, hythread_lib_unlock
+ */
+void VMCALL
+hythread_monitor_lock (hythread_t self, hythread_monitor_t monitor)
+{
+ ASSERT (self);
+
+ if (monitor == NULL)
+ {
+ GLOBAL_LOCK (self, CALLER_GLOBAL_LOCK);
+ }
+ else
+ {
+ ASSERT (0);
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_unlock
+/*
+ * Release the threading library's global lock.
+ *
+ * @param[in] self hythread_t for the current thread
+ * @param[in] monitor
+ * @return none
+ *
+ * @deprecated This has been replaced by hythread_lib_unlock.
+ * @see hythread_lib_lock, hythread_lib_unlock
+ */
+void VMCALL
+hythread_monitor_unlock (hythread_t self, hythread_monitor_t monitor)
+{
+ ASSERT (self);
+
+ if (monitor == NULL)
+ {
+ GLOBAL_UNLOCK (self);
+ }
+ else
+ {
+ ASSERT (0);
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_acquire
+/*
+ * Acquire a monitor from the threading library. (Private)
+ *
+ * @param[in] self current thread
+ * @param[in] locking policy
+ * @param[in] locking policy data or HYTHREAD_LOCKING_NO_DATA
+ * @return NULL on failure, non-NULL on success
+ *
+ * @see hythread_monitor_init_with_name, hythread_monitor_destroy
+ *
+ *
+ */
+static hythread_monitor_t VMCALL
+hythread_monitor_acquire (hythread_t self, IDATA policy, IDATA policyData)
+{
+ hythread_monitor_t entry;
+ hythread_monitor_pool_t pool = self->library->monitor_pool;
+ IDATA rc;
+
+ ASSERT (self);
+ ASSERT (pool);
+
+ GLOBAL_LOCK (self, CALLER_MONITOR_ACQUIRE);
+
+ entry = pool->next_free;
+ if (entry == NULL)
+ {
+ hythread_monitor_pool_t last_pool = pool;
+ while (last_pool->next != NULL)
+ last_pool = last_pool->next;
+ last_pool->next = allocate_monitor_pool ();
+ if (last_pool->next == NULL)
+ {
+ /* failed to grow monitor pool */
+ GLOBAL_UNLOCK (self);
+ return NULL;
+ }
+ entry = last_pool->next->next_free;
+ }
+
+ /* the first time that a mutex is acquired from the pool, we need to
+ * initialize its mutex
+ */
+ if (entry->flags == HYTHREAD_MONITOR_MUTEX_UNINITIALIZED)
+ {
+
+ rc = MUTEX_INIT (entry->mutex);
+
+ if (!rc)
+ {
+ /* failed to initialize mutex */
+ ASSERT_DEBUG (0);
+ GLOBAL_UNLOCK (self);
+ return NULL;
+ }
+
+ entry->flags = 0;
+
+ }
+
+ pool->next_free = (hythread_monitor_t) entry->owner;
+ entry->count = 0;
+
+ GLOBAL_UNLOCK (self);
+
+ return entry;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_cancel
+/**
+ * Terminate a running thread.
+ *
+ * @note This should only be used as a last resort. The system may be in
+ * an unpredictable state once a thread is cancelled. In addition, the thread
+ * may not even stop running if it refuses to cancel.
+ *
+ * @param[in] thread a thread to be terminated
+ * @return none
+ */
+void VMCALL
+hythread_cancel (hythread_t thread)
+{
+ hythread_monitor_t monitor = NULL;
+ hythread_t self = MACRO_SELF ();
+
+ ASSERT (thread);
+ THREAD_LOCK (self, thread, CALLER_CANCEL);
+
+ /* Special case -- we can cancel cleanly if the thread hasn't started yet */
+ if ((thread->flags & HYTHREAD_FLAG_STARTED) == 0)
+ {
+ thread->flags |= HYTHREAD_FLAG_CANCELED;
+ THREAD_UNLOCK (self, thread);
+ hythread_resume (thread);
+ return;
+ }
+
+ THREAD_CANCEL (thread->handle);
+
+ thread->flags |= HYTHREAD_FLAG_CANCELED;
+
+ THREAD_UNLOCK (self, thread);
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_detach
+/**
+ * Detach a thread from the threading library.
+ *
+ * @note Assumes that the thread being detached is already attached.<br>
+ *
+ * If the thread is an attached thread, then detach should only be called by the thread
+ * itself. Internal resources associated with the thread are freed.
+ *
+ * If the thread is already dead, this call will destroy it.
+ *
+ * @param[in] thread a hythread_t representing the thread to be detached.
+ * If this is NULL, the current thread is detached.
+ * @return none
+ *
+ * @see hythread_attach
+ */
+void VMCALL
+hythread_detach (hythread_t thread)
+{
+ UDATA destroy = 0;
+ UDATA attached = 0;
+ hythread_t self = MACRO_SELF ();
+
+ if (thread == NULL)
+ {
+ thread = self;
+ }
+ ASSERT (thread);
+
+ THREAD_LOCK (self, thread, CALLER_DETACH);
+ if (thread->attachcount < 1)
+ {
+ /* error! */
+ }
+ else
+ {
+ if (--thread->attachcount == 0)
+ {
+ if (thread->flags & HYTHREAD_FLAG_ATTACHED)
+ {
+ /* this is an attached thread, and it is now fully
+ detached. Mark it dead so that it can be destroyed */
+ thread->flags |= HYTHREAD_FLAG_DEAD;
+ attached = destroy = 1;
+ }
+ else
+ {
+ destroy = thread->flags & HYTHREAD_FLAG_DEAD;
+ }
+ }
+ }
+ THREAD_UNLOCK (self, thread);
+
+ if (destroy)
+ {
+ hythread_library_t library = thread->library;
+
+ tls_finalize (thread);
+
+ destroy_thread (thread, GLOBAL_NOT_LOCKED);
+ if (attached)
+ {
+ TLS_SET (library->self_ptr, NULL);
+ }
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_exit
+/**
+ * Exit the current thread.
+ *
+ * If the thread has been detached, it is destroyed.
+ *
+ * If monitor is not NULL, the monitor will be exited before the thread terminates.
+ * This is useful if the thread wishes to signal its termination to a watcher, since
+ * it exits the monitor and terminates the thread without ever returning control
+ * to the thread's routine, which might be running in a DLL which is about to
+ * be closed.
+ *
+ * @param[in] monitor monitor to be exited before exiting (ignored if NULL)
+ * @return none
+ */
+void VMCALL NORETURN
+hythread_exit (hythread_monitor_t monitor)
+{
+ hythread_t self = MACRO_SELF ();
+
+ if (monitor)
+ {
+ hythread_monitor_exit (monitor);
+ }
+
+ /* Walk all monitors: if this thread owns a monitor, exit it */
+ monitor = NULL;
+ while ((monitor = hythread_monitor_walk (monitor)) != NULL)
+ {
+ if (monitor->owner == self)
+ {
+ monitor->count = 1; /* exit n-1 times */
+ hythread_monitor_exit (monitor);
+ }
+ }
+
+#if defined(LINUX)
+ /* NPTL calls __pthread_unwind() from pthread_exit(). That walks the stack.
+ * We can't allow that to happen, since our caller might have already been
+ * unloaded. Walking the calling frame could cause a crash. Instead, we
+ * longjmp back out to the initial frame.
+ */
+ if (self->jumpBuffer)
+ {
+ longjmp (*(jmp_buf *) self->jumpBuffer, 1);
+ }
+#endif
+
+ internal_exit ();
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_priority_interrupt
+/**
+ * Priority interrupt a thread.
+ *
+ * If the thread is currently blocked (i.e. waiting on a monitor_wait or sleeping)
+ * resume the thread and return from the blocking function with
+ * HYTHREAD_PRIORITY_INTERRUPTED
+ *
+ * @param[in] thread a thead to be priority interrupted
+ * @return none
+ */
+void VMCALL
+hythread_priority_interrupt (hythread_t thread)
+{
+ interrupt_thread (thread, HYTHREAD_FLAG_PRIORITY_INTERRUPTED);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_priority_interrupted
+/**
+ * Return the value of a thread's priority interrupted flag.
+ *
+ * @param[in] thread thread to be queried
+ * @return 0 if not priority interrupted, non-zero if priority interrupted flag set
+ */
+UDATA VMCALL
+hythread_priority_interrupted (hythread_t thread)
+{
+ return (thread->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED) != 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_clear_priority_interrupted
+/**
+ * Clear the priority interrupted flag of the current thread and return its previous value.
+ *
+ * @return previous value of priority interrupted flag: nonzero if the thread had been priority interrupted.
+ */
+UDATA VMCALL
+hythread_clear_priority_interrupted (void)
+{
+ UDATA oldFlags;
+ hythread_t self = MACRO_SELF ();
+ ASSERT (self);
+
+ THREAD_LOCK (self, self, CALLER_CLEAR_PRIORITY_INTERRUPTED);
+ oldFlags = self->flags;
+ self->flags = oldFlags & ~HYTHREAD_FLAG_PRIORITY_INTERRUPTED;
+ THREAD_UNLOCK (self, self);
+
+ return (oldFlags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED) != 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_try_enter
+/**
+ * Attempt to enter a monitor without blocking.
+ *
+ * If the thread must block before it enters the monitor this function
+ * returns immediately with a negative value to indicate failure.
+ *
+ * @param[in] monitor a monitor
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_monitor_try_enter_using_threadId
+ *
+ */
+IDATA VMCALL
+hythread_monitor_try_enter (hythread_monitor_t monitor)
+{
+ return hythread_monitor_try_enter_using_threadId (monitor, MACRO_SELF ());
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_shutdown
+/**
+ * Shut down the Hy threading library associated with the current thread.
+ *
+ * @return none
+ *
+ * @see hythread_init
+ */
+void VMCALL
+hythread_shutdown (void)
+{
+ hythread_library_t lib = GLOBAL_DATA (default_library);
+ ASSERT (lib);
+ MUTEX_DESTROY (lib->tls_mutex);
+ MUTEX_DESTROY (lib->monitor_mutex);
+ MUTEX_DESTROY (lib->global_mutex);
+ pool_kill (lib->global_pool);
+ free_monitor_pools ();
+#if !defined(LINUX)
+ TLS_DESTROY (lib->self_ptr);
+ pool_kill (lib->thread_pool);
+#endif /* LINUX */
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION allocate_thread
+/*
+ * Allocate a hythread_t from the hythread_t pool.
+ *
+ * @note assumes the threading library's thread pool is already initialized
+ * @param[in] globalIsLocked indicates whether the threading library global mutex is already locked.
+ * @return a new hythread_t on success, NULL on failure.
+ *
+ */
+static hythread_t
+allocate_thread (int globalIsLocked)
+{
+ hythread_t result;
+ hythread_library_t lib = GLOBAL_DATA (default_library);
+ ASSERT (lib);
+
+ if (!globalIsLocked)
+ {
+ GLOBAL_LOCK_SIMPLE (lib);
+ }
+ lib->threadCount++;
+ result = pool_newElement (lib->thread_pool);
+ if (!globalIsLocked)
+ {
+ GLOBAL_UNLOCK_SIMPLE (lib);
+ }
+
+ if (result)
+ {
+ memset (result, 0, sizeof (HyThread));
+ }
+
+ return result;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION free_thread
+/*
+ * Return a hythread_t to the threading library's monitor pool.
+ *
+ * @param[in] thread thread to be returned to the pool
+ * @param[in] globalAlreadyLocked indicated whether the threading library global
+ * mutex is already locked
+ * @return none
+ */
+static void
+free_thread (hythread_t thread, int globalAlreadyLocked)
+{
+ hythread_library_t lib = thread->library;
+
+ ASSERT (thread);
+
+ if (!globalAlreadyLocked)
+ {
+ GLOBAL_LOCK_SIMPLE (lib);
+ }
+ pool_removeElement (lib->thread_pool, thread);
+ lib->threadCount--;
+
+ if (!globalAlreadyLocked)
+ {
+ GLOBAL_UNLOCK_SIMPLE (lib);
+ }
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION thread_malloc
+/*
+ * Malloc a thread (hythread_t struct).
+ *
+ * Helper function used by the library's thread pool
+ *
+ * @param unused ignored
+ * @param size size of struct to be alloc'd
+ * @return pointer to the malloc'd memory<br>
+ * 0 on failure
+ *
+ */
+static void *VMCALL
+thread_malloc (void *unused, U_32 size)
+{
+ return malloc (size);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION thread_free
+/*
+ * Free a thread (hythread_t struct)
+ * Function used by the library's thread pool
+ *
+ * @param unused ignored
+ * @param prt pointer to hythread_t to be freed
+ * @return none
+ *
+ */
+static void VMCALL
+thread_free (void *unused, void *ptr)
+{
+ free (ptr);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION free_monitor_pools
+/*
+ * Free the Hy threading library's monitor pool.
+ *
+ * This requires destroying each and every one of the
+ * monitors in the pool.
+ *
+ * @return none
+ */
+static void
+free_monitor_pools (void)
+{
+ hythread_library_t lib = GLOBAL_DATA (default_library);
+ hythread_monitor_pool_t pool = lib->monitor_pool;
+
+ ASSERT (lib);
+ ASSERT (pool);
+
+ while (pool)
+ {
+ int i;
+ hythread_monitor_pool_t next = pool->next;
+ hythread_monitor_t entry = &pool->entries[0];
+ for (i = 0; i < MONITOR_POOL_SIZE - 1; i++, entry++)
+ {
+ if (entry->flags != HYTHREAD_MONITOR_MUTEX_UNINITIALIZED)
+ {
+ MUTEX_DESTROY (entry->mutex);
+ }
+ }
+ free (pool);
+ pool = next;
+ }
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION init_global_monitor
+/*
+ * Initialize the mutex used to synchronize access
+ * to thread library global data.
+ *
+ * @param[in] lib pointer to the thread library
+ * @return 0 on success or negative value on failure
+ *
+ */
+static IDATA
+init_global_monitor (hythread_library_t lib)
+{
+ hythread_monitor_pool_t pool = lib->monitor_pool;
+ hythread_monitor_t monitor = pool->next_free;
+ ASSERT (monitor);
+ pool->next_free = (hythread_monitor_t) monitor->owner;
+
+ if (init_monitor (monitor, 0) != 0)
+ {
+ return -1;
+ }
+ if (!MUTEX_INIT (monitor->mutex))
+ {
+ return -1;
+ }
+
+ monitor->name = "Thread global";
+
+ *hythread_global ("global_monitor") = (UDATA) monitor;
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION internal_exit
+/*
+ * Exit from the current thread.
+ *
+ * If the thread has been detached it is destroyed.
+ */
+static void NORETURN
+internal_exit (void)
+{
+
+ hythread_t self = MACRO_SELF ();
+ hythread_library_t lib = self->library;
+ int detached;
+
+ ASSERT (self);
+ ASSERT (lib);
+
+ tls_finalize (self);
+
+ GLOBAL_LOCK (self, CALLER_INTERNAL_EXIT1);
+ THREAD_LOCK (self, self, CALLER_INTERNAL_EXIT1);
+ self->flags |= HYTHREAD_FLAG_DEAD;
+ detached = self->attachcount == 0;
+
+ /*
+ * Is there an interruptServer thread out there
+ * trying to interrupt us? Its services are
+ * no longer required.
+ */
+ if (self->interrupter)
+ {
+ THREAD_LOCK (self, self->interrupter, CALLER_INTERNAL_EXIT1);
+ self->interrupter->flags |= HYTHREAD_FLAG_CANCELED;
+ THREAD_UNLOCK (self, self->interrupter);
+ self->interrupter = NULL;
+ }
+
+ THREAD_UNLOCK (self, self);
+
+ /* On z/OS we create the thread in the detached state, so the */
+ /* call to pthread_detach is not required. @dfa1 */
+ THREAD_DETACH (self->handle);
+
+ if (detached)
+ {
+ destroy_thread (self, GLOBAL_IS_LOCKED);
+ }
+
+ GLOBAL_UNLOCK_SIMPLE (lib);
+ THREAD_EXIT ();
+ ASSERT (0);
+ /* UNREACHABLE */
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION enqueue_thread
+/*
+ * Add a thread to a monitor's wait queue.
+ *
+ * @note The calling thread must be the current owner of the monitor
+ * @param[in] queue head of the monitor's wait queue
+ * @param[in] thread thread to be added
+ * @return none
+ *
+ */
+static void
+enqueue_thread (hythread_t * queue, hythread_t thread)
+{
+ hythread_t qthread = *queue;
+
+ ASSERT (thread);
+ /* can't be on two queues at the same time */
+ ASSERT (NULL == thread->next);
+
+ if (qthread != NULL)
+ {
+ while (qthread->next)
+ {
+ qthread = qthread->next;
+ }
+ qthread->next = thread;
+ }
+ else
+ {
+ *queue = thread;
+ }
+
+ ASSERT (*queue != NULL);
+ ASSERT (NULL == thread->next);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_wait_timed
+/**
+ * Wait on a monitor until notified or timed out.
+ *
+ * A timeout of 0 (0ms, 0ns) indicates wait indefinitely.
+ *
+ * @param[in] monitor a monitor to be waited on
+ * @param[in] millis >=0
+ * @param[in] nanos >=0
+ *
+ * @return 0 the monitor has been waited on, notified, and reobtained<br>
+ * HYTHREAD_INVALID_ARGUMENT millis or nanos is out of range (millis or nanos < 0, or nanos >= 1E6)<br>
+ * HYTHREAD_ILLEGAL_MONITOR_STATE the current thread does not own the monitor<br>
+ * HYTHREAD_TIMED_OUT the timeout expired
+ *
+ * @see hythread_monitor_wait, hythread_monitor_wait_interruptable, hythread_monitor_enter
+ *
+ */
+IDATA VMCALL
+hythread_monitor_wait_timed (hythread_monitor_t monitor, I_64 millis,
+ IDATA nanos)
+{
+ return monitor_wait (monitor, millis, nanos, WAIT_UNINTERRUPTABLE);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_dump_trace
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_dump_all
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_dump_trace
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_global
+/**
+ * Fetch or create a 'named global'.
+ *
+ * Return a pointer to the data associated with a named global with the specified name.<br>
+ * A new named global is created if a named global with the specified name can't be found.
+ *
+ * @param[in] name name of named global to read/create
+ * @return a pointer to a UDATA associated with name<br>
+ * 0 on failure.
+ *
+ */
+UDATA *VMCALL
+hythread_global (char *name)
+{
+ HyThreadGlobal *global;
+ hythread_library_t lib = GLOBAL_DATA (default_library);
+
+ MUTEX_ENTER (lib->global_mutex);
+
+ global = lib->globals;
+
+ while (global)
+ {
+ if (strcmp (global->name, name) == 0)
+ {
+ MUTEX_EXIT (lib->global_mutex);
+ return &global->data;
+ }
+ global = global->next;
+ }
+
+ /*
+ * If we got here, we couldn't find it, therefore
+ * we will create a new one
+ */
+
+ global = pool_newElement (lib->global_pool);
+ if (global == NULL)
+ {
+ MUTEX_EXIT (lib->global_mutex);
+ return NULL;
+ }
+
+ global->next = lib->globals;
+ global->name = name;
+ global->data = 0;
+ lib->globals = global;
+
+ MUTEX_EXIT (lib->global_mutex);
+
+ return &global->data;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hysem_init
+/*
+ * Initialize a semaphore.
+ *
+ * Acquire a semaphore from the threading library.
+ *
+ * @param[out] sp pointer to semaphore to be initialized
+ * @param[in] initValue initial count value (>=0) for the semaphore
+ * @return 0 on success or negative value on failure
+ *
+ * @deprecated Semaphores are no longer supported.
+ *
+ * @see hysem_destroy, hysem_init, hysem_post
+ */
+IDATA VMCALL
+hysem_init (hysem_t * sp, I_32 initValue)
+{
+ hysem_t s;
+ IDATA rc = -1;
+
+ (*sp) = s = SEM_CREATE (initValue);
+ if (s)
+ {
+ rc = SEM_INIT (s, 0, initValue);
+ }
+ return rc;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hysem_destroy
+/*
+ * Destroy a semaphore.
+ *
+ * Returns the resources associated with a semaphore back to the Hy threading library.
+ *
+ * @param[in] s semaphore to be destroyed
+ * @return 0 on success or negative value on failure
+ *
+ * @deprecated Semaphores are no longer supported.
+ *
+ * @see hysem_init, hysem_wait, hysem_post
+ */
+IDATA VMCALL
+hysem_destroy (hysem_t s)
+{
+ int rval = 0;
+ if (s)
+ {
+ rval = SEM_DESTROY (s);
+ SEM_FREE (s);
+ }
+ return rval;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hysem_post
+/*
+ * Release a semaphore by 1.
+ *
+ * @param[in] s semaphore to be released by 1
+ * @return 0 on success or negative value on failure
+ *
+ * @deprecated Semaphores are no longer supported.
+ *
+ * @see hysem_init, hysem_destroy, hysem_wait
+ */
+IDATA VMCALL
+hysem_post (hysem_t s)
+{
+ if (s)
+ {
+ return SEM_POST (s);
+ }
+ return -1;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hysem_wait
+/*
+ * Wait on a semaphore.
+ *
+ * @param[in] s semaphore to be waited on
+ * @return 0 on success or negative value on failure
+ *
+ * @deprecated Semaphores are no longer supported.
+ *
+ * @see hysem_init, hysem_destroy, hysem_wait
+ *
+ */
+IDATA VMCALL
+hysem_wait (hysem_t s)
+{
+ if (s)
+ {
+ while (SEM_WAIT (s) != 0)
+ {
+ /* loop until success */
+ }
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION error
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION monitor_enter
+/*
+ * Enter a monitor.
+ *
+ * A thread may enter a monitor it owns multiple times, but must
+ * exit the monitor the same number of times before other threads
+ * waiting on the monitor are permitted to continue
+ *
+ * @param[in] self current thread
+ * @param[in] monitor monitor to enter
+ * @return 0 on success<br>
+ * HYTHREAD_PRIORITY_INTERRUPTED if the thread was priority
+ * interrupted while blocked
+ */
+static IDATA
+monitor_enter (hythread_t self, hythread_monitor_t monitor)
+{
+
+ ASSERT (self);
+ ASSERT (0 == self->monitor);
+ ASSERT (monitor);
+ ASSERT (monitor->owner != self);
+ ASSERT (FREE_TAG != monitor->count);
+
+ return monitor_enter_three_tier (self, monitor);
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION monitor_enter_three_tier
+
+/*
+ * Enter a three-tier monitor.
+ *
+ * Spin on a spinlock. Block when that fails, and repeat.
+ *
+ * @param[in] self current thread
+ * @param[in] monitor monitor to enter
+ * @return 0 on success
+ */
+
+static IDATA
+monitor_enter_three_tier (hythread_t self, hythread_monitor_t monitor)
+{
+ int firstTimeBlocking = 1;
+
+ while (1)
+ {
+
+ if (hythread_spinlock_acquire (self, monitor) == 0)
+ {
+ monitor->owner = self;
+ monitor->count = 1;
+ ASSERT (monitor->spinlockState !=
+ HYTHREAD_MONITOR_SPINLOCK_UNOWNED);
+ break;
+ }
+
+ MONITOR_LOCK (self, monitor, CALLER_MONITOR_ENTER_THREE_TIER1);
+
+ if (HYTHREAD_MONITOR_SPINLOCK_UNOWNED ==
+ hythread_spinlock_swapState (monitor,
+ HYTHREAD_MONITOR_SPINLOCK_EXCEEDED))
+ {
+ MONITOR_UNLOCK (self, monitor);
+ monitor->owner = self;
+ monitor->count = 1;
+ ASSERT (monitor->spinlockState !=
+ HYTHREAD_MONITOR_SPINLOCK_UNOWNED);
+ break;
+ }
+
+ THREAD_LOCK (self, self, CALLER_MONITOR_ENTER_THREE_TIER2);
+ self->flags |= (HYTHREAD_FLAG_BLOCKED);
+ self->monitor = monitor;
+ THREAD_UNLOCK (self, self);
+
+ /*
+ * First time we've had to block?
+ * If so, record the info for JLM.
+ */
+ if (IS_JLM_ENABLED (self))
+ {
+ if (firstTimeBlocking)
+ {
+ firstTimeBlocking = 0;
+
+ }
+ }
+
+ enqueue_thread (&monitor->blocking, self);
+ COND_WAIT (self->condition, monitor->mutex);
+ break;
+ COND_WAIT_LOOP ();
+ remove_from_queue (&monitor->blocking, self);
+
+ MONITOR_UNLOCK (self, monitor);
+
+ }
+
+ /* We now own the monitor */
+
+ /*
+ * If the monitor field is set, we must have blocked on it
+ * at some point. We're no longer blocked, so clear this.
+ */
+ if (self->monitor != 0)
+ {
+ THREAD_LOCK (self, self, CALLER_MONITOR_ENTER_THREE_TIER3);
+ self->flags &= ~(HYTHREAD_FLAG_BLOCKED);
+ self->monitor = 0;
+ THREAD_UNLOCK (self, self);
+ }
+
+ /* Did we block? If so, finish up the JLM calcs */
+ /* TODO: this is pretty much the same as in monitor_enter.... */
+ if (IS_JLM_ENABLED (self))
+ {
+ monitor->tracing->enter_count++;
+ if (0 == firstTimeBlocking)
+ {
+ monitor->tracing->slow_count++;
+
+ }
+ }
+
+ ASSERT (!(self->flags & HYTHREAD_FLAG_BLOCKED));
+ ASSERT (0 == self->monitor);
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION monitor_exit
+/*
+ * Exit a monitor.
+ *
+ * If the current thread is not the owner of the monitor, the
+ * mutex is unaffected, and an error is returned. This should be
+ * tested to determine if IllegalMonitorState should be
+ * thrown.
+ *
+ * @param[in] self current thread
+ * @param[in] monitor monitor to be exited
+ * @return 0 on success<br>
+ * HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not
+ * own the monitor
+ */
+static IDATA
+monitor_exit (hythread_t self, hythread_monitor_t monitor)
+{
+
+ ASSERT (monitor);
+ ASSERT (self);
+ ASSERT (0 == self->monitor);
+
+ if (monitor->owner != self)
+ {
+ ASSERT_DEBUG (0);
+ return HYTHREAD_ILLEGAL_MONITOR_STATE;
+ }
+
+ monitor->count--;
+ ASSERT (monitor->count >= 0);
+
+ if (monitor->count == 0)
+ {
+ monitor->owner = NULL;
+
+ if (HYTHREAD_MONITOR_SPINLOCK_EXCEEDED ==
+ hythread_spinlock_swapState (monitor,
+ HYTHREAD_MONITOR_SPINLOCK_UNOWNED))
+ {
+ MONITOR_LOCK (self, monitor, CALLER_MONITOR_EXIT1);
+ unblock_spinlock_threads (self, monitor);
+ MONITOR_UNLOCK (self, monitor);
+ }
+
+ }
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION unblock_spinlock_threads
+
+/*
+ * Notify all threads blocked on the monitor's mutex, waiting
+ * to be told that it's ok to try again to get the spinlock.
+ *
+ * Assumes that the caller already owns the monitor's mutex.
+ *
+ */
+static void
+unblock_spinlock_threads (hythread_t self, hythread_monitor_t monitor)
+{
+ hythread_t queue, next;
+
+ ASSERT (self);
+ ASSERT (monitor);
+
+ next = monitor->blocking;
+ while (next)
+ {
+ queue = next;
+ next = queue->next;
+ COND_NOTIFY_ALL (queue->condition);
+ }
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_reset_tracing
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_wait_interruptable
+/**
+ * Wait on a monitor until notified, interrupted (priority or normal), or timed out.
+ *
+ * A timeout of 0 (0ms, 0ns) indicates wait indefinitely.
+ *
+ * If 'interruptable' is non-zero, the wait may be interrupted by one of the
+ * interrupt functions. (i.e. hythread_interrupt, hythread_priority_interrupt);
+ *
+ * @param[in] monitor a monitor to be waited on
+ * @param[in] millis >=0
+ * @param[in] nanos >=0
+ * @param[in] interruptable non-zero if the wait is to be interruptable
+ *
+ * @return 0 the monitor has been waited on, notified, and reobtained<br>
+ * HYTHREAD_INVALID_ARGUMENT if millis or nanos is out of range (millis or nanos < 0, or nanos >= 1E6)<br>
+ * HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not own the monitor<br>
+ * HYTHREAD_INTERRUPTED if the thread was interrupted while waiting<br>
+ * HYTHREAD_PRIORITY_INTERRUPTED if the thread was priority interrupted while waiting, or while re-obtaining the monitor<br>
+ * HYTHREAD_TIMED_OUT if the timeout expired<br>
+ *
+ * @see hythread_monitor_wait, hythread_monitor_wait_timed, hythread_monitor_enter
+ * @see hythread_interrupt, hythread_priority_interrupt *
+ */
+IDATA VMCALL
+hythread_monitor_wait_interruptable (hythread_monitor_t monitor, I_64 millis,
+ IDATA nanos)
+{
+ return monitor_wait (monitor, millis, nanos, WAIT_INTERRUPTABLE);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_num_waiting
+/**
+ * Returns how many threads are currently waiting on a monitor.
+ *
+ * @note This can only be called by the owner of this monitor.
+ *
+ * @param[in] monitor a monitor
+ * @return number of threads waiting on the monitor (>=0)
+ */
+UDATA VMCALL
+hythread_monitor_num_waiting (hythread_monitor_t monitor)
+{
+ UDATA numWaiting = 0;
+ hythread_t curr;
+ hythread_t self = MACRO_SELF ();
+
+ ASSERT (monitor);
+
+ MONITOR_LOCK (self, monitor, CALLER_MONITOR_NUM_WAITING);
+
+ curr = monitor->waiting;
+ while (curr != NULL)
+ {
+ numWaiting++;
+ curr = curr->next;
+ }
+
+ MONITOR_UNLOCK (self, monitor);
+
+ return numWaiting;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION monitor_wait
+/*
+ *
+ * Wait on a monitor.
+ *
+ * Release the monitor, wait for a signal (notification), then re-acquire the monitor.
+ *
+ * In this function, we 'unwind' any recursive hold (monitor->count) the thread has
+ * on the monitor and release the OS monitor. When the monitor is re-acquired,
+ * the recursive count is restored to its original value.
+ *
+ * A timeout of 0 (0ms, 0ns) indicates wait indefinitely.
+ *
+ * If 'interruptable' is non-zero, the wait may be interrupted by one of the
+ * interrupt functions. (i.e. hythread_interrupt, hythread_priority_interrupt);
+ *
+ * @param[in] monitor monitor to be waited on
+ * @param[in] millis >=0
+ * @param[in] nanos >=0
+ * @param[in] interruptable non-zero if the wait is to be interruptable
+ *
+ * @return HYTHREAD_INVALID_ARGUMENT - if millis or nanos is out of range (millis or nanos < 0, or nanos >= 1E6)
+ * HYTHREAD_ILLEGAL_MONITOR_STATE - the current thread does not own the monitor
+ * 0 - the monitor has been waited on, notified, and reobtained
+ * HYTHREAD_INTERRUPTED - the thread was interrupted while waiting
+ * HYTHREAD_PRIORITY_INTERRUPTED - if the thread was priority interrupted while waiting, or while re-obtaining the monitor
+ * HYTHREAD_TIMED_OUT - the timeout expired
+ *
+ * @see hythread_monitor_wait, hythread_monitor_wait_interruptable, hythread_monitor_enter
+ * @see hythread_interrupt, hythread_priority_interrupt
+ */
+static IDATA
+monitor_wait (hythread_monitor_t monitor, I_64 millis, IDATA nanos,
+ IDATA interruptable)
+{
+ hythread_t self = MACRO_SELF ();
+ IDATA count = -1;
+ UDATA flags;
+ UDATA interrupted = 0, notified = 0, priorityinterrupted = 0;
+ UDATA timedOut = 0;
+
+ ASSERT (monitor);
+ ASSERT (FREE_TAG != monitor->count);
+
+ if (monitor->owner != self)
+ {
+ ASSERT_DEBUG (0);
+ return HYTHREAD_ILLEGAL_MONITOR_STATE;
+ }
+
+ if ((millis < 0) || (nanos < 0) || (nanos >= 1000000))
+ {
+ ASSERT_DEBUG (0);
+ return HYTHREAD_INVALID_ARGUMENT;
+ }
+
+ count = monitor->count;
+ flags = monitor->flags;
+
+ THREAD_LOCK (self, self, CALLER_MONITOR_WAIT1);
+ ASSERT (0 == self->monitor);
+
+ /*
+ * Before we wait, check if we've already been either interrupted or pri interrupted
+ */
+ if (interruptable && (self->flags & HYTHREAD_FLAG_INTERRUPTED))
+ {
+ self->flags &= ~HYTHREAD_FLAG_INTERRUPTED;
+ THREAD_UNLOCK (self, self);
+ return HYTHREAD_INTERRUPTED;
+ }
+
+ if (interruptable && (self->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED))
+ {
+ self->flags &= ~HYTHREAD_FLAG_PRIORITY_INTERRUPTED;
+ THREAD_UNLOCK (self, self);
+ return HYTHREAD_PRIORITY_INTERRUPTED;
+ }
+
+ self->flags |=
+ (HYTHREAD_FLAG_WAITING |
+ (interruptable ? HYTHREAD_FLAG_INTERRUPTABLE : 0));
+ if (millis || nanos)
+ {
+ self->flags |= HYTHREAD_FLAG_TIMER_SET;
+ }
+ self->monitor = monitor;
+ THREAD_UNLOCK (self, self);
+
+ ASSERT (self->flags & HYTHREAD_FLAG_WAITING);
+ monitor->owner = NULL;
+ monitor->count = 0;
+
+ MONITOR_LOCK (self, monitor, CALLER_MONITOR_WAIT);
+ if (HYTHREAD_MONITOR_SPINLOCK_EXCEEDED ==
+ hythread_spinlock_swapState (monitor,
+ HYTHREAD_MONITOR_SPINLOCK_UNOWNED))
+ {
+ unblock_spinlock_threads (self, monitor);
+ }
+
+ enqueue_thread (&monitor->waiting, self);
+
+ if (millis || nanos)
+ {
+ IDATA boundedMillis = BOUNDED_I64_TO_IDATA (millis);
+
+ COND_WAIT_IF_TIMEDOUT (self->condition, monitor->mutex, boundedMillis,
+ nanos)
+ {
+
+ THREAD_LOCK (self, self, CALLER_MONITOR_WAIT2);
+ interrupted = interruptable
+ && ((self->flags & HYTHREAD_FLAG_INTERRUPTED) != 0);
+ priorityinterrupted = interruptable
+ && ((self->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED) != 0);
+ notified = self->flags & HYTHREAD_FLAG_NOTIFIED;
+ if (!(interrupted || priorityinterrupted || notified))
+ {
+ timedOut = 1;
+ }
+ break;
+ }
+ else
+ {
+
+ THREAD_LOCK (self, self, CALLER_MONITOR_WAIT2);
+ interrupted = interruptable
+ && ((self->flags & HYTHREAD_FLAG_INTERRUPTED) != 0);
+ priorityinterrupted = interruptable
+ && ((self->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED) != 0);
+ notified = self->flags & HYTHREAD_FLAG_NOTIFIED;
+ if (interrupted || priorityinterrupted || notified)
+ {
+ break;
+ }
+ /* must have been spurious */
+ ASSERT_DEBUG (0);
+ THREAD_UNLOCK (self, self);
+ }
+ COND_WAIT_TIMED_LOOP ();
+ }
+ else
+ {
+ /*
+ * WAIT UNTIL NOTIFIED
+ */
+
+ COND_WAIT (self->condition, monitor->mutex);
+
+ THREAD_LOCK (self, self, CALLER_MONITOR_WAIT2);
+ interrupted = interruptable
+ && ((self->flags & HYTHREAD_FLAG_INTERRUPTED) != 0);
+ priorityinterrupted = interruptable
+ && ((self->flags & HYTHREAD_FLAG_PRIORITY_INTERRUPTED) != 0);
+ notified = self->flags & HYTHREAD_FLAG_NOTIFIED;
+ if (interrupted || priorityinterrupted || notified)
+ {
+ break;
+ }
+ /* must have been spurious */
+ ASSERT_DEBUG (0);
+ THREAD_UNLOCK (self, self);
+ COND_WAIT_LOOP ();
+ }
+
+ /* DONE WAITING AT THIS POINT */
+
+ /* we have to remove self from the wait queue */
+ remove_from_queue (&monitor->waiting, self);
+
+ MONITOR_UNLOCK (self, monitor);
+
+ /* at this point, this thread should already be locked */
+ ASSERT (notified || interrupted || priorityinterrupted || timedOut);
+ ASSERT (!interrupted || interruptable); /* if we were interrupted, then we'd better have been interruptable */
+
+ self->flags &=
+ ~(HYTHREAD_FLAG_WAITING | HYTHREAD_FLAG_NOTIFIED |
+ HYTHREAD_FLAG_PRIORITY_INTERRUPTED | HYTHREAD_FLAG_INTERRUPTABLE |
+ HYTHREAD_FLAG_TIMER_SET);
+
+ if (interrupted && !(notified || priorityinterrupted))
+ self->flags &= ~HYTHREAD_FLAG_INTERRUPTED;
+
+ /*
+ * Is there an interruptServer thread out there
+ * trying to interrupt us? Its services are
+ * no longer required.
+ */
+ if (self->interrupter)
+ {
+ ASSERT (interrupted || priorityinterrupted);
+ THREAD_LOCK (self, self->interrupter, CALLER_MONITOR_WAIT2);
+ self->interrupter->flags |= HYTHREAD_FLAG_CANCELED;
+ THREAD_UNLOCK (self, self->interrupter);
+ self->interrupter = NULL;
+ }
+
+ THREAD_UNLOCK (self, self);
+
+ monitor_enter_three_tier (self, monitor);
+
+ monitor->count = count;
+
+ ASSERT (monitor->owner == self);
+ ASSERT (monitor->count == count);
+ ASSERT (monitor->count >= 1);
+ ASSERT (0 == self->monitor);
+ ASSERT (!(monitor->flags & HYTHREAD_FLAG_WAITING));
+ ASSERT (!(monitor->flags & HYTHREAD_FLAG_TIMER_SET));
+ ASSERT (!(monitor->flags & HYTHREAD_FLAG_BLOCKED));
+ ASSERT (!(monitor->flags & HYTHREAD_FLAG_NOTIFIED));
+ ASSERT (!(monitor->flags & HYTHREAD_FLAG_INTERRUPTABLE));
+ ASSERT (NULL == self->next);
+
+ if (priorityinterrupted)
+ return HYTHREAD_PRIORITY_INTERRUPTED;
+ if (notified)
+ return 0;
+ if (interrupted)
+ return HYTHREAD_INTERRUPTED;
+ if (timedOut)
+ return HYTHREAD_TIMED_OUT;
+ ASSERT (0);
+ return 0;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION interrupt_thread
+/*
+ * Interrupt a thread.
+ *
+ * If the thread is currently blocked (e.g. waiting on monitor_wait)
+ * resume the thread and return from the blocking function with
+ * HYTHREAD_INTERRUPTED or HYTHREAD_PRIORITY_INTERRUPTED
+ *
+ * If it can't be resumed (it's not in an interruptable state)
+ * then just set the appropriate interrupt flag.
+ *
+ * @param[in] thread thread to be interrupted
+ * @param[in] interruptFlag indicated whether to priority interrupt or just normally interrupt.
+ * @return none
+ */
+static void
+interrupt_thread (hythread_t thread, UDATA interruptFlag)
+{
+ UDATA currFlags, newFlags;
+ hythread_t self = MACRO_SELF ();
+
+ ASSERT (self);
+ ASSERT (thread);
+
+ GLOBAL_LOCK (self, CALLER_INTERRUPT_THREAD);
+ THREAD_LOCK (self, thread, CALLER_INTERRUPT_THREAD);
+ if (thread->flags & interruptFlag)
+ {
+ THREAD_UNLOCK (self, thread);
+ GLOBAL_UNLOCK (self);
+ return;
+ }
+
+ currFlags = thread->flags;
+ newFlags = currFlags | interruptFlag;
+ if (currFlags & HYTHREAD_FLAG_INTERRUPTABLE)
+ {
+ if (currFlags & (HYTHREAD_FLAG_SLEEPING | HYTHREAD_FLAG_PARKED))
+ {
+ COND_NOTIFY_ALL (thread->condition);
+ }
+ else if (currFlags & HYTHREAD_FLAG_WAITING)
+ {
+ if (interrupt_waiting_thread (self, thread))
+ {
+ newFlags |= HYTHREAD_FLAG_BLOCKED;
+ }
+ }
+ }
+
+ thread->flags = newFlags;
+ THREAD_UNLOCK (self, thread);
+ GLOBAL_UNLOCK (self);
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION interrupt_waiting_thread
+/*
+ * Interrupt a waiting thread.
+ *
+ * @param[in] self current thread
+ * @param[in] threadToInterrupt
+ * @return 1 if the thread was immediately interrupted<br>
+ * 0 if the thread will be interrupted asap by a special thread.
+ * @note: Assumes caller has locked the global mutex
+ */
+static IDATA
+interrupt_waiting_thread (hythread_t self, hythread_t threadToInterrupt)
+{
+
+ IDATA retVal = 0;
+ hythread_monitor_t monitor;
+
+ ASSERT (self);
+ ASSERT (threadToInterrupt);
+ ASSERT (self != threadToInterrupt);
+ ASSERT (threadToInterrupt->flags & HYTHREAD_FLAG_INTERRUPTABLE);
+ ASSERT (threadToInterrupt->monitor);
+ ASSERT (NULL == threadToInterrupt->interrupter);
+
+#if !defined(ALWAYS_SPAWN_THREAD_TO_INTERRUPT)
+ /*
+ * If we can enter the monitor without blocking, we don't need the
+ * interruptServer thread
+ */
+ monitor = threadToInterrupt->monitor;
+ if (hythread_monitor_try_enter_using_threadId (monitor, self) == 0)
+ {
+ ASSERT (monitor->owner == self);
+ COND_NOTIFY_ALL (threadToInterrupt->condition);
+ hythread_monitor_exit_using_threadId (monitor, self);
+ retVal = 1;
+ }
+ else
+#endif
+
+ {
+ /*
+ * spawn a thread to do it for us, because it's possible that
+ * having this thread lock the waiting thread's monitor may
+ * cause deadlock
+ */
+ create_thread (&threadToInterrupt->interrupter, 0,
+ HYTHREAD_PRIORITY_NORMAL, 0, interruptServer,
+ (void *) threadToInterrupt, GLOBAL_IS_LOCKED);
+ }
+ return retVal;
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION interruptServer
+/*
+ * Interrupt a thread waiting on a monitor.
+ *
+ * This function serves as the entry point for a
+ * thread whose sole purpose is to interrupt another
+ * thread.
+ *
+ * @param[in] entryArg pointer to the thread to interrupt (non-NULL)
+ * @return 0
+ */
+static I_32 HYTHREAD_PROC
+interruptServer (void *entryArg)
+{
+ hythread_t self = MACRO_SELF ();
+ hythread_t threadToInterrupt = (hythread_t) entryArg;
+ hythread_monitor_t monitor;
+
+ ASSERT (threadToInterrupt);
+ ASSERT (self);
+
+ GLOBAL_LOCK (self, CALLER_INTERRUPT_SERVER);
+
+ /*
+ * Did the thread to interrupt die or come out of wait already?
+ * If it did, it cancelled this thread (set our CANCELED bit)
+ */
+ if (self->flags & HYTHREAD_FLAG_CANCELED)
+ {
+ GLOBAL_UNLOCK (self);
+ hythread_exit (NULL); /* this should not return */
+ }
+
+ THREAD_LOCK (self, threadToInterrupt, CALLER_INTERRUPT_SERVER);
+
+ if (threadToInterrupt->interrupter != self)
+ {
+ THREAD_UNLOCK (self, threadToInterrupt);
+ GLOBAL_UNLOCK (self);
+ hythread_exit (NULL); /* this should not return */
+ }
+
+ monitor = threadToInterrupt->monitor;
+ ASSERT (monitor);
+ ASSERT (threadToInterrupt->flags & HYTHREAD_FLAG_WAITING);
+
+ hythread_monitor_pin (monitor, self);
+ THREAD_UNLOCK (self, threadToInterrupt);
+ GLOBAL_UNLOCK (self);
+
+ /* try to take the monitor so that we can notify the thread to interrupt */
+ hythread_monitor_enter (monitor);
+
+ GLOBAL_LOCK (self, CALLER_INTERRUPT_SERVER);
+ hythread_monitor_unpin (monitor, self);
+
+ /* Did the thread to interrupt die or come out of wait already? */
+ if (self->flags & HYTHREAD_FLAG_CANCELED)
+ {
+ GLOBAL_UNLOCK (self);
+ hythread_exit (monitor); /* this should not return */
+ ASSERT (0);
+ }
+
+ THREAD_LOCK (self, threadToInterrupt, CALLER_INTERRUPT_SERVER);
+ if ((threadToInterrupt->interrupter == self)
+ && (threadToInterrupt->flags & HYTHREAD_FLAG_WAITING))
+ {
+ notify_thread (threadToInterrupt, DONT_SET_NOTIFIED_FLAG);
+ }
+ threadToInterrupt->interrupter = NULL;
+ ASSERT (threadToInterrupt->flags & HYTHREAD_FLAG_INTERRUPTED);
+ THREAD_UNLOCK (self, threadToInterrupt);
+
+ GLOBAL_UNLOCK (self);
+ hythread_exit (monitor);
+
+ ASSERT (0);
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_exit_using_threadId
+/**
+ * Exit a monitor.
+ *
+ * This is a slightly faster version of hythread_monitor_exit because
+ * the hythread_t for the current thread doesn't have to be looked up
+ *
+ * @param[in] monitor a monitor to be exited
+ * @param[in] threadId hythread_t for the current thread
+ * @return 0 on success<br>
+ * HYTHREAD_ILLEGAL_MONITOR_STATE if the current thread does not own the monitor
+ *
+ * @see hythread_monitor_exit, hythread_monitor_enter, hythread_monitor_enter_using_threadId
+ */
+IDATA VMCALL
+hythread_monitor_exit_using_threadId (hythread_monitor_t monitor,
+ hythread_t threadId)
+{
+ ASSERT (threadId == MACRO_SELF ());
+ ASSERT (monitor);
+ ASSERT (FREE_TAG != monitor->count);
+
+ if (monitor->owner != threadId)
+ {
+ ASSERT_DEBUG (0);
+ return HYTHREAD_ILLEGAL_MONITOR_STATE;
+ }
+
+ return monitor_exit (threadId, monitor);
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_enter_using_threadId
+/**
+ * Enter a monitor.
+ *
+ * This is a slightly faster version of hythread_monitor_enter because
+ * the hythread_t for the current thread doesn't have to be looked up
+ *
+ * @param[in] monitor a monitor to be entered
+ * @param[in] threadId hythread_t for the current thread
+ * @return 0 on success<br>
+ * HYTHREAD_PRIORITY_INTERRUPTED if the thread was priority interrupted while blocked
+ *
+ * @see hythread_monitor_enter, hythread_monitor_exit, hythread_monitor_exit_using_threadId
+ *
+ */
+IDATA VMCALL
+hythread_monitor_enter_using_threadId (hythread_monitor_t monitor,
+ hythread_t threadId)
+{
+ ASSERT (threadId != 0);
+ ASSERT (threadId == MACRO_SELF ());
+ ASSERT (monitor);
+ ASSERT (FREE_TAG != monitor->count);
+
+ if (monitor->owner == threadId)
+ {
+ ASSERT (monitor->count >= 1);
+ monitor->count++;
+
+ if (IS_JLM_ENABLED (threadId))
+ {
+ ASSERT (monitor->tracing);
+ monitor->tracing->recursive_count++;
+ monitor->tracing->enter_count++;
+ } /* if (IS_JLM_ENABLED(threadId)) */
+
+ return 0;
+ }
+ return monitor_enter (threadId, monitor);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_monitor_try_enter_using_threadId
+/**
+ * Attempt to enter a monitor without blocking.
+ *
+ * If the thread must block before it enters the monitor this function
+ * returns immediately with a negative value to indicate failure.<br>
+ *
+ * This is a slightly faster version of hythread_monitor_try_enter because
+ * the current thread's hythread_t doesn't have to be looked up.
+ *
+ * @param[in] monitor a monitor
+ * @param[in] threadId the current thread
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_monitor_try_enter
+ *
+ */
+IDATA VMCALL
+hythread_monitor_try_enter_using_threadId (hythread_monitor_t monitor,
+ hythread_t threadId)
+{
+
+ ASSERT (threadId != 0);
+ ASSERT (threadId == MACRO_SELF ());
+ ASSERT (FREE_TAG != monitor->count);
+
+ /* Are we already the owner? */
+ if (monitor->owner == threadId)
+ {
+ ASSERT (monitor->count >= 1);
+ monitor->count++;
+
+ if (IS_JLM_ENABLED (threadId))
+ {
+ monitor->tracing->recursive_count++;
+ monitor->tracing->enter_count++;
+ } /* if (IS_JLM_ENABLED(threadId)) */
+
+ return 0;
+ }
+
+ if (hythread_spinlock_acquire (threadId, monitor) == 0)
+
+ {
+ ASSERT (NULL == monitor->owner);
+ ASSERT (0 == monitor->count);
+
+ monitor->owner = threadId;
+ monitor->count = 1;
+
+ if (IS_JLM_ENABLED (threadId))
+ {
+ monitor->tracing->enter_count++;
+
+ } /* if (IS_JLM_ENABLED(threadId)) */
+
+ return 0;
+ }
+
+ return -1;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_probe
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION destroy_thread
+/*
+ * Destroy the resources associated with the thread.
+ *
+ * If the thread is not already dead, the function fails.
+ *
+ * @param[in] thread thread to be destroyed
+ * @param[in] globalAlreadyLocked indicated whether the thread library global mutex is already locked
+ * @return 0 on success or negative value on failure.
+ */
+static IDATA
+destroy_thread (hythread_t thread, int globalAlreadyLocked)
+{
+
+ hythread_t self = MACRO_SELF ();
+ hythread_library_t lib = self->library;
+
+ ASSERT (thread);
+ ASSERT (lib);
+
+ THREAD_LOCK (self, thread, CALLER_DESTROY);
+ if ((thread->flags & HYTHREAD_FLAG_DEAD) == 0)
+ {
+ THREAD_UNLOCK (self, thread);
+ return -1;
+ }
+ THREAD_UNLOCK (self, thread);
+
+ COND_DESTROY (thread->condition);
+
+ MUTEX_DESTROY (thread->mutex);
+
+#if defined(WIN32)
+ if (thread->flags & HYTHREAD_FLAG_ATTACHED)
+ {
+ CloseHandle (thread->handle);
+ }
+#endif
+
+ free_thread (thread, globalAlreadyLocked);
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_jlm_thread_init
+
+/*
+ * Initialize and clear a thread's JLM tracing information.
+ *
+ * Tracing information for the thread is allocated if not already allocated
+ * The library's thread tracing pool is initialized if not already initialized.
+ *
+ * @param[in] thread thread to be initialized
+ * @return none
+ *
+ */
+void VMCALL
+hythread_jlm_thread_init (hythread_t thread)
+{
+ hythread_library_t library = thread->library;
+
+ ASSERT (thread);
+ ASSERT (library);
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_jlm_thread_clear
+
+/*
+ * Clear (reset) a thread's JLM tracing structure.
+ *
+ * Assumes the thread's tracing structure has already been allocated.
+ *
+ * @param[in] thread thread to be initialized (non-NULL)
+ * @return none
+ *
+ */
+void VMCALL
+hythread_jlm_thread_clear (hythread_t thread)
+{
+ ASSERT (thread);
+
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_jlm_monitor_init
+
+/*
+ * Initialize and clear a monitor's JLM tracing information.
+ *
+ * Tracing information for the monitor is allocated if not already allocated
+ * The library's monitor tracing pool is initialized if not already initialized.
+ *
+ * @param[in] monitor monitor to be initialized
+ * @return none
+ *
+ */
+void VMCALL
+hythread_jlm_monitor_init (hythread_monitor_t monitor)
+{
+ hythread_t self = MACRO_SELF ();
+ hythread_library_t library;
+ ASSERT (self);
+ ASSERT (monitor);
+ library = self->library;
+ ASSERT (library);
+
+ if (library->monitor_tracing_pool == NULL)
+ {
+ library->monitor_tracing_pool =
+ pool_new (sizeof (HyThreadMonitorTracing), 0, 0, 0, thread_malloc,
+ thread_free, NULL);
+ }
+
+ if (monitor->tracing == NULL)
+ {
+ /* cannot have been set, so set it now */
+ monitor->tracing = pool_newElement (library->monitor_tracing_pool);
+ }
+
+ hythread_jlm_monitor_clear (monitor);
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_jlm_monitor_clear
+
+/*
+ * Clear (reset) a monitor's JLM tracing structure.
+ *
+ * Assumes the monitor's tracing structure has already been allocated.
+ *
+ * @param[in] monitor a monitor to be initialized
+ * @return none
+ */
+void VMCALL
+hythread_jlm_monitor_clear (hythread_monitor_t monitor)
+{
+ ASSERT (monitor);
+ ASSERT (monitor->tracing);
+ memset (monitor->tracing, 0, sizeof (*monitor->tracing));
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION init_monitor
+/*
+ * Re-initialize the 'simple' fields of a monitor
+ * that has been initialized previously, but is now
+ * being re-used.
+ *
+ * @param[in] monitor monitor to be initialized
+ * @return 0 on success or negative value on failure.
+ * @see hythread_monitor_init_with_name
+ *
+ */
+static UDATA
+init_monitor (hythread_monitor_t monitor, UDATA flags)
+{
+ ASSERT (monitor);
+ monitor->count = 0;
+ monitor->owner = NULL;
+ monitor->waiting = NULL;
+ monitor->flags = flags;
+ monitor->userData = 0;
+ monitor->name = 0;
+ monitor->pinCount = 0;
+
+ monitor->proDeflationCount = 0;
+ monitor->antiDeflationCount = 0;
+
+ monitor->blocking = NULL;
+ monitor->spinlockState = HYTHREAD_MONITOR_SPINLOCK_UNOWNED;
+ monitor->lockingWord = 0;
+ /* these numbers are taken from the GC spinlock. They probably need to be tuned more (dynamically?) */
+ /* note that every spinCount must be > 0! */
+
+ monitor->spinCount1 = 256;
+ monitor->spinCount2 = 32;
+ monitor->spinCount3 = 45;
+
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION getCurrentCycles
+/*
+ * Return the cycle count on the current processor.
+ *
+ * Units will be platform dependent.
+ * @todo This will be implmented in builder
+ */
+static hytime_t
+getCurrentCycles (void)
+{
+ return 0;
+}
+
+#undef CDEV_CURRENT_FUNCTION
+
+#define CDEV_CURRENT_FUNCTION hythread_lib_get_flags
+
+/**
+ * Get threading library global flags.
+ *
+ * Returns the flags for the threading library associated with the current thread.
+ *
+ * @note: assumes caller has global lock
+ *
[... 449 lines stripped ...]