1 /*
2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /*
27 * Copyright 2003 Wily Technology, Inc.
28 */
29
30 #include <jni.h>
31 #include <jvmti.h>
32
33 #include "JPLISAssert.h"
34 #include "Reentrancy.h"
35 #include "JPLISAgent.h"
36
37 /*
38 * This module provides some utility functions to support the "same thread" re-entrancy management.
39 * Uses JVMTI TLS to store a single bit per thread.
40 * Non-zero means the thread is already inside; zero means the thread is not inside.
41 */
42
43 /*
44 * Local prototypes
45 */
46
47 /* Wrapper around set that does the set then re-fetches to make sure it worked.
48 * Degenerates to a simple set when assertions are disabled.
49 * This routine is only here because of a bug in the JVMTI where set to 0 fails.
50 */
51 jvmtiError
52 confirmingTLSSet( jvmtiEnv * jvmtienv,
53 jthread thread,
54 const void * newValue);
55
56 /* Confirmation routine only; used to assure that the TLS slot holds the value we expect it to. */
57 void
58 assertTLSValue( jvmtiEnv * jvmtienv,
59 jthread thread,
60 const void * expected);
61
62
63 #define JPLIS_CURRENTLY_INSIDE_TOKEN ((void *) 0x7EFFC0BB)
64 #define JPLIS_CURRENTLY_OUTSIDE_TOKEN ((void *) 0)
65
66
67 jvmtiError
confirmingTLSSet(jvmtiEnv * jvmtienv,jthread thread,const void * newValue)68 confirmingTLSSet( jvmtiEnv * jvmtienv,
69 jthread thread,
70 const void * newValue) {
71 jvmtiError error;
72
73 error = (*jvmtienv)->SetThreadLocalStorage(
74 jvmtienv,
75 thread,
76 newValue);
77 check_phase_ret_blob(error, error);
78
79 #if JPLISASSERT_ENABLEASSERTIONS
80 assertTLSValue( jvmtienv,
81 thread,
82 newValue);
83 #endif
84
85 return error;
86 }
87
88 void
assertTLSValue(jvmtiEnv * jvmtienv,jthread thread,const void * expected)89 assertTLSValue( jvmtiEnv * jvmtienv,
90 jthread thread,
91 const void * expected) {
92 jvmtiError error;
93 void * test = (void *) 0x99999999;
94
95 /* now check if we do a fetch we get what we wrote */
96 error = (*jvmtienv)->GetThreadLocalStorage(
97 jvmtienv,
98 thread,
99 &test);
100 check_phase_ret(error);
101 jplis_assert(error == JVMTI_ERROR_NONE);
102 jplis_assert(test == expected);
103 }
104
105 jboolean
tryToAcquireReentrancyToken(jvmtiEnv * jvmtienv,jthread thread)106 tryToAcquireReentrancyToken( jvmtiEnv * jvmtienv,
107 jthread thread) {
108 jboolean result = JNI_FALSE;
109 jvmtiError error = JVMTI_ERROR_NONE;
110 void * storedValue = NULL;
111
112 error = (*jvmtienv)->GetThreadLocalStorage(
113 jvmtienv,
114 thread,
115 &storedValue);
116 check_phase_ret_false(error);
117 jplis_assert(error == JVMTI_ERROR_NONE);
118 if ( error == JVMTI_ERROR_NONE ) {
119 /* if this thread is already inside, just return false and short-circuit */
120 if ( storedValue == JPLIS_CURRENTLY_INSIDE_TOKEN ) {
121 result = JNI_FALSE;
122 }
123 else {
124 /* stuff in the sentinel and return true */
125 #if JPLISASSERT_ENABLEASSERTIONS
126 assertTLSValue( jvmtienv,
127 thread,
128 JPLIS_CURRENTLY_OUTSIDE_TOKEN);
129 #endif
130 error = confirmingTLSSet ( jvmtienv,
131 thread,
132 JPLIS_CURRENTLY_INSIDE_TOKEN);
133 check_phase_ret_false(error);
134 jplis_assert(error == JVMTI_ERROR_NONE);
135 if ( error != JVMTI_ERROR_NONE ) {
136 result = JNI_FALSE;
137 }
138 else {
139 result = JNI_TRUE;
140 }
141 }
142 }
143 return result;
144 }
145
146
147 void
releaseReentrancyToken(jvmtiEnv * jvmtienv,jthread thread)148 releaseReentrancyToken( jvmtiEnv * jvmtienv,
149 jthread thread) {
150 jvmtiError error = JVMTI_ERROR_NONE;
151
152 /* assert we hold the token */
153 #if JPLISASSERT_ENABLEASSERTIONS
154 assertTLSValue( jvmtienv,
155 thread,
156 JPLIS_CURRENTLY_INSIDE_TOKEN);
157 #endif
158
159 error = confirmingTLSSet( jvmtienv,
160 thread,
161 JPLIS_CURRENTLY_OUTSIDE_TOKEN);
162 check_phase_ret(error);
163 jplis_assert(error == JVMTI_ERROR_NONE);
164
165 }
166