VirtualBox

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

Last change on this file since 85112 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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