0N/A/*
2362N/A * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
0N/A *
0N/A * Redistribution and use in source and binary forms, with or without
0N/A * modification, are permitted provided that the following conditions
0N/A * are met:
0N/A *
0N/A * - Redistributions of source code must retain the above copyright
0N/A * notice, this list of conditions and the following disclaimer.
0N/A *
0N/A * - Redistributions in binary form must reproduce the above copyright
0N/A * notice, this list of conditions and the following disclaimer in the
0N/A * documentation and/or other materials provided with the distribution.
0N/A *
2362N/A * - Neither the name of Oracle nor the names of its
0N/A * contributors may be used to endorse or promote products derived
0N/A * from this software without specific prior written permission.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0N/A * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0N/A * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0N/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0N/A * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0N/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0N/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0N/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0N/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0N/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/A#include <stdio.h>
0N/A#include <stdlib.h>
0N/A#include <string.h>
0N/A#include <stddef.h>
0N/A
0N/A#include "jni.h"
0N/A#include "jvmti.h"
0N/A
0N/A#include "agent_util.h"
0N/A
0N/A#include "Monitor.hpp"
0N/A#include "Thread.hpp"
0N/A#include "Agent.hpp"
0N/A
0N/A/* Implementation of the Agent class */
0N/A
0N/A/* Given a jvmtiEnv* and jthread, find the Thread instance */
0N/AThread *
0N/AAgent::get_thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
0N/A{
0N/A jvmtiError err;
0N/A Thread *t;
0N/A
0N/A /* This should always be in the Thread Local Storage */
0N/A t = NULL;
0N/A err = jvmti->GetThreadLocalStorage(thread, (void**)&t);
0N/A check_jvmti_error(jvmti, err, "get thread local storage");
0N/A if ( t == NULL ) {
0N/A /* This jthread has never been seen before? */
0N/A stdout_message("WARNING: Never before seen jthread?\n");
0N/A t = new Thread(jvmti, env, thread);
0N/A err = jvmti->SetThreadLocalStorage(thread, (const void*)t);
0N/A check_jvmti_error(jvmti, err, "set thread local storage");
0N/A }
0N/A return t;
0N/A}
0N/A
0N/A/* Given a jvmtiEnv* and jobject, find the Monitor instance or create one */
0N/AMonitor *
0N/AAgent::get_monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object)
0N/A{
0N/A jvmtiError err;
0N/A Monitor *m;
1657N/A jlong tag;
0N/A
1657N/A m = NULL;
1657N/A tag = (jlong)0;
1657N/A err = jvmti->GetTag(object, &tag);
1657N/A check_jvmti_error(jvmti, err, "get tag");
1657N/A /*LINTED*/
1657N/A m = (Monitor *)(void *)(ptrdiff_t)tag;
1657N/A if ( m == NULL ) {
1657N/A m = new Monitor(jvmti, env, object);
1657N/A /* Save monitor on list */
1657N/A if (monitor_count == monitor_list_size) {
1657N/A monitor_list_size += monitor_list_grow_size;
1657N/A monitor_list = (Monitor**)realloc((void*)monitor_list,
1657N/A (monitor_list_size)*(int)sizeof(Monitor*));
1657N/A }
1657N/A monitor_list[monitor_count] = m;
1657N/A m->set_slot(monitor_count);
1657N/A monitor_count++;
0N/A /*LINTED*/
1657N/A tag = (jlong)(ptrdiff_t)(void *)m;
1657N/A err = jvmti->SetTag(object, tag);
1657N/A check_jvmti_error(jvmti, err, "set tag");
1657N/A }
0N/A return m;
0N/A}
0N/A
0N/A/* VM initialization and VM death calls to Agent */
0N/AAgent::Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
0N/A{
0N/A jvmtiError err;
0N/A
0N/A stdout_message("Agent created..\n");
0N/A stdout_message("VMInit...\n");
0N/A /* Start monitor list */
0N/A monitor_count = 0;
1657N/A monitor_list_size = initial_monitor_list_size;
1657N/A monitor_list = (Monitor**)
1657N/A malloc(monitor_list_size*(int)sizeof(Monitor*));
0N/A}
0N/A
0N/AAgent::~Agent()
0N/A{
0N/A stdout_message("Agent reclaimed..\n");
0N/A}
0N/A
0N/Avoid Agent::vm_death(jvmtiEnv *jvmti, JNIEnv *env)
0N/A{
0N/A jvmtiError err;
0N/A
0N/A /* Delete all Monitors we allocated */
0N/A for ( int i = 0; i < (int)monitor_count; i++ ) {
0N/A delete monitor_list[i];
0N/A }
0N/A free(monitor_list);
0N/A /* Print death message */
0N/A stdout_message("VMDeath...\n");
0N/A}
0N/A
0N/A/* Thread start event, setup a new thread */
0N/Avoid Agent::thread_start(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
0N/A{
0N/A jvmtiError err;
0N/A Thread *t;
0N/A
0N/A /* Allocate a new Thread instance, put it in the Thread Local
0N/A * Storage for easy access later.
0N/A */
0N/A t = new Thread(jvmti, env, thread);
0N/A err = jvmti->SetThreadLocalStorage(thread, (const void*)t);
0N/A check_jvmti_error(jvmti, err, "set thread local storage");
0N/A}
0N/A
0N/A
0N/A/* Thread end event, we need to reclaim the space */
0N/Avoid Agent::thread_end(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
0N/A{
0N/A jvmtiError err;
0N/A Thread *t;
0N/A
0N/A /* Find the thread */
0N/A t = get_thread(jvmti, env, thread);
0N/A
0N/A /* Clear out the Thread Local Storage */
0N/A err = jvmti->SetThreadLocalStorage(thread, (const void*)NULL);
0N/A check_jvmti_error(jvmti, err, "set thread local storage");
0N/A
0N/A /* Reclaim the C++ object space */
0N/A delete t;
0N/A}
0N/A
0N/A/* Monitor contention begins for a thread. */
0N/Avoid Agent::monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
0N/A jthread thread, jobject object)
0N/A{
0N/A get_monitor(jvmti, env, object)->contended();
0N/A get_thread(jvmti, env, thread)->
0N/A monitor_contended_enter(jvmti, env, thread, object);
0N/A}
0N/A
0N/A/* Monitor contention ends for a thread. */
0N/Avoid Agent::monitor_contended_entered(jvmtiEnv* jvmti, JNIEnv *env,
0N/A jthread thread, jobject object)
0N/A{
0N/A /* Do nothing for now */
0N/A}
0N/A
0N/A/* Monitor wait begins for a thread. */
0N/Avoid Agent::monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
0N/A jthread thread, jobject object, jlong timeout)
0N/A{
0N/A get_monitor(jvmti, env, object)->waited();
0N/A get_thread(jvmti, env, thread)->
0N/A monitor_wait(jvmti, env, thread, object, timeout);
0N/A}
0N/A
0N/A/* Monitor wait ends for a thread. */
0N/Avoid Agent::monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
0N/A jthread thread, jobject object, jboolean timed_out)
0N/A{
0N/A if ( timed_out ) {
0N/A get_monitor(jvmti, env, object)->timeout();
0N/A }
0N/A get_thread(jvmti, env, thread)->
0N/A monitor_waited(jvmti, env, thread, object, timed_out);
0N/A}
0N/A
0N/A/* A tagged object has been freed */
0N/Avoid Agent::object_free(jvmtiEnv* jvmti, jlong tag)
0N/A{
0N/A /* We just cast the tag to a C++ pointer and delete it.
0N/A * we know it can only be a Monitor *.
0N/A */
1657N/A Monitor *m;
0N/A /*LINTED*/
0N/A m = (Monitor *)(ptrdiff_t)tag;
1657N/A if (monitor_count > 1) {
1657N/A /* Move the last element to this Monitor's slot */
1657N/A int slot = m->get_slot();
1657N/A Monitor *last = monitor_list[monitor_count-1];
1657N/A monitor_list[slot] = last;
1657N/A last->set_slot(slot);
1657N/A }
1657N/A monitor_count--;
0N/A delete m;
0N/A}