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 */
51jvmtiError
52confirmingTLSSet( 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. */
57void
58assertTLSValue( 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
67jvmtiError
68confirmingTLSSet( 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
88void
89assertTLSValue( jvmtiEnv * jvmtienv,
90 jthread thread,
91 const void * expected) {
92 jvmtiError error;
93 void * test = (void *) 0x99999999ULL;
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
105jboolean
106tryToAcquireReentrancyToken( 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
147void
148releaseReentrancyToken( 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