94 void CCommandWrapperBase::CmndRelease() |
88 void CCommandWrapperBase::CmndRelease() |
95 { |
89 { |
96 delete this; |
90 delete this; |
97 } |
91 } |
98 |
92 |
|
93 void CCommandWrapperBase::RunL() |
|
94 { |
|
95 // Optionally for use by subclasses |
|
96 } |
|
97 |
|
98 void CCommandWrapperBase::DoCancel() |
|
99 { |
|
100 // Optionally for use by subclasses |
|
101 } |
99 |
102 |
100 // |
103 // |
101 // CThreadCommand. |
104 // CThreadCommand. |
102 // |
105 // |
103 |
106 |
104 CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags) |
107 CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner) |
105 { |
108 { |
106 CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags); |
109 CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags, aTaskRunner); |
107 CleanupStack::PushL(self); |
110 CleanupStack::PushL(self); |
108 self->ConstructL(aName); |
111 self->ConstructL(aName); |
109 CleanupStack::Pop(self); |
112 CleanupStack::Pop(self); |
110 return self; |
113 return self; |
111 } |
114 } |
112 |
115 |
113 CThreadCommand::~CThreadCommand() |
116 CThreadCommand::~CThreadCommand() |
114 { |
117 { |
115 delete iWatcher; |
118 Cancel(); |
116 delete iArgs; |
119 delete iCommandLine; |
117 iThread.Close(); |
120 iThread.Close(); |
118 } |
121 } |
119 |
122 |
120 CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags) |
123 CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner) |
121 : iFlags(aFlags), iCommandConstructor(aCommandConstructor) |
124 : iFlags(aFlags), iCommandConstructor(aCommandConstructor), iTaskRunner(aTaskRunner) |
122 { |
125 { |
|
126 CActiveScheduler::Add(this); |
123 iThread.SetHandle(0); // By default RThread refers to the current thread. This results in fshell's thread exiting if this object gets killed before it has managed to open a real thread handle. |
127 iThread.SetHandle(0); // By default RThread refers to the current thread. This results in fshell's thread exiting if this object gets killed before it has managed to open a real thread handle. |
124 if (iFlags & EUpdateEnvironment) iFlags |= ESharedHeap; // Update environment implies a shared heap, ever since we did away with the explict SwitchAllocator |
128 if (iFlags & EUpdateEnvironment) iFlags |= ESharedHeap; // Update environment implies a shared heap, ever since we did away with the explict SwitchAllocator |
125 } |
129 } |
126 |
130 |
127 void CThreadCommand::ConstructL(const TDesC& aName) |
131 void CThreadCommand::ConstructL(const TDesC& aName) |
128 { |
132 { |
129 BaseConstructL(aName); |
133 BaseConstructL(aName); |
130 iWatcher = CThreadWatcher::NewL(); |
134 } |
131 } |
135 |
132 |
136 void CThreadCommand::DoCommandThreadStartL(TAny* aSelf) |
133 void CommandThreadStartL(CThreadCommand::TArgs& aArgs) |
137 { |
134 { |
138 CThreadCommand* self = static_cast<CThreadCommand*>(aSelf); |
135 if (aArgs.iFlags & CThreadCommand::ESharedHeap) |
|
136 { |
|
137 // If we're sharing the main fshell heap, we have to play by the rules and not crash |
|
138 User::SetCritical(User::EProcessCritical); |
|
139 } |
|
140 |
|
141 CActiveScheduler* scheduler = new(ELeave) CActiveScheduler; |
|
142 CleanupStack::PushL(scheduler); |
|
143 CActiveScheduler::Install(scheduler); |
|
144 |
|
145 HBufC* commandLine = aArgs.iCommandLine.AllocLC(); |
|
146 |
139 |
147 IoUtils::CEnvironment* env; |
140 IoUtils::CEnvironment* env; |
148 if (aArgs.iFlags & CThreadCommand::EUpdateEnvironment) |
141 if (self->iFlags & CThreadCommand::EUpdateEnvironment) |
149 { |
142 { |
150 env = aArgs.iEnv.CreateSharedEnvironmentL(); |
143 env = self->iSuppliedEnv->CreateSharedEnvironmentL(); |
151 } |
144 } |
152 else |
145 else |
153 { |
146 { |
154 // A straight-forward copy |
147 // A straight-forward copy |
155 env = IoUtils::CEnvironment::NewL(aArgs.iEnv); |
148 env = IoUtils::CEnvironment::NewL(*self->iSuppliedEnv); |
156 } |
149 } |
157 CleanupStack::PushL(env); |
150 CleanupStack::PushL(env); |
158 |
151 |
159 CCommandBase* command = (*aArgs.iCommandConstructor)(); |
152 CCommandBase* command = (*self->iCommandConstructor)(); |
160 RThread parentThread; |
153 //RDebug::Print(_L("5. DoCommandThreadStartL rendezvousing for %S %S"), &self->CmndName(), self->iCommandLine); |
161 User::LeaveIfError(parentThread.Open(aArgs.iParentThreadId)); |
154 RThread::Rendezvous(KErrNone); |
162 parentThread.RequestComplete(aArgs.iParentStatus, KErrNone); |
155 command->RunCommandL(self->iCommandLine, env); |
163 parentThread.Close(); |
156 CleanupStack::PopAndDestroy(2, env); // command, env |
164 |
157 } |
165 command->RunCommandL(commandLine, env); |
158 |
166 CleanupStack::PopAndDestroy(4, scheduler); // env, command, commandline, scheduler |
|
167 } |
|
168 |
|
169 TInt CommandThreadStart(TAny* aPtr) |
|
170 { |
|
171 CThreadCommand::TArgs args = *(CThreadCommand::TArgs*)aPtr; |
|
172 TBool sharedHeap = (args.iFlags & CThreadCommand::ESharedHeap); |
|
173 if (!sharedHeap) |
|
174 { |
|
175 __UHEAP_MARK; |
|
176 } |
|
177 TInt err = KErrNoMemory; |
|
178 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
179 if (cleanup) |
|
180 { |
|
181 TRAP(err, CommandThreadStartL(args)); |
|
182 delete cleanup; |
|
183 } |
|
184 if (!sharedHeap) |
|
185 { |
|
186 __UHEAP_MARKEND; |
|
187 } |
|
188 return err; |
|
189 } |
|
190 |
159 |
191 void SetHandleOwnersL(TThreadId aThreadId, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr) |
160 void SetHandleOwnersL(TThreadId aThreadId, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr) |
192 { |
161 { |
193 User::LeaveIfError(aStdin.SetOwner(aThreadId)); |
162 User::LeaveIfError(aStdin.SetOwner(aThreadId)); |
194 User::LeaveIfError(aStdout.SetOwner(aThreadId)); |
163 User::LeaveIfError(aStdout.SetOwner(aThreadId)); |
197 |
166 |
198 TInt CThreadCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession&) |
167 TInt CThreadCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession&) |
199 { |
168 { |
200 ASSERT(iObserver == NULL); |
169 ASSERT(iObserver == NULL); |
201 |
170 |
202 TRequestStatus status(KRequestPending); |
171 MThreadedTask* thread = NULL; |
203 iArgs = new TArgs(iFlags, aEnv, iCommandConstructor, aCommandLine, status); |
172 TRAPD(err, thread = iTaskRunner->NewTaskInSeparateThreadL(CmndName(), iFlags & ESharedHeap, &DoCommandThreadStartL, this)); |
204 if (iArgs == NULL) |
173 if (err) return err; |
205 { |
174 |
206 return KErrNoMemory; |
175 TRAP(err, SetHandleOwnersL(thread->GetThreadId(), CmndStdin(), CmndStdout(), CmndStderr())); |
207 } |
176 |
208 |
177 if (!err) |
209 TInt i = 0; |
178 { |
210 TName threadName; |
179 iCommandLine = aCommandLine.Alloc(); |
211 TInt err = KErrNone; |
180 if (!iCommandLine) err = KErrNoMemory; |
212 do |
181 } |
213 { |
182 |
214 const TDesC& name = CmndName(); |
183 if (!err) |
215 threadName.Format(_L("%S_%02d"), &name, i++); |
184 { |
216 if (iFlags & ESharedHeap) |
185 err = iThread.Open(thread->GetThreadId()); |
217 { |
186 } |
218 err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, NULL, iArgs); |
187 |
219 } |
188 if (!err) |
220 else |
189 { |
221 { |
190 iSuppliedEnv = &aEnv; |
222 err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, iArgs); |
191 iObserver = &aObserver; |
223 } |
192 thread->ExecuteTask(iStatus); |
224 } |
193 SetActive(); |
225 while (err == KErrAlreadyExists); |
194 } |
226 |
195 else |
227 if (err) |
196 { |
228 { |
197 thread->AbortTask(); |
229 return err; |
198 } |
230 } |
199 |
231 |
200 return err; |
232 err = iWatcher->Logon(*this, iThread, aObserver); |
|
233 if (err) |
|
234 { |
|
235 iThread.Kill(0); |
|
236 iThread.Close(); |
|
237 return err; |
|
238 } |
|
239 |
|
240 TThreadId threadId = iThread.Id(); |
|
241 TRAP(err, SetHandleOwnersL(threadId, CmndStdin(), CmndStdout(), CmndStderr())); |
|
242 if (err) |
|
243 { |
|
244 iThread.Kill(0); |
|
245 iThread.Close(); |
|
246 return err; |
|
247 } |
|
248 |
|
249 iThread.Resume(); |
|
250 User::WaitForRequest(status, iWatcher->iStatus); |
|
251 if (status == KRequestPending) |
|
252 { |
|
253 iThread.Close(); |
|
254 return iWatcher->iStatus.Int(); |
|
255 } |
|
256 |
|
257 iWatcher->SetActive(); |
|
258 iObserver = &aObserver; |
|
259 return KErrNone; |
|
260 } |
201 } |
261 |
202 |
262 void CThreadCommand::CmndForeground() |
203 void CThreadCommand::CmndForeground() |
263 { |
204 { |
264 iThread.SetPriority(EPriorityAbsoluteForeground); |
205 iThread.SetPriority(EPriorityAbsoluteForeground); |
298 TExitCategoryName CThreadCommand::CmndExitCategory() const |
239 TExitCategoryName CThreadCommand::CmndExitCategory() const |
299 { |
240 { |
300 return iThread.ExitCategory(); |
241 return iThread.ExitCategory(); |
301 } |
242 } |
302 |
243 |
303 |
244 void CThreadCommand::RunL() |
304 // |
245 { |
305 // CThreadCommand::TArgs. |
246 iObserver->HandleCommandComplete(*this, iStatus.Int()); |
306 // |
247 } |
307 |
248 |
308 CThreadCommand::TArgs::TArgs(TUint aFlags, IoUtils::CEnvironment& aEnv, TCommandConstructor aCommandConstructor, const TDesC& aCommandLine, TRequestStatus& aParentStatus) |
249 void CThreadCommand::DoCancel() |
309 : iFlags(aFlags), iEnv(aEnv), iCommandConstructor(aCommandConstructor), iCommandLine(aCommandLine), iParentStatus(&aParentStatus), iParentThreadId(RThread().Id()) |
250 { |
310 { |
251 CmndKill(); // This is a bit drastic, but effective... |
311 } |
|
312 |
|
313 |
|
314 // |
|
315 // CThreadCommand::CThreadWatcher. |
|
316 // |
|
317 |
|
318 CThreadCommand::CThreadWatcher* CThreadCommand::CThreadWatcher::NewL() |
|
319 { |
|
320 return new(ELeave) CThreadWatcher(); |
|
321 } |
|
322 |
|
323 CThreadCommand::CThreadWatcher::~CThreadWatcher() |
|
324 { |
|
325 Cancel(); |
|
326 } |
|
327 |
|
328 CThreadCommand::CThreadWatcher::CThreadWatcher() |
|
329 : CActive(CActive::EPriorityStandard) |
|
330 { |
|
331 CActiveScheduler::Add(this); |
|
332 } |
|
333 |
|
334 TInt CThreadCommand::CThreadWatcher::Logon(CThreadCommand& aCommand, RThread& aThread, MCommandObserver& aObserver) |
|
335 { |
|
336 TInt ret = KErrNone; |
|
337 aThread.Logon(iStatus); |
|
338 if (iStatus != KRequestPending) |
|
339 { |
|
340 User::WaitForRequest(iStatus); |
|
341 ret = iStatus.Int(); |
|
342 } |
|
343 else |
|
344 { |
|
345 iCommand = &aCommand; |
|
346 iThread = &aThread; |
|
347 iObserver = &aObserver; |
|
348 } |
|
349 return ret; |
|
350 } |
|
351 |
|
352 void CThreadCommand::CThreadWatcher::SetActive() |
|
353 { |
|
354 CActive::SetActive(); |
|
355 } |
|
356 |
|
357 void CThreadCommand::CThreadWatcher::RunL() |
|
358 { |
|
359 iObserver->HandleCommandComplete(*iCommand, iStatus.Int()); |
|
360 } |
|
361 |
|
362 void CThreadCommand::CThreadWatcher::DoCancel() |
|
363 { |
|
364 if (iThread) |
|
365 { |
|
366 iThread->LogonCancel(iStatus); |
|
367 } |
|
368 } |
252 } |
369 |
253 |
370 |
254 |
371 // |
255 // |
372 // CProcessCommand. |
256 // CProcessCommand. |