|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 |
|
17 #include <kernel/kern_priv.h> |
|
18 #include "dpipe.h" |
|
19 |
|
20 //_LIT(KPipePanicCategory,"PipePanic"); |
|
21 const TInt KPipeGranularity = 8; |
|
22 |
|
23 DECLARE_STANDARD_LDD() |
|
24 /** |
|
25 Standard export function for LDDs. This creates a DLogicalDevice derived |
|
26 object, in this case our DPipeDevice |
|
27 */ |
|
28 { |
|
29 return new DPipeDevice; |
|
30 } |
|
31 |
|
32 DPipeDevice::DPipeDevice() |
|
33 /** |
|
34 DPipeDevice Constructor has minimal implementation such setting the version number |
|
35 Indicate the use of unit number |
|
36 |
|
37 @param None |
|
38 |
|
39 @return None |
|
40 */ |
|
41 { |
|
42 iCount = 0; |
|
43 iIdindex = 0; |
|
44 iAllocated = 0; |
|
45 iVersion = RPipe::VersionRequired(); |
|
46 } |
|
47 |
|
48 |
|
49 DPipeDevice::~DPipeDevice() |
|
50 { |
|
51 // Delete the existing pipes |
|
52 for(TInt count = 0; count<iCount; count++) |
|
53 { |
|
54 DPipe* pipe=iDpipes[count]; |
|
55 pipe->Wait(); |
|
56 pipe->CloseAll(); |
|
57 delete pipe; |
|
58 } |
|
59 Kern::Free(iDpipes); |
|
60 iMutex->Close(NULL); |
|
61 } |
|
62 |
|
63 |
|
64 TInt DPipeDevice::Install() |
|
65 /** |
|
66 Second stage constructor and at least set a name for the |
|
67 driver object. Inherited from DLogicalDevice. This must at least set a name |
|
68 for the driver object. |
|
69 |
|
70 @param None |
|
71 |
|
72 @return KErrNone If successful, otherwise one of the system wide error codes. |
|
73 */ |
|
74 { |
|
75 _LIT(KMutexName,"PipeDeviceMutex"); |
|
76 TInt err = Kern::MutexCreate(iMutex, KMutexName, KMutexOrdGeneral1); |
|
77 if (err) |
|
78 { |
|
79 return err; |
|
80 } |
|
81 |
|
82 return SetName(&RPipe::Name()); |
|
83 } |
|
84 |
|
85 |
|
86 void DPipeDevice::GetCaps(TDes8& aDes) const |
|
87 /** |
|
88 Returns the driver capabilities. Called in the response to |
|
89 an RPipe::GetCaps() request |
|
90 |
|
91 @param aDes Descriptor into which capabilities information |
|
92 is to be written |
|
93 @return None |
|
94 */ |
|
95 { |
|
96 // Write it back to user memory |
|
97 TVersion version; |
|
98 version = iVersion; |
|
99 Kern::InfoCopy(aDes,(TUint8*)&version, sizeof(version)); |
|
100 } |
|
101 |
|
102 |
|
103 TInt DPipeDevice::Create(DLogicalChannelBase*& aChannel) |
|
104 /** |
|
105 Called by the kernel's device driver framework to create a Logical Channel. |
|
106 This is called in the context of the user thread (client) which requested the |
|
107 creation of the Logical Channel. |
|
108 |
|
109 @param aChannel Set to point to the created logical channel |
|
110 |
|
111 @return KErrNone If successful, otherwise system one of the other |
|
112 wide error codes. |
|
113 */ |
|
114 { |
|
115 aChannel = new DPipeChannel; |
|
116 if (!aChannel) |
|
117 return KErrNoMemory; |
|
118 return KErrNone; |
|
119 } |
|
120 |
|
121 |
|
122 TInt DPipeDevice::CreatePipe(const TDesC& aName, TInt aSize, DPipe*& aPipe, TAny* aCap) |
|
123 /** |
|
124 Called by DPipeChannel instance to create named DPipe object and |
|
125 associate itself with the newly created named DPipe instance. |
|
126 |
|
127 @param aName name need to be attached to the newly created DPipe object. |
|
128 @param aSize size of the DPipe object. |
|
129 @param aPipe Pointer to DPipe, If successful set the pointer to newly created DPipe instance else NULL |
|
130 @param aCap Pointer to TSecuritypolicy passed as void pointer |
|
131 |
|
132 @return KErrNone If successful, otherwise one of the other system wide error code |
|
133 @pre Calling thread must be in a critical section. |
|
134 @pre Mutex must be held |
|
135 */ |
|
136 { |
|
137 __ASSERT_MUTEX(iMutex); |
|
138 __KTRACE_OPT(KPIPE, Kern::Printf(">DPipeDevice::CreatePipe")); |
|
139 TInt err = KErrNone; |
|
140 DPipe** pS = iDpipes; |
|
141 DPipe** pE = pS + iCount; |
|
142 while(pS < pE) |
|
143 { |
|
144 DPipe* pO = *pS++; |
|
145 if((pO->MatchName(&aName))) |
|
146 { |
|
147 err = KErrAlreadyExists; |
|
148 break; |
|
149 } |
|
150 } |
|
151 if(err == KErrNone) |
|
152 { |
|
153 DPipe* pipe = DPipe::CreatePipe(aName, aSize, aCap); |
|
154 if(pipe) |
|
155 { |
|
156 err = AddPipe(pipe); |
|
157 if(err!= KErrNone) |
|
158 { |
|
159 delete pipe; |
|
160 } |
|
161 else |
|
162 { |
|
163 aPipe = pipe; |
|
164 } |
|
165 } |
|
166 else |
|
167 { |
|
168 err = KErrNoMemory; |
|
169 } |
|
170 } |
|
171 __KTRACE_OPT(KPIPE, Kern::Printf("<DPipeDevice::CreatePipe ret=%d", err)); |
|
172 return err; |
|
173 } |
|
174 |
|
175 |
|
176 DPipe* DPipeDevice::CreatePipe(TInt aSize) |
|
177 /** |
|
178 Called by DPipeChannel instance to create un-named DPipe instance and |
|
179 associate itself with the newly created un-named DPipe instance. |
|
180 |
|
181 @param aSize size of the DPipe object. |
|
182 |
|
183 @return DPipe* If successful, otherwise NULL |
|
184 @pre Mutex must be held |
|
185 @pre In critical section |
|
186 */ |
|
187 { |
|
188 __ASSERT_CRITICAL; |
|
189 __ASSERT_MUTEX(iMutex); |
|
190 TKName aName; |
|
191 DPipe* pipe = DPipe::CreatePipe(aName, aSize); |
|
192 if(!pipe) |
|
193 { |
|
194 return NULL; |
|
195 } |
|
196 |
|
197 TInt r = AddPipe(pipe); |
|
198 if (r != KErrNone) |
|
199 { |
|
200 delete pipe; |
|
201 return NULL; |
|
202 } |
|
203 return pipe; |
|
204 } |
|
205 |
|
206 |
|
207 |
|
208 TInt DPipeDevice::AddPipe(DPipe* aObj) |
|
209 /** |
|
210 Add an instance of Dpipe to the array. |
|
211 @param aObj Pointer to DPipe object |
|
212 @return KErrNone If the call is successful otherwise one of the other |
|
213 system wide error code. |
|
214 |
|
215 @pre Calling thread must be in a critical section. |
|
216 @pre Mutex to be held |
|
217 */ |
|
218 { |
|
219 __ASSERT_CRITICAL; //otherwise iDPipes and iCount could go out of sync |
|
220 __ASSERT_MUTEX(iMutex); |
|
221 // store the current instance to the array |
|
222 if(iCount == iAllocated) |
|
223 { |
|
224 TInt newAlloc = iAllocated + KPipeGranularity; |
|
225 TInt r = Kern::SafeReAlloc((TAny*&)iDpipes, iCount * sizeof(DPipe*), newAlloc * sizeof(DPipe*)); |
|
226 if (r!= KErrNone) |
|
227 { |
|
228 return r; |
|
229 } |
|
230 iAllocated = newAlloc; |
|
231 } |
|
232 TInt id = GenerateId(); |
|
233 aObj->SetId(id); |
|
234 iDpipes[iCount++]= aObj; |
|
235 |
|
236 __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::AddPipe Pipe added ID=%d", id)); |
|
237 return KErrNone; |
|
238 } |
|
239 |
|
240 |
|
241 |
|
242 void DPipeDevice::RemovePipe(DPipe** aObj) |
|
243 /** |
|
244 Remove an instance of DPipe from the array |
|
245 |
|
246 @param Pointer to Dpipe Array |
|
247 |
|
248 @return None |
|
249 |
|
250 @pre Calling thread must not be in a critical section. |
|
251 @pre Mutex to be held |
|
252 */ |
|
253 { |
|
254 __ASSERT_MUTEX(iMutex); |
|
255 __ASSERT_CRITICAL; //we don't want to leave the array inconsistant |
|
256 |
|
257 DPipe** pE = (iDpipes + iCount) - 1; |
|
258 if(aObj<pE) |
|
259 { |
|
260 //bump along array elements to close the gap |
|
261 wordmove((TAny*)aObj, (TAny*)(aObj+1), TInt(pE)- TInt(aObj)); |
|
262 } |
|
263 --iCount; |
|
264 if(iCount % KPipeGranularity == 0) |
|
265 { |
|
266 Kern::SafeReAlloc((TAny*&)iDpipes, iAllocated*sizeof(DPipe*), iCount* sizeof(DPipe*)); |
|
267 iAllocated = iCount; |
|
268 } |
|
269 } |
|
270 |
|
271 |
|
272 DPipe* DPipeDevice::FindNamedPipe(const TDesC* aName) |
|
273 /** |
|
274 Called by the DPipeChannel to check if a named DPipe instance exist with a name |
|
275 as specified by aName parameter. |
|
276 |
|
277 @param aName The name of the DPipe instance to search for. |
|
278 |
|
279 @return DPipe* If successful, otherwise NULL |
|
280 |
|
281 @pre Device mutex to be held |
|
282 */ |
|
283 { |
|
284 __ASSERT_MUTEX(iMutex); |
|
285 DPipe** pS = iDpipes; |
|
286 DPipe** pE = pS + iCount; |
|
287 |
|
288 while(pS < pE) |
|
289 { |
|
290 DPipe* pO = *pS++; |
|
291 if(pO->MatchName(aName)) |
|
292 { |
|
293 return pO; |
|
294 } |
|
295 } |
|
296 return NULL; |
|
297 } |
|
298 |
|
299 DPipe* DPipeDevice::FindUnnamedPipe(const TInt aId) |
|
300 /** |
|
301 Called by the DPipeChannel to check if an un-named DPipe instance exist with an ID |
|
302 as specified by aId parameter. |
|
303 |
|
304 @param aId The ID of the DPipe instance to search for. |
|
305 |
|
306 @return DPipe* If successful, otherwise NULL |
|
307 @pre Device mutex to be held |
|
308 */ |
|
309 { |
|
310 __ASSERT_MUTEX(iMutex); |
|
311 DPipe** pS = iDpipes; |
|
312 DPipe** pE = pS + iCount; |
|
313 while(pS < pE) |
|
314 { |
|
315 DPipe* pO = *pS++; |
|
316 if(pO->MatchId(aId)) |
|
317 { |
|
318 return pO; |
|
319 } |
|
320 } |
|
321 return NULL; |
|
322 } |
|
323 |
|
324 TInt DPipeDevice::Destroy(const TDesC* aName) |
|
325 /** |
|
326 This method is called to destroy a named DPipe instance. The caller needs to have |
|
327 sufficient capabilities to delete a named pipe. This method will fail if there are |
|
328 any handles still open on the pipe. |
|
329 |
|
330 @param aName Name of the DPipe instance to be deleted. |
|
331 |
|
332 @return KErrNone If successful, otherwise one of the other system wide error. |
|
333 |
|
334 */ |
|
335 { |
|
336 TAutoWait<DMutex> autoMutex(*iMutex); |
|
337 DPipe** pS = iDpipes; |
|
338 DPipe** pE = pS + iCount; |
|
339 TInt err = KErrNotFound; |
|
340 TInt count = 0; |
|
341 while(pS < pE) |
|
342 { |
|
343 DPipe** pO = pS++; |
|
344 DPipe* pipe = *pO; |
|
345 if(((*pO)->MatchName(aName))) |
|
346 { |
|
347 //! Check capability |
|
348 if(pipe->GetCap()) |
|
349 { |
|
350 if(!(pipe->GetCap()->CheckPolicy(&Kern::CurrentThread()))) |
|
351 { |
|
352 err = KErrPermissionDenied; |
|
353 break; |
|
354 } |
|
355 } |
|
356 // Check if any handles still opened on the pipe. |
|
357 pipe->Wait(); |
|
358 if (!pipe->IsPipeClosed()) |
|
359 { |
|
360 err = KErrInUse; |
|
361 pipe->Signal(); //need to signal if we won't be destroying pipe |
|
362 break; |
|
363 } |
|
364 __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Destroy remove ID=%d", pipe->OpenId())); |
|
365 delete iDpipes[count]; |
|
366 RemovePipe(pO); |
|
367 err = KErrNone; |
|
368 break; |
|
369 } |
|
370 count ++; |
|
371 } |
|
372 return err; |
|
373 } |
|
374 |
|
375 |
|
376 TInt DPipeDevice::Close(TInt aId) |
|
377 /** |
|
378 This method is called to close both named and un-named DPipe. In case of un-named DPipe |
|
379 if there is no further reference of a DPipeChannel exist, the corresponding un-named DPipe |
|
380 will be deleted. |
|
381 |
|
382 @param aId ID of the pipe that need to be closed. |
|
383 |
|
384 @return KErrNone If successful otherwise one of the other system wide error. |
|
385 |
|
386 */ |
|
387 { |
|
388 TAutoWait<DMutex> autoMutex(*iMutex); |
|
389 DPipe** pS = iDpipes; |
|
390 DPipe** pE = pS + iCount; |
|
391 TInt err = KErrNotFound; |
|
392 while(pS < pE) |
|
393 { |
|
394 DPipe** pO = pS++; |
|
395 DPipe* pipe = *pO; |
|
396 if(pipe->MatchId(aId)) |
|
397 { |
|
398 __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Close found ID=%d", pipe->OpenId())); |
|
399 //even if we can't delete the pipe, we have |
|
400 //found it so don't return KErrNotFound |
|
401 err = KErrNone; |
|
402 |
|
403 pipe->Wait(); |
|
404 |
|
405 // we can only delete an unamed pipe with both ends closed |
|
406 if(!pipe->IsNamedPipe() && pipe->IsPipeClosed()) |
|
407 { |
|
408 __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Close remove ID=%d", pipe->OpenId())); |
|
409 delete pipe; |
|
410 RemovePipe(pO); |
|
411 break; |
|
412 } |
|
413 pipe->Signal(); |
|
414 |
|
415 } |
|
416 } |
|
417 return err; |
|
418 } |
|
419 |
|
420 |
|
421 |
|
422 TInt DPipeDevice::GenerateId() |
|
423 /** |
|
424 Generate a ID and store for a Named pipe while creating. |
|
425 |
|
426 @param None |
|
427 @return TInt ID for the name pipe |
|
428 |
|
429 @pre Mutex to be held |
|
430 |
|
431 */ |
|
432 { |
|
433 __ASSERT_MUTEX(iMutex); |
|
434 iIdindex++; |
|
435 return (KIdBase + iIdindex); |
|
436 } |
|
437 |
|
438 |
|
439 DPipeChannel::DPipeChannel() |
|
440 :iClientRequest(NULL), iData(NULL), iChannelType(RPipe::EChannelUnset) |
|
441 /** |
|
442 Constructor |
|
443 */ |
|
444 { |
|
445 } |
|
446 |
|
447 |
|
448 DPipeChannel::~DPipeChannel() |
|
449 /** |
|
450 Destructor |
|
451 */ |
|
452 { |
|
453 CloseHandle(); |
|
454 |
|
455 Kern::DestroyClientRequest(iClientRequest); //null ptr is safe |
|
456 } |
|
457 |
|
458 |
|
459 |
|
460 TInt DPipeChannel::RequestUserHandle (DThread* aThread, TOwnerType aType) |
|
461 /** |
|
462 Inherited from DObject. This method is called when a user thread requests |
|
463 a handle to this channel. Minimal implantation here is capability check |
|
464 |
|
465 @param aThread DThread instance reference that requests a handle to this channel. |
|
466 @param aType Ownership type for the handle. |
|
467 |
|
468 @return KErrNone If successful otherwise one the system wide error. |
|
469 */ |
|
470 { |
|
471 (void)aThread; |
|
472 (void)aType; |
|
473 return KErrNone; |
|
474 } |
|
475 |
|
476 |
|
477 |
|
478 TInt DPipeChannel::DoCreate (TInt aUnit, const TDesC8* aInfo, const TVersion& aVer) |
|
479 /** |
|
480 Inherited from DLogicalChannelBase class. This method represents the second stage |
|
481 constructor called by the kernel's device driver framework. This is called in the |
|
482 context of the user thread (client) which requested the creation of the Logical |
|
483 Channel. The thread is in critical section. |
|
484 |
|
485 @param aUnit The unit argument supplied by the client |
|
486 @param aInfo The info argument supplied by the client |
|
487 @param aVer The version argument supplied by the client |
|
488 |
|
489 @return KErrNone If successful, otherwise one of the other system wide error codes. |
|
490 */ |
|
491 { |
|
492 (void)aInfo; |
|
493 (void)aUnit; |
|
494 |
|
495 // Check version |
|
496 if (!Kern::QueryVersionSupported(RPipe::VersionRequired(),aVer)) |
|
497 return KErrNotSupported; |
|
498 |
|
499 TInt r = Kern::CreateClientRequest(iClientRequest); |
|
500 if(r != KErrNone) |
|
501 { |
|
502 return r; |
|
503 } |
|
504 |
|
505 // Done |
|
506 return KErrNone; |
|
507 } |
|
508 |
|
509 |
|
510 TInt DPipeChannel::Request(TInt aReqNo, TAny* a1, TAny* a2) |
|
511 /** |
|
512 Called by the Device driver framework upon user request. Stores the |
|
513 Thread pointer under whose context this function is called. |
|
514 |
|
515 @param aFunction A number identifying the message type |
|
516 @param a1 A 32-bit Value passed by the user |
|
517 @param a2 A 32-bit Value passed by the user |
|
518 |
|
519 @return KErrNone If successful, otherwise one of the system wide error code |
|
520 |
|
521 */ |
|
522 { |
|
523 TInt err = KErrNone; |
|
524 |
|
525 DATAPAGING_TEST |
|
526 ( |
|
527 err = Kern::HalFunction(EHalGroupVM, EVMHalFlushCache, 0, 0); |
|
528 if(err != KErrNone) |
|
529 { |
|
530 return err; |
|
531 } |
|
532 ) |
|
533 |
|
534 if(aReqNo == KMaxTInt) |
|
535 { |
|
536 CancelRequest((TInt)a1); |
|
537 return err; |
|
538 } |
|
539 if(aReqNo < 0) |
|
540 { |
|
541 // DoRequest |
|
542 TAny *array[2] = {0,0}; |
|
543 TRequestStatus * pStat = (TRequestStatus*)a1; |
|
544 kumemget32(&array[0], a2, 2*sizeof(TAny*)); |
|
545 err = DoRequest(~aReqNo, pStat, array[0], array[1]); |
|
546 if(err!= KErrNone) |
|
547 Kern::RequestComplete(pStat, err); |
|
548 |
|
549 } |
|
550 else |
|
551 { |
|
552 // DoControl |
|
553 err = DoControl(aReqNo, a1, a2); |
|
554 } |
|
555 return err; |
|
556 } |
|
557 |
|
558 |
|
559 TInt DPipeChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
560 /** |
|
561 Processes Synchronous 'control' requests. This function is called to service |
|
562 any synchronous calls through the user side RPipe handle. |
|
563 |
|
564 @param aFunction A number identifying the message type |
|
565 @param a1 A 32-bit Value passed by the user |
|
566 @param a2 A 32-bit Value passed by the user |
|
567 |
|
568 @return KErrNone If the call is successful, otherwise one of the other |
|
569 system wide error |
|
570 */ |
|
571 { |
|
572 TInt aSize = 0; |
|
573 TInt aId = 0; |
|
574 |
|
575 switch(aFunction) |
|
576 { |
|
577 case RPipe::EDefineNamedPipe: |
|
578 return PipeCreate(a1, a2); |
|
579 |
|
580 case RPipe::EOpenToReadNamedPipe: |
|
581 return PipeOpen((const TDesC*)a1, RPipe::EReadChannel); |
|
582 |
|
583 case RPipe::EOpenToWriteNamedPipe: |
|
584 return PipeOpen((const TDesC*)a1, RPipe::EWriteChannel); |
|
585 |
|
586 case RPipe::EOpenToWriteButFailOnNoReaderNamedPipe: |
|
587 return OpenOnReader((const TDesC*)a1); |
|
588 |
|
589 case RPipe::EDestroyNamedPipe: |
|
590 return PipeDestroy((const TDesC*)a1); |
|
591 |
|
592 case RPipe::ECreateUnNamedPipe: |
|
593 kumemget((TAny*)&aSize, a1, sizeof(TInt)); |
|
594 return PipeCreate( aSize); |
|
595 |
|
596 case RPipe::EOpenUnNamedPipe: |
|
597 kumemget((TAny*)&aId, a1, sizeof(TInt)); |
|
598 return PipeOpen(aId); |
|
599 |
|
600 case RPipe::ERead: |
|
601 kumemget((TAny*)&aSize, a2, sizeof(TInt)); |
|
602 return Read (a1, aSize); |
|
603 |
|
604 case RPipe::EWrite: |
|
605 kumemget((TAny*)&aSize, a2, sizeof(TInt)); |
|
606 return Write (a1, aSize); |
|
607 |
|
608 case RPipe::ESize: |
|
609 return Size(); |
|
610 |
|
611 case RPipe::EDataAvailableCount: |
|
612 { |
|
613 TAutoWait<DMutex> autoMutex(iData->Mutex()); |
|
614 return iData->AvailableDataCount(); |
|
615 } |
|
616 |
|
617 case RPipe::EFlushPipe: |
|
618 Flush(); |
|
619 return KErrNone; |
|
620 |
|
621 case RPipe::EGetPipeInfo: |
|
622 umemput(a1,(TAny*)&iChannelType, sizeof(TInt)); |
|
623 aSize = Size(); |
|
624 umemput(a2,(TAny*)&aSize, sizeof(TInt)); |
|
625 return KErrNone; |
|
626 |
|
627 |
|
628 default: |
|
629 return KErrNotSupported; |
|
630 |
|
631 } |
|
632 |
|
633 } |
|
634 |
|
635 |
|
636 TInt DPipeChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
637 /** |
|
638 Processes Asynchronous requests This function is called to service |
|
639 any asynchronous calls through the user side RPipe handle. |
|
640 |
|
641 @param aFunction A number identifying the message type |
|
642 @param aStatus Status request to be completed. |
|
643 @param a1 A 32-bit Value passed by the user |
|
644 @param a2 A 32-bit Value passed by the user |
|
645 |
|
646 @return KErrNone If the call is successful, else one of the system wide error |
|
647 */ |
|
648 { |
|
649 (void)a2; |
|
650 TInt aSize = 0; |
|
651 TInt aChoice = 0; |
|
652 |
|
653 switch(aReqNo) |
|
654 { |
|
655 case RPipe::EDataAvailable: |
|
656 return NotifyDataAvailable(aStatus, ETrue); |
|
657 |
|
658 case RPipe::ESpaceAvailable: |
|
659 umemget(&aSize, a1, sizeof(aSize)); |
|
660 return NotifySpaceAvailable(aSize, aStatus, ETrue); |
|
661 |
|
662 case RPipe::EWaitNotification: |
|
663 // a2 == RPipe::EWaitForReader is for WaitForReader. |
|
664 // a2 == RPipe::EWaitForWriter is for WaitForWriter. |
|
665 umemget(&aChoice, a2, sizeof(aChoice)); |
|
666 return WaitNotification(aStatus, a1, aChoice); |
|
667 |
|
668 case RPipe::EReadBlocking: |
|
669 { |
|
670 return NotifyDataAvailable(aStatus, EFalse); |
|
671 } |
|
672 |
|
673 case RPipe::EWriteBlocking: |
|
674 { |
|
675 umemget(&aSize, a1, sizeof(aSize)); |
|
676 return NotifySpaceAvailable(aSize, aStatus, EFalse); |
|
677 } |
|
678 default: |
|
679 return KErrNotSupported; |
|
680 } |
|
681 } |
|
682 |
|
683 |
|
684 |
|
685 TInt DPipeChannel::PipeCreate(TAny* a1, TAny* a2) |
|
686 /** |
|
687 Creates named pipes with the specified name and size. It calls Pipe Device |
|
688 object to create the pipe and obtained the pointer to it. The pointer is then |
|
689 stored in its iData member data. |
|
690 @param a1 Pointer to TPipeInfo class |
|
691 |
|
692 @param a2 Pointer to TSecurityPolicy class |
|
693 |
|
694 @return KErrNone If successful, otherwise one of the other system wide error code. |
|
695 */ |
|
696 { |
|
697 if(iData) |
|
698 { |
|
699 //this channel already has a pipe |
|
700 return KErrInUse; |
|
701 } |
|
702 |
|
703 // The following code safely gets the 3 arguments into kernel memory. |
|
704 // (The user side API is badly designed,) |
|
705 RPipe::TPipeInfo& info = (*(RPipe::TPipeInfoBuf*)a1)(); // reference to user side 'TPipeInfo' |
|
706 TInt size; |
|
707 kumemget(&size,&info.isize,sizeof(size)); |
|
708 TKName name; |
|
709 Kern::KUDesGet(name,info.iName); |
|
710 TSecurityPolicy* securityPolicy = 0; |
|
711 TSecurityPolicy securityPolicyBuffer; |
|
712 if(a2) |
|
713 { |
|
714 kumemget(&securityPolicyBuffer,a2,sizeof(securityPolicyBuffer)); |
|
715 securityPolicy = &securityPolicyBuffer; |
|
716 } |
|
717 |
|
718 DPipe * pipe = NULL; |
|
719 DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice); |
|
720 |
|
721 //must wait on device since after creation |
|
722 //the pipe becomes globably findable |
|
723 //and destroyable |
|
724 TAutoWait<DMutex> outerAutoMutex(device.Mutex()); |
|
725 |
|
726 TInt err = ((DPipeDevice*)iDevice)->CreatePipe(name, size, pipe, securityPolicy); |
|
727 if(err!= KErrNone) |
|
728 { |
|
729 return err; |
|
730 } |
|
731 |
|
732 TAutoWait<DMutex> innerAutoMutex(pipe->Mutex()); |
|
733 pipe->SetReadEnd(this); |
|
734 iData = pipe; |
|
735 iChannelType = RPipe::EReadChannel; |
|
736 return err; |
|
737 } |
|
738 |
|
739 |
|
740 TInt DPipeChannel::PipeCreate(const TInt aSize) |
|
741 /** |
|
742 Creates unnamed pipes with the specified Id and size. It calls Pipe Device |
|
743 object to create the pipe and obtained the pointer to it. The pointer is then |
|
744 stored in its iData member data. Marked the current channel as read end. |
|
745 |
|
746 @param aSize Size of the unnamed pipe to be created. |
|
747 |
|
748 @return Handle ID if successful, otherwise one of the other system wide error code. |
|
749 */ |
|
750 { |
|
751 if(iData) |
|
752 { |
|
753 //this channel already has a pipe |
|
754 return KErrInUse; |
|
755 } |
|
756 |
|
757 DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice); |
|
758 |
|
759 TAutoWait<DMutex> outerAutoMutex(device.Mutex()); |
|
760 |
|
761 DPipe* pipe = device.CreatePipe(aSize); |
|
762 if(pipe == NULL) |
|
763 { |
|
764 return KErrNoMemory; |
|
765 } |
|
766 |
|
767 TAutoWait<DMutex> innerAutoMutex(pipe->Mutex()); |
|
768 |
|
769 pipe->SetReadEnd(this); |
|
770 iData = pipe; |
|
771 iChannelType = RPipe::EReadChannel; |
|
772 |
|
773 return iData->OpenId(); |
|
774 } |
|
775 |
|
776 |
|
777 TInt DPipeChannel::OpenOnReader(const TDesC* aName) |
|
778 /** |
|
779 Opens a named pipe identified by the name parameter. It calls Pipe Device object |
|
780 to open the Pipe identified by the name and obtained the pointer to the pipe. The |
|
781 pointer is them stored in its iData member data. Marked the current channel as write |
|
782 end. |
|
783 @param aName The name of the pipe to be opened. |
|
784 |
|
785 @return KErrNone If successful, otherwise one of the other system wide error code. |
|
786 */ |
|
787 { |
|
788 if(iData) |
|
789 { |
|
790 //this channel already has a pipe |
|
791 return KErrInUse; |
|
792 } |
|
793 |
|
794 TKName PName; |
|
795 Kern::KUDesGet(PName, *aName); |
|
796 |
|
797 DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice); |
|
798 |
|
799 //need to hold the device mutex to |
|
800 //prevent the pipe getting deleted before we can call |
|
801 //SetWriteEnd |
|
802 TAutoWait<DMutex> outerAutoMutex(device.Mutex()); |
|
803 DPipe* pipe = device.FindNamedPipe(&PName); |
|
804 |
|
805 if(pipe == NULL) |
|
806 { |
|
807 return KErrNotFound; |
|
808 } |
|
809 |
|
810 TAutoWait<DMutex> innerAutoMutex(pipe->Mutex()); |
|
811 if (!pipe->IsReadEndOpened()) |
|
812 { |
|
813 return KErrNotReady; |
|
814 } |
|
815 |
|
816 iData = pipe; |
|
817 |
|
818 if(!CheckCap()) |
|
819 { |
|
820 iData = NULL; |
|
821 return KErrPermissionDenied; |
|
822 } |
|
823 |
|
824 if(pipe->IsWriteEndOpened()) |
|
825 { |
|
826 iData = NULL; |
|
827 return KErrInUse; |
|
828 } |
|
829 |
|
830 iData->SetWriteEnd(this); |
|
831 iChannelType = RPipe::EWriteChannel; |
|
832 return KErrNone; |
|
833 } |
|
834 |
|
835 |
|
836 TInt DPipeChannel::PipeDestroy(const TDesC* aName) |
|
837 /** |
|
838 Destroys the named pipe. |
|
839 @param aName Name of the Kernel pipe to be destroyed. |
|
840 |
|
841 @return KErrNone If the pipe is successfully destroyed, otherwise one of the |
|
842 other system wide error codes |
|
843 */ |
|
844 { |
|
845 TKName PName; |
|
846 Kern::KUDesGet(PName, *aName); |
|
847 return ((DPipeDevice*)iDevice)->Destroy(&PName); |
|
848 } |
|
849 |
|
850 TInt DPipeChannel::PipeOpen(const TInt aId) |
|
851 /** |
|
852 Opens a unnamed pipe identified by the specified id. It calls Pipe Device object |
|
853 to open a unnamed pipe identified by the specified id and obtain the pointer to the |
|
854 pipe. The pipe reference is then stored in its iData member data and marked the |
|
855 current channel as write end. |
|
856 |
|
857 @param aId Id of the unnamed pipe to be opened. |
|
858 |
|
859 @return KErrNone If successful, otherwise one of the system wide error code. |
|
860 */ |
|
861 { |
|
862 if(iData) |
|
863 { |
|
864 //this channel already has a pipe |
|
865 return KErrInUse; |
|
866 } |
|
867 |
|
868 DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice); |
|
869 TAutoWait<DMutex> outerAutoMutex(device.Mutex()); |
|
870 |
|
871 DPipe* pipe = device.FindUnnamedPipe(aId); |
|
872 if(pipe == NULL) |
|
873 { |
|
874 return KErrNotFound; |
|
875 } |
|
876 |
|
877 TAutoWait<DMutex> innerAutoMutex(pipe->Mutex()); |
|
878 if (pipe->IsWriteEndOpened() ) |
|
879 { |
|
880 return KErrInUse; |
|
881 } |
|
882 |
|
883 pipe->SetWriteEnd(this); |
|
884 |
|
885 iChannelType = RPipe::EWriteChannel; |
|
886 iData = pipe; |
|
887 |
|
888 return KErrNone; |
|
889 } |
|
890 |
|
891 |
|
892 TInt DPipeChannel::PipeOpen(const TDesC* aName, RPipe::TChannelType aType) |
|
893 /** |
|
894 This function will be called under DoControl(); |
|
895 Attempts to open the pipe for reading (iReadEnd) or writing (iWriteEnd) |
|
896 @param aName Name of the pipe to be opened |
|
897 |
|
898 @param aType Type of operation to be performed. |
|
899 |
|
900 @return KErrNone Pipe successfully created, otherwise one of the other system wide |
|
901 error code |
|
902 */ |
|
903 { |
|
904 if(iData) |
|
905 { |
|
906 //this channel already has a pipe |
|
907 return KErrInUse; |
|
908 } |
|
909 |
|
910 TKName PName; |
|
911 Kern::KUDesGet(PName, *aName); |
|
912 |
|
913 DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice); |
|
914 |
|
915 TAutoWait<DMutex> outerAutoMutex(device.Mutex()); |
|
916 |
|
917 DPipe* pipe = device.FindNamedPipe(&PName); |
|
918 if(pipe == NULL) |
|
919 { |
|
920 return KErrNotFound; |
|
921 } |
|
922 |
|
923 |
|
924 TAutoWait<DMutex> innerAutoMutex(pipe->Mutex()); |
|
925 iData = pipe; |
|
926 //! Check capabilitity if applicalble |
|
927 if(!CheckCap()) |
|
928 { |
|
929 iData = NULL; |
|
930 return KErrPermissionDenied; |
|
931 } |
|
932 |
|
933 // Check if the pipe is already opened. |
|
934 if(aType == RPipe::EReadChannel) |
|
935 { |
|
936 if(iData->IsReadEndOpened()) |
|
937 { |
|
938 iData = NULL; |
|
939 return KErrInUse; |
|
940 } |
|
941 iData->SetReadEnd(this); |
|
942 } |
|
943 else |
|
944 { |
|
945 if(iData->IsWriteEndOpened()) |
|
946 { |
|
947 iData = NULL; |
|
948 return KErrInUse; |
|
949 } |
|
950 iData->SetWriteEnd(this); |
|
951 } |
|
952 |
|
953 iChannelType = aType; |
|
954 |
|
955 return KErrNone; |
|
956 } |
|
957 |
|
958 |
|
959 |
|
960 TBool DPipeChannel::CheckCap() |
|
961 /** |
|
962 Check if Security policy is installed, if so, checks if the current thread |
|
963 has required capabilities |
|
964 |
|
965 @param None |
|
966 |
|
967 @return TBool ETrue if The current thread has required capabilities and also if |
|
968 no capabilities is installed, otherwise EFlase. |
|
969 |
|
970 */ |
|
971 { |
|
972 //iData->GetCap is always true |
|
973 if(iData->GetCap()) |
|
974 return iData->GetCap()->CheckPolicy(&Kern::CurrentThread()); |
|
975 else |
|
976 return ETrue; |
|
977 } |
|
978 |
|
979 |
|
980 |
|
981 TInt DPipeChannel::Read (TAny* aBuff, TInt aSize) |
|
982 /** |
|
983 Synchronous, non-blocking read operation. If the pipe is empty it will |
|
984 return immediately with KErrUnderflow. A successful DPipe::Read() operation |
|
985 will free up more space in the pipe. If a request status object has been registered |
|
986 for Space Available notification, it will complete. Note that there is no |
|
987 guarantee that the amount of space freed up in the pipe will be sufficient |
|
988 for the next DPipe::Write() operation. |
|
989 |
|
990 @param aBuff Buffer from which data need to be read |
|
991 |
|
992 @param aSize Size of the data to be read |
|
993 |
|
994 @return:>0 Amount of data read in octets. |
|
995 KErrArgument Invalid Length Amount of data to be read is invalid (e.g. negative) |
|
996 KErrNotReady If the write end is closed, |
|
997 otherwise one of the other system wide error code |
|
998 */ |
|
999 { |
|
1000 |
|
1001 if( iChannelType != RPipe::EReadChannel) |
|
1002 return KErrAccessDenied; |
|
1003 |
|
1004 |
|
1005 TAutoWait<DMutex> outerAutoMutex(*iData->iReadMutex); |
|
1006 TAutoWait<DMutex> innerAutoMutex(iData->Mutex()); |
|
1007 //iData->Wait(); |
|
1008 if(!iData->IsWriteEndOpened() && iData->IsBufferEmpty()) |
|
1009 { |
|
1010 //it is ok to read from a broken pipe provided there is data in it |
|
1011 return KErrNotReady; |
|
1012 } |
|
1013 |
|
1014 return iData->Read(aBuff, aSize); |
|
1015 } |
|
1016 |
|
1017 |
|
1018 TInt DPipeChannel::Write (TAny* aBuff, TInt aSize) |
|
1019 /** |
|
1020 Synchronous, non-blocking write operation. If the pipe is full it will |
|
1021 return immediately with KErrOverflow. A successful DPipe::Write() operation will |
|
1022 return amount of data written to the pipe.If a request status object has been registered |
|
1023 for Data Available notification, it will complete. |
|
1024 |
|
1025 |
|
1026 @param aBuf Buffer from which data need to be written to the pipe. |
|
1027 |
|
1028 @param aSize Amount of data to be written to the pipe. |
|
1029 |
|
1030 @return >0 Amount of data written to the pipe, in octets. |
|
1031 KErrOverflow The pipe is full no data is written. |
|
1032 KErrArgument if the amount of data to be written in invalid |
|
1033 KErrNotReady if the read end is not opened. |
|
1034 otherwise one of the other system wide error code |
|
1035 */ |
|
1036 { |
|
1037 |
|
1038 if(iChannelType!= RPipe::EWriteChannel) |
|
1039 return KErrAccessDenied; |
|
1040 |
|
1041 TAutoWait<DMutex> outerAutoMutex(*iData->iWriteMutex); |
|
1042 TAutoWait<DMutex> innerAutoMutex(iData->Mutex()); |
|
1043 |
|
1044 if(!(iData->IsReadEndOpened())) |
|
1045 { |
|
1046 return KErrNotReady; |
|
1047 } |
|
1048 |
|
1049 return iData->Write(aBuff, aSize); |
|
1050 } |
|
1051 |
|
1052 |
|
1053 |
|
1054 TInt DPipeChannel::CloseHandle() |
|
1055 /** |
|
1056 Attempts to close the pipe for reading or writing . |
|
1057 |
|
1058 @param None |
|
1059 |
|
1060 @return KErrNone Success. |
|
1061 KErrCouldNotDisconnect The pipe is already closed for that operation. |
|
1062 |
|
1063 */ |
|
1064 { |
|
1065 if(iData==NULL) |
|
1066 { |
|
1067 return KErrNone; |
|
1068 } |
|
1069 |
|
1070 __KTRACE_OPT(KPIPE, Kern::Printf("DPipeChannel::CloseHandle ID=%d, ChannelType=%d", iData->OpenId(), iChannelType)); |
|
1071 |
|
1072 NKern::ThreadEnterCS(); |
|
1073 iData->Wait(); |
|
1074 TInt err = KErrNone; |
|
1075 if(iChannelType == RPipe::EReadChannel) |
|
1076 { |
|
1077 CancelRequest(RPipe::EDataAvailable); |
|
1078 err = iData->CloseReadEnd(); |
|
1079 } |
|
1080 else if(iChannelType == RPipe::EWriteChannel) |
|
1081 { |
|
1082 CancelRequest(RPipe::ESpaceAvailable); |
|
1083 err = iData->CloseWriteEnd(); |
|
1084 } |
|
1085 else |
|
1086 { |
|
1087 FAULT(); //iChannelType should be set correctly if iData was non-null |
|
1088 } |
|
1089 // If we had a pointer to the pipe but it had no back pointer |
|
1090 // to us something has gone wrong. |
|
1091 __NK_ASSERT_DEBUG(err == KErrNone); |
|
1092 |
|
1093 const TInt pipeId=iData->OpenId(); |
|
1094 iData->Signal(); |
|
1095 iData = NULL; |
|
1096 |
|
1097 // The return code from close would inform us if |
|
1098 // the device had no record of the pipe. |
|
1099 // However, for a named pipe there is no gurrantee that the pipe |
|
1100 // hasn't been deleted once we close our end of the pipe and |
|
1101 // Signal. |
|
1102 static_cast<DPipeDevice*>(iDevice)->Close(pipeId); |
|
1103 |
|
1104 NKern::ThreadLeaveCS(); |
|
1105 |
|
1106 return err; |
|
1107 } |
|
1108 |
|
1109 |
|
1110 |
|
1111 TInt DPipeChannel::NotifySpaceAvailable ( TInt aSize,TRequestStatus* aStat, TBool aAllowDisconnected) |
|
1112 /** |
|
1113 Registers the request status object to be completed when space becomes |
|
1114 available in the pipe. |
|
1115 |
|
1116 @param aSize The size for which the user has requested for notification |
|
1117 |
|
1118 @param aStat Status request to be registered |
|
1119 @param aAllowDisconnected If false then confirm that the pipe has a reader |
|
1120 |
|
1121 @return KErrNone Success in registering the request |
|
1122 KErrAccessDenied If the correct end is not used to register the request |
|
1123 KErrInUse A notifier of this type has already been registered. |
|
1124 otherwise one of the other system wide error code. |
|
1125 KErrNotReady The pipe has no reader |
|
1126 */ |
|
1127 { |
|
1128 |
|
1129 //! Check if correct end is used |
|
1130 if(iChannelType!= RPipe::EWriteChannel) |
|
1131 { |
|
1132 return KErrAccessDenied; |
|
1133 } |
|
1134 |
|
1135 TAutoWait<DMutex> autoMutex(iData->Mutex()); |
|
1136 //Check if there is already a pending Space Available request. |
|
1137 if(iClientRequest->StatusPtr()) |
|
1138 { |
|
1139 return KErrInUse; |
|
1140 } |
|
1141 else |
|
1142 { |
|
1143 if(!aAllowDisconnected && !(iData->IsReadEndOpened()) ) |
|
1144 return KErrNotReady; |
|
1145 |
|
1146 TInt r = iClientRequest->SetStatus(aStat); |
|
1147 __NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr |
|
1148 DThread* const currThread = &Kern::CurrentThread(); |
|
1149 |
|
1150 if((iData->RegisterSpaceAvailableNotification(aSize))==KErrCompletion) |
|
1151 { |
|
1152 Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone); |
|
1153 } |
|
1154 else |
|
1155 { |
|
1156 iRequestThread = currThread; |
|
1157 // Open a reference on client thread so its control block can't disappear until |
|
1158 // this channel has finished with it. |
|
1159 iRequestThread->Open(); |
|
1160 iRequestType = RPipe::ESpaceAvailable; |
|
1161 } |
|
1162 } |
|
1163 return KErrNone; |
|
1164 } |
|
1165 |
|
1166 |
|
1167 TInt DPipeChannel::NotifyDataAvailable (TRequestStatus* aStat, TBool aAllowDisconnected) |
|
1168 /** |
|
1169 Registers the request status object to be completed when data becomes |
|
1170 available in the pipe. |
|
1171 |
|
1172 @param aStat Status request to be registered |
|
1173 @param aAllowDisconnected If false then fail if the pipe is empty with no writer. |
|
1174 |
|
1175 @return KErrNone Success in registering the request |
|
1176 KErrAccessDenied If the correct end is not used to register the request |
|
1177 KErrInUse A notifier of this type has already been registered. |
|
1178 otherwise one of the other system wide error code. |
|
1179 KErrNotReady The pipe was empty and had no writer |
|
1180 */ |
|
1181 { |
|
1182 |
|
1183 //! Check if correct end is used |
|
1184 if(iChannelType!= RPipe::EReadChannel) |
|
1185 { |
|
1186 return KErrAccessDenied; |
|
1187 } |
|
1188 |
|
1189 // Check if there is already a pending Data Available request. |
|
1190 TAutoWait<DMutex> autoMutex(iData->Mutex() ); |
|
1191 if(iClientRequest->StatusPtr()) |
|
1192 { |
|
1193 return KErrInUse; |
|
1194 } |
|
1195 else |
|
1196 { |
|
1197 if(!aAllowDisconnected) |
|
1198 { |
|
1199 if(iData->IsBufferEmpty() && (!iData->IsWriteEndOpened())) |
|
1200 return KErrNotReady; |
|
1201 } |
|
1202 |
|
1203 TInt r = iClientRequest->SetStatus(aStat); |
|
1204 __NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr |
|
1205 DThread* const currThread = &Kern::CurrentThread(); |
|
1206 |
|
1207 if((iData->RegisterDataAvailableNotification()) == KErrCompletion) |
|
1208 { |
|
1209 Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone); |
|
1210 } |
|
1211 else |
|
1212 { |
|
1213 iRequestThread = currThread; |
|
1214 // Open a reference on client thread so its control block can't disappear until |
|
1215 // this channel has finished with it. |
|
1216 iRequestThread->Open(); |
|
1217 iRequestType = RPipe::EDataAvailable; |
|
1218 } |
|
1219 } |
|
1220 return KErrNone;; |
|
1221 } |
|
1222 |
|
1223 |
|
1224 TInt DPipeChannel::WaitNotification(TRequestStatus* aStat, TAny* aName, TInt aChoice) |
|
1225 /** |
|
1226 Registers the request status object to be completed when other end of the pipe |
|
1227 is opened for reading (or writing).This method completes immediately if the other end of the |
|
1228 pipe is already opened. |
|
1229 |
|
1230 |
|
1231 @param aName Pointer to the a name passed as void pointer |
|
1232 |
|
1233 @param aStat Status request to be registered |
|
1234 |
|
1235 @param aChoice EWaitForReader,wait notification for Read end Opened. |
|
1236 EWaitForWriter,wait notification for Write end Opened. |
|
1237 |
|
1238 @return KErrNone Success in registering the request |
|
1239 KErrInUse A notifier of this type has already been registered. |
|
1240 KErrAccessDenied If the correct end is not used to register the request |
|
1241 otherwise one of the other system wide error code |
|
1242 |
|
1243 */ |
|
1244 { |
|
1245 //! Check if correct end is used |
|
1246 if(((aChoice == RPipe::EWaitForReader) && (iChannelType!= RPipe::EWriteChannel)) |
|
1247 || ((aChoice == RPipe::EWaitForWriter) && (iChannelType!= RPipe::EReadChannel))) |
|
1248 { |
|
1249 return KErrAccessDenied; |
|
1250 } |
|
1251 |
|
1252 TKName PName; |
|
1253 Kern::KUDesGet(PName, *(TDesC*)aName); |
|
1254 |
|
1255 TAutoWait<DMutex> autoMutex(iData->Mutex()); |
|
1256 if(iData->MatchName(&PName)== EFalse) |
|
1257 { |
|
1258 return KErrNotFound; |
|
1259 } |
|
1260 // Check if there is already a pending request. |
|
1261 else if(iClientRequest->StatusPtr()) |
|
1262 { |
|
1263 return KErrInUse; |
|
1264 } |
|
1265 else |
|
1266 { |
|
1267 TInt r = iClientRequest->SetStatus(aStat); |
|
1268 __NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr |
|
1269 DThread* const currThread = &Kern::CurrentThread(); |
|
1270 |
|
1271 //register the request. |
|
1272 if((iData->RegisterWaitNotification((TInt )aChoice))== KErrCompletion) |
|
1273 { |
|
1274 Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone); |
|
1275 } |
|
1276 else |
|
1277 { |
|
1278 iRequestThread = currThread; |
|
1279 // Open a reference on client thread so its control block can't disappear until |
|
1280 // this channel has finished with it. |
|
1281 iRequestThread->Open(); |
|
1282 iRequestType = RPipe::EWaitNotification; |
|
1283 } |
|
1284 } |
|
1285 return KErrNone; |
|
1286 } |
|
1287 |
|
1288 |
|
1289 /** |
|
1290 For a given request return true if the notification |
|
1291 we are cancelling is outstanding. If not, or |
|
1292 if the supplied request is not a valid cancllation |
|
1293 return false |
|
1294 */ |
|
1295 TBool DPipeChannel::ValidCancellation(TInt aReqType) |
|
1296 { |
|
1297 switch(aReqType) |
|
1298 { |
|
1299 case RPipe::ECancelDataAvailable: |
|
1300 return (iRequestType==RPipe::EDataAvailable); |
|
1301 case RPipe::ECancelSpaceAvailable: |
|
1302 return (iRequestType==RPipe::ESpaceAvailable); |
|
1303 case RPipe::ECancelWaitNotification: |
|
1304 return (iRequestType==RPipe::EWaitNotification); |
|
1305 default: |
|
1306 return EFalse; |
|
1307 } |
|
1308 } |
|
1309 |
|
1310 void DPipeChannel::CancelRequest ( TInt aReqType) |
|
1311 /** |
|
1312 Cancels an outstanding space available notifier request. |
|
1313 |
|
1314 @param aReqType A number identifying the message type |
|
1315 |
|
1316 @return None |
|
1317 */ |
|
1318 { |
|
1319 TAutoWait<DMutex> autoMutex(iData->Mutex() ); |
|
1320 if(iClientRequest->StatusPtr() && ValidCancellation(aReqType)) |
|
1321 { |
|
1322 switch(aReqType) |
|
1323 { |
|
1324 case RPipe::ECancelDataAvailable: |
|
1325 iData->CancelDataAvailable(); |
|
1326 break; |
|
1327 |
|
1328 case RPipe::ECancelSpaceAvailable: |
|
1329 iData->CancelSpaceAvailable(); |
|
1330 break; |
|
1331 |
|
1332 case RPipe::ECancelWaitNotification: |
|
1333 iData->CancelWaitNotifier(); |
|
1334 break; |
|
1335 |
|
1336 default: |
|
1337 FAULT(); |
|
1338 } |
|
1339 Kern::QueueRequestComplete(iRequestThread, iClientRequest, KErrCancel); |
|
1340 // Close our reference on the client thread |
|
1341 Kern::SafeClose((DObject*&)iRequestThread,NULL); |
|
1342 iRequestThread = NULL; |
|
1343 } |
|
1344 return; |
|
1345 } |
|
1346 |
|
1347 |
|
1348 TInt DPipeChannel::Size() |
|
1349 /** |
|
1350 Returns the size of the Pipe's buffer |
|
1351 |
|
1352 @param None |
|
1353 |
|
1354 @return TInt Return the size of the pipe, otherwise one of the other system wide |
|
1355 error code. |
|
1356 */ { |
|
1357 if(!iData) |
|
1358 return KErrNotReady; |
|
1359 else |
|
1360 return iData->Size(); |
|
1361 } |
|
1362 |
|
1363 |
|
1364 void DPipeChannel::Flush() |
|
1365 /* |
|
1366 Flush the content of the pipe |
|
1367 |
|
1368 @param None |
|
1369 @pre Must be in a critical section. |
|
1370 @return None |
|
1371 |
|
1372 */ { |
|
1373 //The flush is, in effect, a read where the data is ignored |
|
1374 TAutoWait<DMutex> autoMutex(*iData->iReadMutex); |
|
1375 |
|
1376 iData->Wait(); |
|
1377 iData->FlushPipe(); |
|
1378 iData->Signal(); |
|
1379 } |
|
1380 |
|
1381 |
|
1382 // Called from the DPipe |
|
1383 |
|
1384 void DPipeChannel::DoRequestCallback() |
|
1385 /** |
|
1386 It is called from the DPipe to complete the Outstanding request |
|
1387 |
|
1388 @param None |
|
1389 |
|
1390 @return None |
|
1391 */ |
|
1392 { |
|
1393 __ASSERT_MUTEX(&iData->Mutex()); |
|
1394 __NK_ASSERT_DEBUG(iRequestThread); |
|
1395 Kern::QueueRequestComplete(iRequestThread, iClientRequest, KErrNone); |
|
1396 Kern::SafeClose((DObject*&)iRequestThread,NULL); |
|
1397 iRequestThread=NULL; |
|
1398 } |
|
1399 |
|
1400 |
|
1401 |
|
1402 // DPipe the Kernel side pipe representing class |
|
1403 |
|
1404 DPipe::~DPipe() |
|
1405 /** |
|
1406 Destructor |
|
1407 */ |
|
1408 { |
|
1409 delete iBuffer; |
|
1410 if (iPipeMutex) |
|
1411 iPipeMutex->Close(NULL); |
|
1412 if (iReadMutex) |
|
1413 iReadMutex->Close(NULL); |
|
1414 if(iWriteMutex) |
|
1415 iWriteMutex->Close(NULL); |
|
1416 } |
|
1417 |
|
1418 |
|
1419 // Creates a Named pipe |
|
1420 DPipe* DPipe::CreatePipe(const TDesC& aName, TInt aSize, TAny *aPolicy) |
|
1421 /** |
|
1422 Static method to Create a Named pipe. |
|
1423 @param aName Reference to the Name to be set to the current named pipe. |
|
1424 @param aSize Size of the Pipe. |
|
1425 @param TAny Pointer to TSecurityPolicy passed as void pointer |
|
1426 |
|
1427 @return DPipe* Reference to DPipe* instance if successful, otherwise NULL |
|
1428 */ |
|
1429 { |
|
1430 |
|
1431 DPipe* tmp = new DPipe; |
|
1432 if (!tmp) |
|
1433 { |
|
1434 return NULL; |
|
1435 } |
|
1436 if(tmp->ConstructPipe(aName, aSize, aPolicy)!= KErrNone) |
|
1437 { |
|
1438 delete tmp; |
|
1439 return NULL; |
|
1440 } |
|
1441 return tmp; |
|
1442 } |
|
1443 |
|
1444 |
|
1445 TInt DPipe::ConstructPipe(const TDesC& aName, TInt aSize,TAny* aPolicy) |
|
1446 /** |
|
1447 Second phase constructor |
|
1448 |
|
1449 @param aName The name of the pipe to be created |
|
1450 @param aSize The size of the pipe to be created |
|
1451 @param TAny Pointer to TSecurityPolicy passed as void pointer |
|
1452 |
|
1453 @return KErrNone If successful, otherwise one of the other system wide error code |
|
1454 */ |
|
1455 { |
|
1456 // check the size parameter. |
|
1457 if(aPolicy) |
|
1458 { |
|
1459 |
|
1460 memcpy(&iPolicy,aPolicy,sizeof(TSecurityPolicy)); |
|
1461 |
|
1462 } |
|
1463 else |
|
1464 { |
|
1465 TSecurityPolicy apolicy(ECapability_None); |
|
1466 memcpy(&iPolicy,&apolicy,sizeof(TSecurityPolicy)); |
|
1467 } |
|
1468 |
|
1469 if(aName.Length() != 0) |
|
1470 { |
|
1471 iName.Copy(aName); |
|
1472 } |
|
1473 |
|
1474 iBuffer = static_cast<TUint8*>(Kern::AllocZ(aSize)); |
|
1475 if(!iBuffer) |
|
1476 return KErrNoMemory; |
|
1477 |
|
1478 // Initialisation |
|
1479 _LIT(KMutexName,"PipeMutex"); |
|
1480 TInt err = Kern::MutexCreate(iPipeMutex, KMutexName, KMutexOrdGeneral0); |
|
1481 if (err) |
|
1482 { |
|
1483 return err; |
|
1484 } |
|
1485 _LIT(KReadMutex,"ReadMutex"); |
|
1486 err = Kern::MutexCreate(iReadMutex, KReadMutex, KMutexOrdGeneral1); |
|
1487 if (err) |
|
1488 { |
|
1489 return err; |
|
1490 } |
|
1491 |
|
1492 _LIT(KWriteMutex,"WriteMutex"); |
|
1493 err = Kern::MutexCreate(iWriteMutex, KWriteMutex, KMutexOrdGeneral1); |
|
1494 if (err) |
|
1495 { |
|
1496 return err; |
|
1497 } |
|
1498 |
|
1499 iSize = aSize; |
|
1500 iWritePointer = iReadPointer = 0; |
|
1501 iFull = EFalse; |
|
1502 return KErrNone; |
|
1503 } |
|
1504 |
|
1505 |
|
1506 TInt DPipe::OpenId() |
|
1507 /** |
|
1508 Returns the id of the Pipe |
|
1509 |
|
1510 @param None |
|
1511 |
|
1512 @return iID ID of the pipe |
|
1513 */ |
|
1514 { |
|
1515 //could be const |
|
1516 return iID; |
|
1517 } |
|
1518 |
|
1519 |
|
1520 void DPipe::SetId(TInt aId) |
|
1521 /** |
|
1522 Set the id of the Pipe |
|
1523 |
|
1524 @param aId The id to be set |
|
1525 |
|
1526 @return None |
|
1527 */ |
|
1528 { |
|
1529 //this is only called by the pipe device |
|
1530 //it could also be set at construction time |
|
1531 iID = aId; |
|
1532 } |
|
1533 |
|
1534 |
|
1535 TBool DPipe::IsPipeClosed() |
|
1536 /** |
|
1537 Check if the Pipe is Closed. |
|
1538 @param None |
|
1539 @return TBool ETure if Successful, otherwise EFalse; |
|
1540 */ |
|
1541 { |
|
1542 __ASSERT_MUTEX(iPipeMutex); |
|
1543 |
|
1544 return !(iReadChannel || iWriteChannel); |
|
1545 } |
|
1546 |
|
1547 |
|
1548 TBool DPipe::MatchName(const TDesC8* aName) |
|
1549 /** |
|
1550 Check if the current instance of DPipe Name is matching with aName parameter |
|
1551 |
|
1552 @param aName Name to be checked with the current DPipe's name. |
|
1553 |
|
1554 @return TBool ETrue if match found, otherwise EFalse |
|
1555 */ |
|
1556 { |
|
1557 //name could be const |
|
1558 return (iName.Compare(*aName) == 0); |
|
1559 } |
|
1560 |
|
1561 |
|
1562 TBool DPipe::MatchId(const TInt aId) |
|
1563 /** |
|
1564 Checks if the current instance of DPipe is matching with the aId parameter |
|
1565 |
|
1566 @param aId ID to be checked with the current DPipe's id |
|
1567 |
|
1568 @return TBool ETure if match found , otherwise EFalse; |
|
1569 */ |
|
1570 { |
|
1571 return (iID == aId); |
|
1572 } |
|
1573 |
|
1574 |
|
1575 TBool DPipe::IsBufferEmpty() |
|
1576 /** |
|
1577 Checks if the Buffer is Empty |
|
1578 |
|
1579 @param None |
|
1580 @return ETrue if buffer is empty |
|
1581 */ |
|
1582 { |
|
1583 return (AvailableDataCount()==0); |
|
1584 } |
|
1585 |
|
1586 |
|
1587 TInt DPipe::Write(TAny* aBuf, TInt aSize) |
|
1588 /** |
|
1589 Synchronous, non-blocking write operation. If the pipe is full it will |
|
1590 return immediately with KErrOverflow. A successful DPipe::Write() operation will |
|
1591 return amount of data written to the pipe.If a request status object has been registered |
|
1592 for Data Available notification, it will complete. |
|
1593 |
|
1594 @param aBuf Buffer from which data need to be written to the pipe. |
|
1595 @param aSize Amount of data to be written to the pipe. |
|
1596 |
|
1597 @return >0 Amount of data written to the pipe, in octets. |
|
1598 KErrNone No data written to the pipe. |
|
1599 KErrOverflow Pipe is full, cannot write any more data. |
|
1600 KErrArgument If the amount of data to be written is invalid. |
|
1601 Otherwise one of the other system wide error code |
|
1602 |
|
1603 @pre iPipeMutex held |
|
1604 @pre iWriteMutex held |
|
1605 |
|
1606 @note Write enters and exists with the pipe mutex held - but releases and reaquires internally |
|
1607 */ |
|
1608 { |
|
1609 __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::Write(aBuf=0x%08x, aSize=%d)", aBuf, aSize)); |
|
1610 |
|
1611 __ASSERT_MUTEX(iPipeMutex); |
|
1612 __ASSERT_MUTEX(iWriteMutex); |
|
1613 // Check for the Invalid Length |
|
1614 if(aSize < 0) |
|
1615 { |
|
1616 return KErrArgument; |
|
1617 } |
|
1618 |
|
1619 if(aSize == 0) |
|
1620 { |
|
1621 return KErrNone; |
|
1622 } |
|
1623 |
|
1624 //Since only one thread can be writing to the write end |
|
1625 //of a pipe it is sufficient that AvailableDataCount |
|
1626 //holds the pipe mutex. After it returns the |
|
1627 //available space may increase |
|
1628 //but can not decrease |
|
1629 const TInt spaceavailable = (iSize - AvailableDataCount()); |
|
1630 if (spaceavailable < aSize) |
|
1631 { |
|
1632 //Though the API may suggest otherwise - partial writes are not supported. |
|
1633 return KErrOverflow; |
|
1634 } |
|
1635 |
|
1636 //release mutex before IPC read |
|
1637 Signal(); |
|
1638 |
|
1639 //First half |
|
1640 const TDesC8* pBuf = (const TDesC8*)aBuf; |
|
1641 |
|
1642 const TInt distanceToEnd = iSize - iWritePointer; |
|
1643 const TInt firstHalf = Min(distanceToEnd, aSize); |
|
1644 TPtr ptr(&iBuffer[iWritePointer], firstHalf); |
|
1645 |
|
1646 DThread* const currThread = &Kern::CurrentThread(); |
|
1647 TInt r=Kern::ThreadDesRead(currThread, pBuf, ptr, 0, KChunkShiftBy0); |
|
1648 if(r!=KErrNone) |
|
1649 { |
|
1650 Wait(); //we must exit with mutex held |
|
1651 return r; |
|
1652 } |
|
1653 |
|
1654 //Second half |
|
1655 const TInt secondHalf = aSize - firstHalf; |
|
1656 __NK_ASSERT_DEBUG( secondHalf >= 0); |
|
1657 if(secondHalf != 0) |
|
1658 { |
|
1659 ptr.Set(&iBuffer[0], secondHalf, secondHalf); |
|
1660 |
|
1661 r = Kern::ThreadDesRead(currThread, pBuf, ptr, firstHalf, KChunkShiftBy0); |
|
1662 if(r!=KErrNone) |
|
1663 { |
|
1664 Wait(); //we must exit with mutex held |
|
1665 return r; |
|
1666 } |
|
1667 } |
|
1668 |
|
1669 Wait(); //reaquire mutex for state update |
|
1670 iWritePointer = (iWritePointer + aSize)% iSize; |
|
1671 |
|
1672 if(iWritePointer == iReadPointer) |
|
1673 { |
|
1674 iFull = ETrue; |
|
1675 } |
|
1676 |
|
1677 if(iDataAvailableRequest) |
|
1678 { |
|
1679 iReadChannel->DoRequestCallback(); |
|
1680 iDataAvailableRequest = EFalse; |
|
1681 } |
|
1682 |
|
1683 return aSize; |
|
1684 } |
|
1685 |
|
1686 |
|
1687 TInt DPipe::Read(TAny* aBuf, TInt aSize) |
|
1688 /** |
|
1689 Synchronous, non-blocking read operation. If the pipe is empty it will |
|
1690 return immediately with KErrUnderflow. A successful DPipe::Read() operation |
|
1691 will free up more space in the pipe. If a request status object has been registered |
|
1692 for Space Available notification, it will complete. Note that there is no |
|
1693 guarantee that the amount of space freed up in the pipe will be sufficient |
|
1694 for the next DPipe::Write() operation. |
|
1695 |
|
1696 @param aBuff Buffer to which data need to be written. |
|
1697 @param aSize Size of the data to be read from the pipe. |
|
1698 |
|
1699 @return >0 Amount of data read from the pipe, in octets. |
|
1700 KErrNone The pipe is empty , no data was read from the pipe. |
|
1701 KErrArgument If the amount of data to be read is invalid. |
|
1702 Otherwise one of the system wide error code |
|
1703 @pre iPipeMutex held |
|
1704 @pre iReadMutex held |
|
1705 |
|
1706 @note Read enters and exists with the pipe mutex held - but releases and reaquires internally |
|
1707 */ |
|
1708 { |
|
1709 __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::Read(aBuf=0x%08x, aSize=%d)", aBuf, aSize)); |
|
1710 __ASSERT_MUTEX(iPipeMutex); |
|
1711 __ASSERT_MUTEX(iReadMutex); |
|
1712 |
|
1713 if(aSize < 0) |
|
1714 { |
|
1715 return KErrArgument; |
|
1716 } |
|
1717 |
|
1718 const TInt totalToRead = Min(AvailableDataCount(), aSize); |
|
1719 |
|
1720 |
|
1721 if(totalToRead == 0) |
|
1722 return 0; |
|
1723 |
|
1724 Signal(); |
|
1725 |
|
1726 |
|
1727 //! First half |
|
1728 const TInt distanceToEnd = iSize - iReadPointer; |
|
1729 __NK_ASSERT_DEBUG(distanceToEnd>=0); |
|
1730 const TInt firstHalf = Min(totalToRead, distanceToEnd); |
|
1731 |
|
1732 TPtrC8 pipeBuffer(&iBuffer[iReadPointer], firstHalf); |
|
1733 TDes8* userBuffer = (TDes8*)aBuf; |
|
1734 |
|
1735 DThread* const currThread = &Kern::CurrentThread(); |
|
1736 TInt r = Kern::ThreadDesWrite(currThread, userBuffer, pipeBuffer, 0, KChunkShiftBy0, NULL); |
|
1737 if(r!=KErrNone) |
|
1738 { |
|
1739 Wait(); //we must exit with mutex held |
|
1740 return r; |
|
1741 } |
|
1742 |
|
1743 const TInt secondHalf=totalToRead-firstHalf; |
|
1744 __NK_ASSERT_DEBUG(secondHalf>=0); |
|
1745 if(secondHalf!=0) |
|
1746 { |
|
1747 //! Second half |
|
1748 pipeBuffer.Set(&iBuffer[0], secondHalf); |
|
1749 r = Kern::ThreadDesWrite(currThread, userBuffer, pipeBuffer, firstHalf, KChunkShiftBy0, NULL); |
|
1750 if(r!=KErrNone) |
|
1751 { |
|
1752 Wait(); //we must exit with mutex held |
|
1753 return r; |
|
1754 } |
|
1755 } |
|
1756 __NK_ASSERT_DEBUG(firstHalf+secondHalf==totalToRead); |
|
1757 |
|
1758 Wait(); //Reaquire mutex for state update |
|
1759 |
|
1760 iReadPointer = (iReadPointer + totalToRead)% iSize; |
|
1761 iFull = EFalse; |
|
1762 MaybeCompleteSpaceNotification(); |
|
1763 |
|
1764 __ASSERT_MUTEX(iReadMutex); |
|
1765 return totalToRead; |
|
1766 } |
|
1767 |
|
1768 TInt DPipe::AvailableDataCount() |
|
1769 /** |
|
1770 Returns the Data available in the pipe. |
|
1771 |
|
1772 @param None |
|
1773 |
|
1774 @return TInt Amount of data available in the pipe |
|
1775 |
|
1776 */ |
|
1777 { |
|
1778 __ASSERT_MUTEX(iPipeMutex); |
|
1779 TInt size=-1; |
|
1780 if ( iWritePointer > iReadPointer ) |
|
1781 { |
|
1782 size = iWritePointer - iReadPointer; |
|
1783 } |
|
1784 else if ( iReadPointer > iWritePointer ) |
|
1785 { |
|
1786 size = iSize - iReadPointer + iWritePointer; |
|
1787 } |
|
1788 else |
|
1789 { |
|
1790 //iReadPointer == iWritePointer |
|
1791 size = iFull ? iSize : 0; |
|
1792 } |
|
1793 return size; |
|
1794 } |
|
1795 |
|
1796 TInt DPipe::RegisterSpaceAvailableNotification(TInt aSize) |
|
1797 /** |
|
1798 Registers the request status object to be completed when space becomes |
|
1799 available in the pipe. |
|
1800 |
|
1801 @param aSize The size for which the space availability be notified. |
|
1802 |
|
1803 @return KErrNone Success. |
|
1804 KErrCompletion The request is not registered as it completes immediately |
|
1805 otherwise one of the system wide error code. |
|
1806 @pre Mutex must be held. |
|
1807 @pre Must be in a critical section. |
|
1808 */ |
|
1809 { |
|
1810 __ASSERT_MUTEX(iPipeMutex); |
|
1811 __NK_ASSERT_DEBUG(Rng(1, aSize, iSize)); |
|
1812 |
|
1813 // Check if Specified size is available. |
|
1814 TInt err = KErrNone; |
|
1815 if ((aSize <= (iSize - AvailableDataCount()))) |
|
1816 { |
|
1817 iSpaceAvailableRequest = EFalse; |
|
1818 err = KErrCompletion; |
|
1819 } |
|
1820 else |
|
1821 { |
|
1822 iSpaceAvailableSize = aSize; |
|
1823 iSpaceAvailableRequest = ETrue; |
|
1824 } |
|
1825 return err; |
|
1826 } |
|
1827 |
|
1828 |
|
1829 TInt DPipe::RegisterDataAvailableNotification() |
|
1830 /** |
|
1831 Registers the request status object to be completed when data becomes |
|
1832 available in the pipe. |
|
1833 |
|
1834 @param None |
|
1835 |
|
1836 @return KErrNone If successful, otherwise one of the other system wide |
|
1837 error code. |
|
1838 @pre Mutex must be held. |
|
1839 @pre Must be in a critical section. |
|
1840 */ |
|
1841 { |
|
1842 __ASSERT_MUTEX(iPipeMutex); |
|
1843 |
|
1844 TInt err = KErrNone; |
|
1845 // Check if Data is available. |
|
1846 if(AvailableDataCount()) |
|
1847 { |
|
1848 iDataAvailableRequest = EFalse; |
|
1849 err = KErrCompletion; |
|
1850 } |
|
1851 else |
|
1852 { |
|
1853 iDataAvailableRequest = ETrue; |
|
1854 } |
|
1855 return err; |
|
1856 } |
|
1857 |
|
1858 |
|
1859 TInt DPipe::RegisterWaitNotification(TInt aChoice) |
|
1860 /** |
|
1861 Registers the request status object to be completed when other end of the pipe |
|
1862 is opened for reading. This method completes immediately if the other end of the |
|
1863 pipe is already opened. |
|
1864 |
|
1865 @param None |
|
1866 |
|
1867 @return KErrNone Successfully registered, otherwise one of the other system wide |
|
1868 error code. |
|
1869 @pre Mutex must be held. |
|
1870 @pre Must be in a critical section. |
|
1871 */ |
|
1872 { |
|
1873 __ASSERT_MUTEX(iPipeMutex); |
|
1874 |
|
1875 TInt err = KErrNone; |
|
1876 // Check if Read end is opened |
|
1877 if (aChoice == RPipe::EWaitForReader) |
|
1878 { |
|
1879 if(IsReadEndOpened()) |
|
1880 { |
|
1881 iWaitRequest = EFalse; |
|
1882 err = KErrCompletion; |
|
1883 } |
|
1884 else |
|
1885 { |
|
1886 iWaitRequest = ETrue; |
|
1887 } |
|
1888 |
|
1889 } |
|
1890 else |
|
1891 { |
|
1892 if(IsWriteEndOpened()) |
|
1893 { |
|
1894 iWaitRequest = EFalse; |
|
1895 err = KErrCompletion; |
|
1896 } |
|
1897 else |
|
1898 { |
|
1899 iWaitRequest = ETrue; |
|
1900 } |
|
1901 } |
|
1902 |
|
1903 return err; |
|
1904 } |
|
1905 |
|
1906 |
|
1907 //! Cancellation methods |
|
1908 void DPipe::CancelSpaceAvailable() |
|
1909 /** |
|
1910 Cancels an outstanding space available notifier request. |
|
1911 |
|
1912 @param None |
|
1913 |
|
1914 @return None |
|
1915 */ |
|
1916 { |
|
1917 __ASSERT_MUTEX(iPipeMutex); |
|
1918 if(iSpaceAvailableRequest) |
|
1919 iSpaceAvailableRequest = EFalse; |
|
1920 } |
|
1921 |
|
1922 |
|
1923 void DPipe::CancelDataAvailable() |
|
1924 /** |
|
1925 Cancels an outstanding data available notifier request. |
|
1926 |
|
1927 @param None |
|
1928 |
|
1929 @return None |
|
1930 */ |
|
1931 { |
|
1932 __ASSERT_MUTEX(iPipeMutex); |
|
1933 if(iDataAvailableRequest) |
|
1934 iDataAvailableRequest = EFalse; |
|
1935 } |
|
1936 |
|
1937 |
|
1938 void DPipe::CancelWaitNotifier() |
|
1939 /** |
|
1940 Cancel an outstanding wait notifier request |
|
1941 |
|
1942 @param None |
|
1943 |
|
1944 @return KErrNone If Successful, otherwise one of the other system wide error code. |
|
1945 |
|
1946 */ |
|
1947 { |
|
1948 __ASSERT_MUTEX(iPipeMutex); |
|
1949 // Cancel Wait Notifier request |
|
1950 if(iWaitRequest) |
|
1951 iWaitRequest = EFalse; |
|
1952 } |
|
1953 |
|
1954 |
|
1955 void DPipe::CloseAll() |
|
1956 /** |
|
1957 Cancel any outstanding request. |
|
1958 |
|
1959 @param None |
|
1960 |
|
1961 @return None |
|
1962 */ |
|
1963 { |
|
1964 CancelSpaceAvailable(); |
|
1965 CancelDataAvailable(); |
|
1966 CancelWaitNotifier(); |
|
1967 |
|
1968 CloseWriteEnd(); |
|
1969 CloseReadEnd(); |
|
1970 } |
|
1971 |
|
1972 |
|
1973 TInt DPipe::CloseReadEnd() |
|
1974 /** |
|
1975 Close the read end of the pipe. |
|
1976 |
|
1977 Cancels outstanding requests placed by the *write* |
|
1978 channel and clears pipe's pointer to the read channel. |
|
1979 If this function is called then the read channel's back |
|
1980 pointer to the pipe must also be cleared. |
|
1981 |
|
1982 @param None |
|
1983 |
|
1984 @return KErrNone If the end is closed, else one of the other system |
|
1985 wide error code |
|
1986 */ |
|
1987 { |
|
1988 __ASSERT_MUTEX(iPipeMutex); |
|
1989 __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::CloseReadEnd ID=%d, iReadChannel=0x%08x", OpenId(), iReadChannel)); |
|
1990 |
|
1991 if (!iReadChannel) |
|
1992 return KErrCouldNotDisconnect; |
|
1993 else |
|
1994 { |
|
1995 if(iWriteChannel) |
|
1996 { |
|
1997 iWriteChannel->CancelRequest(RPipe::ECancelSpaceAvailable); |
|
1998 } |
|
1999 iReadChannel = NULL; |
|
2000 } |
|
2001 return KErrNone; |
|
2002 } |
|
2003 |
|
2004 |
|
2005 TInt DPipe::CloseWriteEnd() |
|
2006 /** |
|
2007 Close the write end of the pipe |
|
2008 |
|
2009 Cancels outstanding requests placed by the *read* |
|
2010 channel and clears pipe's pointer to the write channel. |
|
2011 If this function is called then the write channel's back |
|
2012 pointer to the pipe must also be cleared. |
|
2013 |
|
2014 @param None |
|
2015 |
|
2016 @return KErrNone If the write end is successfully closed, else |
|
2017 one of the other system wide error code. |
|
2018 */ |
|
2019 { |
|
2020 __ASSERT_MUTEX(iPipeMutex); |
|
2021 __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::CloseWriteEnd ID=%d, iWriteChannel=0x%08x", OpenId(), iWriteChannel)); |
|
2022 |
|
2023 if (!iWriteChannel) |
|
2024 return KErrCouldNotDisconnect; |
|
2025 else |
|
2026 { |
|
2027 // Cancel RBlocking call if it is there |
|
2028 if(iReadChannel) |
|
2029 { |
|
2030 iReadChannel->CancelRequest(RPipe::ECancelDataAvailable); |
|
2031 } |
|
2032 iWriteChannel = NULL; |
|
2033 } |
|
2034 return KErrNone; |
|
2035 } |
|
2036 |
|
2037 |
|
2038 |
|
2039 void DPipe::FlushPipe() |
|
2040 /** |
|
2041 Flush all the date from the pipe and reinitialise the buffer pointer. |
|
2042 |
|
2043 @param None |
|
2044 |
|
2045 @return None |
|
2046 |
|
2047 @pre Pipe Mutex to be held |
|
2048 @pre Read Mutex to be held |
|
2049 |
|
2050 */ |
|
2051 { |
|
2052 __ASSERT_MUTEX(iPipeMutex); |
|
2053 __ASSERT_MUTEX(iReadMutex); |
|
2054 |
|
2055 iReadPointer = iWritePointer; |
|
2056 iFull = EFalse; |
|
2057 |
|
2058 MaybeCompleteSpaceNotification(); |
|
2059 } |
|
2060 |
|
2061 /** |
|
2062 If there is an outstanding space request, and |
|
2063 there is enough space to satisfy it then complete |
|
2064 and clear request. |
|
2065 |
|
2066 @pre the pipe mutex must be held |
|
2067 */ |
|
2068 void DPipe::MaybeCompleteSpaceNotification() |
|
2069 { |
|
2070 __ASSERT_MUTEX(iPipeMutex); |
|
2071 |
|
2072 // Check if there is writeblocking request |
|
2073 if(iSpaceAvailableRequest) |
|
2074 { |
|
2075 const TInt spacecount = (iSize - AvailableDataCount()); |
|
2076 if (iSpaceAvailableSize <= spacecount) |
|
2077 { |
|
2078 iWriteChannel->DoRequestCallback(); |
|
2079 iSpaceAvailableRequest = EFalse; |
|
2080 } |
|
2081 } |
|
2082 } |
|
2083 |
|
2084 TBool DPipe::IsReadEndOpened() |
|
2085 /** |
|
2086 Returns information regarding the read end of the current pipe instance. |
|
2087 |
|
2088 @return TBool ETrue if read end is Opened, otherwise EFalse |
|
2089 @pre the pipe mutex must be held |
|
2090 */ |
|
2091 { |
|
2092 __ASSERT_MUTEX(iPipeMutex); |
|
2093 return (iReadChannel != NULL); |
|
2094 } |
|
2095 |
|
2096 |
|
2097 TBool DPipe::IsWriteEndOpened() |
|
2098 /** |
|
2099 Returns information regarding the write end of the current pipe instance. |
|
2100 |
|
2101 @return TBool ETrue if WriteChannel is opened, otherwise EFalse |
|
2102 @pre the pipe mutex must be held |
|
2103 */ |
|
2104 { |
|
2105 __ASSERT_MUTEX(iPipeMutex); |
|
2106 return (iWriteChannel != NULL); |
|
2107 } |
|
2108 |
|
2109 |
|
2110 TBool DPipe::IsNamedPipe() |
|
2111 /** |
|
2112 Returns whether the pipe is named or unnamed. |
|
2113 |
|
2114 @return TBool ETrue if it is a named pipe, otherwise EFalse |
|
2115 |
|
2116 */ |
|
2117 { |
|
2118 return (iName.Length() != 0); |
|
2119 } |
|
2120 |
|
2121 |
|
2122 void DPipe::SetReadEnd(DPipeChannel* aChannel) |
|
2123 /** |
|
2124 Set the Read end of the pipe as opened and store the pointer for the read channel |
|
2125 It also notify if there is any pending Wait Request. |
|
2126 |
|
2127 @param aChannel The pointer to the read channel |
|
2128 |
|
2129 @pre the pipe mutex must be held |
|
2130 @pre The pipe's read end must be closed ie. IsReadEndOpened returns false |
|
2131 */ |
|
2132 { |
|
2133 __ASSERT_MUTEX(iPipeMutex); |
|
2134 __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::SetReadEnd ID=%d", OpenId())); |
|
2135 |
|
2136 |
|
2137 //A channel must be sure this function |
|
2138 //succeeded otherwise the pipe |
|
2139 //could be destroyed without the channel's |
|
2140 //knowledge |
|
2141 __NK_ASSERT_DEBUG(iReadChannel==NULL); |
|
2142 |
|
2143 iReadChannel = aChannel; |
|
2144 __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::SetReadEnd set iReadChannel=0x%08x", iReadChannel)); |
|
2145 |
|
2146 if(iWaitRequest) |
|
2147 { |
|
2148 if(iWriteChannel) |
|
2149 iWriteChannel->DoRequestCallback(); |
|
2150 iWaitRequest=EFalse; |
|
2151 } |
|
2152 } |
|
2153 |
|
2154 |
|
2155 void DPipe::SetWriteEnd(DPipeChannel* aChannel) |
|
2156 /** |
|
2157 Set the write end of the pipe as opened and store the pointer to the write channel |
|
2158 |
|
2159 @param aChannel The pointer to the write channel |
|
2160 |
|
2161 |
|
2162 @pre the pipe mutex must be held |
|
2163 @pre The pipe's write end must be closed ie. IsWriteEndOpened returns false |
|
2164 */ |
|
2165 { |
|
2166 __ASSERT_MUTEX(iPipeMutex); |
|
2167 __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::SetWriteEnd ID=%d", OpenId())); |
|
2168 |
|
2169 //A channel must be sure this function |
|
2170 //succeeded otherwise the pipe |
|
2171 //could be destroyed without the channel's |
|
2172 //knowledge |
|
2173 __NK_ASSERT_DEBUG(iWriteChannel==NULL); |
|
2174 |
|
2175 iWriteChannel = aChannel; |
|
2176 __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::SetWriteEnd set iWriteChannel=0x%08x", iWriteChannel)); |
|
2177 |
|
2178 if(iWaitRequest) |
|
2179 { |
|
2180 if(iReadChannel) |
|
2181 iReadChannel->DoRequestCallback(); |
|
2182 iWaitRequest=EFalse; |
|
2183 } |
|
2184 } |
|
2185 |
|
2186 TInt DPipe::Size() |
|
2187 /** |
|
2188 @return The size of the pipe's circular buffer |
|
2189 */ |
|
2190 { |
|
2191 //this could be const |
|
2192 return iSize; |
|
2193 } |
|
2194 |