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 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 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 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 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 }