VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/pipe-win.cpp@ 93019

Last change on this file since 93019 was 86412, checked in by vboxsync, 4 years ago

IPRT/pipe: Adding RTPipeCloseEx w/ a fLeaveOpen parameter so we can prevent leaks via RTHandleGetStandard. Adding RTPIPE_N_LEAVE_OPEN to RTPipeFromNative. bugref:9841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.4 KB
Line 
1/* $Id: pipe-win.cpp 86412 2020-10-02 11:39:26Z vboxsync $ */
2/** @file
3 * IPRT - Anonymous Pipes, Windows Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/win/windows.h>
32
33#include <iprt/pipe.h>
34#include "internal/iprt.h"
35
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/critsect.h>
39#include <iprt/err.h>
40#include <iprt/mem.h>
41#include <iprt/string.h>
42#include <iprt/poll.h>
43#include <iprt/process.h>
44#include <iprt/thread.h>
45#include <iprt/time.h>
46#include "internal/pipe.h"
47#include "internal/magics.h"
48#include "internal-r3-win.h"
49
50
51/*********************************************************************************************************************************
52* Defined Constants And Macros *
53*********************************************************************************************************************************/
54/** The pipe buffer size we prefer. */
55#define RTPIPE_NT_SIZE _64K
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61typedef struct RTPIPEINTERNAL
62{
63 /** Magic value (RTPIPE_MAGIC). */
64 uint32_t u32Magic;
65 /** The pipe handle. */
66 HANDLE hPipe;
67 /** Set if this is the read end, clear if it's the write end. */
68 bool fRead;
69 /** RTPipeFromNative: Leave native handle open on RTPipeClose. */
70 bool fLeaveOpen;
71 /** Set if there is already pending I/O. */
72 bool fIOPending;
73 /** Set if the zero byte read that the poll code using is pending. */
74 bool fZeroByteRead;
75 /** Set if the pipe is broken. */
76 bool fBrokenPipe;
77 /** Set if we've promised that the handle is writable. */
78 bool fPromisedWritable;
79 /** Set if created inheritable. */
80 bool fCreatedInheritable;
81 /** Usage counter. */
82 uint32_t cUsers;
83 /** The overlapped I/O structure we use. */
84 OVERLAPPED Overlapped;
85 /** Bounce buffer for writes. */
86 uint8_t *pbBounceBuf;
87 /** Amount of used buffer space. */
88 size_t cbBounceBufUsed;
89 /** Amount of allocated buffer space. */
90 size_t cbBounceBufAlloc;
91 /** The handle of the poll set currently polling on this pipe.
92 * We can only have one poller at the time (lazy bird). */
93 RTPOLLSET hPollSet;
94 /** Critical section protecting the above members.
95 * (Taking the lazy/simple approach.) */
96 RTCRITSECT CritSect;
97 /** Buffer for the zero byte read. */
98 uint8_t abBuf[8];
99} RTPIPEINTERNAL;
100
101
102/* from ntdef.h */
103typedef LONG NTSTATUS;
104
105/* from ntddk.h */
106typedef struct _IO_STATUS_BLOCK {
107 union {
108 NTSTATUS Status;
109 PVOID Pointer;
110 };
111 ULONG_PTR Information;
112} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
113
114typedef enum _FILE_INFORMATION_CLASS {
115 FilePipeInformation = 23,
116 FilePipeLocalInformation = 24,
117 FilePipeRemoteInformation = 25,
118} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
119
120/* from ntifs.h */
121typedef struct _FILE_PIPE_LOCAL_INFORMATION {
122 ULONG NamedPipeType;
123 ULONG NamedPipeConfiguration;
124 ULONG MaximumInstances;
125 ULONG CurrentInstances;
126 ULONG InboundQuota;
127 ULONG ReadDataAvailable;
128 ULONG OutboundQuota;
129 ULONG WriteQuotaAvailable;
130 ULONG NamedPipeState;
131 ULONG NamedPipeEnd;
132} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
133
134#define FILE_PIPE_DISCONNECTED_STATE 0x00000001U
135#define FILE_PIPE_LISTENING_STATE 0x00000002U
136#define FILE_PIPE_CONNECTED_STATE 0x00000003U
137#define FILE_PIPE_CLOSING_STATE 0x00000004U
138
139#define FILE_PIPE_INBOUND 0x00000000U
140#define FILE_PIPE_OUTBOUND 0x00000001U
141#define FILE_PIPE_FULL_DUPLEX 0x00000002U
142
143#define FILE_PIPE_CLIENT_END 0x00000000U
144#define FILE_PIPE_SERVER_END 0x00000001U
145
146extern "C" NTSYSAPI NTSTATUS WINAPI NtQueryInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, LONG, FILE_INFORMATION_CLASS);
147
148
149/**
150 * Wrapper for getting FILE_PIPE_LOCAL_INFORMATION via the NT API.
151 *
152 * @returns Success indicator (true/false).
153 * @param pThis The pipe.
154 * @param pInfo The info structure.
155 */
156static bool rtPipeQueryNtInfo(RTPIPEINTERNAL *pThis, FILE_PIPE_LOCAL_INFORMATION *pInfo)
157{
158 IO_STATUS_BLOCK Ios;
159 RT_ZERO(Ios);
160 RT_ZERO(*pInfo);
161 NTSTATUS rcNt = NtQueryInformationFile(pThis->hPipe, &Ios, pInfo, sizeof(*pInfo), FilePipeLocalInformation);
162 return rcNt >= 0;
163}
164
165
166RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags)
167{
168 AssertPtrReturn(phPipeRead, VERR_INVALID_POINTER);
169 AssertPtrReturn(phPipeWrite, VERR_INVALID_POINTER);
170 AssertReturn(!(fFlags & ~RTPIPE_C_VALID_MASK), VERR_INVALID_PARAMETER);
171
172 /*
173 * Create the read end of the pipe.
174 */
175 DWORD dwErr;
176 HANDLE hPipeR;
177 HANDLE hPipeW;
178 int rc;
179 for (;;)
180 {
181 static volatile uint32_t g_iNextPipe = 0;
182 char szName[128];
183 RTStrPrintf(szName, sizeof(szName), "\\\\.\\pipe\\iprt-pipe-%u-%u", RTProcSelf(), ASMAtomicIncU32(&g_iNextPipe));
184
185 SECURITY_ATTRIBUTES SecurityAttributes;
186 PSECURITY_ATTRIBUTES pSecurityAttributes = NULL;
187 if (fFlags & RTPIPE_C_INHERIT_READ)
188 {
189 SecurityAttributes.nLength = sizeof(SecurityAttributes);
190 SecurityAttributes.lpSecurityDescriptor = NULL;
191 SecurityAttributes.bInheritHandle = TRUE;
192 pSecurityAttributes = &SecurityAttributes;
193 }
194
195 DWORD dwOpenMode = PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED;
196#ifdef FILE_FLAG_FIRST_PIPE_INSTANCE
197 dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
198#endif
199
200 DWORD dwPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
201#ifdef PIPE_REJECT_REMOTE_CLIENTS
202 dwPipeMode |= PIPE_REJECT_REMOTE_CLIENTS;
203#endif
204
205 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, RTPIPE_NT_SIZE, RTPIPE_NT_SIZE,
206 NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes);
207#ifdef PIPE_REJECT_REMOTE_CLIENTS
208 if (hPipeR == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER)
209 {
210 dwPipeMode &= ~PIPE_REJECT_REMOTE_CLIENTS;
211 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, RTPIPE_NT_SIZE, RTPIPE_NT_SIZE,
212 NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes);
213 }
214#endif
215#ifdef FILE_FLAG_FIRST_PIPE_INSTANCE
216 if (hPipeR == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER)
217 {
218 dwOpenMode &= ~FILE_FLAG_FIRST_PIPE_INSTANCE;
219 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, RTPIPE_NT_SIZE, RTPIPE_NT_SIZE,
220 NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes);
221 }
222#endif
223 if (hPipeR != INVALID_HANDLE_VALUE)
224 {
225 /*
226 * Connect to the pipe (the write end).
227 * We add FILE_READ_ATTRIBUTES here to make sure we can query the
228 * pipe state later on.
229 */
230 pSecurityAttributes = NULL;
231 if (fFlags & RTPIPE_C_INHERIT_WRITE)
232 {
233 SecurityAttributes.nLength = sizeof(SecurityAttributes);
234 SecurityAttributes.lpSecurityDescriptor = NULL;
235 SecurityAttributes.bInheritHandle = TRUE;
236 pSecurityAttributes = &SecurityAttributes;
237 }
238
239 hPipeW = CreateFileA(szName,
240 GENERIC_WRITE | FILE_READ_ATTRIBUTES /*dwDesiredAccess*/,
241 0 /*dwShareMode*/,
242 pSecurityAttributes,
243 OPEN_EXISTING /* dwCreationDisposition */,
244 FILE_FLAG_OVERLAPPED /*dwFlagsAndAttributes*/,
245 NULL /*hTemplateFile*/);
246 if (hPipeW != INVALID_HANDLE_VALUE)
247 break;
248 dwErr = GetLastError();
249 CloseHandle(hPipeR);
250 }
251 else
252 dwErr = GetLastError();
253 if ( dwErr != ERROR_PIPE_BUSY /* already exist - compatible */
254 && dwErr != ERROR_ACCESS_DENIED /* already exist - incompatible */)
255 return RTErrConvertFromWin32(dwErr);
256 /* else: try again with a new name */
257 }
258
259 /*
260 * Create the two handles.
261 */
262 RTPIPEINTERNAL *pThisR = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
263 if (pThisR)
264 {
265 RTPIPEINTERNAL *pThisW = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
266 if (pThisW)
267 {
268 rc = RTCritSectInit(&pThisR->CritSect);
269 if (RT_SUCCESS(rc))
270 {
271 rc = RTCritSectInit(&pThisW->CritSect);
272 if (RT_SUCCESS(rc))
273 {
274 pThisR->Overlapped.hEvent = CreateEvent(NULL, TRUE /*fManualReset*/,
275 TRUE /*fInitialState*/, NULL /*pName*/);
276 if (pThisR->Overlapped.hEvent != NULL)
277 {
278 pThisW->Overlapped.hEvent = CreateEvent(NULL, TRUE /*fManualReset*/,
279 TRUE /*fInitialState*/, NULL /*pName*/);
280 if (pThisW->Overlapped.hEvent != NULL)
281 {
282 pThisR->u32Magic = RTPIPE_MAGIC;
283 pThisW->u32Magic = RTPIPE_MAGIC;
284 pThisR->hPipe = hPipeR;
285 pThisW->hPipe = hPipeW;
286 pThisR->fRead = true;
287 pThisW->fRead = false;
288 pThisR->fLeaveOpen = false;
289 pThisW->fLeaveOpen = false;
290 //pThisR->fIOPending = false;
291 //pThisW->fIOPending = false;
292 //pThisR->fZeroByteRead = false;
293 //pThisW->fZeroByteRead = false;
294 //pThisR->fBrokenPipe = false;
295 //pThisW->fBrokenPipe = false;
296 //pThisW->fPromisedWritable = false;
297 //pThisR->fPromisedWritable = false;
298 pThisW->fCreatedInheritable = RT_BOOL(fFlags & RTPIPE_C_INHERIT_WRITE);
299 pThisR->fCreatedInheritable = RT_BOOL(fFlags & RTPIPE_C_INHERIT_READ);
300 //pThisR->cUsers = 0;
301 //pThisW->cUsers = 0;
302 //pThisR->pbBounceBuf = NULL;
303 //pThisW->pbBounceBuf = NULL;
304 //pThisR->cbBounceBufUsed = 0;
305 //pThisW->cbBounceBufUsed = 0;
306 //pThisR->cbBounceBufAlloc = 0;
307 //pThisW->cbBounceBufAlloc = 0;
308 pThisR->hPollSet = NIL_RTPOLLSET;
309 pThisW->hPollSet = NIL_RTPOLLSET;
310
311 *phPipeRead = pThisR;
312 *phPipeWrite = pThisW;
313 return VINF_SUCCESS;
314 }
315 CloseHandle(pThisR->Overlapped.hEvent);
316 }
317 RTCritSectDelete(&pThisW->CritSect);
318 }
319 RTCritSectDelete(&pThisR->CritSect);
320 }
321 RTMemFree(pThisW);
322 }
323 else
324 rc = VERR_NO_MEMORY;
325 RTMemFree(pThisR);
326 }
327 else
328 rc = VERR_NO_MEMORY;
329
330 CloseHandle(hPipeR);
331 CloseHandle(hPipeW);
332 return rc;
333}
334
335
336/**
337 * Common worker for handling I/O completion.
338 *
339 * This is used by RTPipeClose, RTPipeWrite and RTPipeWriteBlocking.
340 *
341 * @returns IPRT status code.
342 * @param pThis The pipe instance handle.
343 */
344static int rtPipeWriteCheckCompletion(RTPIPEINTERNAL *pThis)
345{
346 int rc;
347 DWORD dwRc = WaitForSingleObject(pThis->Overlapped.hEvent, 0);
348 if (dwRc == WAIT_OBJECT_0)
349 {
350 DWORD cbWritten = 0;
351 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbWritten, TRUE))
352 {
353 for (;;)
354 {
355 if (cbWritten >= pThis->cbBounceBufUsed)
356 {
357 pThis->fIOPending = false;
358 rc = VINF_SUCCESS;
359 break;
360 }
361
362 /* resubmit the remainder of the buffer - can this actually happen? */
363 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
364 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
365 if (!WriteFile(pThis->hPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
366 &cbWritten, &pThis->Overlapped))
367 {
368 if (GetLastError() == ERROR_IO_PENDING)
369 rc = VINF_TRY_AGAIN;
370 else
371 {
372 pThis->fIOPending = false;
373 if (GetLastError() == ERROR_NO_DATA)
374 rc = VERR_BROKEN_PIPE;
375 else
376 rc = RTErrConvertFromWin32(GetLastError());
377 if (rc == VERR_BROKEN_PIPE)
378 pThis->fBrokenPipe = true;
379 }
380 break;
381 }
382 Assert(cbWritten > 0);
383 }
384 }
385 else
386 {
387 pThis->fIOPending = false;
388 rc = RTErrConvertFromWin32(GetLastError());
389 }
390 }
391 else if (dwRc == WAIT_TIMEOUT)
392 rc = VINF_TRY_AGAIN;
393 else
394 {
395 pThis->fIOPending = false;
396 if (dwRc == WAIT_ABANDONED)
397 rc = VERR_INVALID_HANDLE;
398 else
399 rc = RTErrConvertFromWin32(GetLastError());
400 }
401 return rc;
402}
403
404
405
406RTDECL(int) RTPipeCloseEx(RTPIPE hPipe, bool fLeaveOpen)
407{
408 RTPIPEINTERNAL *pThis = hPipe;
409 if (pThis == NIL_RTPIPE)
410 return VINF_SUCCESS;
411 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
412 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
413
414 /*
415 * Do the cleanup.
416 */
417 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE);
418 RTCritSectEnter(&pThis->CritSect);
419 Assert(pThis->cUsers == 0);
420
421 if (!pThis->fRead && pThis->fIOPending)
422 rtPipeWriteCheckCompletion(pThis);
423
424 if (!fLeaveOpen && !pThis->fLeaveOpen)
425 CloseHandle(pThis->hPipe);
426 pThis->hPipe = INVALID_HANDLE_VALUE;
427
428 CloseHandle(pThis->Overlapped.hEvent);
429 pThis->Overlapped.hEvent = NULL;
430
431 RTMemFree(pThis->pbBounceBuf);
432 pThis->pbBounceBuf = NULL;
433
434 RTCritSectLeave(&pThis->CritSect);
435 RTCritSectDelete(&pThis->CritSect);
436
437 RTMemFree(pThis);
438
439 return VINF_SUCCESS;
440}
441
442
443RTDECL(int) RTPipeClose(RTPIPE hPipe)
444{
445 return RTPipeCloseEx(hPipe, false /*fLeaveOpen*/);
446}
447
448
449RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags)
450{
451 AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
452 AssertReturn(!(fFlags & ~RTPIPE_N_VALID_MASK_FN), VERR_INVALID_PARAMETER);
453 AssertReturn(!!(fFlags & RTPIPE_N_READ) != !!(fFlags & RTPIPE_N_WRITE), VERR_INVALID_PARAMETER);
454
455 /*
456 * Get and validate the pipe handle info.
457 */
458 HANDLE hNative = (HANDLE)hNativePipe;
459 AssertReturn(GetFileType(hNative) == FILE_TYPE_PIPE, VERR_INVALID_HANDLE);
460
461 DWORD cMaxInstances;
462 DWORD fInfo;
463 if (!GetNamedPipeInfo(hNative, &fInfo, NULL, NULL, &cMaxInstances))
464 return RTErrConvertFromWin32(GetLastError());
465 /* Doesn't seem to matter to much if the pipe is message or byte type. Cygwin
466 seems to hand us such pipes when capturing output (@bugref{9397}), so just
467 ignore skip this check:
468 AssertReturn(!(fInfo & PIPE_TYPE_MESSAGE), VERR_INVALID_HANDLE); */
469 AssertReturn(cMaxInstances == 1, VERR_INVALID_HANDLE);
470
471 DWORD cInstances;
472 DWORD fState;
473 if (!GetNamedPipeHandleState(hNative, &fState, &cInstances, NULL, NULL, NULL, 0))
474 return RTErrConvertFromWin32(GetLastError());
475 AssertReturn(!(fState & PIPE_NOWAIT), VERR_INVALID_HANDLE);
476 AssertReturn(!(fState & PIPE_READMODE_MESSAGE), VERR_INVALID_HANDLE);
477 AssertReturn(cInstances <= 1, VERR_INVALID_HANDLE);
478
479 /*
480 * Looks kind of OK, create a handle so we can try rtPipeQueryNtInfo on it
481 * and see if we need to duplicate it to make that call work.
482 */
483 RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
484 if (!pThis)
485 return VERR_NO_MEMORY;
486 int rc = RTCritSectInit(&pThis->CritSect);
487 if (RT_SUCCESS(rc))
488 {
489 pThis->Overlapped.hEvent = CreateEvent(NULL, TRUE /*fManualReset*/,
490 TRUE /*fInitialState*/, NULL /*pName*/);
491 if (pThis->Overlapped.hEvent != NULL)
492 {
493 pThis->u32Magic = RTPIPE_MAGIC;
494 pThis->hPipe = hNative;
495 pThis->fRead = RT_BOOL(fFlags & RTPIPE_N_READ);
496 pThis->fLeaveOpen = RT_BOOL(fFlags & RTPIPE_N_LEAVE_OPEN);
497 //pThis->fIOPending = false;
498 //pThis->fZeroByteRead = false;
499 //pThis->fBrokenPipe = false;
500 //pThis->fPromisedWritable = false;
501 pThis->fCreatedInheritable = RT_BOOL(fFlags & RTPIPE_N_INHERIT);
502 //pThis->cUsers = 0;
503 //pThis->pbBounceBuf = NULL;
504 //pThis->cbBounceBufUsed = 0;
505 //pThis->cbBounceBufAlloc = 0;
506 pThis->hPollSet = NIL_RTPOLLSET;
507
508 HANDLE hNative2 = INVALID_HANDLE_VALUE;
509 FILE_PIPE_LOCAL_INFORMATION Info;
510 RT_ZERO(Info);
511 if ( g_enmWinVer != kRTWinOSType_NT310
512 && rtPipeQueryNtInfo(pThis, &Info))
513 rc = VINF_SUCCESS;
514 else
515 {
516 if (DuplicateHandle(GetCurrentProcess() /*hSrcProcess*/, hNative /*hSrcHandle*/,
517 GetCurrentProcess() /*hDstProcess*/, &hNative2 /*phDstHandle*/,
518 pThis->fRead ? GENERIC_READ : GENERIC_WRITE | FILE_READ_ATTRIBUTES /*dwDesiredAccess*/,
519 !!(fFlags & RTPIPE_N_INHERIT) /*fInheritHandle*/,
520 0 /*dwOptions*/))
521 {
522 pThis->hPipe = hNative2;
523 if (rtPipeQueryNtInfo(pThis, &Info))
524 {
525 pThis->fLeaveOpen = false;
526 rc = VINF_SUCCESS;
527 }
528 else
529 {
530 rc = VERR_ACCESS_DENIED;
531 CloseHandle(hNative2);
532 }
533 }
534 else
535 hNative2 = INVALID_HANDLE_VALUE;
536 }
537 if (RT_SUCCESS(rc))
538 {
539 /*
540 * Verify the pipe state and correct the inheritability.
541 */
542 AssertStmt( Info.NamedPipeState == FILE_PIPE_CONNECTED_STATE
543 || Info.NamedPipeState == FILE_PIPE_CLOSING_STATE
544 || Info.NamedPipeState == FILE_PIPE_DISCONNECTED_STATE,
545 VERR_INVALID_HANDLE);
546 AssertStmt( Info.NamedPipeConfiguration
547 == ( Info.NamedPipeEnd == FILE_PIPE_SERVER_END
548 ? (pThis->fRead ? FILE_PIPE_INBOUND : FILE_PIPE_OUTBOUND)
549 : (pThis->fRead ? FILE_PIPE_OUTBOUND : FILE_PIPE_INBOUND) )
550 || Info.NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX,
551 VERR_INVALID_HANDLE);
552 if ( RT_SUCCESS(rc)
553 && hNative2 == INVALID_HANDLE_VALUE
554 && !SetHandleInformation(hNative,
555 HANDLE_FLAG_INHERIT /*dwMask*/,
556 fFlags & RTPIPE_N_INHERIT ? HANDLE_FLAG_INHERIT : 0))
557 {
558 rc = RTErrConvertFromWin32(GetLastError());
559 AssertMsgFailed(("%Rrc\n", rc));
560 }
561 if (RT_SUCCESS(rc))
562 {
563 /*
564 * Ok, we're good! If we replaced the handle, make sure it's not a standard
565 * handle if we think we need to close it.
566 */
567 if (hNative2 != INVALID_HANDLE_VALUE)
568 {
569 if ( !(fFlags & RTPIPE_N_LEAVE_OPEN)
570 && hNative != GetStdHandle(STD_INPUT_HANDLE)
571 && hNative != GetStdHandle(STD_OUTPUT_HANDLE)
572 && hNative != GetStdHandle(STD_ERROR_HANDLE) )
573 CloseHandle(hNative);
574 }
575 *phPipe = pThis;
576 return VINF_SUCCESS;
577 }
578 }
579
580 /* Bail out. */
581 if (hNative2 != INVALID_HANDLE_VALUE)
582 CloseHandle(hNative2);
583 CloseHandle(pThis->Overlapped.hEvent);
584 }
585 RTCritSectDelete(&pThis->CritSect);
586 }
587 RTMemFree(pThis);
588 return rc;
589}
590
591
592RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe)
593{
594 RTPIPEINTERNAL *pThis = hPipe;
595 AssertPtrReturn(pThis, -1);
596 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, -1);
597
598 return (RTHCINTPTR)pThis->hPipe;
599}
600
601
602RTDECL(int) RTPipeGetCreationInheritability(RTPIPE hPipe)
603{
604 RTPIPEINTERNAL *pThis = hPipe;
605 AssertPtrReturn(pThis, false);
606 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, false);
607
608 return pThis->fCreatedInheritable;
609}
610
611
612RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
613{
614 RTPIPEINTERNAL *pThis = hPipe;
615 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
616 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
617 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
618 AssertPtr(pcbRead);
619 AssertPtr(pvBuf);
620
621 int rc = RTCritSectEnter(&pThis->CritSect);
622 if (RT_SUCCESS(rc))
623 {
624 /* No concurrent readers, sorry. */
625 if (pThis->cUsers == 0)
626 {
627 pThis->cUsers++;
628
629 /*
630 * Kick of a an overlapped read. It should return immediately if
631 * there is bytes in the buffer. If not, we'll cancel it and see
632 * what we get back.
633 */
634 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
635 DWORD cbRead = 0;
636 if ( cbToRead == 0
637 || ReadFile(pThis->hPipe, pvBuf,
638 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
639 &cbRead, &pThis->Overlapped))
640 {
641 *pcbRead = cbRead;
642 rc = VINF_SUCCESS;
643 }
644 else if (GetLastError() == ERROR_IO_PENDING)
645 {
646 pThis->fIOPending = true;
647 RTCritSectLeave(&pThis->CritSect);
648
649 if (!CancelIo(pThis->hPipe))
650 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
651 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
652 {
653 *pcbRead = cbRead;
654 rc = VINF_SUCCESS;
655 }
656 else if (GetLastError() == ERROR_OPERATION_ABORTED)
657 {
658 *pcbRead = 0;
659 rc = VINF_TRY_AGAIN;
660 }
661 else
662 rc = RTErrConvertFromWin32(GetLastError());
663
664 RTCritSectEnter(&pThis->CritSect);
665 pThis->fIOPending = false;
666 }
667 else
668 rc = RTErrConvertFromWin32(GetLastError());
669 if (rc == VERR_BROKEN_PIPE)
670 pThis->fBrokenPipe = true;
671
672 pThis->cUsers--;
673 }
674 else
675 rc = VERR_WRONG_ORDER;
676 RTCritSectLeave(&pThis->CritSect);
677 }
678 return rc;
679}
680
681
682RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
683{
684 RTPIPEINTERNAL *pThis = hPipe;
685 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
686 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
687 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
688 AssertPtr(pvBuf);
689
690 int rc = RTCritSectEnter(&pThis->CritSect);
691 if (RT_SUCCESS(rc))
692 {
693 /* No concurrent readers, sorry. */
694 if (pThis->cUsers == 0)
695 {
696 pThis->cUsers++;
697
698 size_t cbTotalRead = 0;
699 while (cbToRead > 0)
700 {
701 /*
702 * Kick of a an overlapped read. It should return immediately if
703 * there is bytes in the buffer. If not, we'll cancel it and see
704 * what we get back.
705 */
706 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
707 DWORD cbRead = 0;
708 pThis->fIOPending = true;
709 RTCritSectLeave(&pThis->CritSect);
710
711 if (ReadFile(pThis->hPipe, pvBuf,
712 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
713 &cbRead, &pThis->Overlapped))
714 rc = VINF_SUCCESS;
715 else if (GetLastError() == ERROR_IO_PENDING)
716 {
717 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
718 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
719 rc = VINF_SUCCESS;
720 else
721 rc = RTErrConvertFromWin32(GetLastError());
722 }
723 else
724 rc = RTErrConvertFromWin32(GetLastError());
725
726 RTCritSectEnter(&pThis->CritSect);
727 pThis->fIOPending = false;
728 if (RT_FAILURE(rc))
729 break;
730
731 /* advance */
732 cbToRead -= cbRead;
733 cbTotalRead += cbRead;
734 pvBuf = (uint8_t *)pvBuf + cbRead;
735 }
736
737 if (rc == VERR_BROKEN_PIPE)
738 pThis->fBrokenPipe = true;
739
740 if (pcbRead)
741 {
742 *pcbRead = cbTotalRead;
743 if ( RT_FAILURE(rc)
744 && cbTotalRead
745 && rc != VERR_INVALID_POINTER)
746 rc = VINF_SUCCESS;
747 }
748
749 pThis->cUsers--;
750 }
751 else
752 rc = VERR_WRONG_ORDER;
753 RTCritSectLeave(&pThis->CritSect);
754 }
755 return rc;
756}
757
758
759RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
760{
761 RTPIPEINTERNAL *pThis = hPipe;
762 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
763 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
764 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
765 AssertPtr(pcbWritten);
766 AssertPtr(pvBuf);
767
768 int rc = RTCritSectEnter(&pThis->CritSect);
769 if (RT_SUCCESS(rc))
770 {
771 /* No concurrent writers, sorry. */
772 if (pThis->cUsers == 0)
773 {
774 pThis->cUsers++;
775
776 /* If I/O is pending, check if it has completed. */
777 if (pThis->fIOPending)
778 rc = rtPipeWriteCheckCompletion(pThis);
779 else
780 rc = VINF_SUCCESS;
781 if (rc == VINF_SUCCESS)
782 {
783 Assert(!pThis->fIOPending);
784
785 /* Adjust the number of bytes to write to fit into the current
786 buffer quota, unless we've promised stuff in RTPipeSelectOne.
787 WriteQuotaAvailable better not be zero when it shouldn't!! */
788 FILE_PIPE_LOCAL_INFORMATION Info;
789 if ( !pThis->fPromisedWritable
790 && cbToWrite > 0
791 && rtPipeQueryNtInfo(pThis, &Info))
792 {
793 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
794 rc = VERR_BROKEN_PIPE;
795 /** @todo fixme: To get the pipe writing support to work the
796 * block below needs to be commented out until a
797 * way is found to address the problem of the incorrectly
798 * set field Info.WriteQuotaAvailable. */
799#if 0
800 else if ( cbToWrite >= Info.WriteQuotaAvailable
801 && Info.OutboundQuota != 0
802 && (Info.WriteQuotaAvailable || pThis->cbBounceBufAlloc)
803 )
804 {
805 cbToWrite = Info.WriteQuotaAvailable;
806 if (!cbToWrite)
807 rc = VINF_TRY_AGAIN;
808 }
809#endif
810 }
811 pThis->fPromisedWritable = false;
812
813 /* Do the bounce buffering. */
814 if ( pThis->cbBounceBufAlloc < cbToWrite
815 && pThis->cbBounceBufAlloc < RTPIPE_NT_SIZE)
816 {
817 if (cbToWrite > RTPIPE_NT_SIZE)
818 cbToWrite = RTPIPE_NT_SIZE;
819 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K));
820 if (pv)
821 {
822 pThis->pbBounceBuf = (uint8_t *)pv;
823 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K);
824 }
825 else
826 rc = VERR_NO_MEMORY;
827 }
828 else if (cbToWrite > RTPIPE_NT_SIZE)
829 cbToWrite = RTPIPE_NT_SIZE;
830 if (RT_SUCCESS(rc) && cbToWrite)
831 {
832 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite);
833 pThis->cbBounceBufUsed = (uint32_t)cbToWrite;
834
835 /* Submit the write. */
836 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
837 DWORD cbWritten = 0;
838 if (WriteFile(pThis->hPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
839 &cbWritten, &pThis->Overlapped))
840 {
841 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */
842 rc = VINF_SUCCESS;
843 }
844 else if (GetLastError() == ERROR_IO_PENDING)
845 {
846 *pcbWritten = cbToWrite;
847 pThis->fIOPending = true;
848 rc = VINF_SUCCESS;
849 }
850 else if (GetLastError() == ERROR_NO_DATA)
851 rc = VERR_BROKEN_PIPE;
852 else
853 rc = RTErrConvertFromWin32(GetLastError());
854 }
855 else if (RT_SUCCESS(rc))
856 *pcbWritten = 0;
857 }
858 else if (RT_SUCCESS(rc))
859 *pcbWritten = 0;
860
861 if (rc == VERR_BROKEN_PIPE)
862 pThis->fBrokenPipe = true;
863
864 pThis->cUsers--;
865 }
866 else
867 rc = VERR_WRONG_ORDER;
868 RTCritSectLeave(&pThis->CritSect);
869 }
870 return rc;
871}
872
873
874RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
875{
876 RTPIPEINTERNAL *pThis = hPipe;
877 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
878 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
879 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
880 AssertPtr(pvBuf);
881 AssertPtrNull(pcbWritten);
882
883 int rc = RTCritSectEnter(&pThis->CritSect);
884 if (RT_SUCCESS(rc))
885 {
886 /* No concurrent writers, sorry. */
887 if (pThis->cUsers == 0)
888 {
889 pThis->cUsers++;
890
891 /*
892 * If I/O is pending, wait for it to complete.
893 */
894 if (pThis->fIOPending)
895 {
896 rc = rtPipeWriteCheckCompletion(pThis);
897 while (rc == VINF_TRY_AGAIN)
898 {
899 Assert(pThis->fIOPending);
900 HANDLE hEvent = pThis->Overlapped.hEvent;
901 RTCritSectLeave(&pThis->CritSect);
902 WaitForSingleObject(hEvent, INFINITE);
903 RTCritSectEnter(&pThis->CritSect);
904 }
905 }
906 if (RT_SUCCESS(rc))
907 {
908 Assert(!pThis->fIOPending);
909 pThis->fPromisedWritable = false;
910
911 /*
912 * Try write everything.
913 * No bounce buffering, cUsers protects us.
914 */
915 size_t cbTotalWritten = 0;
916 while (cbToWrite > 0)
917 {
918 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
919 pThis->fIOPending = true;
920 RTCritSectLeave(&pThis->CritSect);
921
922 DWORD cbWritten = 0;
923 DWORD const cbToWriteInThisIteration = cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0;
924 if (WriteFile(pThis->hPipe, pvBuf, cbToWriteInThisIteration, &cbWritten, &pThis->Overlapped))
925 rc = VINF_SUCCESS;
926 else if (GetLastError() == ERROR_IO_PENDING)
927 {
928 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
929 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbWritten, TRUE /*fWait*/))
930 rc = VINF_SUCCESS;
931 else
932 rc = RTErrConvertFromWin32(GetLastError());
933 }
934 else if (GetLastError() == ERROR_NO_DATA)
935 rc = VERR_BROKEN_PIPE;
936 else
937 rc = RTErrConvertFromWin32(GetLastError());
938
939 RTCritSectEnter(&pThis->CritSect);
940 pThis->fIOPending = false;
941 if (RT_FAILURE(rc))
942 break;
943
944 /* advance */
945 if (cbWritten > cbToWriteInThisIteration) /* paranoia^3 */
946 cbWritten = cbToWriteInThisIteration;
947 pvBuf = (char const *)pvBuf + cbWritten;
948 cbTotalWritten += cbWritten;
949 cbToWrite -= cbWritten;
950 }
951
952 if (pcbWritten)
953 {
954 *pcbWritten = cbTotalWritten;
955 if ( RT_FAILURE(rc)
956 && cbTotalWritten
957 && rc != VERR_INVALID_POINTER)
958 rc = VINF_SUCCESS;
959 }
960 }
961
962 if (rc == VERR_BROKEN_PIPE)
963 pThis->fBrokenPipe = true;
964
965 pThis->cUsers--;
966 }
967 else
968 rc = VERR_WRONG_ORDER;
969 RTCritSectLeave(&pThis->CritSect);
970 }
971 return rc;
972
973#if 0 /** @todo r=bird: What's this? */
974 int rc = rtPipeTryBlocking(pThis);
975 if (RT_SUCCESS(rc))
976 {
977 size_t cbTotalWritten = 0;
978 while (cbToWrite > 0)
979 {
980 ssize_t cbWritten = write(pThis->fd, pvBuf, RT_MIN(cbToWrite, SSIZE_MAX));
981 if (cbWritten < 0)
982 {
983 rc = RTErrConvertFromErrno(errno);
984 break;
985 }
986
987 /* advance */
988 pvBuf = (char const *)pvBuf + cbWritten;
989 cbTotalWritten += cbWritten;
990 cbToWrite -= cbWritten;
991 }
992
993 if (pcbWritten)
994 {
995 *pcbWritten = cbTotalWritten;
996 if ( RT_FAILURE(rc)
997 && cbTotalWritten
998 && rc != VERR_INVALID_POINTER)
999 rc = VINF_SUCCESS;
1000 }
1001
1002 ASMAtomicDecU32(&pThis->u32State);
1003 }
1004 return rc;
1005#endif
1006}
1007
1008
1009RTDECL(int) RTPipeFlush(RTPIPE hPipe)
1010{
1011 RTPIPEINTERNAL *pThis = hPipe;
1012 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1013 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1014 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
1015
1016 if (!FlushFileBuffers(pThis->hPipe))
1017 {
1018 int rc = RTErrConvertFromWin32(GetLastError());
1019 if (rc == VERR_BROKEN_PIPE)
1020 pThis->fBrokenPipe = true;
1021 return rc;
1022 }
1023 return VINF_SUCCESS;
1024}
1025
1026
1027RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies)
1028{
1029 RTPIPEINTERNAL *pThis = hPipe;
1030 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1031 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1032
1033 uint64_t const StartMsTS = RTTimeMilliTS();
1034
1035 int rc = RTCritSectEnter(&pThis->CritSect);
1036 if (RT_FAILURE(rc))
1037 return rc;
1038 for (unsigned iLoop = 0;; iLoop++)
1039 {
1040 HANDLE hWait = INVALID_HANDLE_VALUE;
1041 if (pThis->fRead)
1042 {
1043 if (pThis->fIOPending)
1044 hWait = pThis->Overlapped.hEvent;
1045 else
1046 {
1047 /* Peek at the pipe buffer and see how many bytes it contains. */
1048 DWORD cbAvailable;
1049 if ( PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL)
1050 && cbAvailable > 0)
1051 {
1052 rc = VINF_SUCCESS;
1053 break;
1054 }
1055
1056 /* Start a zero byte read operation that we can wait on. */
1057 if (cMillies == 0)
1058 {
1059 rc = VERR_TIMEOUT;
1060 break;
1061 }
1062 AssertBreakStmt(pThis->cUsers == 0, rc = VERR_INTERNAL_ERROR_5);
1063 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
1064 DWORD cbRead = 0;
1065 if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped))
1066 {
1067 rc = VINF_SUCCESS;
1068 if (iLoop > 10)
1069 RTThreadYield();
1070 }
1071 else if (GetLastError() == ERROR_IO_PENDING)
1072 {
1073 pThis->cUsers++;
1074 pThis->fIOPending = true;
1075 pThis->fZeroByteRead = true;
1076 hWait = pThis->Overlapped.hEvent;
1077 }
1078 else
1079 rc = RTErrConvertFromWin32(GetLastError());
1080 }
1081 }
1082 else
1083 {
1084 if (pThis->fIOPending)
1085 {
1086 rc = rtPipeWriteCheckCompletion(pThis);
1087 if (RT_FAILURE(rc))
1088 break;
1089 }
1090 if (pThis->fIOPending)
1091 hWait = pThis->Overlapped.hEvent;
1092 else
1093 {
1094 FILE_PIPE_LOCAL_INFORMATION Info;
1095 if (rtPipeQueryNtInfo(pThis, &Info))
1096 {
1097 /* Check for broken pipe. */
1098 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
1099 {
1100 rc = VERR_BROKEN_PIPE;
1101 break;
1102 }
1103 /* Check for available write buffer space. */
1104 else if (Info.WriteQuotaAvailable > 0)
1105 {
1106 pThis->fPromisedWritable = false;
1107 rc = VINF_SUCCESS;
1108 break;
1109 }
1110 /* delayed buffer alloc or timeout: phony promise
1111 later: See if we still can associate a semaphore with
1112 the pipe, like on OS/2. */
1113 else if ( Info.OutboundQuota == 0
1114 || cMillies)
1115 {
1116 pThis->fPromisedWritable = true;
1117 rc = VINF_SUCCESS;
1118 break;
1119 }
1120 }
1121 else
1122 {
1123 pThis->fPromisedWritable = true;
1124 rc = VINF_SUCCESS;
1125 break;
1126 }
1127 }
1128 }
1129 if (RT_FAILURE(rc))
1130 break;
1131
1132 /*
1133 * Check for timeout.
1134 */
1135 DWORD cMsMaxWait = INFINITE;
1136 if ( cMillies != RT_INDEFINITE_WAIT
1137 && ( hWait != INVALID_HANDLE_VALUE
1138 || iLoop > 10)
1139 )
1140 {
1141 uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
1142 if (cElapsed >= cMillies)
1143 {
1144 rc = VERR_TIMEOUT;
1145 break;
1146 }
1147 cMsMaxWait = cMillies - (uint32_t)cElapsed;
1148 }
1149
1150 /*
1151 * Wait.
1152 */
1153 if (hWait != INVALID_HANDLE_VALUE)
1154 {
1155 RTCritSectLeave(&pThis->CritSect);
1156
1157 DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
1158 if (dwRc == WAIT_OBJECT_0)
1159 rc = VINF_SUCCESS;
1160 else if (dwRc == WAIT_TIMEOUT)
1161 rc = VERR_TIMEOUT;
1162 else if (dwRc == WAIT_ABANDONED)
1163 rc = VERR_INVALID_HANDLE;
1164 else
1165 rc = RTErrConvertFromWin32(GetLastError());
1166 if ( RT_FAILURE(rc)
1167 && pThis->u32Magic != RTPIPE_MAGIC)
1168 return rc;
1169
1170 RTCritSectEnter(&pThis->CritSect);
1171 if (pThis->fZeroByteRead)
1172 {
1173 pThis->cUsers--;
1174 pThis->fIOPending = false;
1175 if (rc != VINF_SUCCESS)
1176 CancelIo(pThis->hPipe);
1177 DWORD cbRead = 0;
1178 GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/);
1179 }
1180 if (RT_FAILURE(rc))
1181 break;
1182 }
1183 }
1184
1185 if (rc == VERR_BROKEN_PIPE)
1186 pThis->fBrokenPipe = true;
1187
1188 RTCritSectLeave(&pThis->CritSect);
1189 return rc;
1190}
1191
1192
1193RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
1194{
1195 RTPIPEINTERNAL *pThis = hPipe;
1196 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1197 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1198 AssertReturn(pThis->fRead, VERR_PIPE_NOT_READ);
1199 AssertPtrReturn(pcbReadable, VERR_INVALID_POINTER);
1200
1201 int rc = RTCritSectEnter(&pThis->CritSect);
1202 if (RT_FAILURE(rc))
1203 return rc;
1204
1205 DWORD cbAvailable = 0;
1206 if (PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL))
1207 *pcbReadable = cbAvailable;
1208 else
1209 rc = RTErrConvertFromWin32(GetLastError());
1210
1211 RTCritSectLeave(&pThis->CritSect);
1212 return rc;
1213}
1214
1215
1216RTDECL(int) RTPipeQueryInfo(RTPIPE hPipe, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1217{
1218 RTPIPEINTERNAL *pThis = hPipe;
1219 AssertPtrReturn(pThis, 0);
1220 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
1221
1222 int rc = RTCritSectEnter(&pThis->CritSect);
1223 AssertRCReturn(rc, 0);
1224
1225 rtPipeFakeQueryInfo(pObjInfo, enmAddAttr, pThis->fRead);
1226
1227 FILE_PIPE_LOCAL_INFORMATION Info;
1228 if (rtPipeQueryNtInfo(pThis, &Info))
1229 {
1230 pObjInfo->cbAllocated = pThis->fRead ? Info.InboundQuota : Info.OutboundQuota;
1231 pObjInfo->cbObject = pThis->fRead ? Info.ReadDataAvailable : Info.WriteQuotaAvailable;
1232 }
1233
1234 RTCritSectLeave(&pThis->CritSect);
1235 return VINF_SUCCESS;
1236}
1237
1238
1239int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
1240{
1241 RTPIPEINTERNAL *pThis = hPipe;
1242 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1243 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1244
1245 AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
1246 AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
1247
1248 /* Later: Try register an event handle with the pipe like on OS/2, there is
1249 a file control for doing this obviously intended for the OS/2 subsys.
1250 The question is whether this still exists on Vista and W7. */
1251 *phNative = (RTHCINTPTR)pThis->Overlapped.hEvent;
1252 return VINF_SUCCESS;
1253}
1254
1255
1256/**
1257 * Checks for pending events.
1258 *
1259 * @returns Event mask or 0.
1260 * @param pThis The pipe handle.
1261 * @param fEvents The desired events.
1262 */
1263static uint32_t rtPipePollCheck(RTPIPEINTERNAL *pThis, uint32_t fEvents)
1264{
1265 uint32_t fRetEvents = 0;
1266 if (pThis->fBrokenPipe)
1267 fRetEvents |= RTPOLL_EVT_ERROR;
1268 else if (pThis->fRead)
1269 {
1270 if (!pThis->fIOPending)
1271 {
1272 DWORD cbAvailable;
1273 if (PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL))
1274 {
1275 if ( (fEvents & RTPOLL_EVT_READ)
1276 && cbAvailable > 0)
1277 fRetEvents |= RTPOLL_EVT_READ;
1278 }
1279 else
1280 {
1281 if (GetLastError() == ERROR_BROKEN_PIPE)
1282 pThis->fBrokenPipe = true;
1283 fRetEvents |= RTPOLL_EVT_ERROR;
1284 }
1285 }
1286 }
1287 else
1288 {
1289 if (pThis->fIOPending)
1290 {
1291 rtPipeWriteCheckCompletion(pThis);
1292 if (pThis->fBrokenPipe)
1293 fRetEvents |= RTPOLL_EVT_ERROR;
1294 }
1295 if ( !pThis->fIOPending
1296 && !fRetEvents)
1297 {
1298 FILE_PIPE_LOCAL_INFORMATION Info;
1299 if (rtPipeQueryNtInfo(pThis, &Info))
1300 {
1301 /* Check for broken pipe. */
1302 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
1303 {
1304 fRetEvents = RTPOLL_EVT_ERROR;
1305 pThis->fBrokenPipe = true;
1306 }
1307
1308 /* Check if there is available buffer space. */
1309 if ( !fRetEvents
1310 && (fEvents & RTPOLL_EVT_WRITE)
1311 && ( Info.WriteQuotaAvailable > 0
1312 || Info.OutboundQuota == 0)
1313 )
1314 fRetEvents |= RTPOLL_EVT_WRITE;
1315 }
1316 else if (fEvents & RTPOLL_EVT_WRITE)
1317 fRetEvents |= RTPOLL_EVT_WRITE;
1318 }
1319 }
1320
1321 return fRetEvents;
1322}
1323
1324
1325/**
1326 * Internal RTPoll helper that polls the pipe handle and, if @a fNoWait is
1327 * clear, starts whatever actions we've got running during the poll call.
1328 *
1329 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1330 * Event mask (in @a fEvents) and no actions if the handle is ready
1331 * already.
1332 * UINT32_MAX (asserted) if the pipe handle is busy in I/O or a
1333 * different poll set.
1334 *
1335 * @param hPipe The pipe handle.
1336 * @param hPollSet The poll set handle (for access checks).
1337 * @param fEvents The events we're polling for.
1338 * @param fFinalEntry Set if this is the final entry for this handle
1339 * in this poll set. This can be used for dealing
1340 * with duplicate entries.
1341 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1342 * we'll wait for an event to occur.
1343 */
1344uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1345{
1346 /** @todo All this polling code could be optimized to make fewer system
1347 * calls; like for instance the ResetEvent calls. */
1348 RTPIPEINTERNAL *pThis = hPipe;
1349 AssertPtrReturn(pThis, UINT32_MAX);
1350 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, UINT32_MAX);
1351 RT_NOREF_PV(fFinalEntry);
1352
1353 int rc = RTCritSectEnter(&pThis->CritSect);
1354 AssertRCReturn(rc, UINT32_MAX);
1355
1356 /* Check that this is the only current use of this pipe. */
1357 uint32_t fRetEvents;
1358 if ( pThis->cUsers == 0
1359 || pThis->hPollSet == hPollSet)
1360 {
1361 /* Check what the current events are. */
1362 fRetEvents = rtPipePollCheck(pThis, fEvents);
1363 if ( !fRetEvents
1364 && !fNoWait)
1365 {
1366 /* Make sure the event semaphore has been reset. */
1367 if (!pThis->fIOPending)
1368 {
1369 rc = ResetEvent(pThis->Overlapped.hEvent);
1370 Assert(rc == TRUE);
1371 }
1372
1373 /* Kick off the zero byte read thing if applicable. */
1374 if ( !pThis->fIOPending
1375 && pThis->fRead
1376 && (fEvents & RTPOLL_EVT_READ)
1377 )
1378 {
1379 DWORD cbRead = 0;
1380 if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped))
1381 fRetEvents = rtPipePollCheck(pThis, fEvents);
1382 else if (GetLastError() == ERROR_IO_PENDING)
1383 {
1384 pThis->fIOPending = true;
1385 pThis->fZeroByteRead = true;
1386 }
1387 else
1388 fRetEvents = RTPOLL_EVT_ERROR;
1389 }
1390
1391 /* If we're still set for the waiting, record the poll set and
1392 mark the pipe used. */
1393 if (!fRetEvents)
1394 {
1395 pThis->cUsers++;
1396 pThis->hPollSet = hPollSet;
1397 }
1398 }
1399 }
1400 else
1401 {
1402 AssertFailed();
1403 fRetEvents = UINT32_MAX;
1404 }
1405
1406 RTCritSectLeave(&pThis->CritSect);
1407 return fRetEvents;
1408}
1409
1410
1411/**
1412 * Called after a WaitForMultipleObjects returned in order to check for pending
1413 * events and stop whatever actions that rtPipePollStart() initiated.
1414 *
1415 * @returns Event mask or 0.
1416 *
1417 * @param hPipe The pipe handle.
1418 * @param fEvents The events we're polling for.
1419 * @param fFinalEntry Set if this is the final entry for this handle
1420 * in this poll set. This can be used for dealing
1421 * with duplicate entries. Only keep in mind that
1422 * this method is called in reverse order, so the
1423 * first call will have this set (when the entire
1424 * set was processed).
1425 * @param fHarvestEvents Set if we should check for pending events.
1426 */
1427uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
1428{
1429 RTPIPEINTERNAL *pThis = hPipe;
1430 AssertPtrReturn(pThis, 0);
1431 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
1432 RT_NOREF_PV(fFinalEntry);
1433 RT_NOREF_PV(fHarvestEvents);
1434
1435 int rc = RTCritSectEnter(&pThis->CritSect);
1436 AssertRCReturn(rc, 0);
1437
1438 Assert(pThis->cUsers > 0);
1439
1440
1441 /* Cancel the zero byte read. */
1442 uint32_t fRetEvents = 0;
1443 if (pThis->fZeroByteRead)
1444 {
1445 CancelIo(pThis->hPipe);
1446 DWORD cbRead = 0;
1447 if ( !GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/)
1448 && GetLastError() != ERROR_OPERATION_ABORTED)
1449 fRetEvents = RTPOLL_EVT_ERROR;
1450
1451 pThis->fIOPending = false;
1452 pThis->fZeroByteRead = false;
1453 }
1454
1455 /* harvest events. */
1456 fRetEvents |= rtPipePollCheck(pThis, fEvents);
1457
1458 /* update counters. */
1459 pThis->cUsers--;
1460 /** @todo This isn't sane, or is it? See OS/2 impl. */
1461 if (!pThis->cUsers)
1462 pThis->hPollSet = NIL_RTPOLLSET;
1463
1464 RTCritSectLeave(&pThis->CritSect);
1465 return fRetEvents;
1466}
1467
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette