blob: 1252ef3dfed0ac3f22fd08863ef2b5a8d5b13733 [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 thread_ti_monitors.c
* @brief JVMTI raw monitors related functions
*/
#include <open/hythread_ext.h>
#include "port_mutex.h"
#include "vm_threads.h"
typedef struct ResizableArrayEntry *array_entry_t;
typedef struct ResizableArrayType *array_t;
struct ResizableArrayEntry {
void *entry;
UDATA next_free;
};
struct ResizableArrayType {
UDATA size;
UDATA capacity;
UDATA next_index;
array_entry_t entries;
};
/**
* Resizable array implementation
*/
static IDATA array_create(array_t * arr)
{
array_t ptr = (array_t) malloc(sizeof(ResizableArrayType));
if (!ptr) {
return -1;
}
ptr->capacity = 1024;
ptr->size = 0;
ptr->next_index = 0;
ptr->entries =
(array_entry_t) malloc(sizeof(ResizableArrayEntry) * ptr->capacity);
if (!ptr->entries) {
free(ptr);
return -1;
}
*arr = ptr;
return 0;
} // array_create
static IDATA array_destroy(array_t arr)
{
if (!arr) {
return -1;
}
free(arr->entries);
free(arr);
return 0;
} // array_destroy
static UDATA array_add(array_t arr, void *value)
{
UDATA index;
if (!arr) {
return 0;
}
if (arr->next_index) {
index = arr->next_index;
} else {
index = arr->size + 1;
if (index >= arr->capacity) {
arr->entries = (array_entry_t)realloc(arr->entries,
sizeof(void *) * arr->capacity * 2);
if (!arr->entries)
return 0;
arr->capacity *= 2;
}
arr->entries[index].next_free = 0;
}
arr->next_index = arr->entries[index].next_free;
arr->entries[index].entry = value;
arr->size++;
return index;
} // array_add
static void * array_delete(array_t arr, UDATA index)
{
void *return_value;
if (!arr || index > arr->size || index == 0) {
return NULL;
}
return_value = arr->entries[index].entry;
arr->entries[index].entry = NULL;
arr->entries[index].next_free = arr->next_index;
arr->next_index = index;
return return_value;
} // array_delete
static void * array_get(array_t arr, UDATA index)
{
if (!arr || index > arr->size || index == 0) {
return NULL;
}
return arr->entries[index].entry;
} // array_get
static array_t jvmti_monitor_table = 0;
static osmutex_t jvmti_monitor_table_lock;
static IDATA jthread_init_jvmti_monitor_table()
{
IDATA status = hythread_global_lock();
if (status != TM_ERROR_NONE) {
return status;
}
if (!jvmti_monitor_table) {
if (array_create(&jvmti_monitor_table)) {
hythread_global_unlock();
return TM_ERROR_OUT_OF_MEMORY;
}
status = port_mutex_create(&jvmti_monitor_table_lock, APR_THREAD_MUTEX_NESTED);
if (status != TM_ERROR_NONE) {
hythread_global_unlock();
return status;
}
}
status = hythread_global_unlock();
return status;
} // jthread_init_jvmti_monitor_table
/**
* Initializes raw monitor.
*
* Raw monitors are a simple combination of mutex and conditional variable which is
* not associated with any Java object. This function creates the raw monitor at the
* address specified as mon_ptr.
* User needs to allocate space equal to sizeof(jrawMonitorID) before doing this call.
*
* @param[in] mon_ptr address where monitor needs to be created and initialized.
*/
IDATA VMCALL jthread_raw_monitor_create(jrawMonitorID * mon_ptr)
{
assert(mon_ptr);
hythread_monitor_t monitor;
IDATA status = hythread_monitor_init(&monitor, 0);
if (status != TM_ERROR_NONE) {
return status;
}
// possibly should be moved to jvmti(environment?) init section
if (!jvmti_monitor_table) {
status = jthread_init_jvmti_monitor_table();
if (status != TM_ERROR_NONE) {
return status;
}
}
status = port_mutex_lock(&jvmti_monitor_table_lock);
if (status != TM_ERROR_NONE) {
return status;
}
*mon_ptr = (jrawMonitorID)array_add(jvmti_monitor_table, monitor);
if (!(*mon_ptr)) {
port_mutex_unlock(&jvmti_monitor_table_lock);
return TM_ERROR_OUT_OF_MEMORY;
}
status = port_mutex_unlock(&jvmti_monitor_table_lock);
return status;
} // jthread_raw_monitor_create
/**
* Destroys raw monitor.
*
* @param[in] mon_ptr address where monitor needs to be destroyed.
*/
IDATA VMCALL jthread_raw_monitor_destroy(jrawMonitorID mon_ptr)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
while (hythread_monitor_destroy((hythread_monitor_t)monitor) != TM_ERROR_NONE)
{
IDATA status = hythread_monitor_exit((hythread_monitor_t) monitor);
if (status != TM_ERROR_NONE) {
return status;
}
}
IDATA status = port_mutex_lock(&jvmti_monitor_table_lock);
if (status != TM_ERROR_NONE) {
return status;
}
array_delete(jvmti_monitor_table, (UDATA) mon_ptr);
status = port_mutex_unlock(&jvmti_monitor_table_lock);
return status;
} // jthread_raw_monitor_destroy
/**
* Gains the ownership over monitor.
*
* Current thread blocks if the specified monitor is owned by other thread.
*
* @param[in] mon_ptr monitor
*/
IDATA VMCALL jthread_raw_monitor_enter(jrawMonitorID mon_ptr)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
IDATA status = hythread_monitor_enter(monitor);
hythread_safe_point();
hythread_exception_safe_point();
return status;
} // jthread_raw_monitor_enter
/**
* Attempt to gain the ownership over monitor without blocking.
*
* @param[in] mon_ptr monitor
* @return 0 in case of successful attempt.
*/
IDATA VMCALL jthread_raw_monitor_try_enter(jrawMonitorID mon_ptr)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
return hythread_monitor_try_enter((hythread_monitor_t) monitor);
} // jthread_raw_monitor_try_enter
/**
* Releases the ownership over monitor.
*
* @param[in] mon_ptr monitor
*/
IDATA VMCALL jthread_raw_monitor_exit(jrawMonitorID mon_ptr)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
IDATA status = hythread_monitor_exit(monitor);
hythread_safe_point();
hythread_exception_safe_point();
return status;
} // jthread_raw_monitor_exit
/**
* Wait on the monitor.
*
* This function instructs the current thread to be scheduled off
* the processor and wait on the monitor until the following occurs:
* <UL>
* <LI>another thread invokes <code>thread_notify(object)</code>
* and VM chooses this thread to wake up;
* <LI>another thread invokes <code>thread_notifyAll(object);</code>
* <LI>another thread invokes <code>thread_interrupt(thread);</code>
* <LI>real time elapsed from the waiting begin is
* greater or equal the timeout specified.
* </UL>
*
* @param[in] mon_ptr monitor
* @param[in] millis timeout in milliseconds. Zero timeout is not taken into consideration.
* @return
* TM_ERROR_NONE success
* TM_ERROR_INTERRUPT wait was interrupted
* TM_ERROR_INVALID_MONITOR current thread isn't the owner
*/
IDATA VMCALL jthread_raw_monitor_wait(jrawMonitorID mon_ptr, I_64 millis)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
// JDWP agent expects RawMonitor waiting thread has RUNNABLE state.
// That why no Java thread state change is done here.
// RI behaviour confirms this assumption.
return hythread_monitor_wait_interruptable(monitor, millis, 0);
} // jthread_raw_monitor_wait
/**
* Notifies one thread waiting on the monitor.
*
* Only single thread waiting on the
* object's monitor is waked up.
* Nothing happens if no threads are waiting on the monitor.
*
* @param[in] mon_ptr monitor
*/
IDATA VMCALL jthread_raw_monitor_notify(jrawMonitorID mon_ptr)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
return hythread_monitor_notify(monitor);
} // jthread_raw_monitor_notify
/**
* Notifies all threads which are waiting on the monitor.
*
* Each thread from the set of threads waiting on the
* object's monitor is waked up.
*
* @param[in] mon_ptr monitor
*/
IDATA VMCALL jthread_raw_monitor_notify_all(jrawMonitorID mon_ptr)
{
hythread_monitor_t monitor =
(hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr);
if (!monitor) {
return TM_ERROR_INVALID_MONITOR;
}
return hythread_monitor_notify_all(monitor);
} // jthread_raw_monitor_notify_all