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