blob: 1b517b37a33c3c1421674efd772830662c33697c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*/
/*
* This file contains thread routines which are compiled twice -- once for in-process, and
* once for out-of-process uses (e.g. debug extensions).
* The APIs in this file are only used for inspecting threads -- not for modifying them
*/
#if defined(HYVM_OUT_OF_PROCESS)
#include "hydbgext.h"
#endif
#include "threaddef.h"
#if defined(HYVM_OUT_OF_PROCESS)
#define READU(field) dbgReadUDATA((UDATA*)&(field))
#define READP(field) ((void*)dbgReadUDATA((UDATA*)&(field)))
#undef MUTEX_ENTER
#define MUTEX_ENTER(a)
#undef MUTEX_EXIT
#define MUTEX_EXIT(a)
#undef GLOBAL_LOCK
#define GLOBAL_LOCK(a, b)
#undef GLOBAL_UNLOCK
#define GLOBAL_UNLOCK(a)
#else /* defined (HYVM_OUT_OF_PROCESS) */
#define READU(field) ((UDATA)(field))
#define READP(field) (field)
#endif
#define CDEV_CURRENT_FUNCTION _prototypes_private
static hythread_monitor_pool_t pool_for_monitor
PROTOTYPE ((hythread_library_t lib, hythread_monitor_t monitor));
static hythread_library_t get_default_library PROTOTYPE ((void));
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_monitor_walk
/**
* Walk all active monitors.
*
* @param[in] monitor If NULL, the first monitor is returned and the monitor pool is locked (thread lib is globally locked)<br>
* If non-NULL, the next monitor is returned.
* @return a pointer to a monitor, or NULL if all monitors walked (and thread lib is globally unlocked).
*
* @note As this is currently implemented, this must be called to walk ALL monitors. It can't
* be used to look for a specific monitor and then quit.
*
*/
hythread_monitor_t VMCALL
hythread_monitor_walk (hythread_monitor_t monitor)
{
hythread_monitor_pool_t pool;
hythread_library_t lib = get_default_library ();
ASSERT (lib);
ASSERT (lib->monitor_pool);
ASSERT (lib->monitor_pool->entries);
ASSERT (MACRO_SELF () != 0);
if (monitor == NULL)
{
GLOBAL_LOCK (MACRO_SELF (), CALLER_MONITOR_WALK);
pool = READP (lib->monitor_pool);
monitor = &pool->entries[0];
if (READU (monitor->count) != FREE_TAG)
return monitor;
}
else
{
pool = pool_for_monitor (lib, monitor);
if (pool == NULL)
{
/* should never happen */
GLOBAL_UNLOCK (MACRO_SELF ());
return NULL;
}
}
do
{
if (monitor >= &pool->entries[MONITOR_POOL_SIZE - 1])
{
if ((pool = READP (pool->next)) == NULL)
{
/* we've walked all monitors */
GLOBAL_UNLOCK (MACRO_SELF ());
return NULL;
}
monitor = &pool->entries[0];
}
else
{
monitor++;
}
}
while (READU (monitor->count) == FREE_TAG);
return monitor;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_tls_get
/**
* Get a thread's thread local storage (TLS) value.
*
* @param[in] thread a thread
* @param[in] key key to have TLS value returned (value returned by hythread_tls_alloc)
* @return pointer to location of TLS or NULL on failure.
*
*/
void *VMCALL
hythread_tls_get (hythread_t thread, hythread_tls_key_t key)
{
return (void *) READU (thread->tls[key - 1]);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION pool_for_monitor
/*
* Return the monitor pool holding a monitor.
*
* @param[in] lib threading library (non-NULL)
* @param[in] monitor
* @return pointer to pool on success, NULL on failure (invalid monitor?)
*/
static hythread_monitor_pool_t
pool_for_monitor (hythread_library_t lib, hythread_monitor_t monitor)
{
hythread_monitor_pool_t pool = READP (lib->monitor_pool);
/* find out which pool the monitor is from (cache this, maybe?)
(NOTE: technically, this search invokes undefined behaviour (comparing pointers from different
malloc's). But it should work on every platform with a flat memory model. */
ASSERT (lib);
ASSERT (monitor);
ASSERT (pool);
while (monitor < &pool->entries[0]
|| monitor > &pool->entries[MONITOR_POOL_SIZE - 1])
{
if ((pool = READP (pool->next)) == NULL)
{
break;
}
}
return pool;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_priority
/**
* Return a thread's scheduling priority.
*
* @param[in] thread (non-NULL)
* @return scheduling priority
* @see hythread_create, hythread_set_priority
*
*/
UDATA VMCALL
hythread_get_priority (hythread_t thread)
{
ASSERT (thread);
return READU (thread->priority);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_flags
/**
* Return a thread's flags.
*
* @param[in] thread (non-NULL)
* @param[in] blocker if non-NULL, will be set to the monitor on which the thread is blocked (if any)
* @return flags
*
*/
UDATA VMCALL
hythread_get_flags (hythread_t thread, hythread_monitor_t * blocker)
{
UDATA flags;
ASSERT (thread);
MUTEX_ENTER (thread->mutex);
if (blocker)
{
*blocker = READP (thread->monitor);
}
flags = READU (thread->flags);
MUTEX_EXIT (thread->mutex);
return flags;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_monitor_get_name
/**
* Return a monitor's name.
*
* @param[in] monitor (non-NULL)
* @return pointer to the monitor's name (may be NULL)
*
* @see hythread_monitor_init_with_name
*
*/
const char *VMCALL
hythread_monitor_get_name (hythread_monitor_t monitor)
{
ASSERT (monitor);
return READP (monitor->name);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_monitor_get_tracing
/*
* Return a monitor's tracing information.
*
* @param[in] monitor (non-NULL)
* @return pointer to the monitor's tracing information (may be NULL)
*
*/
HyThreadMonitorTracing *VMCALL
hythread_monitor_get_tracing (hythread_monitor_t monitor)
{
ASSERT (monitor);
return READP (monitor->tracing);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION getDefaultLibrary
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION get_default_library
/*
* Return the default threading library.
*
* @return pointer to the default threading library
*
*/
static hythread_library_t
get_default_library (void)
{
#if defined(HYVM_OUT_OF_PROCESS)
return dbgGetThreadLibrary ();
#else
return GLOBAL_DATA (default_library);
#endif
}
#undef CDEV_CURRENT_FUNCTION