blob: 0c051519059ba8107c3ffd099c905591355f93a9 [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
*/
/*
* the following must come before the standard includes because thrdsup.h
* includes windows.h in Win32.
*/
#include "thrdsup.h"
#include "hythread.h"
#include "thrtypes.h"
#define CDEV_CURRENT_FUNCTION _prototypes_private
void paint_stack PROTOTYPE ((hythread_t thread));
#undef CDEV_CURRENT_FUNCTION
extern UDATA current_stack_depth PROTOTYPE ((void));
#define STACK_PATTERN 0xBAADF00D
#define CDEV_CURRENT_FUNCTION hythread_get_flags
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_cpu_time
/**
* Return the amount of CPU time used by a thread.
*
* @param[in] thread
* @return actual time on CPU used by thread (nanoseconds) or
* negative value if not supported.
*/
I_64 VMCALL
hythread_get_cpu_time (hythread_t thread)
{
#if defined(WIN32)
FILETIME creationTime, exitTime, kernelTime, userTime;
I_64 totalTime;
/* WARNING! Not supported on Win95! Need to test to ensure this fails gracefully */
if (GetThreadTimes
(thread->handle, &creationTime, &exitTime, &kernelTime, &userTime))
{
totalTime =
((I_64) kernelTime.
dwLowDateTime | ((I_64) kernelTime.dwHighDateTime << 32)) +
((I_64) userTime.
dwLowDateTime | ((I_64) userTime.dwHighDateTime << 32));
/* totalTime is in 100's of nanos. Convert to nanos */
return totalTime * 100;
}
#endif /* WIN32 */
return -1;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_handle
/**
* Return the OS handle for a thread.
*
* @param thread a thread
* @return OS handle
*/
UDATA VMCALL
hythread_get_handle (hythread_t thread)
{
return (UDATA) thread->handle;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_enable_stack_usage
/**
* Enable or disable monitoring of stack usage.
*
* @param[in] enable 0 to disable or non-zero to enable.
* @return none
*
*/
void VMCALL
hythread_enable_stack_usage (UDATA enable)
{
hythread_library_t lib = GLOBAL_DATA (default_library);
lib->stack_usage = enable;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_stack_usage
/**
* Return the approximate stack usage by a thread
*
* @param[in] thread a thread
* @return 0 if the stack has not been painted<br>
* (UDATA)-1 if the stack has overflowed<br>
* otherwise the approximate maximum number of bytes used on the stack
*/
UDATA VMCALL
hythread_get_stack_usage (hythread_t thread)
{
#if defined(LINUX)
return 0;
#else
UDATA *tos = thread->tos;
UDATA count = thread->stacksize;
if (tos == NULL || count == 0)
{
return 0;
}
if (*tos != STACK_PATTERN)
{
return (UDATA) - 1;
}
while (*tos++ == STACK_PATTERN)
{
count -= sizeof (UDATA);
}
return count;
#endif
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION paint_stack
/*
* Paint a thread's stack.
*
* Attempt to paint the stack region with STACK_PATTERN so we can
* detect stack usage. Sets thread->tos to the maximum stack
* address.
* @note This won't work on PA-RISC because of backwards stacks
*
* @param thread a thread
* @return none
*/
void
paint_stack (hythread_t thread)
{
#if defined(LINUX)
/* z/OS and Linux don't let us set the stack size, so we can't paint the stack safely */
#elif defined(WIN32)
MEMORY_BASIC_INFORMATION memInfo;
SYSTEM_INFO sysInfo;
UDATA *curr;
UDATA *stack = (UDATA *) & stack;
/* Find out where the stack starts. */
VirtualQuery (stack, &memInfo, sizeof (MEMORY_BASIC_INFORMATION));
/* Start painting. Skip the top 32 slots (to protect this stack frame) */
curr = stack - 32;
__try
{
while (curr > (UDATA *) memInfo.AllocationBase)
*curr-- = STACK_PATTERN;
}
__except (1)
{
/* Ran off the end of the stack. Stop */
}
thread->tos = curr + 1;
/* Round up to the system page size. */
GetSystemInfo (&sysInfo);
thread->stacksize =
((UDATA) stack - (UDATA) thread->tos +
sysInfo.dwPageSize) & ~(sysInfo.dwPageSize - 1);
#else
IDATA maxStack, stackSize, index;
UDATA *stack = (UDATA *) & stack;
stackSize = thread->stacksize - current_stack_depth ();
maxStack = stackSize / sizeof (UDATA) - 32;
if (maxStack <= 0)
{
return;
}
thread->tos = stack - maxStack;
/* don't paint the top 32 slots (to protect this stack frame) */
for (index = 32; index <= maxStack; index++)
{
*(stack - index) = STACK_PATTERN;
}
#endif
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_stack_size
/**
* Returns a thread's stack size.
*
* @param[in] thread a thread
* @return 0 if the thread is an attached thread
* or the initial size of the thread's stack,
*
*/
UDATA VMCALL
hythread_get_stack_size (hythread_t thread)
{
return thread->stacksize;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_os_priority
/**
* Return the OS's scheduling policy and priority for a thread.
*
* Query the OS to determine the actual priority of the specified thread.
* The priority and scheduling policy are stored in the pointers provided.
* On Windows the "policy" contains the thread's priority class.
* On POSIX systems it contains the scheduling policy
* On OS/2 no information is available. 0 is stored in both pointers.
*
* @param[in] thread a thread
* @param[in] policy pointer to location where policy will be stored (non-NULL)
* @param[in] priority pointer to location where priority will be stored (non-NULL)
* @return 0 on success or negative value on failure
*/
IDATA VMCALL
hythread_get_os_priority (hythread_t thread, IDATA * policy, IDATA * priority)
{
#if defined(HY_POSIX_THREADS)
struct sched_param sched_param;
int osPolicy, rc;
rc = pthread_getschedparam (thread->handle, &osPolicy, &sched_param);
if (rc)
return -1;
*priority = sched_param.sched_priority;
*policy = osPolicy;
#else
#if defined(WIN32)
*priority = GetThreadPriority (thread->handle);
if (*priority == THREAD_PRIORITY_ERROR_RETURN)
return -1;
*policy = GetPriorityClass (thread->handle);
if (*policy == 0)
return -1;
#else
#error Unknown platform
#endif /* HY_POSIX_THREADS */
#endif /* HYEPOC32 */
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hythread_get_user_time
/**
* Return the amount of USER time used by a thread.
*
* @param[in] thread
* @return actual time on USER used by thread (nanoseconds) or
* negative value if not supported.
*/
I_64 VMCALL
hythread_get_user_time (hythread_t thread)
{
#if defined(WIN32)
FILETIME creationTime, exitTime, kernelTime, userTime;
I_64 totalTime;
/* WARNING! Not supported on Win95! Need to test to ensure this fails gracefully */
if (GetThreadTimes
(thread->handle, &creationTime, &exitTime, &kernelTime, &userTime))
{
totalTime =
((I_64) userTime.
dwLowDateTime | ((I_64) userTime.dwHighDateTime << 32));
/* totalTime is in 100's of nanos. Convert to nanos */
return totalTime * 100;
}
#endif /* WIN32 */
return -1;
}
#undef CDEV_CURRENT_FUNCTION