1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/pipe/dpipe.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,2194 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +
1.20 +#include <kernel/kern_priv.h>
1.21 +#include "dpipe.h"
1.22 +
1.23 +//_LIT(KPipePanicCategory,"PipePanic");
1.24 +const TInt KPipeGranularity = 8;
1.25 +
1.26 +DECLARE_STANDARD_LDD()
1.27 +/**
1.28 +Standard export function for LDDs. This creates a DLogicalDevice derived
1.29 +object, in this case our DPipeDevice
1.30 +*/
1.31 + {
1.32 + return new DPipeDevice;
1.33 + }
1.34 +
1.35 +DPipeDevice::DPipeDevice()
1.36 +/**
1.37 +DPipeDevice Constructor has minimal implementation such setting the version number
1.38 +Indicate the use of unit number
1.39 +
1.40 +@param None
1.41 +
1.42 +@return None
1.43 +*/
1.44 + {
1.45 + iCount = 0;
1.46 + iIdindex = 0;
1.47 + iAllocated = 0;
1.48 + iVersion = RPipe::VersionRequired();
1.49 + }
1.50 +
1.51 +
1.52 +DPipeDevice::~DPipeDevice()
1.53 + {
1.54 + // Delete the existing pipes
1.55 + for(TInt count = 0; count<iCount; count++)
1.56 + {
1.57 + DPipe* pipe=iDpipes[count];
1.58 + pipe->Wait();
1.59 + pipe->CloseAll();
1.60 + delete pipe;
1.61 + }
1.62 + Kern::Free(iDpipes);
1.63 + iMutex->Close(NULL);
1.64 + }
1.65 +
1.66 +
1.67 +TInt DPipeDevice::Install()
1.68 +/**
1.69 +Second stage constructor and at least set a name for the
1.70 +driver object. Inherited from DLogicalDevice. This must at least set a name
1.71 +for the driver object.
1.72 +
1.73 +@param None
1.74 +
1.75 +@return KErrNone If successful, otherwise one of the system wide error codes.
1.76 +*/
1.77 + {
1.78 + _LIT(KMutexName,"PipeDeviceMutex");
1.79 + TInt err = Kern::MutexCreate(iMutex, KMutexName, KMutexOrdGeneral1);
1.80 + if (err)
1.81 + {
1.82 + return err;
1.83 + }
1.84 +
1.85 + return SetName(&RPipe::Name());
1.86 + }
1.87 +
1.88 +
1.89 +void DPipeDevice::GetCaps(TDes8& aDes) const
1.90 +/**
1.91 +Returns the driver capabilities. Called in the response to
1.92 +an RPipe::GetCaps() request
1.93 +
1.94 +@param aDes Descriptor into which capabilities information
1.95 + is to be written
1.96 +@return None
1.97 +*/
1.98 + {
1.99 + // Write it back to user memory
1.100 + TVersion version;
1.101 + version = iVersion;
1.102 + Kern::InfoCopy(aDes,(TUint8*)&version, sizeof(version));
1.103 + }
1.104 +
1.105 +
1.106 +TInt DPipeDevice::Create(DLogicalChannelBase*& aChannel)
1.107 +/**
1.108 +Called by the kernel's device driver framework to create a Logical Channel.
1.109 +This is called in the context of the user thread (client) which requested the
1.110 +creation of the Logical Channel.
1.111 +
1.112 + @param aChannel Set to point to the created logical channel
1.113 +
1.114 + @return KErrNone If successful, otherwise system one of the other
1.115 + wide error codes.
1.116 + */
1.117 + {
1.118 + aChannel = new DPipeChannel;
1.119 + if (!aChannel)
1.120 + return KErrNoMemory;
1.121 + return KErrNone;
1.122 + }
1.123 +
1.124 +
1.125 +TInt DPipeDevice::CreatePipe(const TDesC& aName, TInt aSize, DPipe*& aPipe, TAny* aCap)
1.126 +/**
1.127 +Called by DPipeChannel instance to create named DPipe object and
1.128 +associate itself with the newly created named DPipe instance.
1.129 +
1.130 +@param aName name need to be attached to the newly created DPipe object.
1.131 +@param aSize size of the DPipe object.
1.132 +@param aPipe Pointer to DPipe, If successful set the pointer to newly created DPipe instance else NULL
1.133 +@param aCap Pointer to TSecuritypolicy passed as void pointer
1.134 +
1.135 +@return KErrNone If successful, otherwise one of the other system wide error code
1.136 +@pre Calling thread must be in a critical section.
1.137 +@pre Mutex must be held
1.138 +*/
1.139 + {
1.140 + __ASSERT_MUTEX(iMutex);
1.141 + __KTRACE_OPT(KPIPE, Kern::Printf(">DPipeDevice::CreatePipe"));
1.142 + TInt err = KErrNone;
1.143 + DPipe** pS = iDpipes;
1.144 + DPipe** pE = pS + iCount;
1.145 + while(pS < pE)
1.146 + {
1.147 + DPipe* pO = *pS++;
1.148 + if((pO->MatchName(&aName)))
1.149 + {
1.150 + err = KErrAlreadyExists;
1.151 + break;
1.152 + }
1.153 + }
1.154 + if(err == KErrNone)
1.155 + {
1.156 + DPipe* pipe = DPipe::CreatePipe(aName, aSize, aCap);
1.157 + if(pipe)
1.158 + {
1.159 + err = AddPipe(pipe);
1.160 + if(err!= KErrNone)
1.161 + {
1.162 + delete pipe;
1.163 + }
1.164 + else
1.165 + {
1.166 + aPipe = pipe;
1.167 + }
1.168 + }
1.169 + else
1.170 + {
1.171 + err = KErrNoMemory;
1.172 + }
1.173 + }
1.174 + __KTRACE_OPT(KPIPE, Kern::Printf("<DPipeDevice::CreatePipe ret=%d", err));
1.175 + return err;
1.176 + }
1.177 +
1.178 +
1.179 +DPipe* DPipeDevice::CreatePipe(TInt aSize)
1.180 +/**
1.181 +Called by DPipeChannel instance to create un-named DPipe instance and
1.182 +associate itself with the newly created un-named DPipe instance.
1.183 +
1.184 +@param aSize size of the DPipe object.
1.185 +
1.186 +@return DPipe* If successful, otherwise NULL
1.187 +@pre Mutex must be held
1.188 +@pre In critical section
1.189 +*/
1.190 + {
1.191 + __ASSERT_CRITICAL;
1.192 + __ASSERT_MUTEX(iMutex);
1.193 + TKName aName;
1.194 + DPipe* pipe = DPipe::CreatePipe(aName, aSize);
1.195 + if(!pipe)
1.196 + {
1.197 + return NULL;
1.198 + }
1.199 +
1.200 + TInt r = AddPipe(pipe);
1.201 + if (r != KErrNone)
1.202 + {
1.203 + delete pipe;
1.204 + return NULL;
1.205 + }
1.206 + return pipe;
1.207 + }
1.208 +
1.209 +
1.210 +
1.211 +TInt DPipeDevice::AddPipe(DPipe* aObj)
1.212 +/**
1.213 +Add an instance of Dpipe to the array.
1.214 +@param aObj Pointer to DPipe object
1.215 +@return KErrNone If the call is successful otherwise one of the other
1.216 + system wide error code.
1.217 +
1.218 +@pre Calling thread must be in a critical section.
1.219 +@pre Mutex to be held
1.220 +*/
1.221 + {
1.222 + __ASSERT_CRITICAL; //otherwise iDPipes and iCount could go out of sync
1.223 + __ASSERT_MUTEX(iMutex);
1.224 + // store the current instance to the array
1.225 + if(iCount == iAllocated)
1.226 + {
1.227 + TInt newAlloc = iAllocated + KPipeGranularity;
1.228 + TInt r = Kern::SafeReAlloc((TAny*&)iDpipes, iCount * sizeof(DPipe*), newAlloc * sizeof(DPipe*));
1.229 + if (r!= KErrNone)
1.230 + {
1.231 + return r;
1.232 + }
1.233 + iAllocated = newAlloc;
1.234 + }
1.235 + TInt id = GenerateId();
1.236 + aObj->SetId(id);
1.237 + iDpipes[iCount++]= aObj;
1.238 +
1.239 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::AddPipe Pipe added ID=%d", id));
1.240 + return KErrNone;
1.241 + }
1.242 +
1.243 +
1.244 +
1.245 +void DPipeDevice::RemovePipe(DPipe** aObj)
1.246 +/**
1.247 +Remove an instance of DPipe from the array
1.248 +
1.249 +@param Pointer to Dpipe Array
1.250 +
1.251 +@return None
1.252 +
1.253 +@pre Calling thread must not be in a critical section.
1.254 +@pre Mutex to be held
1.255 +*/
1.256 + {
1.257 + __ASSERT_MUTEX(iMutex);
1.258 + __ASSERT_CRITICAL; //we don't want to leave the array inconsistant
1.259 +
1.260 + DPipe** pE = (iDpipes + iCount) - 1;
1.261 + if(aObj<pE)
1.262 + {
1.263 + //bump along array elements to close the gap
1.264 + wordmove((TAny*)aObj, (TAny*)(aObj+1), TInt(pE)- TInt(aObj));
1.265 + }
1.266 + --iCount;
1.267 + if(iCount % KPipeGranularity == 0)
1.268 + {
1.269 + Kern::SafeReAlloc((TAny*&)iDpipes, iAllocated*sizeof(DPipe*), iCount* sizeof(DPipe*));
1.270 + iAllocated = iCount;
1.271 + }
1.272 + }
1.273 +
1.274 +
1.275 +DPipe* DPipeDevice::FindNamedPipe(const TDesC* aName)
1.276 +/**
1.277 +Called by the DPipeChannel to check if a named DPipe instance exist with a name
1.278 +as specified by aName parameter.
1.279 +
1.280 +@param aName The name of the DPipe instance to search for.
1.281 +
1.282 +@return DPipe* If successful, otherwise NULL
1.283 +
1.284 +@pre Device mutex to be held
1.285 +*/
1.286 + {
1.287 + __ASSERT_MUTEX(iMutex);
1.288 + DPipe** pS = iDpipes;
1.289 + DPipe** pE = pS + iCount;
1.290 +
1.291 + while(pS < pE)
1.292 + {
1.293 + DPipe* pO = *pS++;
1.294 + if(pO->MatchName(aName))
1.295 + {
1.296 + return pO;
1.297 + }
1.298 + }
1.299 + return NULL;
1.300 + }
1.301 +
1.302 +DPipe* DPipeDevice::FindUnnamedPipe(const TInt aId)
1.303 +/**
1.304 +Called by the DPipeChannel to check if an un-named DPipe instance exist with an ID
1.305 +as specified by aId parameter.
1.306 +
1.307 +@param aId The ID of the DPipe instance to search for.
1.308 +
1.309 +@return DPipe* If successful, otherwise NULL
1.310 +@pre Device mutex to be held
1.311 +*/
1.312 + {
1.313 + __ASSERT_MUTEX(iMutex);
1.314 + DPipe** pS = iDpipes;
1.315 + DPipe** pE = pS + iCount;
1.316 + while(pS < pE)
1.317 + {
1.318 + DPipe* pO = *pS++;
1.319 + if(pO->MatchId(aId))
1.320 + {
1.321 + return pO;
1.322 + }
1.323 + }
1.324 + return NULL;
1.325 + }
1.326 +
1.327 +TInt DPipeDevice::Destroy(const TDesC* aName)
1.328 +/**
1.329 +This method is called to destroy a named DPipe instance. The caller needs to have
1.330 +sufficient capabilities to delete a named pipe. This method will fail if there are
1.331 +any handles still open on the pipe.
1.332 +
1.333 +@param aName Name of the DPipe instance to be deleted.
1.334 +
1.335 +@return KErrNone If successful, otherwise one of the other system wide error.
1.336 +
1.337 +*/
1.338 + {
1.339 + TAutoWait<DMutex> autoMutex(*iMutex);
1.340 + DPipe** pS = iDpipes;
1.341 + DPipe** pE = pS + iCount;
1.342 + TInt err = KErrNotFound;
1.343 + TInt count = 0;
1.344 + while(pS < pE)
1.345 + {
1.346 + DPipe** pO = pS++;
1.347 + DPipe* pipe = *pO;
1.348 + if(((*pO)->MatchName(aName)))
1.349 + {
1.350 + //! Check capability
1.351 + if(pipe->GetCap())
1.352 + {
1.353 + if(!(pipe->GetCap()->CheckPolicy(&Kern::CurrentThread())))
1.354 + {
1.355 + err = KErrPermissionDenied;
1.356 + break;
1.357 + }
1.358 + }
1.359 + // Check if any handles still opened on the pipe.
1.360 + pipe->Wait();
1.361 + if (!pipe->IsPipeClosed())
1.362 + {
1.363 + err = KErrInUse;
1.364 + pipe->Signal(); //need to signal if we won't be destroying pipe
1.365 + break;
1.366 + }
1.367 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Destroy remove ID=%d", pipe->OpenId()));
1.368 + delete iDpipes[count];
1.369 + RemovePipe(pO);
1.370 + err = KErrNone;
1.371 + break;
1.372 + }
1.373 + count ++;
1.374 + }
1.375 + return err;
1.376 + }
1.377 +
1.378 +
1.379 +TInt DPipeDevice::Close(TInt aId)
1.380 +/**
1.381 +This method is called to close both named and un-named DPipe. In case of un-named DPipe
1.382 +if there is no further reference of a DPipeChannel exist, the corresponding un-named DPipe
1.383 +will be deleted.
1.384 +
1.385 +@param aId ID of the pipe that need to be closed.
1.386 +
1.387 +@return KErrNone If successful otherwise one of the other system wide error.
1.388 +
1.389 +*/
1.390 + {
1.391 + TAutoWait<DMutex> autoMutex(*iMutex);
1.392 + DPipe** pS = iDpipes;
1.393 + DPipe** pE = pS + iCount;
1.394 + TInt err = KErrNotFound;
1.395 + while(pS < pE)
1.396 + {
1.397 + DPipe** pO = pS++;
1.398 + DPipe* pipe = *pO;
1.399 + if(pipe->MatchId(aId))
1.400 + {
1.401 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Close found ID=%d", pipe->OpenId()));
1.402 + //even if we can't delete the pipe, we have
1.403 + //found it so don't return KErrNotFound
1.404 + err = KErrNone;
1.405 +
1.406 + pipe->Wait();
1.407 +
1.408 + // we can only delete an unamed pipe with both ends closed
1.409 + if(!pipe->IsNamedPipe() && pipe->IsPipeClosed())
1.410 + {
1.411 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Close remove ID=%d", pipe->OpenId()));
1.412 + delete pipe;
1.413 + RemovePipe(pO);
1.414 + break;
1.415 + }
1.416 + pipe->Signal();
1.417 +
1.418 + }
1.419 + }
1.420 + return err;
1.421 + }
1.422 +
1.423 +
1.424 +
1.425 +TInt DPipeDevice::GenerateId()
1.426 +/**
1.427 +Generate a ID and store for a Named pipe while creating.
1.428 +
1.429 +@param None
1.430 +@return TInt ID for the name pipe
1.431 +
1.432 +@pre Mutex to be held
1.433 +
1.434 +*/
1.435 + {
1.436 + __ASSERT_MUTEX(iMutex);
1.437 + iIdindex++;
1.438 + return (KIdBase + iIdindex);
1.439 + }
1.440 +
1.441 +
1.442 +DPipeChannel::DPipeChannel()
1.443 + :iClientRequest(NULL), iData(NULL), iChannelType(RPipe::EChannelUnset)
1.444 +/**
1.445 +Constructor
1.446 +*/
1.447 + {
1.448 + }
1.449 +
1.450 +
1.451 +DPipeChannel::~DPipeChannel()
1.452 +/**
1.453 +Destructor
1.454 +*/
1.455 + {
1.456 + CloseHandle();
1.457 +
1.458 + Kern::DestroyClientRequest(iClientRequest); //null ptr is safe
1.459 + }
1.460 +
1.461 +
1.462 +
1.463 +TInt DPipeChannel::RequestUserHandle (DThread* aThread, TOwnerType aType)
1.464 +/**
1.465 +Inherited from DObject. This method is called when a user thread requests
1.466 +a handle to this channel. Minimal implantation here is capability check
1.467 +
1.468 +@param aThread DThread instance reference that requests a handle to this channel.
1.469 +@param aType Ownership type for the handle.
1.470 +
1.471 +@return KErrNone If successful otherwise one the system wide error.
1.472 +*/
1.473 + {
1.474 + (void)aThread;
1.475 + (void)aType;
1.476 + return KErrNone;
1.477 + }
1.478 +
1.479 +
1.480 +
1.481 +TInt DPipeChannel::DoCreate (TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
1.482 +/**
1.483 +Inherited from DLogicalChannelBase class. This method represents the second stage
1.484 +constructor called by the kernel's device driver framework. This is called in the
1.485 +context of the user thread (client) which requested the creation of the Logical
1.486 +Channel. The thread is in critical section.
1.487 +
1.488 +@param aUnit The unit argument supplied by the client
1.489 +@param aInfo The info argument supplied by the client
1.490 +@param aVer The version argument supplied by the client
1.491 +
1.492 +@return KErrNone If successful, otherwise one of the other system wide error codes.
1.493 +*/
1.494 + {
1.495 + (void)aInfo;
1.496 + (void)aUnit;
1.497 +
1.498 + // Check version
1.499 + if (!Kern::QueryVersionSupported(RPipe::VersionRequired(),aVer))
1.500 + return KErrNotSupported;
1.501 +
1.502 + TInt r = Kern::CreateClientRequest(iClientRequest);
1.503 + if(r != KErrNone)
1.504 + {
1.505 + return r;
1.506 + }
1.507 +
1.508 + // Done
1.509 + return KErrNone;
1.510 + }
1.511 +
1.512 +
1.513 +TInt DPipeChannel::Request(TInt aReqNo, TAny* a1, TAny* a2)
1.514 +/**
1.515 +Called by the Device driver framework upon user request. Stores the
1.516 +Thread pointer under whose context this function is called.
1.517 +
1.518 +@param aFunction A number identifying the message type
1.519 +@param a1 A 32-bit Value passed by the user
1.520 +@param a2 A 32-bit Value passed by the user
1.521 +
1.522 +@return KErrNone If successful, otherwise one of the system wide error code
1.523 +
1.524 +*/
1.525 + {
1.526 + TInt err = KErrNone;
1.527 +
1.528 + DATAPAGING_TEST
1.529 + (
1.530 + err = Kern::HalFunction(EHalGroupVM, EVMHalFlushCache, 0, 0);
1.531 + if(err != KErrNone)
1.532 + {
1.533 + return err;
1.534 + }
1.535 + )
1.536 +
1.537 + if(aReqNo == KMaxTInt)
1.538 + {
1.539 + CancelRequest((TInt)a1);
1.540 + return err;
1.541 + }
1.542 + if(aReqNo < 0)
1.543 + {
1.544 + // DoRequest
1.545 + TAny *array[2] = {0,0};
1.546 + TRequestStatus * pStat = (TRequestStatus*)a1;
1.547 + kumemget32(&array[0], a2, 2*sizeof(TAny*));
1.548 + err = DoRequest(~aReqNo, pStat, array[0], array[1]);
1.549 + if(err!= KErrNone)
1.550 + Kern::RequestComplete(pStat, err);
1.551 +
1.552 + }
1.553 + else
1.554 + {
1.555 + // DoControl
1.556 + err = DoControl(aReqNo, a1, a2);
1.557 + }
1.558 + return err;
1.559 + }
1.560 +
1.561 +
1.562 +TInt DPipeChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
1.563 +/**
1.564 +Processes Synchronous 'control' requests. This function is called to service
1.565 +any synchronous calls through the user side RPipe handle.
1.566 +
1.567 +@param aFunction A number identifying the message type
1.568 +@param a1 A 32-bit Value passed by the user
1.569 +@param a2 A 32-bit Value passed by the user
1.570 +
1.571 +@return KErrNone If the call is successful, otherwise one of the other
1.572 + system wide error
1.573 +*/
1.574 + {
1.575 + TInt aSize = 0;
1.576 + TInt aId = 0;
1.577 +
1.578 + switch(aFunction)
1.579 + {
1.580 + case RPipe::EDefineNamedPipe:
1.581 + return PipeCreate(a1, a2);
1.582 +
1.583 + case RPipe::EOpenToReadNamedPipe:
1.584 + return PipeOpen((const TDesC*)a1, RPipe::EReadChannel);
1.585 +
1.586 + case RPipe::EOpenToWriteNamedPipe:
1.587 + return PipeOpen((const TDesC*)a1, RPipe::EWriteChannel);
1.588 +
1.589 + case RPipe::EOpenToWriteButFailOnNoReaderNamedPipe:
1.590 + return OpenOnReader((const TDesC*)a1);
1.591 +
1.592 + case RPipe::EDestroyNamedPipe:
1.593 + return PipeDestroy((const TDesC*)a1);
1.594 +
1.595 + case RPipe::ECreateUnNamedPipe:
1.596 + kumemget((TAny*)&aSize, a1, sizeof(TInt));
1.597 + return PipeCreate( aSize);
1.598 +
1.599 + case RPipe::EOpenUnNamedPipe:
1.600 + kumemget((TAny*)&aId, a1, sizeof(TInt));
1.601 + return PipeOpen(aId);
1.602 +
1.603 + case RPipe::ERead:
1.604 + kumemget((TAny*)&aSize, a2, sizeof(TInt));
1.605 + return Read (a1, aSize);
1.606 +
1.607 + case RPipe::EWrite:
1.608 + kumemget((TAny*)&aSize, a2, sizeof(TInt));
1.609 + return Write (a1, aSize);
1.610 +
1.611 + case RPipe::ESize:
1.612 + return Size();
1.613 +
1.614 + case RPipe::EDataAvailableCount:
1.615 + {
1.616 + TAutoWait<DMutex> autoMutex(iData->Mutex());
1.617 + return iData->AvailableDataCount();
1.618 + }
1.619 +
1.620 + case RPipe::EFlushPipe:
1.621 + Flush();
1.622 + return KErrNone;
1.623 +
1.624 + case RPipe::EGetPipeInfo:
1.625 + umemput(a1,(TAny*)&iChannelType, sizeof(TInt));
1.626 + aSize = Size();
1.627 + umemput(a2,(TAny*)&aSize, sizeof(TInt));
1.628 + return KErrNone;
1.629 +
1.630 +
1.631 + default:
1.632 + return KErrNotSupported;
1.633 +
1.634 + }
1.635 +
1.636 + }
1.637 +
1.638 +
1.639 +TInt DPipeChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
1.640 +/**
1.641 +Processes Asynchronous requests This function is called to service
1.642 +any asynchronous calls through the user side RPipe handle.
1.643 +
1.644 +@param aFunction A number identifying the message type
1.645 +@param aStatus Status request to be completed.
1.646 +@param a1 A 32-bit Value passed by the user
1.647 +@param a2 A 32-bit Value passed by the user
1.648 +
1.649 +@return KErrNone If the call is successful, else one of the system wide error
1.650 +*/
1.651 + {
1.652 + (void)a2;
1.653 + TInt aSize = 0;
1.654 + TInt aChoice = 0;
1.655 +
1.656 + switch(aReqNo)
1.657 + {
1.658 + case RPipe::EDataAvailable:
1.659 + return NotifyDataAvailable(aStatus, ETrue);
1.660 +
1.661 + case RPipe::ESpaceAvailable:
1.662 + umemget(&aSize, a1, sizeof(aSize));
1.663 + return NotifySpaceAvailable(aSize, aStatus, ETrue);
1.664 +
1.665 + case RPipe::EWaitNotification:
1.666 + // a2 == RPipe::EWaitForReader is for WaitForReader.
1.667 + // a2 == RPipe::EWaitForWriter is for WaitForWriter.
1.668 + umemget(&aChoice, a2, sizeof(aChoice));
1.669 + return WaitNotification(aStatus, a1, aChoice);
1.670 +
1.671 + case RPipe::EReadBlocking:
1.672 + {
1.673 + return NotifyDataAvailable(aStatus, EFalse);
1.674 + }
1.675 +
1.676 + case RPipe::EWriteBlocking:
1.677 + {
1.678 + umemget(&aSize, a1, sizeof(aSize));
1.679 + return NotifySpaceAvailable(aSize, aStatus, EFalse);
1.680 + }
1.681 + default:
1.682 + return KErrNotSupported;
1.683 + }
1.684 + }
1.685 +
1.686 +
1.687 +
1.688 +TInt DPipeChannel::PipeCreate(TAny* a1, TAny* a2)
1.689 +/**
1.690 +Creates named pipes with the specified name and size. It calls Pipe Device
1.691 +object to create the pipe and obtained the pointer to it. The pointer is then
1.692 +stored in its iData member data.
1.693 +@param a1 Pointer to TPipeInfo class
1.694 +
1.695 +@param a2 Pointer to TSecurityPolicy class
1.696 +
1.697 +@return KErrNone If successful, otherwise one of the other system wide error code.
1.698 +*/
1.699 + {
1.700 + if(iData)
1.701 + {
1.702 + //this channel already has a pipe
1.703 + return KErrInUse;
1.704 + }
1.705 +
1.706 + // The following code safely gets the 3 arguments into kernel memory.
1.707 + // (The user side API is badly designed,)
1.708 + RPipe::TPipeInfo& info = (*(RPipe::TPipeInfoBuf*)a1)(); // reference to user side 'TPipeInfo'
1.709 + TInt size;
1.710 + kumemget(&size,&info.isize,sizeof(size));
1.711 + TKName name;
1.712 + Kern::KUDesGet(name,info.iName);
1.713 + TSecurityPolicy* securityPolicy = 0;
1.714 + TSecurityPolicy securityPolicyBuffer;
1.715 + if(a2)
1.716 + {
1.717 + kumemget(&securityPolicyBuffer,a2,sizeof(securityPolicyBuffer));
1.718 + securityPolicy = &securityPolicyBuffer;
1.719 + }
1.720 +
1.721 + DPipe * pipe = NULL;
1.722 + DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
1.723 +
1.724 + //must wait on device since after creation
1.725 + //the pipe becomes globably findable
1.726 + //and destroyable
1.727 + TAutoWait<DMutex> outerAutoMutex(device.Mutex());
1.728 +
1.729 + TInt err = ((DPipeDevice*)iDevice)->CreatePipe(name, size, pipe, securityPolicy);
1.730 + if(err!= KErrNone)
1.731 + {
1.732 + return err;
1.733 + }
1.734 +
1.735 + TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
1.736 + pipe->SetReadEnd(this);
1.737 + iData = pipe;
1.738 + iChannelType = RPipe::EReadChannel;
1.739 + return err;
1.740 + }
1.741 +
1.742 +
1.743 +TInt DPipeChannel::PipeCreate(const TInt aSize)
1.744 +/**
1.745 +Creates unnamed pipes with the specified Id and size. It calls Pipe Device
1.746 +object to create the pipe and obtained the pointer to it. The pointer is then
1.747 +stored in its iData member data. Marked the current channel as read end.
1.748 +
1.749 +@param aSize Size of the unnamed pipe to be created.
1.750 +
1.751 +@return Handle ID if successful, otherwise one of the other system wide error code.
1.752 +*/
1.753 + {
1.754 + if(iData)
1.755 + {
1.756 + //this channel already has a pipe
1.757 + return KErrInUse;
1.758 + }
1.759 +
1.760 + DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
1.761 +
1.762 + TAutoWait<DMutex> outerAutoMutex(device.Mutex());
1.763 +
1.764 + DPipe* pipe = device.CreatePipe(aSize);
1.765 + if(pipe == NULL)
1.766 + {
1.767 + return KErrNoMemory;
1.768 + }
1.769 +
1.770 + TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
1.771 +
1.772 + pipe->SetReadEnd(this);
1.773 + iData = pipe;
1.774 + iChannelType = RPipe::EReadChannel;
1.775 +
1.776 + return iData->OpenId();
1.777 + }
1.778 +
1.779 +
1.780 +TInt DPipeChannel::OpenOnReader(const TDesC* aName)
1.781 +/**
1.782 +Opens a named pipe identified by the name parameter. It calls Pipe Device object
1.783 +to open the Pipe identified by the name and obtained the pointer to the pipe. The
1.784 +pointer is them stored in its iData member data. Marked the current channel as write
1.785 +end.
1.786 +@param aName The name of the pipe to be opened.
1.787 +
1.788 +@return KErrNone If successful, otherwise one of the other system wide error code.
1.789 +*/
1.790 + {
1.791 + if(iData)
1.792 + {
1.793 + //this channel already has a pipe
1.794 + return KErrInUse;
1.795 + }
1.796 +
1.797 + TKName PName;
1.798 + Kern::KUDesGet(PName, *aName);
1.799 +
1.800 + DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
1.801 +
1.802 + //need to hold the device mutex to
1.803 + //prevent the pipe getting deleted before we can call
1.804 + //SetWriteEnd
1.805 + TAutoWait<DMutex> outerAutoMutex(device.Mutex());
1.806 + DPipe* pipe = device.FindNamedPipe(&PName);
1.807 +
1.808 + if(pipe == NULL)
1.809 + {
1.810 + return KErrNotFound;
1.811 + }
1.812 +
1.813 + TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
1.814 + if (!pipe->IsReadEndOpened())
1.815 + {
1.816 + return KErrNotReady;
1.817 + }
1.818 +
1.819 + iData = pipe;
1.820 +
1.821 + if(!CheckCap())
1.822 + {
1.823 + iData = NULL;
1.824 + return KErrPermissionDenied;
1.825 + }
1.826 +
1.827 + if(pipe->IsWriteEndOpened())
1.828 + {
1.829 + iData = NULL;
1.830 + return KErrInUse;
1.831 + }
1.832 +
1.833 + iData->SetWriteEnd(this);
1.834 + iChannelType = RPipe::EWriteChannel;
1.835 + return KErrNone;
1.836 + }
1.837 +
1.838 +
1.839 +TInt DPipeChannel::PipeDestroy(const TDesC* aName)
1.840 +/**
1.841 +Destroys the named pipe.
1.842 +@param aName Name of the Kernel pipe to be destroyed.
1.843 +
1.844 +@return KErrNone If the pipe is successfully destroyed, otherwise one of the
1.845 + other system wide error codes
1.846 +*/
1.847 + {
1.848 + TKName PName;
1.849 + Kern::KUDesGet(PName, *aName);
1.850 + return ((DPipeDevice*)iDevice)->Destroy(&PName);
1.851 + }
1.852 +
1.853 +TInt DPipeChannel::PipeOpen(const TInt aId)
1.854 +/**
1.855 +Opens a unnamed pipe identified by the specified id. It calls Pipe Device object
1.856 +to open a unnamed pipe identified by the specified id and obtain the pointer to the
1.857 +pipe. The pipe reference is then stored in its iData member data and marked the
1.858 +current channel as write end.
1.859 +
1.860 +@param aId Id of the unnamed pipe to be opened.
1.861 +
1.862 +@return KErrNone If successful, otherwise one of the system wide error code.
1.863 +*/
1.864 + {
1.865 + if(iData)
1.866 + {
1.867 + //this channel already has a pipe
1.868 + return KErrInUse;
1.869 + }
1.870 +
1.871 + DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
1.872 + TAutoWait<DMutex> outerAutoMutex(device.Mutex());
1.873 +
1.874 + DPipe* pipe = device.FindUnnamedPipe(aId);
1.875 + if(pipe == NULL)
1.876 + {
1.877 + return KErrNotFound;
1.878 + }
1.879 +
1.880 + TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
1.881 + if (pipe->IsWriteEndOpened() )
1.882 + {
1.883 + return KErrInUse;
1.884 + }
1.885 +
1.886 + pipe->SetWriteEnd(this);
1.887 +
1.888 + iChannelType = RPipe::EWriteChannel;
1.889 + iData = pipe;
1.890 +
1.891 + return KErrNone;
1.892 + }
1.893 +
1.894 +
1.895 +TInt DPipeChannel::PipeOpen(const TDesC* aName, RPipe::TChannelType aType)
1.896 +/**
1.897 +This function will be called under DoControl();
1.898 +Attempts to open the pipe for reading (iReadEnd) or writing (iWriteEnd)
1.899 +@param aName Name of the pipe to be opened
1.900 +
1.901 +@param aType Type of operation to be performed.
1.902 +
1.903 +@return KErrNone Pipe successfully created, otherwise one of the other system wide
1.904 + error code
1.905 +*/
1.906 + {
1.907 + if(iData)
1.908 + {
1.909 + //this channel already has a pipe
1.910 + return KErrInUse;
1.911 + }
1.912 +
1.913 + TKName PName;
1.914 + Kern::KUDesGet(PName, *aName);
1.915 +
1.916 + DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
1.917 +
1.918 + TAutoWait<DMutex> outerAutoMutex(device.Mutex());
1.919 +
1.920 + DPipe* pipe = device.FindNamedPipe(&PName);
1.921 + if(pipe == NULL)
1.922 + {
1.923 + return KErrNotFound;
1.924 + }
1.925 +
1.926 +
1.927 + TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
1.928 + iData = pipe;
1.929 + //! Check capabilitity if applicalble
1.930 + if(!CheckCap())
1.931 + {
1.932 + iData = NULL;
1.933 + return KErrPermissionDenied;
1.934 + }
1.935 +
1.936 + // Check if the pipe is already opened.
1.937 + if(aType == RPipe::EReadChannel)
1.938 + {
1.939 + if(iData->IsReadEndOpened())
1.940 + {
1.941 + iData = NULL;
1.942 + return KErrInUse;
1.943 + }
1.944 + iData->SetReadEnd(this);
1.945 + }
1.946 + else
1.947 + {
1.948 + if(iData->IsWriteEndOpened())
1.949 + {
1.950 + iData = NULL;
1.951 + return KErrInUse;
1.952 + }
1.953 + iData->SetWriteEnd(this);
1.954 + }
1.955 +
1.956 + iChannelType = aType;
1.957 +
1.958 + return KErrNone;
1.959 + }
1.960 +
1.961 +
1.962 +
1.963 +TBool DPipeChannel::CheckCap()
1.964 +/**
1.965 +Check if Security policy is installed, if so, checks if the current thread
1.966 +has required capabilities
1.967 +
1.968 +@param None
1.969 +
1.970 +@return TBool ETrue if The current thread has required capabilities and also if
1.971 + no capabilities is installed, otherwise EFlase.
1.972 +
1.973 +*/
1.974 + {
1.975 + //iData->GetCap is always true
1.976 + if(iData->GetCap())
1.977 + return iData->GetCap()->CheckPolicy(&Kern::CurrentThread());
1.978 + else
1.979 + return ETrue;
1.980 + }
1.981 +
1.982 +
1.983 +
1.984 +TInt DPipeChannel::Read (TAny* aBuff, TInt aSize)
1.985 +/**
1.986 +Synchronous, non-blocking read operation. If the pipe is empty it will
1.987 +return immediately with KErrUnderflow. A successful DPipe::Read() operation
1.988 +will free up more space in the pipe. If a request status object has been registered
1.989 +for Space Available notification, it will complete. Note that there is no
1.990 +guarantee that the amount of space freed up in the pipe will be sufficient
1.991 +for the next DPipe::Write() operation.
1.992 +
1.993 +@param aBuff Buffer from which data need to be read
1.994 +
1.995 +@param aSize Size of the data to be read
1.996 +
1.997 +@return:>0 Amount of data read in octets.
1.998 + KErrArgument Invalid Length Amount of data to be read is invalid (e.g. negative)
1.999 + KErrNotReady If the write end is closed,
1.1000 + otherwise one of the other system wide error code
1.1001 +*/
1.1002 + {
1.1003 +
1.1004 + if( iChannelType != RPipe::EReadChannel)
1.1005 + return KErrAccessDenied;
1.1006 +
1.1007 +
1.1008 + TAutoWait<DMutex> outerAutoMutex(*iData->iReadMutex);
1.1009 + TAutoWait<DMutex> innerAutoMutex(iData->Mutex());
1.1010 + //iData->Wait();
1.1011 + if(!iData->IsWriteEndOpened() && iData->IsBufferEmpty())
1.1012 + {
1.1013 + //it is ok to read from a broken pipe provided there is data in it
1.1014 + return KErrNotReady;
1.1015 + }
1.1016 +
1.1017 + return iData->Read(aBuff, aSize);
1.1018 + }
1.1019 +
1.1020 +
1.1021 +TInt DPipeChannel::Write (TAny* aBuff, TInt aSize)
1.1022 +/**
1.1023 +Synchronous, non-blocking write operation. If the pipe is full it will
1.1024 +return immediately with KErrOverflow. A successful DPipe::Write() operation will
1.1025 +return amount of data written to the pipe.If a request status object has been registered
1.1026 +for Data Available notification, it will complete.
1.1027 +
1.1028 +
1.1029 +@param aBuf Buffer from which data need to be written to the pipe.
1.1030 +
1.1031 +@param aSize Amount of data to be written to the pipe.
1.1032 +
1.1033 +@return >0 Amount of data written to the pipe, in octets.
1.1034 + KErrOverflow The pipe is full no data is written.
1.1035 + KErrArgument if the amount of data to be written in invalid
1.1036 + KErrNotReady if the read end is not opened.
1.1037 + otherwise one of the other system wide error code
1.1038 +*/
1.1039 + {
1.1040 +
1.1041 + if(iChannelType!= RPipe::EWriteChannel)
1.1042 + return KErrAccessDenied;
1.1043 +
1.1044 + TAutoWait<DMutex> outerAutoMutex(*iData->iWriteMutex);
1.1045 + TAutoWait<DMutex> innerAutoMutex(iData->Mutex());
1.1046 +
1.1047 + if(!(iData->IsReadEndOpened()))
1.1048 + {
1.1049 + return KErrNotReady;
1.1050 + }
1.1051 +
1.1052 + return iData->Write(aBuff, aSize);
1.1053 + }
1.1054 +
1.1055 +
1.1056 +
1.1057 +TInt DPipeChannel::CloseHandle()
1.1058 +/**
1.1059 +Attempts to close the pipe for reading or writing .
1.1060 +
1.1061 +@param None
1.1062 +
1.1063 +@return KErrNone Success.
1.1064 + KErrCouldNotDisconnect The pipe is already closed for that operation.
1.1065 +
1.1066 +*/
1.1067 + {
1.1068 + if(iData==NULL)
1.1069 + {
1.1070 + return KErrNone;
1.1071 + }
1.1072 +
1.1073 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipeChannel::CloseHandle ID=%d, ChannelType=%d", iData->OpenId(), iChannelType));
1.1074 +
1.1075 + NKern::ThreadEnterCS();
1.1076 + iData->Wait();
1.1077 + TInt err = KErrNone;
1.1078 + if(iChannelType == RPipe::EReadChannel)
1.1079 + {
1.1080 + CancelRequest(RPipe::EDataAvailable);
1.1081 + err = iData->CloseReadEnd();
1.1082 + }
1.1083 + else if(iChannelType == RPipe::EWriteChannel)
1.1084 + {
1.1085 + CancelRequest(RPipe::ESpaceAvailable);
1.1086 + err = iData->CloseWriteEnd();
1.1087 + }
1.1088 + else
1.1089 + {
1.1090 + FAULT(); //iChannelType should be set correctly if iData was non-null
1.1091 + }
1.1092 + // If we had a pointer to the pipe but it had no back pointer
1.1093 + // to us something has gone wrong.
1.1094 + __NK_ASSERT_DEBUG(err == KErrNone);
1.1095 +
1.1096 + const TInt pipeId=iData->OpenId();
1.1097 + iData->Signal();
1.1098 + iData = NULL;
1.1099 +
1.1100 + // The return code from close would inform us if
1.1101 + // the device had no record of the pipe.
1.1102 + // However, for a named pipe there is no gurrantee that the pipe
1.1103 + // hasn't been deleted once we close our end of the pipe and
1.1104 + // Signal.
1.1105 + static_cast<DPipeDevice*>(iDevice)->Close(pipeId);
1.1106 +
1.1107 + NKern::ThreadLeaveCS();
1.1108 +
1.1109 + return err;
1.1110 + }
1.1111 +
1.1112 +
1.1113 +
1.1114 +TInt DPipeChannel::NotifySpaceAvailable ( TInt aSize,TRequestStatus* aStat, TBool aAllowDisconnected)
1.1115 +/**
1.1116 +Registers the request status object to be completed when space becomes
1.1117 +available in the pipe.
1.1118 +
1.1119 +@param aSize The size for which the user has requested for notification
1.1120 +
1.1121 +@param aStat Status request to be registered
1.1122 +@param aAllowDisconnected If false then confirm that the pipe has a reader
1.1123 +
1.1124 +@return KErrNone Success in registering the request
1.1125 + KErrAccessDenied If the correct end is not used to register the request
1.1126 + KErrInUse A notifier of this type has already been registered.
1.1127 + otherwise one of the other system wide error code.
1.1128 + KErrNotReady The pipe has no reader
1.1129 +*/
1.1130 + {
1.1131 +
1.1132 + //! Check if correct end is used
1.1133 + if(iChannelType!= RPipe::EWriteChannel)
1.1134 + {
1.1135 + return KErrAccessDenied;
1.1136 + }
1.1137 +
1.1138 + TAutoWait<DMutex> autoMutex(iData->Mutex());
1.1139 + //Check if there is already a pending Space Available request.
1.1140 + if(iClientRequest->StatusPtr())
1.1141 + {
1.1142 + return KErrInUse;
1.1143 + }
1.1144 + else
1.1145 + {
1.1146 + if(!aAllowDisconnected && !(iData->IsReadEndOpened()) )
1.1147 + return KErrNotReady;
1.1148 +
1.1149 + TInt r = iClientRequest->SetStatus(aStat);
1.1150 + __NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr
1.1151 + DThread* const currThread = &Kern::CurrentThread();
1.1152 +
1.1153 + if((iData->RegisterSpaceAvailableNotification(aSize))==KErrCompletion)
1.1154 + {
1.1155 + Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone);
1.1156 + }
1.1157 + else
1.1158 + {
1.1159 + iRequestThread = currThread;
1.1160 + // Open a reference on client thread so its control block can't disappear until
1.1161 + // this channel has finished with it.
1.1162 + iRequestThread->Open();
1.1163 + iRequestType = RPipe::ESpaceAvailable;
1.1164 + }
1.1165 + }
1.1166 + return KErrNone;
1.1167 + }
1.1168 +
1.1169 +
1.1170 +TInt DPipeChannel::NotifyDataAvailable (TRequestStatus* aStat, TBool aAllowDisconnected)
1.1171 +/**
1.1172 +Registers the request status object to be completed when data becomes
1.1173 +available in the pipe.
1.1174 +
1.1175 +@param aStat Status request to be registered
1.1176 +@param aAllowDisconnected If false then fail if the pipe is empty with no writer.
1.1177 +
1.1178 +@return KErrNone Success in registering the request
1.1179 + KErrAccessDenied If the correct end is not used to register the request
1.1180 + KErrInUse A notifier of this type has already been registered.
1.1181 + otherwise one of the other system wide error code.
1.1182 + KErrNotReady The pipe was empty and had no writer
1.1183 +*/
1.1184 + {
1.1185 +
1.1186 + //! Check if correct end is used
1.1187 + if(iChannelType!= RPipe::EReadChannel)
1.1188 + {
1.1189 + return KErrAccessDenied;
1.1190 + }
1.1191 +
1.1192 + // Check if there is already a pending Data Available request.
1.1193 + TAutoWait<DMutex> autoMutex(iData->Mutex() );
1.1194 + if(iClientRequest->StatusPtr())
1.1195 + {
1.1196 + return KErrInUse;
1.1197 + }
1.1198 + else
1.1199 + {
1.1200 + if(!aAllowDisconnected)
1.1201 + {
1.1202 + if(iData->IsBufferEmpty() && (!iData->IsWriteEndOpened()))
1.1203 + return KErrNotReady;
1.1204 + }
1.1205 +
1.1206 + TInt r = iClientRequest->SetStatus(aStat);
1.1207 + __NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr
1.1208 + DThread* const currThread = &Kern::CurrentThread();
1.1209 +
1.1210 + if((iData->RegisterDataAvailableNotification()) == KErrCompletion)
1.1211 + {
1.1212 + Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone);
1.1213 + }
1.1214 + else
1.1215 + {
1.1216 + iRequestThread = currThread;
1.1217 + // Open a reference on client thread so its control block can't disappear until
1.1218 + // this channel has finished with it.
1.1219 + iRequestThread->Open();
1.1220 + iRequestType = RPipe::EDataAvailable;
1.1221 + }
1.1222 + }
1.1223 + return KErrNone;;
1.1224 + }
1.1225 +
1.1226 +
1.1227 +TInt DPipeChannel::WaitNotification(TRequestStatus* aStat, TAny* aName, TInt aChoice)
1.1228 +/**
1.1229 +Registers the request status object to be completed when other end of the pipe
1.1230 +is opened for reading (or writing).This method completes immediately if the other end of the
1.1231 +pipe is already opened.
1.1232 +
1.1233 +
1.1234 +@param aName Pointer to the a name passed as void pointer
1.1235 +
1.1236 +@param aStat Status request to be registered
1.1237 +
1.1238 +@param aChoice EWaitForReader,wait notification for Read end Opened.
1.1239 + EWaitForWriter,wait notification for Write end Opened.
1.1240 +
1.1241 +@return KErrNone Success in registering the request
1.1242 + KErrInUse A notifier of this type has already been registered.
1.1243 + KErrAccessDenied If the correct end is not used to register the request
1.1244 + otherwise one of the other system wide error code
1.1245 +
1.1246 +*/
1.1247 + {
1.1248 + //! Check if correct end is used
1.1249 + if(((aChoice == RPipe::EWaitForReader) && (iChannelType!= RPipe::EWriteChannel))
1.1250 + || ((aChoice == RPipe::EWaitForWriter) && (iChannelType!= RPipe::EReadChannel)))
1.1251 + {
1.1252 + return KErrAccessDenied;
1.1253 + }
1.1254 +
1.1255 + TKName PName;
1.1256 + Kern::KUDesGet(PName, *(TDesC*)aName);
1.1257 +
1.1258 + TAutoWait<DMutex> autoMutex(iData->Mutex());
1.1259 + if(iData->MatchName(&PName)== EFalse)
1.1260 + {
1.1261 + return KErrNotFound;
1.1262 + }
1.1263 + // Check if there is already a pending request.
1.1264 + else if(iClientRequest->StatusPtr())
1.1265 + {
1.1266 + return KErrInUse;
1.1267 + }
1.1268 + else
1.1269 + {
1.1270 + TInt r = iClientRequest->SetStatus(aStat);
1.1271 + __NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr
1.1272 + DThread* const currThread = &Kern::CurrentThread();
1.1273 +
1.1274 + //register the request.
1.1275 + if((iData->RegisterWaitNotification((TInt )aChoice))== KErrCompletion)
1.1276 + {
1.1277 + Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone);
1.1278 + }
1.1279 + else
1.1280 + {
1.1281 + iRequestThread = currThread;
1.1282 + // Open a reference on client thread so its control block can't disappear until
1.1283 + // this channel has finished with it.
1.1284 + iRequestThread->Open();
1.1285 + iRequestType = RPipe::EWaitNotification;
1.1286 + }
1.1287 + }
1.1288 + return KErrNone;
1.1289 + }
1.1290 +
1.1291 +
1.1292 +/**
1.1293 +For a given request return true if the notification
1.1294 +we are cancelling is outstanding. If not, or
1.1295 +if the supplied request is not a valid cancllation
1.1296 +return false
1.1297 +*/
1.1298 +TBool DPipeChannel::ValidCancellation(TInt aReqType)
1.1299 +{
1.1300 + switch(aReqType)
1.1301 + {
1.1302 + case RPipe::ECancelDataAvailable:
1.1303 + return (iRequestType==RPipe::EDataAvailable);
1.1304 + case RPipe::ECancelSpaceAvailable:
1.1305 + return (iRequestType==RPipe::ESpaceAvailable);
1.1306 + case RPipe::ECancelWaitNotification:
1.1307 + return (iRequestType==RPipe::EWaitNotification);
1.1308 + default:
1.1309 + return EFalse;
1.1310 + }
1.1311 +}
1.1312 +
1.1313 +void DPipeChannel::CancelRequest ( TInt aReqType)
1.1314 +/**
1.1315 +Cancels an outstanding space available notifier request.
1.1316 +
1.1317 +@param aReqType A number identifying the message type
1.1318 +
1.1319 +@return None
1.1320 +*/
1.1321 +{
1.1322 + TAutoWait<DMutex> autoMutex(iData->Mutex() );
1.1323 + if(iClientRequest->StatusPtr() && ValidCancellation(aReqType))
1.1324 + {
1.1325 + switch(aReqType)
1.1326 + {
1.1327 + case RPipe::ECancelDataAvailable:
1.1328 + iData->CancelDataAvailable();
1.1329 + break;
1.1330 +
1.1331 + case RPipe::ECancelSpaceAvailable:
1.1332 + iData->CancelSpaceAvailable();
1.1333 + break;
1.1334 +
1.1335 + case RPipe::ECancelWaitNotification:
1.1336 + iData->CancelWaitNotifier();
1.1337 + break;
1.1338 +
1.1339 + default:
1.1340 + FAULT();
1.1341 + }
1.1342 + Kern::QueueRequestComplete(iRequestThread, iClientRequest, KErrCancel);
1.1343 + // Close our reference on the client thread
1.1344 + Kern::SafeClose((DObject*&)iRequestThread,NULL);
1.1345 + iRequestThread = NULL;
1.1346 + }
1.1347 + return;
1.1348 + }
1.1349 +
1.1350 +
1.1351 +TInt DPipeChannel::Size()
1.1352 +/**
1.1353 +Returns the size of the Pipe's buffer
1.1354 +
1.1355 +@param None
1.1356 +
1.1357 +@return TInt Return the size of the pipe, otherwise one of the other system wide
1.1358 + error code.
1.1359 +*/ {
1.1360 + if(!iData)
1.1361 + return KErrNotReady;
1.1362 + else
1.1363 + return iData->Size();
1.1364 + }
1.1365 +
1.1366 +
1.1367 +void DPipeChannel::Flush()
1.1368 +/*
1.1369 +Flush the content of the pipe
1.1370 +
1.1371 +@param None
1.1372 +@pre Must be in a critical section.
1.1373 +@return None
1.1374 +
1.1375 +*/ {
1.1376 + //The flush is, in effect, a read where the data is ignored
1.1377 + TAutoWait<DMutex> autoMutex(*iData->iReadMutex);
1.1378 +
1.1379 + iData->Wait();
1.1380 + iData->FlushPipe();
1.1381 + iData->Signal();
1.1382 + }
1.1383 +
1.1384 +
1.1385 +// Called from the DPipe
1.1386 +
1.1387 +void DPipeChannel::DoRequestCallback()
1.1388 +/**
1.1389 +It is called from the DPipe to complete the Outstanding request
1.1390 +
1.1391 +@param None
1.1392 +
1.1393 +@return None
1.1394 +*/
1.1395 + {
1.1396 + __ASSERT_MUTEX(&iData->Mutex());
1.1397 + __NK_ASSERT_DEBUG(iRequestThread);
1.1398 + Kern::QueueRequestComplete(iRequestThread, iClientRequest, KErrNone);
1.1399 + Kern::SafeClose((DObject*&)iRequestThread,NULL);
1.1400 + iRequestThread=NULL;
1.1401 + }
1.1402 +
1.1403 +
1.1404 +
1.1405 +// DPipe the Kernel side pipe representing class
1.1406 +
1.1407 +DPipe::~DPipe()
1.1408 +/**
1.1409 +Destructor
1.1410 +*/
1.1411 + {
1.1412 + delete iBuffer;
1.1413 + if (iPipeMutex)
1.1414 + iPipeMutex->Close(NULL);
1.1415 + if (iReadMutex)
1.1416 + iReadMutex->Close(NULL);
1.1417 + if(iWriteMutex)
1.1418 + iWriteMutex->Close(NULL);
1.1419 + }
1.1420 +
1.1421 +
1.1422 +// Creates a Named pipe
1.1423 +DPipe* DPipe::CreatePipe(const TDesC& aName, TInt aSize, TAny *aPolicy)
1.1424 +/**
1.1425 +Static method to Create a Named pipe.
1.1426 +@param aName Reference to the Name to be set to the current named pipe.
1.1427 +@param aSize Size of the Pipe.
1.1428 +@param TAny Pointer to TSecurityPolicy passed as void pointer
1.1429 +
1.1430 +@return DPipe* Reference to DPipe* instance if successful, otherwise NULL
1.1431 +*/
1.1432 + {
1.1433 +
1.1434 + DPipe* tmp = new DPipe;
1.1435 + if (!tmp)
1.1436 + {
1.1437 + return NULL;
1.1438 + }
1.1439 + if(tmp->ConstructPipe(aName, aSize, aPolicy)!= KErrNone)
1.1440 + {
1.1441 + delete tmp;
1.1442 + return NULL;
1.1443 + }
1.1444 + return tmp;
1.1445 + }
1.1446 +
1.1447 +
1.1448 +TInt DPipe::ConstructPipe(const TDesC& aName, TInt aSize,TAny* aPolicy)
1.1449 +/**
1.1450 +Second phase constructor
1.1451 +
1.1452 +@param aName The name of the pipe to be created
1.1453 +@param aSize The size of the pipe to be created
1.1454 +@param TAny Pointer to TSecurityPolicy passed as void pointer
1.1455 +
1.1456 +@return KErrNone If successful, otherwise one of the other system wide error code
1.1457 +*/
1.1458 + {
1.1459 + // check the size parameter.
1.1460 + if(aPolicy)
1.1461 + {
1.1462 +
1.1463 + memcpy(&iPolicy,aPolicy,sizeof(TSecurityPolicy));
1.1464 +
1.1465 + }
1.1466 + else
1.1467 + {
1.1468 + TSecurityPolicy apolicy(ECapability_None);
1.1469 + memcpy(&iPolicy,&apolicy,sizeof(TSecurityPolicy));
1.1470 + }
1.1471 +
1.1472 + if(aName.Length() != 0)
1.1473 + {
1.1474 + iName.Copy(aName);
1.1475 + }
1.1476 +
1.1477 + iBuffer = static_cast<TUint8*>(Kern::AllocZ(aSize));
1.1478 + if(!iBuffer)
1.1479 + return KErrNoMemory;
1.1480 +
1.1481 + // Initialisation
1.1482 + _LIT(KMutexName,"PipeMutex");
1.1483 + TInt err = Kern::MutexCreate(iPipeMutex, KMutexName, KMutexOrdGeneral0);
1.1484 + if (err)
1.1485 + {
1.1486 + return err;
1.1487 + }
1.1488 + _LIT(KReadMutex,"ReadMutex");
1.1489 + err = Kern::MutexCreate(iReadMutex, KReadMutex, KMutexOrdGeneral1);
1.1490 + if (err)
1.1491 + {
1.1492 + return err;
1.1493 + }
1.1494 +
1.1495 + _LIT(KWriteMutex,"WriteMutex");
1.1496 + err = Kern::MutexCreate(iWriteMutex, KWriteMutex, KMutexOrdGeneral1);
1.1497 + if (err)
1.1498 + {
1.1499 + return err;
1.1500 + }
1.1501 +
1.1502 + iSize = aSize;
1.1503 + iWritePointer = iReadPointer = 0;
1.1504 + iFull = EFalse;
1.1505 + return KErrNone;
1.1506 + }
1.1507 +
1.1508 +
1.1509 +TInt DPipe::OpenId()
1.1510 +/**
1.1511 +Returns the id of the Pipe
1.1512 +
1.1513 +@param None
1.1514 +
1.1515 +@return iID ID of the pipe
1.1516 +*/
1.1517 + {
1.1518 + //could be const
1.1519 + return iID;
1.1520 + }
1.1521 +
1.1522 +
1.1523 +void DPipe::SetId(TInt aId)
1.1524 +/**
1.1525 +Set the id of the Pipe
1.1526 +
1.1527 +@param aId The id to be set
1.1528 +
1.1529 +@return None
1.1530 +*/
1.1531 + {
1.1532 + //this is only called by the pipe device
1.1533 + //it could also be set at construction time
1.1534 + iID = aId;
1.1535 + }
1.1536 +
1.1537 +
1.1538 +TBool DPipe::IsPipeClosed()
1.1539 +/**
1.1540 +Check if the Pipe is Closed.
1.1541 +@param None
1.1542 +@return TBool ETure if Successful, otherwise EFalse;
1.1543 +*/
1.1544 + {
1.1545 + __ASSERT_MUTEX(iPipeMutex);
1.1546 +
1.1547 + return !(iReadChannel || iWriteChannel);
1.1548 + }
1.1549 +
1.1550 +
1.1551 +TBool DPipe::MatchName(const TDesC8* aName)
1.1552 +/**
1.1553 +Check if the current instance of DPipe Name is matching with aName parameter
1.1554 +
1.1555 +@param aName Name to be checked with the current DPipe's name.
1.1556 +
1.1557 +@return TBool ETrue if match found, otherwise EFalse
1.1558 +*/
1.1559 + {
1.1560 + //name could be const
1.1561 + return (iName.Compare(*aName) == 0);
1.1562 + }
1.1563 +
1.1564 +
1.1565 +TBool DPipe::MatchId(const TInt aId)
1.1566 +/**
1.1567 +Checks if the current instance of DPipe is matching with the aId parameter
1.1568 +
1.1569 +@param aId ID to be checked with the current DPipe's id
1.1570 +
1.1571 +@return TBool ETure if match found , otherwise EFalse;
1.1572 +*/
1.1573 + {
1.1574 + return (iID == aId);
1.1575 + }
1.1576 +
1.1577 +
1.1578 +TBool DPipe::IsBufferEmpty()
1.1579 +/**
1.1580 +Checks if the Buffer is Empty
1.1581 +
1.1582 +@param None
1.1583 +@return ETrue if buffer is empty
1.1584 +*/
1.1585 + {
1.1586 + return (AvailableDataCount()==0);
1.1587 + }
1.1588 +
1.1589 +
1.1590 +TInt DPipe::Write(TAny* aBuf, TInt aSize)
1.1591 +/**
1.1592 +Synchronous, non-blocking write operation. If the pipe is full it will
1.1593 +return immediately with KErrOverflow. A successful DPipe::Write() operation will
1.1594 +return amount of data written to the pipe.If a request status object has been registered
1.1595 +for Data Available notification, it will complete.
1.1596 +
1.1597 +@param aBuf Buffer from which data need to be written to the pipe.
1.1598 +@param aSize Amount of data to be written to the pipe.
1.1599 +
1.1600 +@return >0 Amount of data written to the pipe, in octets.
1.1601 + KErrNone No data written to the pipe.
1.1602 + KErrOverflow Pipe is full, cannot write any more data.
1.1603 + KErrArgument If the amount of data to be written is invalid.
1.1604 + Otherwise one of the other system wide error code
1.1605 +
1.1606 +@pre iPipeMutex held
1.1607 +@pre iWriteMutex held
1.1608 +
1.1609 +@note Write enters and exists with the pipe mutex held - but releases and reaquires internally
1.1610 +*/
1.1611 + {
1.1612 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::Write(aBuf=0x%08x, aSize=%d)", aBuf, aSize));
1.1613 +
1.1614 + __ASSERT_MUTEX(iPipeMutex);
1.1615 + __ASSERT_MUTEX(iWriteMutex);
1.1616 + // Check for the Invalid Length
1.1617 + if(aSize < 0)
1.1618 + {
1.1619 + return KErrArgument;
1.1620 + }
1.1621 +
1.1622 + if(aSize == 0)
1.1623 + {
1.1624 + return KErrNone;
1.1625 + }
1.1626 +
1.1627 + //Since only one thread can be writing to the write end
1.1628 + //of a pipe it is sufficient that AvailableDataCount
1.1629 + //holds the pipe mutex. After it returns the
1.1630 + //available space may increase
1.1631 + //but can not decrease
1.1632 + const TInt spaceavailable = (iSize - AvailableDataCount());
1.1633 + if (spaceavailable < aSize)
1.1634 + {
1.1635 + //Though the API may suggest otherwise - partial writes are not supported.
1.1636 + return KErrOverflow;
1.1637 + }
1.1638 +
1.1639 + //release mutex before IPC read
1.1640 + Signal();
1.1641 +
1.1642 + //First half
1.1643 + const TDesC8* pBuf = (const TDesC8*)aBuf;
1.1644 +
1.1645 + const TInt distanceToEnd = iSize - iWritePointer;
1.1646 + const TInt firstHalf = Min(distanceToEnd, aSize);
1.1647 + TPtr ptr(&iBuffer[iWritePointer], firstHalf);
1.1648 +
1.1649 + DThread* const currThread = &Kern::CurrentThread();
1.1650 + TInt r=Kern::ThreadDesRead(currThread, pBuf, ptr, 0, KChunkShiftBy0);
1.1651 + if(r!=KErrNone)
1.1652 + {
1.1653 + Wait(); //we must exit with mutex held
1.1654 + return r;
1.1655 + }
1.1656 +
1.1657 + //Second half
1.1658 + const TInt secondHalf = aSize - firstHalf;
1.1659 + __NK_ASSERT_DEBUG( secondHalf >= 0);
1.1660 + if(secondHalf != 0)
1.1661 + {
1.1662 + ptr.Set(&iBuffer[0], secondHalf, secondHalf);
1.1663 +
1.1664 + r = Kern::ThreadDesRead(currThread, pBuf, ptr, firstHalf, KChunkShiftBy0);
1.1665 + if(r!=KErrNone)
1.1666 + {
1.1667 + Wait(); //we must exit with mutex held
1.1668 + return r;
1.1669 + }
1.1670 + }
1.1671 +
1.1672 + Wait(); //reaquire mutex for state update
1.1673 + iWritePointer = (iWritePointer + aSize)% iSize;
1.1674 +
1.1675 + if(iWritePointer == iReadPointer)
1.1676 + {
1.1677 + iFull = ETrue;
1.1678 + }
1.1679 +
1.1680 + if(iDataAvailableRequest)
1.1681 + {
1.1682 + iReadChannel->DoRequestCallback();
1.1683 + iDataAvailableRequest = EFalse;
1.1684 + }
1.1685 +
1.1686 + return aSize;
1.1687 + }
1.1688 +
1.1689 +
1.1690 +TInt DPipe::Read(TAny* aBuf, TInt aSize)
1.1691 +/**
1.1692 +Synchronous, non-blocking read operation. If the pipe is empty it will
1.1693 +return immediately with KErrUnderflow. A successful DPipe::Read() operation
1.1694 +will free up more space in the pipe. If a request status object has been registered
1.1695 +for Space Available notification, it will complete. Note that there is no
1.1696 +guarantee that the amount of space freed up in the pipe will be sufficient
1.1697 +for the next DPipe::Write() operation.
1.1698 +
1.1699 +@param aBuff Buffer to which data need to be written.
1.1700 +@param aSize Size of the data to be read from the pipe.
1.1701 +
1.1702 +@return >0 Amount of data read from the pipe, in octets.
1.1703 + KErrNone The pipe is empty , no data was read from the pipe.
1.1704 + KErrArgument If the amount of data to be read is invalid.
1.1705 + Otherwise one of the system wide error code
1.1706 +@pre iPipeMutex held
1.1707 +@pre iReadMutex held
1.1708 +
1.1709 +@note Read enters and exists with the pipe mutex held - but releases and reaquires internally
1.1710 +*/
1.1711 + {
1.1712 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::Read(aBuf=0x%08x, aSize=%d)", aBuf, aSize));
1.1713 + __ASSERT_MUTEX(iPipeMutex);
1.1714 + __ASSERT_MUTEX(iReadMutex);
1.1715 +
1.1716 + if(aSize < 0)
1.1717 + {
1.1718 + return KErrArgument;
1.1719 + }
1.1720 +
1.1721 + const TInt totalToRead = Min(AvailableDataCount(), aSize);
1.1722 +
1.1723 +
1.1724 + if(totalToRead == 0)
1.1725 + return 0;
1.1726 +
1.1727 + Signal();
1.1728 +
1.1729 +
1.1730 + //! First half
1.1731 + const TInt distanceToEnd = iSize - iReadPointer;
1.1732 + __NK_ASSERT_DEBUG(distanceToEnd>=0);
1.1733 + const TInt firstHalf = Min(totalToRead, distanceToEnd);
1.1734 +
1.1735 + TPtrC8 pipeBuffer(&iBuffer[iReadPointer], firstHalf);
1.1736 + TDes8* userBuffer = (TDes8*)aBuf;
1.1737 +
1.1738 + DThread* const currThread = &Kern::CurrentThread();
1.1739 + TInt r = Kern::ThreadDesWrite(currThread, userBuffer, pipeBuffer, 0, KChunkShiftBy0, NULL);
1.1740 + if(r!=KErrNone)
1.1741 + {
1.1742 + Wait(); //we must exit with mutex held
1.1743 + return r;
1.1744 + }
1.1745 +
1.1746 + const TInt secondHalf=totalToRead-firstHalf;
1.1747 + __NK_ASSERT_DEBUG(secondHalf>=0);
1.1748 + if(secondHalf!=0)
1.1749 + {
1.1750 + //! Second half
1.1751 + pipeBuffer.Set(&iBuffer[0], secondHalf);
1.1752 + r = Kern::ThreadDesWrite(currThread, userBuffer, pipeBuffer, firstHalf, KChunkShiftBy0, NULL);
1.1753 + if(r!=KErrNone)
1.1754 + {
1.1755 + Wait(); //we must exit with mutex held
1.1756 + return r;
1.1757 + }
1.1758 + }
1.1759 + __NK_ASSERT_DEBUG(firstHalf+secondHalf==totalToRead);
1.1760 +
1.1761 + Wait(); //Reaquire mutex for state update
1.1762 +
1.1763 + iReadPointer = (iReadPointer + totalToRead)% iSize;
1.1764 + iFull = EFalse;
1.1765 + MaybeCompleteSpaceNotification();
1.1766 +
1.1767 + __ASSERT_MUTEX(iReadMutex);
1.1768 + return totalToRead;
1.1769 + }
1.1770 +
1.1771 +TInt DPipe::AvailableDataCount()
1.1772 +/**
1.1773 +Returns the Data available in the pipe.
1.1774 +
1.1775 +@param None
1.1776 +
1.1777 +@return TInt Amount of data available in the pipe
1.1778 +
1.1779 +*/
1.1780 + {
1.1781 + __ASSERT_MUTEX(iPipeMutex);
1.1782 + TInt size=-1;
1.1783 + if ( iWritePointer > iReadPointer )
1.1784 + {
1.1785 + size = iWritePointer - iReadPointer;
1.1786 + }
1.1787 + else if ( iReadPointer > iWritePointer )
1.1788 + {
1.1789 + size = iSize - iReadPointer + iWritePointer;
1.1790 + }
1.1791 + else
1.1792 + {
1.1793 + //iReadPointer == iWritePointer
1.1794 + size = iFull ? iSize : 0;
1.1795 + }
1.1796 + return size;
1.1797 + }
1.1798 +
1.1799 +TInt DPipe::RegisterSpaceAvailableNotification(TInt aSize)
1.1800 +/**
1.1801 +Registers the request status object to be completed when space becomes
1.1802 +available in the pipe.
1.1803 +
1.1804 +@param aSize The size for which the space availability be notified.
1.1805 +
1.1806 +@return KErrNone Success.
1.1807 + KErrCompletion The request is not registered as it completes immediately
1.1808 + otherwise one of the system wide error code.
1.1809 +@pre Mutex must be held.
1.1810 +@pre Must be in a critical section.
1.1811 +*/
1.1812 + {
1.1813 + __ASSERT_MUTEX(iPipeMutex);
1.1814 + __NK_ASSERT_DEBUG(Rng(1, aSize, iSize));
1.1815 +
1.1816 + // Check if Specified size is available.
1.1817 + TInt err = KErrNone;
1.1818 + if ((aSize <= (iSize - AvailableDataCount())))
1.1819 + {
1.1820 + iSpaceAvailableRequest = EFalse;
1.1821 + err = KErrCompletion;
1.1822 + }
1.1823 + else
1.1824 + {
1.1825 + iSpaceAvailableSize = aSize;
1.1826 + iSpaceAvailableRequest = ETrue;
1.1827 + }
1.1828 + return err;
1.1829 + }
1.1830 +
1.1831 +
1.1832 +TInt DPipe::RegisterDataAvailableNotification()
1.1833 +/**
1.1834 +Registers the request status object to be completed when data becomes
1.1835 +available in the pipe.
1.1836 +
1.1837 +@param None
1.1838 +
1.1839 +@return KErrNone If successful, otherwise one of the other system wide
1.1840 + error code.
1.1841 +@pre Mutex must be held.
1.1842 +@pre Must be in a critical section.
1.1843 +*/
1.1844 + {
1.1845 + __ASSERT_MUTEX(iPipeMutex);
1.1846 +
1.1847 + TInt err = KErrNone;
1.1848 + // Check if Data is available.
1.1849 + if(AvailableDataCount())
1.1850 + {
1.1851 + iDataAvailableRequest = EFalse;
1.1852 + err = KErrCompletion;
1.1853 + }
1.1854 + else
1.1855 + {
1.1856 + iDataAvailableRequest = ETrue;
1.1857 + }
1.1858 + return err;
1.1859 + }
1.1860 +
1.1861 +
1.1862 +TInt DPipe::RegisterWaitNotification(TInt aChoice)
1.1863 +/**
1.1864 +Registers the request status object to be completed when other end of the pipe
1.1865 +is opened for reading. This method completes immediately if the other end of the
1.1866 +pipe is already opened.
1.1867 +
1.1868 +@param None
1.1869 +
1.1870 +@return KErrNone Successfully registered, otherwise one of the other system wide
1.1871 + error code.
1.1872 +@pre Mutex must be held.
1.1873 +@pre Must be in a critical section.
1.1874 +*/
1.1875 + {
1.1876 + __ASSERT_MUTEX(iPipeMutex);
1.1877 +
1.1878 + TInt err = KErrNone;
1.1879 + // Check if Read end is opened
1.1880 + if (aChoice == RPipe::EWaitForReader)
1.1881 + {
1.1882 + if(IsReadEndOpened())
1.1883 + {
1.1884 + iWaitRequest = EFalse;
1.1885 + err = KErrCompletion;
1.1886 + }
1.1887 + else
1.1888 + {
1.1889 + iWaitRequest = ETrue;
1.1890 + }
1.1891 +
1.1892 + }
1.1893 + else
1.1894 + {
1.1895 + if(IsWriteEndOpened())
1.1896 + {
1.1897 + iWaitRequest = EFalse;
1.1898 + err = KErrCompletion;
1.1899 + }
1.1900 + else
1.1901 + {
1.1902 + iWaitRequest = ETrue;
1.1903 + }
1.1904 + }
1.1905 +
1.1906 + return err;
1.1907 + }
1.1908 +
1.1909 +
1.1910 +//! Cancellation methods
1.1911 +void DPipe::CancelSpaceAvailable()
1.1912 +/**
1.1913 +Cancels an outstanding space available notifier request.
1.1914 +
1.1915 +@param None
1.1916 +
1.1917 +@return None
1.1918 +*/
1.1919 + {
1.1920 + __ASSERT_MUTEX(iPipeMutex);
1.1921 + if(iSpaceAvailableRequest)
1.1922 + iSpaceAvailableRequest = EFalse;
1.1923 + }
1.1924 +
1.1925 +
1.1926 +void DPipe::CancelDataAvailable()
1.1927 +/**
1.1928 +Cancels an outstanding data available notifier request.
1.1929 +
1.1930 +@param None
1.1931 +
1.1932 +@return None
1.1933 +*/
1.1934 + {
1.1935 + __ASSERT_MUTEX(iPipeMutex);
1.1936 + if(iDataAvailableRequest)
1.1937 + iDataAvailableRequest = EFalse;
1.1938 + }
1.1939 +
1.1940 +
1.1941 +void DPipe::CancelWaitNotifier()
1.1942 +/**
1.1943 +Cancel an outstanding wait notifier request
1.1944 +
1.1945 +@param None
1.1946 +
1.1947 +@return KErrNone If Successful, otherwise one of the other system wide error code.
1.1948 +
1.1949 +*/
1.1950 + {
1.1951 + __ASSERT_MUTEX(iPipeMutex);
1.1952 + // Cancel Wait Notifier request
1.1953 + if(iWaitRequest)
1.1954 + iWaitRequest = EFalse;
1.1955 + }
1.1956 +
1.1957 +
1.1958 +void DPipe::CloseAll()
1.1959 +/**
1.1960 +Cancel any outstanding request.
1.1961 +
1.1962 +@param None
1.1963 +
1.1964 +@return None
1.1965 +*/
1.1966 + {
1.1967 + CancelSpaceAvailable();
1.1968 + CancelDataAvailable();
1.1969 + CancelWaitNotifier();
1.1970 +
1.1971 + CloseWriteEnd();
1.1972 + CloseReadEnd();
1.1973 + }
1.1974 +
1.1975 +
1.1976 +TInt DPipe::CloseReadEnd()
1.1977 +/**
1.1978 +Close the read end of the pipe.
1.1979 +
1.1980 +Cancels outstanding requests placed by the *write*
1.1981 +channel and clears pipe's pointer to the read channel.
1.1982 +If this function is called then the read channel's back
1.1983 +pointer to the pipe must also be cleared.
1.1984 +
1.1985 +@param None
1.1986 +
1.1987 +@return KErrNone If the end is closed, else one of the other system
1.1988 + wide error code
1.1989 +*/
1.1990 + {
1.1991 + __ASSERT_MUTEX(iPipeMutex);
1.1992 + __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::CloseReadEnd ID=%d, iReadChannel=0x%08x", OpenId(), iReadChannel));
1.1993 +
1.1994 + if (!iReadChannel)
1.1995 + return KErrCouldNotDisconnect;
1.1996 + else
1.1997 + {
1.1998 + if(iWriteChannel)
1.1999 + {
1.2000 + iWriteChannel->CancelRequest(RPipe::ECancelSpaceAvailable);
1.2001 + }
1.2002 + iReadChannel = NULL;
1.2003 + }
1.2004 + return KErrNone;
1.2005 + }
1.2006 +
1.2007 +
1.2008 +TInt DPipe::CloseWriteEnd()
1.2009 +/**
1.2010 +Close the write end of the pipe
1.2011 +
1.2012 +Cancels outstanding requests placed by the *read*
1.2013 +channel and clears pipe's pointer to the write channel.
1.2014 +If this function is called then the write channel's back
1.2015 +pointer to the pipe must also be cleared.
1.2016 +
1.2017 +@param None
1.2018 +
1.2019 +@return KErrNone If the write end is successfully closed, else
1.2020 + one of the other system wide error code.
1.2021 +*/
1.2022 + {
1.2023 + __ASSERT_MUTEX(iPipeMutex);
1.2024 + __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::CloseWriteEnd ID=%d, iWriteChannel=0x%08x", OpenId(), iWriteChannel));
1.2025 +
1.2026 + if (!iWriteChannel)
1.2027 + return KErrCouldNotDisconnect;
1.2028 + else
1.2029 + {
1.2030 + // Cancel RBlocking call if it is there
1.2031 + if(iReadChannel)
1.2032 + {
1.2033 + iReadChannel->CancelRequest(RPipe::ECancelDataAvailable);
1.2034 + }
1.2035 + iWriteChannel = NULL;
1.2036 + }
1.2037 + return KErrNone;
1.2038 + }
1.2039 +
1.2040 +
1.2041 +
1.2042 +void DPipe::FlushPipe()
1.2043 +/**
1.2044 +Flush all the date from the pipe and reinitialise the buffer pointer.
1.2045 +
1.2046 +@param None
1.2047 +
1.2048 +@return None
1.2049 +
1.2050 +@pre Pipe Mutex to be held
1.2051 +@pre Read Mutex to be held
1.2052 +
1.2053 +*/
1.2054 + {
1.2055 + __ASSERT_MUTEX(iPipeMutex);
1.2056 + __ASSERT_MUTEX(iReadMutex);
1.2057 +
1.2058 + iReadPointer = iWritePointer;
1.2059 + iFull = EFalse;
1.2060 +
1.2061 + MaybeCompleteSpaceNotification();
1.2062 + }
1.2063 +
1.2064 +/**
1.2065 +If there is an outstanding space request, and
1.2066 +there is enough space to satisfy it then complete
1.2067 +and clear request.
1.2068 +
1.2069 +@pre the pipe mutex must be held
1.2070 +*/
1.2071 +void DPipe::MaybeCompleteSpaceNotification()
1.2072 + {
1.2073 + __ASSERT_MUTEX(iPipeMutex);
1.2074 +
1.2075 + // Check if there is writeblocking request
1.2076 + if(iSpaceAvailableRequest)
1.2077 + {
1.2078 + const TInt spacecount = (iSize - AvailableDataCount());
1.2079 + if (iSpaceAvailableSize <= spacecount)
1.2080 + {
1.2081 + iWriteChannel->DoRequestCallback();
1.2082 + iSpaceAvailableRequest = EFalse;
1.2083 + }
1.2084 + }
1.2085 + }
1.2086 +
1.2087 +TBool DPipe::IsReadEndOpened()
1.2088 +/**
1.2089 +Returns information regarding the read end of the current pipe instance.
1.2090 +
1.2091 +@return TBool ETrue if read end is Opened, otherwise EFalse
1.2092 +@pre the pipe mutex must be held
1.2093 +*/
1.2094 + {
1.2095 + __ASSERT_MUTEX(iPipeMutex);
1.2096 + return (iReadChannel != NULL);
1.2097 + }
1.2098 +
1.2099 +
1.2100 +TBool DPipe::IsWriteEndOpened()
1.2101 +/**
1.2102 +Returns information regarding the write end of the current pipe instance.
1.2103 +
1.2104 +@return TBool ETrue if WriteChannel is opened, otherwise EFalse
1.2105 +@pre the pipe mutex must be held
1.2106 +*/
1.2107 + {
1.2108 + __ASSERT_MUTEX(iPipeMutex);
1.2109 + return (iWriteChannel != NULL);
1.2110 + }
1.2111 +
1.2112 +
1.2113 +TBool DPipe::IsNamedPipe()
1.2114 +/**
1.2115 +Returns whether the pipe is named or unnamed.
1.2116 +
1.2117 +@return TBool ETrue if it is a named pipe, otherwise EFalse
1.2118 +
1.2119 +*/
1.2120 + {
1.2121 + return (iName.Length() != 0);
1.2122 + }
1.2123 +
1.2124 +
1.2125 +void DPipe::SetReadEnd(DPipeChannel* aChannel)
1.2126 +/**
1.2127 +Set the Read end of the pipe as opened and store the pointer for the read channel
1.2128 +It also notify if there is any pending Wait Request.
1.2129 +
1.2130 +@param aChannel The pointer to the read channel
1.2131 +
1.2132 +@pre the pipe mutex must be held
1.2133 +@pre The pipe's read end must be closed ie. IsReadEndOpened returns false
1.2134 +*/
1.2135 + {
1.2136 + __ASSERT_MUTEX(iPipeMutex);
1.2137 + __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::SetReadEnd ID=%d", OpenId()));
1.2138 +
1.2139 +
1.2140 + //A channel must be sure this function
1.2141 + //succeeded otherwise the pipe
1.2142 + //could be destroyed without the channel's
1.2143 + //knowledge
1.2144 + __NK_ASSERT_DEBUG(iReadChannel==NULL);
1.2145 +
1.2146 + iReadChannel = aChannel;
1.2147 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::SetReadEnd set iReadChannel=0x%08x", iReadChannel));
1.2148 +
1.2149 + if(iWaitRequest)
1.2150 + {
1.2151 + if(iWriteChannel)
1.2152 + iWriteChannel->DoRequestCallback();
1.2153 + iWaitRequest=EFalse;
1.2154 + }
1.2155 + }
1.2156 +
1.2157 +
1.2158 +void DPipe::SetWriteEnd(DPipeChannel* aChannel)
1.2159 +/**
1.2160 +Set the write end of the pipe as opened and store the pointer to the write channel
1.2161 +
1.2162 +@param aChannel The pointer to the write channel
1.2163 +
1.2164 +
1.2165 +@pre the pipe mutex must be held
1.2166 +@pre The pipe's write end must be closed ie. IsWriteEndOpened returns false
1.2167 +*/
1.2168 + {
1.2169 + __ASSERT_MUTEX(iPipeMutex);
1.2170 + __KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::SetWriteEnd ID=%d", OpenId()));
1.2171 +
1.2172 + //A channel must be sure this function
1.2173 + //succeeded otherwise the pipe
1.2174 + //could be destroyed without the channel's
1.2175 + //knowledge
1.2176 + __NK_ASSERT_DEBUG(iWriteChannel==NULL);
1.2177 +
1.2178 + iWriteChannel = aChannel;
1.2179 + __KTRACE_OPT(KPIPE, Kern::Printf("DPipe::SetWriteEnd set iWriteChannel=0x%08x", iWriteChannel));
1.2180 +
1.2181 + if(iWaitRequest)
1.2182 + {
1.2183 + if(iReadChannel)
1.2184 + iReadChannel->DoRequestCallback();
1.2185 + iWaitRequest=EFalse;
1.2186 + }
1.2187 + }
1.2188 +
1.2189 +TInt DPipe::Size()
1.2190 +/**
1.2191 +@return The size of the pipe's circular buffer
1.2192 +*/
1.2193 + {
1.2194 + //this could be const
1.2195 + return iSize;
1.2196 + }
1.2197 +