|
1 /* |
|
2 * Copyright (c) 2009 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: This class is for thread death monitoring. |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <e32base.h> |
|
19 |
|
20 #include "osthreadsupervisor.h" |
|
21 |
|
22 #include "runtimeexception.h" |
|
23 |
|
24 #include "logger.h" |
|
25 #include "javacommonutils.h" |
|
26 |
|
27 using namespace java::runtime; |
|
28 using namespace java::util; |
|
29 |
|
30 |
|
31 OsThreadSupervisor::OsThreadSupervisor(bool tryThreadDumping) : |
|
32 mDoExit(false), mTryThreadDump(tryThreadDumping) |
|
33 { |
|
34 JELOG2(EJavaRuntime); |
|
35 startUndertakerThread(); |
|
36 } |
|
37 |
|
38 OsThreadSupervisor::~OsThreadSupervisor() |
|
39 { |
|
40 JELOG2(EJavaRuntime); |
|
41 // Wake the undertaker thread in order to close it. |
|
42 mDoExit = true; |
|
43 mRequestStatus = KRequestPending; |
|
44 TRequestStatus* requestStatus = &mRequestStatus; |
|
45 mSupervisorThread.RequestComplete(requestStatus, KErrNone); |
|
46 mSupervisorThread.Close(); |
|
47 } |
|
48 |
|
49 |
|
50 void OsThreadSupervisor::startUndertakerThread() |
|
51 { |
|
52 JELOG2(EJavaRuntime); |
|
53 RThread thread; |
|
54 |
|
55 // Create the undertaker thread. |
|
56 _LIT(KUndertakerName, "JavaMidp undertaker"); |
|
57 TInt err = thread.Create(KUndertakerName, |
|
58 OsThreadSupervisor::underTakerThreadMain, |
|
59 0x2000, 0, this); |
|
60 |
|
61 if (err == KErrNone) |
|
62 { |
|
63 // Set the prioroty to high. |
|
64 thread.SetPriority(EPriorityMuchMore); |
|
65 thread.Resume(); |
|
66 thread.Close(); |
|
67 } |
|
68 else |
|
69 { |
|
70 thread.Close(); |
|
71 std::string errorStr("Not able to create undertaker thread. Reason: "); |
|
72 errorStr.append(JavaCommonUtils::intToString(err)); |
|
73 throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__); |
|
74 } |
|
75 |
|
76 } |
|
77 |
|
78 int OsThreadSupervisor::underTakerThreadMain(void* starter) |
|
79 { |
|
80 JELOG2(EJavaRuntime); |
|
81 OsThreadSupervisor* supervisor = |
|
82 reinterpret_cast<OsThreadSupervisor*>(starter); |
|
83 |
|
84 // Open the thread handle so that RequstComplete methods can be |
|
85 // called from another thread. |
|
86 supervisor->mSupervisorThread.Open(RThread().Id()); |
|
87 |
|
88 RUndertaker underTaker; |
|
89 if (underTaker.Create() == KErrNone) |
|
90 { |
|
91 // Get the process id of this process. |
|
92 TProcessId processId = RProcess().Id(); |
|
93 int status = KErrNone; |
|
94 LOG1(EJavaRuntime, EInfo, "Starting to monitor MIDP process %lld", |
|
95 processId.Id()); |
|
96 // We will receive notification from ALL the thread deaths from all |
|
97 // processes. That is why the looping is needed. |
|
98 while (status == KErrNone) |
|
99 { |
|
100 int threadHandle; |
|
101 |
|
102 // Logon to monitor thread deaths. |
|
103 status = underTaker.Logon(supervisor->mRequestStatus, threadHandle); |
|
104 if (status != KErrNone) |
|
105 { |
|
106 ELOG1(EJavaRuntime, "Undertaker thread failed to do logon. " |
|
107 " Reason: %d", status); |
|
108 break; |
|
109 } |
|
110 |
|
111 // Start to wait thread deaths or shutdown indication. |
|
112 User::WaitForRequest(supervisor->mRequestStatus); |
|
113 if (supervisor->mDoExit) |
|
114 { |
|
115 // We are going down, so no need to monitor thread deaths. |
|
116 // Closing the undertaker thread. |
|
117 LOG(EJavaRuntime, EInfo, "Undertaker closed succesfully"); |
|
118 return 0; |
|
119 } |
|
120 RThread thread; |
|
121 thread.SetHandle(threadHandle); |
|
122 LOG2(EJavaRuntime, EInfo, "A thread %lld has died with exit type %d", |
|
123 thread.Id().Id(), thread.ExitType()); |
|
124 |
|
125 // We are only interested in panicing threads. |
|
126 if (thread.ExitType() == EExitPanic) |
|
127 { |
|
128 RProcess terminatedProcess; |
|
129 status = thread.Process(terminatedProcess); |
|
130 if (status == KErrNone) |
|
131 { |
|
132 LOG2(EJavaRuntime, EInfo, |
|
133 "Thread panic from process id: %lld. " |
|
134 "Our id is: %lld", |
|
135 terminatedProcess.Id().Id(), processId.Id()); |
|
136 // Check if this thread belong to our process. |
|
137 if (terminatedProcess.Id() == processId) |
|
138 { |
|
139 // One of MIDP threads has paniced, so lets terminate |
|
140 // the whole process. |
|
141 status = KErrDied; |
|
142 } |
|
143 terminatedProcess.Close(); |
|
144 } |
|
145 else |
|
146 { |
|
147 ELOG1(EJavaRuntime, "Solving paniced thread's process " |
|
148 "failed. Reason: %d", status); |
|
149 } |
|
150 } |
|
151 thread.Close(); |
|
152 } |
|
153 } |
|
154 ELOG(EJavaRuntime, "Panic in one of the MIDP threads. Stopping process!"); |
|
155 RProcess().Terminate(KErrAbort); |
|
156 return 0; |
|
157 } |
|
158 |