|
1 /* |
|
2 * Copyright (c) 2009 - 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Thread dump server of J9 VM in S60, |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <string> // Needed for strcmp |
|
20 |
|
21 #include "logger.h" |
|
22 #include "fileutilities.h" |
|
23 #include "exceptionbase.h" |
|
24 #include "javacommonutils.h" |
|
25 #include "javasymbianoslayer.h" |
|
26 |
|
27 #include "j9threaddumper.h" |
|
28 |
|
29 using namespace java::util; |
|
30 |
|
31 // ======== STATIC VARIABLES ======== |
|
32 |
|
33 OS_NONSHARABLE_CLASS(ThreadDumperGlobals) |
|
34 { |
|
35 public: |
|
36 ThreadDumperGlobals() : mDumper(0) |
|
37 { |
|
38 } |
|
39 |
|
40 public: |
|
41 J9ThreadDumper* mDumper; |
|
42 }; |
|
43 |
|
44 |
|
45 #if defined(__WINSCW__) |
|
46 |
|
47 #include <pls.h> |
|
48 ThreadDumperGlobals* getThreadDumperGlobals() |
|
49 { |
|
50 // Access the PLS of this process |
|
51 ThreadDumperGlobals* globals = |
|
52 Pls<ThreadDumperGlobals>(TUid::Uid(0x20022E77)); |
|
53 return globals; |
|
54 } |
|
55 |
|
56 #else |
|
57 |
|
58 static ThreadDumperGlobals* sGlobals = 0; |
|
59 |
|
60 ThreadDumperGlobals* getThreadDumperGlobals() |
|
61 { |
|
62 if (sGlobals == 0) |
|
63 { |
|
64 sGlobals = new ThreadDumperGlobals(); |
|
65 } |
|
66 return sGlobals; |
|
67 } |
|
68 #endif |
|
69 |
|
70 |
|
71 // Function prototypes |
|
72 void JNICALL agentThread(void* args); |
|
73 jint JNICALL JVM_OnLoad(JavaVM* vm, char* options, void* reserved); |
|
74 |
|
75 |
|
76 |
|
77 J9ThreadDumper::J9ThreadDumper(JavaVM* vm, DgRasInterface* jvmri) : |
|
78 mJavaVM(vm), mJNIEnv(0), mJvmriInterface(jvmri), |
|
79 mTask(NO_TASK), mState(CREATED) |
|
80 { |
|
81 JELOG2(EJavaRuntime); |
|
82 } |
|
83 |
|
84 J9ThreadDumper::~J9ThreadDumper() |
|
85 { |
|
86 JELOG2(EJavaRuntime); |
|
87 } |
|
88 |
|
89 |
|
90 void JNICALL agentThread(void* /*args*/) |
|
91 { |
|
92 #ifdef __SYMBIAN32__ |
|
93 RThread().SetPriority(EPriorityMore); |
|
94 #endif // __SYMBIAN32__ |
|
95 JELOG2(EJavaRuntime); |
|
96 getThreadDumperGlobals()->mDumper->doRun(); |
|
97 delete getThreadDumperGlobals()->mDumper; |
|
98 getThreadDumperGlobals()->mDumper = 0; |
|
99 #ifndef __WINSCW__ |
|
100 delete sGlobals; |
|
101 sGlobals = 0; |
|
102 #endif |
|
103 |
|
104 } |
|
105 |
|
106 void J9ThreadDumper::doDump() |
|
107 { |
|
108 JELOG2(EJavaRuntime); |
|
109 mTask = DO_DUMP; |
|
110 wakeUp(); |
|
111 } |
|
112 |
|
113 void J9ThreadDumper::close() |
|
114 { |
|
115 JELOG2(EJavaRuntime); |
|
116 mTask = CLOSE; |
|
117 wakeUp(); |
|
118 mState = CLOSED; |
|
119 } |
|
120 |
|
121 |
|
122 |
|
123 void J9ThreadDumper::moveGeneratedDumpFile() |
|
124 { |
|
125 #ifdef __SYMBIAN32__ |
|
126 JELOG2(EJavaRuntime); |
|
127 const wchar_t* const midpPrivateDataCage = L"c:\\private\\102033E6"; |
|
128 const wchar_t* const destRoot = L"c:\\logs\\java\\"; |
|
129 |
|
130 |
|
131 // Ensure that the target dir exists. |
|
132 std::wstring dest(destRoot); |
|
133 std::replace(dest.begin(), dest.end(), '\\', '/'); |
|
134 java::fileutils::FileUtilities::makeDirAll(dest); |
|
135 |
|
136 // Get all the files of the private data cage. |
|
137 std::list<std::wstring> dirList = java::fileutils::FileUtilities::getDirContentsList(midpPrivateDataCage); |
|
138 |
|
139 // Loop all existing files and try to find generated core dumps. |
|
140 std::list<std::wstring>::const_iterator it; |
|
141 for (it = dirList.begin(); it != dirList.end(); it++) |
|
142 { |
|
143 if (it->find(L"javacore.") == 0) |
|
144 { |
|
145 std::wstring oldName(midpPrivateDataCage); |
|
146 oldName += L"\\"; |
|
147 oldName += *it; |
|
148 std::wstring newName(destRoot); |
|
149 newName += *it; |
|
150 |
|
151 char* oldUtf8Name = JavaCommonUtils::wstringToUtf8(oldName); |
|
152 char* newUtf8Name = JavaCommonUtils::wstringToUtf8(newName); |
|
153 |
|
154 int error = rename(oldUtf8Name, newUtf8Name); |
|
155 delete[] oldUtf8Name; |
|
156 delete[] newUtf8Name; |
|
157 } |
|
158 } |
|
159 #endif // __SYMBIAN32__ |
|
160 } |
|
161 |
|
162 void J9ThreadDumper::wakeUp() |
|
163 { |
|
164 JELOG2(EJavaRuntime); |
|
165 if (mState == ACTIVE) |
|
166 { |
|
167 mMonitor->notify(); |
|
168 } |
|
169 } |
|
170 |
|
171 void J9ThreadDumper::doRun() |
|
172 { |
|
173 JELOG2(EJavaRuntime); |
|
174 if (mState != CREATED) |
|
175 { |
|
176 return; |
|
177 } |
|
178 |
|
179 int status = mJavaVM->AttachCurrentThreadAsDaemon((void**)&mJNIEnv, 0); |
|
180 if (status == 0) |
|
181 { |
|
182 mMonitor.reset(Monitor::createMonitor()); |
|
183 mState = ACTIVE; |
|
184 while (mState == ACTIVE) |
|
185 { |
|
186 mMonitor->wait(); |
|
187 switch (mTask) |
|
188 { |
|
189 case DO_DUMP: |
|
190 mJvmriInterface->GenerateJavacore(mJNIEnv); |
|
191 moveGeneratedDumpFile(); |
|
192 break; |
|
193 case CLOSE: |
|
194 mState = CLOSED; |
|
195 break; |
|
196 } |
|
197 mTask = NO_TASK; |
|
198 } |
|
199 mJavaVM->DetachCurrentThread(); |
|
200 } |
|
201 else |
|
202 { |
|
203 ELOG1(EUtils, "Thread dumper failed to attach to VM: %d", status); |
|
204 } |
|
205 } |
|
206 |
|
207 JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM* vm, char* options, void* /*reserved*/) |
|
208 { |
|
209 JELOG2(EJavaRuntime); |
|
210 int rc = -1; |
|
211 JNIEnv* env; |
|
212 |
|
213 try |
|
214 { |
|
215 // Get the JNIEnv for the current thread |
|
216 rc = vm->GetEnv((void **)&env, JNI_VERSION_1_2); |
|
217 if (rc != JNI_OK) |
|
218 { |
|
219 // No JNIEnv; fail |
|
220 return JNI_ERR; |
|
221 } |
|
222 |
|
223 // Get the RAS Interface |
|
224 DgRasInterface* jvmriInterface; |
|
225 rc = vm->GetEnv((void **)&jvmriInterface, JVMRAS_VERSION_1_3); |
|
226 if (rc != JNI_OK) |
|
227 { |
|
228 // No RAS Interface available; fail |
|
229 return JNI_ERR; |
|
230 } |
|
231 |
|
232 getThreadDumperGlobals()->mDumper = new J9ThreadDumper(vm, jvmriInterface); |
|
233 |
|
234 if (options != 0) |
|
235 { |
|
236 LOG1(EUtils, EInfo, "Dump options = %s", options); |
|
237 } |
|
238 // Request creation of the agent thread |
|
239 rc = jvmriInterface->CreateThread(env, agentThread,0 , 0); |
|
240 } |
|
241 |
|
242 catch (ExceptionBase& ex) |
|
243 { |
|
244 ELOG1(EJavaRuntime,"ERROR in Thread Dump. ExceptionBase: %s",ex.toString().c_str()); |
|
245 } |
|
246 catch (std::exception& e) |
|
247 { |
|
248 |
|
249 ELOG1(EJavaRuntime,"ERROR in Thread Dump. std::exception: %s",e.what()); |
|
250 } |
|
251 catch (...) |
|
252 { |
|
253 ELOG(EJavaRuntime,"ERROR in Thread Dump. Unexpected exception was caught"); |
|
254 } |
|
255 return rc; |
|
256 } |
|
257 |
|
258 // Keep this in sync with typedef in threaddumper.h file |
|
259 void doThreadDump() |
|
260 { |
|
261 JELOG2(EJavaRuntime); |
|
262 J9ThreadDumper* instance = getThreadDumperGlobals()->mDumper; |
|
263 if (instance) |
|
264 { |
|
265 instance->doDump(); |
|
266 } |
|
267 #ifndef __WINSCW__ |
|
268 else |
|
269 { |
|
270 delete sGlobals; |
|
271 sGlobals = 0; |
|
272 } |
|
273 #endif |
|
274 } |
|
275 |
|
276 // Keep this in sync with typedef in threaddumper.h file |
|
277 void closeThreadDump() |
|
278 { |
|
279 JELOG2(EJavaRuntime); |
|
280 J9ThreadDumper* instance = getThreadDumperGlobals()->mDumper; |
|
281 if (instance) |
|
282 { |
|
283 instance->close(); |
|
284 } |
|
285 #ifndef __WINSCW__ |
|
286 else |
|
287 { |
|
288 delete sGlobals; |
|
289 sGlobals = 0; |
|
290 } |
|
291 #endif |
|
292 } |
|
293 |
|
294 |
|
295 #ifdef __SYMBIAN32__ |
|
296 EXPORT_C FuncPtr JNICALL jni_lookup(const char* aName) |
|
297 { |
|
298 JELOG2(EJavaRuntime); |
|
299 if (!strcmp(aName, "JVM_OnLoad")) |
|
300 { |
|
301 return (FuncPtr)JVM_OnLoad; |
|
302 } |
|
303 |
|
304 else if (!strcmp(aName, "doThreadDump")) |
|
305 { |
|
306 return (FuncPtr)doThreadDump; |
|
307 } |
|
308 |
|
309 else if (!strcmp(aName, "closeThreadDump")) |
|
310 { |
|
311 return (FuncPtr)closeThreadDump; |
|
312 } |
|
313 |
|
314 return 0; |
|
315 } |
|
316 #endif // __SYMBIAN32__ |