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