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 #if defined _WIN32 && _MSC_VER >= 1900 94 void * test = (void *)(uintptr_t) 0x99999999; 95 #else 96 void * test = (void *) 0x99999999; 97 #endif 98 99 /* now check if we do a fetch we get what we wrote */ 100 error = (*jvmtienv)->GetThreadLocalStorage( 101 jvmtienv, 102 thread, 103 &test); 104 check_phase_ret(error); 105 jplis_assert(error == JVMTI_ERROR_NONE); 106 jplis_assert(test == expected); 107 } 108 109 jboolean 110 tryToAcquireReentrancyToken( jvmtiEnv * jvmtienv, 111 jthread thread) { 112 jboolean result = JNI_FALSE; 113 jvmtiError error = JVMTI_ERROR_NONE; 114 void * storedValue = NULL; 115 116 error = (*jvmtienv)->GetThreadLocalStorage( 117 jvmtienv, 118 thread, 119 &storedValue); 120 check_phase_ret_false(error); 121 jplis_assert(error == JVMTI_ERROR_NONE); 122 if ( error == JVMTI_ERROR_NONE ) { 123 /* if this thread is already inside, just return false and short-circuit */ 124 if ( storedValue == JPLIS_CURRENTLY_INSIDE_TOKEN ) { 125 result = JNI_FALSE; 126 } 127 else { 128 /* stuff in the sentinel and return true */ 129 #if JPLISASSERT_ENABLEASSERTIONS 130 assertTLSValue( jvmtienv, 131 thread, 132 JPLIS_CURRENTLY_OUTSIDE_TOKEN); 133 #endif 134 error = confirmingTLSSet ( jvmtienv, 135 thread, 136 JPLIS_CURRENTLY_INSIDE_TOKEN); 137 check_phase_ret_false(error); 138 jplis_assert(error == JVMTI_ERROR_NONE); 139 if ( error != JVMTI_ERROR_NONE ) { 140 result = JNI_FALSE; 141 } 142 else { 143 result = JNI_TRUE; 144 } 145 } 146 } 147 return result; 148 } 149 150 151 void 152 releaseReentrancyToken( jvmtiEnv * jvmtienv, 153 jthread thread) { 154 jvmtiError error = JVMTI_ERROR_NONE; 155 156 /* assert we hold the token */ 157 #if JPLISASSERT_ENABLEASSERTIONS 158 assertTLSValue( jvmtienv, 159 thread, 160 JPLIS_CURRENTLY_INSIDE_TOKEN); 161 #endif 162 163 error = confirmingTLSSet( jvmtienv, 164 thread, 165 JPLIS_CURRENTLY_OUTSIDE_TOKEN); 166 check_phase_ret(error); 167 jplis_assert(error == JVMTI_ERROR_NONE); 168 169 }