1 /*
2  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stddef.h>
45 
46 #include "jni.h"
47 #include "jvmti.h"
48 
49 #include "agent_util.h"
50 
51 #include "Monitor.hpp"
52 #include "Thread.hpp"
53 #include "Agent.hpp"
54 
55 /* Implementation of the Agent class */
56 
57 /* Given a jvmtiEnv* and jthread, find the Thread instance */
58 Thread *
get_thread(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)59 Agent::get_thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
60 {
61     jvmtiError err;
62     Thread    *t;
63 
64     /* This should always be in the Thread Local Storage */
65     t = NULL;
66     err = jvmti->GetThreadLocalStorage(thread, (void**)&t);
67     check_jvmti_error(jvmti, err, "get thread local storage");
68     if ( t == NULL ) {
69         /* This jthread has never been seen before? */
70         stdout_message("WARNING: Never before seen jthread?\n");
71         t = new Thread(jvmti, env, thread);
72         err = jvmti->SetThreadLocalStorage(thread, (const void*)t);
73         check_jvmti_error(jvmti, err, "set thread local storage");
74     }
75     return t;
76 }
77 
78 /* Given a jvmtiEnv* and jobject, find the Monitor instance or create one */
79 Monitor *
get_monitor(jvmtiEnv * jvmti,JNIEnv * env,jobject object)80 Agent::get_monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object)
81 {
82     jvmtiError err;
83     Monitor   *m;
84     jlong      tag;
85 
86     m   = NULL;
87     tag = (jlong)0;
88     err = jvmti->GetTag(object, &tag);
89     check_jvmti_error(jvmti, err, "get tag");
90     /*LINTED*/
91     m = (Monitor *)(void *)(ptrdiff_t)tag;
92     if ( m == NULL ) {
93         m = new Monitor(jvmti, env, object);
94         /* Save monitor on list */
95         if (monitor_count == monitor_list_size) {
96             monitor_list_size += monitor_list_grow_size;
97             monitor_list = (Monitor**)realloc((void*)monitor_list,
98                 (monitor_list_size)*(int)sizeof(Monitor*));
99         }
100         monitor_list[monitor_count] = m;
101         m->set_slot(monitor_count);
102         monitor_count++;
103         /*LINTED*/
104         tag = (jlong)(ptrdiff_t)(void *)m;
105         err = jvmti->SetTag(object, tag);
106         check_jvmti_error(jvmti, err, "set tag");
107     }
108     return m;
109 }
110 
111 /* VM initialization and VM death calls to Agent */
Agent(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)112 Agent::Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
113 {
114     jvmtiError err;
115 
116     stdout_message("Agent created..\n");
117     stdout_message("VMInit...\n");
118     /* Start monitor list */
119     monitor_count = 0;
120     monitor_list_size = initial_monitor_list_size;
121     monitor_list = (Monitor**)
122         malloc(monitor_list_size*(int)sizeof(Monitor*));
123 }
124 
~Agent()125 Agent::~Agent()
126 {
127     stdout_message("Agent reclaimed..\n");
128 }
129 
vm_death(jvmtiEnv * jvmti,JNIEnv * env)130 void Agent::vm_death(jvmtiEnv *jvmti, JNIEnv *env)
131 {
132     jvmtiError err;
133 
134     /* Delete all Monitors we allocated */
135     for ( int i = 0; i < (int)monitor_count; i++ ) {
136         delete monitor_list[i];
137     }
138     free(monitor_list);
139     /* Print death message */
140     stdout_message("VMDeath...\n");
141 }
142 
143 /* Thread start event, setup a new thread */
thread_start(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)144 void Agent::thread_start(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
145 {
146     jvmtiError err;
147     Thread    *t;
148 
149     /* Allocate a new Thread instance, put it in the Thread Local
150      *    Storage for easy access later.
151      */
152     t = new Thread(jvmti, env, thread);
153     err = jvmti->SetThreadLocalStorage(thread, (const void*)t);
154     check_jvmti_error(jvmti, err, "set thread local storage");
155 }
156 
157 
158 /* Thread end event, we need to reclaim the space */
thread_end(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)159 void Agent::thread_end(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
160 {
161     jvmtiError err;
162     Thread    *t;
163 
164     /* Find the thread */
165     t = get_thread(jvmti, env, thread);
166 
167     /* Clear out the Thread Local Storage */
168     err = jvmti->SetThreadLocalStorage(thread, (const void*)NULL);
169     check_jvmti_error(jvmti, err, "set thread local storage");
170 
171     /* Reclaim the C++ object space */
172     delete t;
173 }
174 
175 /* Monitor contention begins for a thread. */
monitor_contended_enter(jvmtiEnv * jvmti,JNIEnv * env,jthread thread,jobject object)176 void Agent::monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
177              jthread thread, jobject object)
178 {
179     get_monitor(jvmti, env, object)->contended();
180     get_thread(jvmti, env, thread)->
181                 monitor_contended_enter(jvmti, env, thread, object);
182 }
183 
184 /* Monitor contention ends for a thread. */
monitor_contended_entered(jvmtiEnv * jvmti,JNIEnv * env,jthread thread,jobject object)185 void Agent::monitor_contended_entered(jvmtiEnv* jvmti, JNIEnv *env,
186                jthread thread, jobject object)
187 {
188     /* Do nothing for now */
189 }
190 
191 /* Monitor wait begins for a thread. */
monitor_wait(jvmtiEnv * jvmti,JNIEnv * env,jthread thread,jobject object,jlong timeout)192 void Agent::monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
193              jthread thread, jobject object, jlong timeout)
194 {
195     get_monitor(jvmti, env, object)->waited();
196     get_thread(jvmti, env, thread)->
197                 monitor_wait(jvmti, env, thread, object, timeout);
198 }
199 
200 /* Monitor wait ends for a thread. */
monitor_waited(jvmtiEnv * jvmti,JNIEnv * env,jthread thread,jobject object,jboolean timed_out)201 void Agent::monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
202                jthread thread, jobject object, jboolean timed_out)
203 {
204     if ( timed_out ) {
205         get_monitor(jvmti, env, object)->timeout();
206     }
207     get_thread(jvmti, env, thread)->
208                 monitor_waited(jvmti, env, thread, object, timed_out);
209 }
210 
211 /* A tagged object has been freed */
object_free(jvmtiEnv * jvmti,jlong tag)212 void Agent::object_free(jvmtiEnv* jvmti, jlong tag)
213 {
214     /* We just cast the tag to a C++ pointer and delete it.
215      *   we know it can only be a Monitor *.
216      */
217     Monitor   *m;
218     /*LINTED*/
219     m = (Monitor *)(ptrdiff_t)tag;
220     if (monitor_count > 1) {
221         /* Move the last element to this Monitor's slot */
222         int slot = m->get_slot();
223         Monitor *last = monitor_list[monitor_count-1];
224         monitor_list[slot] = last;
225         last->set_slot(slot);
226     }
227     monitor_count--;
228     delete m;
229 }
230