1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericopenlibs/cstdlib/USTLIB/UPIPE.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,514 @@
1.4 +// Copyright (c) 1997-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 "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 +// Implementation of pipes
1.18 +//
1.19 +//
1.20 +
1.21 +#include "POSIXIF.H"
1.22 +#include <sys/errno.h>
1.23 +#include <sys/stat.h>
1.24 +
1.25 +// Child end of the pipe
1.26 +
1.27 +CPipeChildDesc::CPipeChildDesc(TInt anIndex, RPosixSession& aSession)
1.28 + : CFileDescBase(), iIndex(anIndex), iSession(aSession), iParamDes(0,0,0)
1.29 + {}
1.30 +
1.31 +TInt CPipeChildDesc::LSeek (int&, int)
1.32 + {
1.33 + return ESPIPE; // can't seek on a pipe
1.34 + }
1.35 +
1.36 +TInt CPipeChildDesc::FStat(struct stat *st)
1.37 + {
1.38 + // I am a fifo about which little is known
1.39 + st->st_mode = S_IFIFO;
1.40 + st->st_blksize=0;
1.41 + return KErrNone;
1.42 + }
1.43 +
1.44 +void CPipeChildDesc::Read (TDes8& aBuf, TRequestStatus& aStatus)
1.45 + {
1.46 + if (iClientClosed || !IsReadable())
1.47 + {
1.48 + Complete(aStatus,KErrEof);
1.49 + return;
1.50 + }
1.51 + TIpcArgs args(iIndex,&aBuf,aBuf.MaxLength());
1.52 + iSession.Request(PMPipeRead,args,aStatus); // asynchronous request
1.53 + }
1.54 +
1.55 +void CPipeChildDesc::ReadCancel()
1.56 + {
1.57 + Cancel(PMPipeRead);
1.58 + }
1.59 +
1.60 +TInt CPipeChildDesc::ReadCompletion(TDes8& aDesc, TInt aStatus)
1.61 + {
1.62 + if (aStatus==KErrEof)
1.63 + {
1.64 + ClientClose();
1.65 + aDesc.Zero(); // set read length to zero
1.66 + return KErrNone; // indicates graceful close at the other end
1.67 + }
1.68 + return aStatus;
1.69 + }
1.70 +
1.71 +void CPipeChildDesc::Write(TDes8& aDesc, TRequestStatus& aStatus)
1.72 + {
1.73 + if (iClientClosed || !IsWriteable())
1.74 + {
1.75 + Complete(aStatus,KErrEof);
1.76 + return;
1.77 + }
1.78 + TIpcArgs args(iIndex,&aDesc,aDesc.Length());
1.79 + iSession.Request(PMPipeWrite,args,aStatus); // asynchronous request
1.80 + }
1.81 +
1.82 +void CPipeChildDesc::WriteCancel()
1.83 + {
1.84 + Cancel(PMPipeWrite);
1.85 + }
1.86 +
1.87 +TInt CPipeChildDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus)
1.88 + {
1.89 + if (aStatus==KErrEof)
1.90 + ClientClose();
1.91 + return aStatus;
1.92 + }
1.93 +
1.94 +void CPipeChildDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
1.95 +//
1.96 +// The work of the Ioctl is done in the parent, including writing back to aParam?
1.97 +// Use the default completion which just returns aStatus.Int()
1.98 +//
1.99 + {
1.100 + if (iClientClosed)
1.101 + {
1.102 + Complete(aStatus,KErrEof);
1.103 + return;
1.104 + }
1.105 + iParamDes.Set((TText8*)aParam,4,4);
1.106 + TIpcArgs args(iIndex,aCmd,&iParamDes);
1.107 + if (aCmd==E32IOSELECT)
1.108 + args.Set(3, *((TInt*)aParam));
1.109 + iSession.Request(PMPipeIoctl,args,aStatus); // asynchronous request
1.110 + }
1.111 +
1.112 +void CPipeChildDesc::IoctlCancel()
1.113 + {
1.114 + Cancel(PMPipeIoctl);
1.115 + }
1.116 +
1.117 +void CPipeChildDesc::Cancel(TInt aType)
1.118 + {
1.119 + if (iClientClosed)
1.120 + return;
1.121 + TIpcArgs args(iIndex,aType);
1.122 + iSession.Request(PMPipeCancel,args);
1.123 + }
1.124 +
1.125 +TInt CPipeChildDesc::FinalClose()
1.126 + {
1.127 + ClientClose();
1.128 + TIpcArgs args(iIndex);
1.129 + return iSession.Request(PMPipeClose,args); // synchronous request
1.130 + }
1.131 +
1.132 +//
1.133 +// Parent end of the pipe, where the real work is done
1.134 +//
1.135 +
1.136 +CPipeDesc::CPipeDesc(TInt anIndex) : CFileDescBase()
1.137 + {
1.138 + iIndex=anIndex;
1.139 + }
1.140 +
1.141 +void CPipeDesc::SetClientSide(CPipeDesc*& aClientPointer)
1.142 + {
1.143 + iClientSide=&aClientPointer;
1.144 + }
1.145 +
1.146 +_LIT(KCPipeDescPanic, "CPipeDesc");
1.147 +void CPipeDesc::Panic(TInt aReason)
1.148 + {
1.149 + User::Panic(KCPipeDescPanic,aReason);
1.150 + }
1.151 +
1.152 +void CPipeDesc::Panic(RMessage2& aMessage, TInt aReason)
1.153 + {
1.154 + aMessage.Panic(KCPipeDescPanic,aReason);
1.155 + }
1.156 +
1.157 +TInt CPipeDesc::LSeek (int&, int)
1.158 + {
1.159 + return ESPIPE; // can't seek on a pipe
1.160 + }
1.161 +
1.162 +TInt CPipeDesc::FStat(struct stat *st)
1.163 + {
1.164 + // I am a fifo about which little is known
1.165 + st->st_mode = S_IFIFO;
1.166 + st->st_blksize=0;
1.167 + return KErrNone;
1.168 + }
1.169 +
1.170 +void CPipeDesc::Read (TDes8& aBuf, TRequestStatus& aStatus)
1.171 + {
1.172 + if (!IsReadable())
1.173 + {
1.174 + Complete(aStatus, KErrEof); // avoids treading on iStatus of pending Write
1.175 + return;
1.176 + }
1.177 + __ASSERT_DEBUG(iStatus==0,Panic(1));
1.178 + iStatus=&aStatus;
1.179 + if (iClientClosed)
1.180 + {
1.181 + User::RequestComplete(iStatus,KErrEof);
1.182 + return;
1.183 + }
1.184 + iReadBuf=&aBuf;
1.185 + if (ClientIoctlPending())
1.186 + CompleteClientIoctl();
1.187 + if (iClientLength!=0)
1.188 + TransferFromClient();
1.189 + }
1.190 +
1.191 +void CPipeDesc::ReadCancel()
1.192 + {
1.193 + Cancel();
1.194 + }
1.195 +
1.196 +TInt CPipeDesc::ReadCompletion(TDes8& aDesc, TInt aStatus)
1.197 + {
1.198 + if (aStatus==KErrEof)
1.199 + {
1.200 + ClientClose();
1.201 + aDesc.Zero(); // set read length to zero
1.202 + return KErrNone; // indicates graceful close at the other end
1.203 + }
1.204 + return aStatus;
1.205 + }
1.206 +
1.207 +void CPipeDesc::Write(TDes8& aDesc, TRequestStatus& aStatus)
1.208 + {
1.209 + if (!IsWriteable())
1.210 + {
1.211 + Complete(aStatus, KErrEof); // avoids treading on iStatus of pending Read
1.212 + return;
1.213 + }
1.214 + __ASSERT_DEBUG(iStatus==0,Panic(2));
1.215 + iStatus=&aStatus;
1.216 + if (iClientClosed)
1.217 + {
1.218 + User::RequestComplete(iStatus,KErrEof);
1.219 + return;
1.220 + }
1.221 + iWriteBuf.Set(aDesc);
1.222 + if (ClientIoctlPending())
1.223 + CompleteClientIoctl();
1.224 + if (iClientLength!=0)
1.225 + TransferToClient();
1.226 + }
1.227 +
1.228 +void CPipeDesc::WriteCancel()
1.229 + {
1.230 + Cancel();
1.231 + }
1.232 +
1.233 +TInt CPipeDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus)
1.234 + {
1.235 + if (aStatus==KErrEof)
1.236 + ClientClose();
1.237 + return aStatus;
1.238 + }
1.239 +
1.240 +void CPipeDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus)
1.241 + {
1.242 + TInt ret=KErrNone;
1.243 + iIoctlStatus=&aStatus;
1.244 + int *param=REINTERPRET_CAST(int*,aParam);
1.245 + switch (aCmd)
1.246 + {
1.247 + case E32IONREAD:
1.248 + // synchronous ioctls are handled in the completion routine.
1.249 + break;
1.250 + case E32IOSELECT:
1.251 + {
1.252 + int mask=(*param)&SelectMask();
1.253 + if (mask!=0 && iClientLength==0)
1.254 + return; // wait for client to show up
1.255 + }
1.256 + break;
1.257 + default:
1.258 + ret=KErrNotSupported;
1.259 + break;
1.260 + }
1.261 + User::RequestComplete(iIoctlStatus,ret);
1.262 + }
1.263 +
1.264 +TInt CPipeDesc::IoctlCompletion(int aCmd, void* aParam, TInt aStatus)
1.265 + {
1.266 + TInt ret=aStatus;
1.267 + if (ret!=KErrNone)
1.268 + return ret;
1.269 + int *param=REINTERPRET_CAST(int*,aParam);
1.270 + switch (aCmd)
1.271 + {
1.272 + case E32IONREAD:
1.273 + if (IsReadable())
1.274 + *param=iClientLength; // 0 if no outstanding client data
1.275 + else
1.276 + *param=0; // claim that no data is available
1.277 + break;
1.278 + case E32IOSELECT:
1.279 + {
1.280 + int mask=0;
1.281 + if (iClientLength!=0)
1.282 + mask = SelectMask();
1.283 + *param=(*param)&mask;
1.284 + }
1.285 + break;
1.286 + default:
1.287 + ret=KErrNotSupported;
1.288 + break;
1.289 + }
1.290 + return ret;
1.291 + }
1.292 +
1.293 +void CPipeDesc::IoctlCancel()
1.294 + {
1.295 + User::RequestComplete(iIoctlStatus,KErrCancel);
1.296 + }
1.297 +
1.298 +void CPipeDesc::Cancel()
1.299 + {
1.300 + // Pipes are unidirectional, so don't need to distinguish between
1.301 + // ReadCancel and WriteCancel
1.302 + User::RequestComplete(iStatus,KErrCancel);
1.303 + }
1.304 +
1.305 +// Client-side interface
1.306 +
1.307 +void CPipeDesc::ClientWrite(const RMessage2& aMessage)
1.308 + {
1.309 + __ASSERT_DEBUG(iClientLength==0,Panic(3));
1.310 + if (iClientClosed)
1.311 + {
1.312 + aMessage.Complete(KErrEof);
1.313 + return;
1.314 + }
1.315 + iClientLength=aMessage.Int2();
1.316 + iClientOffset=0;
1.317 + iMessage=aMessage;
1.318 + if (iIoctlStatus!=0)
1.319 + User::RequestComplete(iIoctlStatus,KErrNone);
1.320 + if (iStatus!=0)
1.321 + TransferFromClient();
1.322 + }
1.323 +
1.324 +void CPipeDesc::ClientRead(const RMessage2& aMessage)
1.325 + {
1.326 + __ASSERT_DEBUG(iClientLength==0,Panic(4));
1.327 + if (iClientClosed)
1.328 + {
1.329 + aMessage.Complete(KErrEof);
1.330 + return;
1.331 + }
1.332 + iClientLength=aMessage.Int2();
1.333 + iMessage=aMessage;
1.334 + if (iIoctlStatus!=0)
1.335 + User::RequestComplete(iIoctlStatus,KErrNone);
1.336 + if (iStatus!=0)
1.337 + TransferToClient();
1.338 + }
1.339 +
1.340 +void CPipeDesc::ClientIoctl(const RMessage2& aMessage)
1.341 + {
1.342 + __ASSERT_DEBUG(!ClientIoctlPending(),Panic(7));
1.343 + if (iClientClosed)
1.344 + {
1.345 + aMessage.Complete(KErrEof);
1.346 + return;
1.347 + }
1.348 + iClientIoctlPending=1;
1.349 + iIoctlMessage=aMessage;
1.350 + TInt ret=KErrNone;
1.351 + switch (aMessage.Int1())
1.352 + {
1.353 + case E32IONREAD:
1.354 + // synchronous ioctls are handled in the completion routine.
1.355 + break;
1.356 + case E32IOSELECT:
1.357 + {
1.358 + int mask=aMessage.Int3();
1.359 + mask&=ClientSelectMask();
1.360 + if (mask!=0 && iStatus==0)
1.361 + return; // wait for parent activity
1.362 + }
1.363 + break;
1.364 + default:
1.365 + ret=KErrNotSupported;
1.366 + break;
1.367 + }
1.368 + CompleteClientIoctl(ret);
1.369 + }
1.370 +
1.371 +void CPipeDesc::ClientCancel(const RMessage2& aMessage)
1.372 + {
1.373 + if (aMessage.Int1()==PMPipeIoctl)
1.374 + {
1.375 + if (ClientIoctlPending())
1.376 + CompleteClientIoctl(KErrCancel);
1.377 + return;
1.378 + }
1.379 + // Pipes are unidirectional, so Read and Write are cancelled by
1.380 + // cancelling the current client operation.
1.381 + //
1.382 + if (iClientLength!=0)
1.383 + {
1.384 + iMessage.Complete(KErrCancel);
1.385 + iClientLength=0;
1.386 + }
1.387 + }
1.388 +
1.389 +void CPipeDesc::ClientClose()
1.390 + {
1.391 + iClientClosed=1;
1.392 + // terminate any pending requests
1.393 + if (iStatus!=0)
1.394 + User::RequestComplete(iStatus,KErrEof);
1.395 + if (ClientIoctlPending())
1.396 + CompleteClientIoctl(KErrEof);
1.397 + if (iClientLength!=0)
1.398 + {
1.399 + iMessage.Complete(KErrEof);
1.400 + iClientLength=0;
1.401 + }
1.402 + }
1.403 +
1.404 +TInt CPipeDesc::FinalClose()
1.405 + {
1.406 + ClientClose();
1.407 + if (iClientSide)
1.408 + {
1.409 + *iClientSide=0;
1.410 + iClientSide=0;
1.411 + }
1.412 + return KErrNone;
1.413 + }
1.414 +
1.415 +void CPipeDesc::TransferFromClient()
1.416 +//
1.417 +// Handle transfer of data from client to parent.
1.418 +// Always complete the parent read, but only complete the child write when
1.419 +// all of the data has been consumed.
1.420 +//
1.421 + {
1.422 + TRAPD(err,iMessage.ReadL(1,*iReadBuf,iClientOffset));
1.423 + if (err)
1.424 + {
1.425 + Panic(iMessage,5);
1.426 + iClientLength=0;
1.427 + ClientClose(); // will complete the parent read
1.428 + return;
1.429 + }
1.430 + TInt length=iReadBuf->Length(); // record the amount of data transferred
1.431 + User::RequestComplete(iStatus,KErrNone);
1.432 + iClientOffset+=length;
1.433 + iClientLength-=length;
1.434 + if (iClientLength==0)
1.435 + iMessage.Complete(KErrNone);
1.436 + }
1.437 +
1.438 +void CPipeDesc::TransferToClient()
1.439 +//
1.440 +// Handle transfer from parent to client
1.441 +// Always complete the client read, but only complete the parent write when
1.442 +// all of the data has been consumed.
1.443 +//
1.444 + {
1.445 + TInt err=KErrNone;
1.446 + TInt length=iWriteBuf.Length();
1.447 + TInt written=length;
1.448 + if (iClientLength >= length)
1.449 + {
1.450 + TRAP(err,iMessage.WriteL(1,iWriteBuf,0));
1.451 + }
1.452 + else
1.453 + {
1.454 + written=iClientLength;
1.455 + TRAP(err,iMessage.WriteL(1,iWriteBuf.Left(written),0));
1.456 + }
1.457 + iClientLength=0;
1.458 + if (err)
1.459 + {
1.460 + Panic(iMessage,6);
1.461 + ClientClose(); // will complete the parent write
1.462 + return;
1.463 + }
1.464 + iMessage.Complete(KErrNone);
1.465 + length-=written;
1.466 + if (length==0)
1.467 + User::RequestComplete(iStatus,KErrNone);
1.468 + else
1.469 + iWriteBuf.Set(iWriteBuf.Right(length));
1.470 + }
1.471 +
1.472 +void CPipeDesc::CompleteClientIoctl(TInt ret)
1.473 + {
1.474 + if (ret!=KErrNone)
1.475 + {
1.476 + iIoctlMessage.Complete(ret);
1.477 + iClientIoctlPending=0;
1.478 + return;
1.479 + }
1.480 + CompleteClientIoctl();
1.481 + }
1.482 +
1.483 +void CPipeDesc::CompleteClientIoctl()
1.484 +//
1.485 +// Complete outstanding PMPipeIoctl message
1.486 +//
1.487 + {
1.488 + TInt ret=KErrNone;
1.489 + int param=0;
1.490 + switch (iIoctlMessage.Int1())
1.491 + {
1.492 + case E32IONREAD:
1.493 + if (IsWriteable() && iStatus!=0)
1.494 + param=iWriteBuf.Length();
1.495 + else
1.496 + param=0; // claim that no data is available
1.497 + break;
1.498 + case E32IOSELECT:
1.499 + {
1.500 + int mask=0;
1.501 + if (iStatus!=0)
1.502 + mask=ClientSelectMask();
1.503 + param=(iIoctlMessage.Int3())&mask;
1.504 + }
1.505 + break;
1.506 + default:
1.507 + ret=KErrNotSupported;
1.508 + break;
1.509 + }
1.510 + if (ret==KErrNone)
1.511 + {
1.512 + TPtrC8 paramReturn((const TText8*)¶m,4);
1.513 + TRAP(ret,iIoctlMessage.WriteL(2,paramReturn,0));
1.514 + }
1.515 + iIoctlMessage.Complete(ret);
1.516 + iClientIoctlPending=0;
1.517 + }