VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.5 KB
Line 
1/* $Id: pipe-win.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Anonymous Pipes, Windows Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2019 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 AssertReturn(!(fInfo & PIPE_TYPE_MESSAGE), VERR_INVALID_HANDLE);
455 AssertReturn(cMaxInstances == 1, VERR_INVALID_HANDLE);
456
457 DWORD cInstances;
458 DWORD fState;
459 if (!GetNamedPipeHandleState(hNative, &fState, &cInstances, NULL, NULL, NULL, 0))
460 return RTErrConvertFromWin32(GetLastError());
461 AssertReturn(!(fState & PIPE_NOWAIT), VERR_INVALID_HANDLE);
462 AssertReturn(!(fState & PIPE_READMODE_MESSAGE), VERR_INVALID_HANDLE);
463 AssertReturn(cInstances <= 1, VERR_INVALID_HANDLE);
464
465 /*
466 * Looks kind of OK, create a handle so we can try rtPipeQueryNtInfo on it
467 * and see if we need to duplicate it to make that call work.
468 */
469 RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
470 if (!pThis)
471 return VERR_NO_MEMORY;
472 int rc = RTCritSectInit(&pThis->CritSect);
473 if (RT_SUCCESS(rc))
474 {
475 pThis->Overlapped.hEvent = CreateEvent(NULL, TRUE /*fManualReset*/,
476 TRUE /*fInitialState*/, NULL /*pName*/);
477 if (pThis->Overlapped.hEvent != NULL)
478 {
479 pThis->u32Magic = RTPIPE_MAGIC;
480 pThis->hPipe = hNative;
481 pThis->fRead = !!(fFlags & RTPIPE_N_READ);
482 //pThis->fIOPending = false;
483 //pThis->fZeroByteRead = false;
484 //pThis->fBrokenPipe = false;
485 //pThis->fPromisedWritable = false;
486 pThis->fCreatedInheritable = RT_BOOL(fFlags & RTPIPE_N_INHERIT);
487 //pThis->cUsers = 0;
488 //pThis->pbBounceBuf = NULL;
489 //pThis->cbBounceBufUsed = 0;
490 //pThis->cbBounceBufAlloc = 0;
491 pThis->hPollSet = NIL_RTPOLLSET;
492
493 HANDLE hNative2 = INVALID_HANDLE_VALUE;
494 FILE_PIPE_LOCAL_INFORMATION Info;
495 RT_ZERO(Info);
496 if ( g_enmWinVer != kRTWinOSType_NT310
497 && rtPipeQueryNtInfo(pThis, &Info))
498 rc = VINF_SUCCESS;
499 else
500 {
501 if (DuplicateHandle(GetCurrentProcess() /*hSrcProcess*/, hNative /*hSrcHandle*/,
502 GetCurrentProcess() /*hDstProcess*/, &hNative2 /*phDstHandle*/,
503 pThis->fRead ? GENERIC_READ : GENERIC_WRITE | FILE_READ_ATTRIBUTES /*dwDesiredAccess*/,
504 !!(fFlags & RTPIPE_N_INHERIT) /*fInheritHandle*/,
505 0 /*dwOptions*/))
506 {
507 pThis->hPipe = hNative2;
508 if (rtPipeQueryNtInfo(pThis, &Info))
509 rc = VINF_SUCCESS;
510 else
511 {
512 rc = VERR_ACCESS_DENIED;
513 CloseHandle(hNative2);
514 }
515 }
516 else
517 hNative2 = INVALID_HANDLE_VALUE;
518 }
519 if (RT_SUCCESS(rc))
520 {
521 /*
522 * Verify the pipe state and correct the inheritability.
523 */
524 AssertStmt( Info.NamedPipeState == FILE_PIPE_CONNECTED_STATE
525 || Info.NamedPipeState == FILE_PIPE_CLOSING_STATE
526 || Info.NamedPipeState == FILE_PIPE_DISCONNECTED_STATE,
527 VERR_INVALID_HANDLE);
528 AssertStmt( Info.NamedPipeConfiguration
529 == ( Info.NamedPipeEnd == FILE_PIPE_SERVER_END
530 ? (pThis->fRead ? FILE_PIPE_INBOUND : FILE_PIPE_OUTBOUND)
531 : (pThis->fRead ? FILE_PIPE_OUTBOUND : FILE_PIPE_INBOUND) )
532 || Info.NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX,
533 VERR_INVALID_HANDLE);
534 if ( RT_SUCCESS(rc)
535 && hNative2 == INVALID_HANDLE_VALUE
536 && !SetHandleInformation(hNative,
537 HANDLE_FLAG_INHERIT /*dwMask*/,
538 fFlags & RTPIPE_N_INHERIT ? HANDLE_FLAG_INHERIT : 0))
539 {
540 rc = RTErrConvertFromWin32(GetLastError());
541 AssertMsgFailed(("%Rrc\n", rc));
542 }
543 if (RT_SUCCESS(rc))
544 {
545 /*
546 * Ok, we're good! If we replaced the handle, make sure it's not a standard
547 * handle if we think we need to close it.
548 */
549 if (hNative2 != INVALID_HANDLE_VALUE)
550 {
551 if ( hNative != GetStdHandle(STD_INPUT_HANDLE)
552 && hNative != GetStdHandle(STD_OUTPUT_HANDLE)
553 && hNative != GetStdHandle(STD_ERROR_HANDLE))
554 CloseHandle(hNative);
555 }
556 *phPipe = pThis;
557 return VINF_SUCCESS;
558 }
559 }
560
561 /* Bail out. */
562 if (hNative2 != INVALID_HANDLE_VALUE)
563 CloseHandle(hNative2);
564 CloseHandle(pThis->Overlapped.hEvent);
565 }
566 RTCritSectDelete(&pThis->CritSect);
567 }
568 RTMemFree(pThis);
569 return rc;
570}
571
572
573RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe)
574{
575 RTPIPEINTERNAL *pThis = hPipe;
576 AssertPtrReturn(pThis, -1);
577 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, -1);
578
579 return (RTHCINTPTR)pThis->hPipe;
580}
581
582
583RTDECL(int) RTPipeGetCreationInheritability(RTPIPE hPipe)
584{
585 RTPIPEINTERNAL *pThis = hPipe;
586 AssertPtrReturn(pThis, false);
587 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, false);
588
589 return pThis->fCreatedInheritable;
590}
591
592
593RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
594{
595 RTPIPEINTERNAL *pThis = hPipe;
596 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
597 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
598 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
599 AssertPtr(pcbRead);
600 AssertPtr(pvBuf);
601
602 int rc = RTCritSectEnter(&pThis->CritSect);
603 if (RT_SUCCESS(rc))
604 {
605 /* No concurrent readers, sorry. */
606 if (pThis->cUsers == 0)
607 {
608 pThis->cUsers++;
609
610 /*
611 * Kick of a an overlapped read. It should return immediately if
612 * there is bytes in the buffer. If not, we'll cancel it and see
613 * what we get back.
614 */
615 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
616 DWORD cbRead = 0;
617 if ( cbToRead == 0
618 || ReadFile(pThis->hPipe, pvBuf,
619 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
620 &cbRead, &pThis->Overlapped))
621 {
622 *pcbRead = cbRead;
623 rc = VINF_SUCCESS;
624 }
625 else if (GetLastError() == ERROR_IO_PENDING)
626 {
627 pThis->fIOPending = true;
628 RTCritSectLeave(&pThis->CritSect);
629
630 if (!CancelIo(pThis->hPipe))
631 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
632 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
633 {
634 *pcbRead = cbRead;
635 rc = VINF_SUCCESS;
636 }
637 else if (GetLastError() == ERROR_OPERATION_ABORTED)
638 {
639 *pcbRead = 0;
640 rc = VINF_TRY_AGAIN;
641 }
642 else
643 rc = RTErrConvertFromWin32(GetLastError());
644
645 RTCritSectEnter(&pThis->CritSect);
646 pThis->fIOPending = false;
647 }
648 else
649 rc = RTErrConvertFromWin32(GetLastError());
650 if (rc == VERR_BROKEN_PIPE)
651 pThis->fBrokenPipe = true;
652
653 pThis->cUsers--;
654 }
655 else
656 rc = VERR_WRONG_ORDER;
657 RTCritSectLeave(&pThis->CritSect);
658 }
659 return rc;
660}
661
662
663RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
664{
665 RTPIPEINTERNAL *pThis = hPipe;
666 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
667 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
668 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
669 AssertPtr(pvBuf);
670
671 int rc = RTCritSectEnter(&pThis->CritSect);
672 if (RT_SUCCESS(rc))
673 {
674 /* No concurrent readers, sorry. */
675 if (pThis->cUsers == 0)
676 {
677 pThis->cUsers++;
678
679 size_t cbTotalRead = 0;
680 while (cbToRead > 0)
681 {
682 /*
683 * Kick of a an overlapped read. It should return immediately if
684 * there is bytes in the buffer. If not, we'll cancel it and see
685 * what we get back.
686 */
687 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
688 DWORD cbRead = 0;
689 pThis->fIOPending = true;
690 RTCritSectLeave(&pThis->CritSect);
691
692 if (ReadFile(pThis->hPipe, pvBuf,
693 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
694 &cbRead, &pThis->Overlapped))
695 rc = VINF_SUCCESS;
696 else if (GetLastError() == ERROR_IO_PENDING)
697 {
698 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
699 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
700 rc = VINF_SUCCESS;
701 else
702 rc = RTErrConvertFromWin32(GetLastError());
703 }
704 else
705 rc = RTErrConvertFromWin32(GetLastError());
706
707 RTCritSectEnter(&pThis->CritSect);
708 pThis->fIOPending = false;
709 if (RT_FAILURE(rc))
710 break;
711
712 /* advance */
713 cbToRead -= cbRead;
714 cbTotalRead += cbRead;
715 pvBuf = (uint8_t *)pvBuf + cbRead;
716 }
717
718 if (rc == VERR_BROKEN_PIPE)
719 pThis->fBrokenPipe = true;
720
721 if (pcbRead)
722 {
723 *pcbRead = cbTotalRead;
724 if ( RT_FAILURE(rc)
725 && cbTotalRead
726 && rc != VERR_INVALID_POINTER)
727 rc = VINF_SUCCESS;
728 }
729
730 pThis->cUsers--;
731 }
732 else
733 rc = VERR_WRONG_ORDER;
734 RTCritSectLeave(&pThis->CritSect);
735 }
736 return rc;
737}
738
739
740RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
741{
742 RTPIPEINTERNAL *pThis = hPipe;
743 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
744 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
745 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
746 AssertPtr(pcbWritten);
747 AssertPtr(pvBuf);
748
749 int rc = RTCritSectEnter(&pThis->CritSect);
750 if (RT_SUCCESS(rc))
751 {
752 /* No concurrent writers, sorry. */
753 if (pThis->cUsers == 0)
754 {
755 pThis->cUsers++;
756
757 /* If I/O is pending, check if it has completed. */
758 if (pThis->fIOPending)
759 rc = rtPipeWriteCheckCompletion(pThis);
760 else
761 rc = VINF_SUCCESS;
762 if (rc == VINF_SUCCESS)
763 {
764 Assert(!pThis->fIOPending);
765
766 /* Adjust the number of bytes to write to fit into the current
767 buffer quota, unless we've promised stuff in RTPipeSelectOne.
768 WriteQuotaAvailable better not be zero when it shouldn't!! */
769 FILE_PIPE_LOCAL_INFORMATION Info;
770 if ( !pThis->fPromisedWritable
771 && cbToWrite > 0
772 && rtPipeQueryNtInfo(pThis, &Info))
773 {
774 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
775 rc = VERR_BROKEN_PIPE;
776 /** @todo fixme: To get the pipe writing support to work the
777 * block below needs to be commented out until a
778 * way is found to address the problem of the incorrectly
779 * set field Info.WriteQuotaAvailable. */
780#if 0
781 else if ( cbToWrite >= Info.WriteQuotaAvailable
782 && Info.OutboundQuota != 0
783 && (Info.WriteQuotaAvailable || pThis->cbBounceBufAlloc)
784 )
785 {
786 cbToWrite = Info.WriteQuotaAvailable;
787 if (!cbToWrite)
788 rc = VINF_TRY_AGAIN;
789 }
790#endif
791 }
792 pThis->fPromisedWritable = false;
793
794 /* Do the bounce buffering. */
795 if ( pThis->cbBounceBufAlloc < cbToWrite
796 && pThis->cbBounceBufAlloc < RTPIPE_NT_SIZE)
797 {
798 if (cbToWrite > RTPIPE_NT_SIZE)
799 cbToWrite = RTPIPE_NT_SIZE;
800 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K));
801 if (pv)
802 {
803 pThis->pbBounceBuf = (uint8_t *)pv;
804 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K);
805 }
806 else
807 rc = VERR_NO_MEMORY;
808 }
809 else if (cbToWrite > RTPIPE_NT_SIZE)
810 cbToWrite = RTPIPE_NT_SIZE;
811 if (RT_SUCCESS(rc) && cbToWrite)
812 {
813 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite);
814 pThis->cbBounceBufUsed = (uint32_t)cbToWrite;
815
816 /* Submit the write. */
817 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
818 DWORD cbWritten = 0;
819 if (WriteFile(pThis->hPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
820 &cbWritten, &pThis->Overlapped))
821 {
822 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */
823 rc = VINF_SUCCESS;
824 }
825 else if (GetLastError() == ERROR_IO_PENDING)
826 {
827 *pcbWritten = cbToWrite;
828 pThis->fIOPending = true;
829 rc = VINF_SUCCESS;
830 }
831 else if (GetLastError() == ERROR_NO_DATA)
832 rc = VERR_BROKEN_PIPE;
833 else
834 rc = RTErrConvertFromWin32(GetLastError());
835 }
836 else if (RT_SUCCESS(rc))
837 *pcbWritten = 0;
838 }
839 else if (RT_SUCCESS(rc))
840 *pcbWritten = 0;
841
842 if (rc == VERR_BROKEN_PIPE)
843 pThis->fBrokenPipe = true;
844
845 pThis->cUsers--;
846 }
847 else
848 rc = VERR_WRONG_ORDER;
849 RTCritSectLeave(&pThis->CritSect);
850 }
851 return rc;
852}
853
854
855RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
856{
857 RTPIPEINTERNAL *pThis = hPipe;
858 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
859 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
860 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
861 AssertPtr(pvBuf);
862 AssertPtrNull(pcbWritten);
863
864 int rc = RTCritSectEnter(&pThis->CritSect);
865 if (RT_SUCCESS(rc))
866 {
867 /* No concurrent writers, sorry. */
868 if (pThis->cUsers == 0)
869 {
870 pThis->cUsers++;
871
872 /*
873 * If I/O is pending, wait for it to complete.
874 */
875 if (pThis->fIOPending)
876 {
877 rc = rtPipeWriteCheckCompletion(pThis);
878 while (rc == VINF_TRY_AGAIN)
879 {
880 Assert(pThis->fIOPending);
881 HANDLE hEvent = pThis->Overlapped.hEvent;
882 RTCritSectLeave(&pThis->CritSect);
883 WaitForSingleObject(hEvent, INFINITE);
884 RTCritSectEnter(&pThis->CritSect);
885 }
886 }
887 if (RT_SUCCESS(rc))
888 {
889 Assert(!pThis->fIOPending);
890 pThis->fPromisedWritable = false;
891
892 /*
893 * Try write everything.
894 * No bounce buffering, cUsers protects us.
895 */
896 size_t cbTotalWritten = 0;
897 while (cbToWrite > 0)
898 {
899 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
900 pThis->fIOPending = true;
901 RTCritSectLeave(&pThis->CritSect);
902
903 DWORD cbWritten = 0;
904 DWORD const cbToWriteInThisIteration = cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0;
905 if (WriteFile(pThis->hPipe, pvBuf, cbToWriteInThisIteration, &cbWritten, &pThis->Overlapped))
906 rc = VINF_SUCCESS;
907 else if (GetLastError() == ERROR_IO_PENDING)
908 {
909 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
910 if (GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbWritten, TRUE /*fWait*/))
911 rc = VINF_SUCCESS;
912 else
913 rc = RTErrConvertFromWin32(GetLastError());
914 }
915 else if (GetLastError() == ERROR_NO_DATA)
916 rc = VERR_BROKEN_PIPE;
917 else
918 rc = RTErrConvertFromWin32(GetLastError());
919
920 RTCritSectEnter(&pThis->CritSect);
921 pThis->fIOPending = false;
922 if (RT_FAILURE(rc))
923 break;
924
925 /* advance */
926 if (cbWritten > cbToWriteInThisIteration) /* paranoia^3 */
927 cbWritten = cbToWriteInThisIteration;
928 pvBuf = (char const *)pvBuf + cbWritten;
929 cbTotalWritten += cbWritten;
930 cbToWrite -= cbWritten;
931 }
932
933 if (pcbWritten)
934 {
935 *pcbWritten = cbTotalWritten;
936 if ( RT_FAILURE(rc)
937 && cbTotalWritten
938 && rc != VERR_INVALID_POINTER)
939 rc = VINF_SUCCESS;
940 }
941 }
942
943 if (rc == VERR_BROKEN_PIPE)
944 pThis->fBrokenPipe = true;
945
946 pThis->cUsers--;
947 }
948 else
949 rc = VERR_WRONG_ORDER;
950 RTCritSectLeave(&pThis->CritSect);
951 }
952 return rc;
953
954#if 0 /** @todo r=bird: What's this? */
955 int rc = rtPipeTryBlocking(pThis);
956 if (RT_SUCCESS(rc))
957 {
958 size_t cbTotalWritten = 0;
959 while (cbToWrite > 0)
960 {
961 ssize_t cbWritten = write(pThis->fd, pvBuf, RT_MIN(cbToWrite, SSIZE_MAX));
962 if (cbWritten < 0)
963 {
964 rc = RTErrConvertFromErrno(errno);
965 break;
966 }
967
968 /* advance */
969 pvBuf = (char const *)pvBuf + cbWritten;
970 cbTotalWritten += cbWritten;
971 cbToWrite -= cbWritten;
972 }
973
974 if (pcbWritten)
975 {
976 *pcbWritten = cbTotalWritten;
977 if ( RT_FAILURE(rc)
978 && cbTotalWritten
979 && rc != VERR_INVALID_POINTER)
980 rc = VINF_SUCCESS;
981 }
982
983 ASMAtomicDecU32(&pThis->u32State);
984 }
985 return rc;
986#endif
987}
988
989
990RTDECL(int) RTPipeFlush(RTPIPE hPipe)
991{
992 RTPIPEINTERNAL *pThis = hPipe;
993 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
994 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
995 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
996
997 if (!FlushFileBuffers(pThis->hPipe))
998 {
999 int rc = RTErrConvertFromWin32(GetLastError());
1000 if (rc == VERR_BROKEN_PIPE)
1001 pThis->fBrokenPipe = true;
1002 return rc;
1003 }
1004 return VINF_SUCCESS;
1005}
1006
1007
1008RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies)
1009{
1010 RTPIPEINTERNAL *pThis = hPipe;
1011 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1012 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1013
1014 uint64_t const StartMsTS = RTTimeMilliTS();
1015
1016 int rc = RTCritSectEnter(&pThis->CritSect);
1017 if (RT_FAILURE(rc))
1018 return rc;
1019 for (unsigned iLoop = 0;; iLoop++)
1020 {
1021 HANDLE hWait = INVALID_HANDLE_VALUE;
1022 if (pThis->fRead)
1023 {
1024 if (pThis->fIOPending)
1025 hWait = pThis->Overlapped.hEvent;
1026 else
1027 {
1028 /* Peek at the pipe buffer and see how many bytes it contains. */
1029 DWORD cbAvailable;
1030 if ( PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL)
1031 && cbAvailable > 0)
1032 {
1033 rc = VINF_SUCCESS;
1034 break;
1035 }
1036
1037 /* Start a zero byte read operation that we can wait on. */
1038 if (cMillies == 0)
1039 {
1040 rc = VERR_TIMEOUT;
1041 break;
1042 }
1043 AssertBreakStmt(pThis->cUsers == 0, rc = VERR_INTERNAL_ERROR_5);
1044 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
1045 DWORD cbRead = 0;
1046 if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped))
1047 {
1048 rc = VINF_SUCCESS;
1049 if (iLoop > 10)
1050 RTThreadYield();
1051 }
1052 else if (GetLastError() == ERROR_IO_PENDING)
1053 {
1054 pThis->cUsers++;
1055 pThis->fIOPending = true;
1056 pThis->fZeroByteRead = true;
1057 hWait = pThis->Overlapped.hEvent;
1058 }
1059 else
1060 rc = RTErrConvertFromWin32(GetLastError());
1061 }
1062 }
1063 else
1064 {
1065 if (pThis->fIOPending)
1066 {
1067 rc = rtPipeWriteCheckCompletion(pThis);
1068 if (RT_FAILURE(rc))
1069 break;
1070 }
1071 if (pThis->fIOPending)
1072 hWait = pThis->Overlapped.hEvent;
1073 else
1074 {
1075 FILE_PIPE_LOCAL_INFORMATION Info;
1076 if (rtPipeQueryNtInfo(pThis, &Info))
1077 {
1078 /* Check for broken pipe. */
1079 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
1080 {
1081 rc = VERR_BROKEN_PIPE;
1082 break;
1083 }
1084 /* Check for available write buffer space. */
1085 else if (Info.WriteQuotaAvailable > 0)
1086 {
1087 pThis->fPromisedWritable = false;
1088 rc = VINF_SUCCESS;
1089 break;
1090 }
1091 /* delayed buffer alloc or timeout: phony promise
1092 later: See if we still can associate a semaphore with
1093 the pipe, like on OS/2. */
1094 else if ( Info.OutboundQuota == 0
1095 || cMillies)
1096 {
1097 pThis->fPromisedWritable = true;
1098 rc = VINF_SUCCESS;
1099 break;
1100 }
1101 }
1102 else
1103 {
1104 pThis->fPromisedWritable = true;
1105 rc = VINF_SUCCESS;
1106 break;
1107 }
1108 }
1109 }
1110 if (RT_FAILURE(rc))
1111 break;
1112
1113 /*
1114 * Check for timeout.
1115 */
1116 DWORD cMsMaxWait = INFINITE;
1117 if ( cMillies != RT_INDEFINITE_WAIT
1118 && ( hWait != INVALID_HANDLE_VALUE
1119 || iLoop > 10)
1120 )
1121 {
1122 uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
1123 if (cElapsed >= cMillies)
1124 {
1125 rc = VERR_TIMEOUT;
1126 break;
1127 }
1128 cMsMaxWait = cMillies - (uint32_t)cElapsed;
1129 }
1130
1131 /*
1132 * Wait.
1133 */
1134 if (hWait != INVALID_HANDLE_VALUE)
1135 {
1136 RTCritSectLeave(&pThis->CritSect);
1137
1138 DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
1139 if (dwRc == WAIT_OBJECT_0)
1140 rc = VINF_SUCCESS;
1141 else if (dwRc == WAIT_TIMEOUT)
1142 rc = VERR_TIMEOUT;
1143 else if (dwRc == WAIT_ABANDONED)
1144 rc = VERR_INVALID_HANDLE;
1145 else
1146 rc = RTErrConvertFromWin32(GetLastError());
1147 if ( RT_FAILURE(rc)
1148 && pThis->u32Magic != RTPIPE_MAGIC)
1149 return rc;
1150
1151 RTCritSectEnter(&pThis->CritSect);
1152 if (pThis->fZeroByteRead)
1153 {
1154 pThis->cUsers--;
1155 pThis->fIOPending = false;
1156 if (rc != VINF_SUCCESS)
1157 CancelIo(pThis->hPipe);
1158 DWORD cbRead = 0;
1159 GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/);
1160 }
1161 if (RT_FAILURE(rc))
1162 break;
1163 }
1164 }
1165
1166 if (rc == VERR_BROKEN_PIPE)
1167 pThis->fBrokenPipe = true;
1168
1169 RTCritSectLeave(&pThis->CritSect);
1170 return rc;
1171}
1172
1173
1174RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
1175{
1176 RTPIPEINTERNAL *pThis = hPipe;
1177 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1178 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1179 AssertReturn(pThis->fRead, VERR_PIPE_NOT_READ);
1180 AssertPtrReturn(pcbReadable, VERR_INVALID_POINTER);
1181
1182 int rc = RTCritSectEnter(&pThis->CritSect);
1183 if (RT_FAILURE(rc))
1184 return rc;
1185
1186 DWORD cbAvailable = 0;
1187 if (PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL))
1188 *pcbReadable = cbAvailable;
1189 else
1190 rc = RTErrConvertFromWin32(GetLastError());
1191
1192 RTCritSectLeave(&pThis->CritSect);
1193 return rc;
1194}
1195
1196
1197RTDECL(int) RTPipeQueryInfo(RTPIPE hPipe, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1198{
1199 RTPIPEINTERNAL *pThis = hPipe;
1200 AssertPtrReturn(pThis, 0);
1201 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
1202
1203 int rc = RTCritSectEnter(&pThis->CritSect);
1204 AssertRCReturn(rc, 0);
1205
1206 rtPipeFakeQueryInfo(pObjInfo, enmAddAttr, pThis->fRead);
1207
1208 FILE_PIPE_LOCAL_INFORMATION Info;
1209 if (rtPipeQueryNtInfo(pThis, &Info))
1210 {
1211 pObjInfo->cbAllocated = pThis->fRead ? Info.InboundQuota : Info.OutboundQuota;
1212 pObjInfo->cbObject = pThis->fRead ? Info.ReadDataAvailable : Info.WriteQuotaAvailable;
1213 }
1214
1215 RTCritSectLeave(&pThis->CritSect);
1216 return VINF_SUCCESS;
1217}
1218
1219
1220int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
1221{
1222 RTPIPEINTERNAL *pThis = hPipe;
1223 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1224 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
1225
1226 AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
1227 AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
1228
1229 /* Later: Try register an event handle with the pipe like on OS/2, there is
1230 a file control for doing this obviously intended for the OS/2 subsys.
1231 The question is whether this still exists on Vista and W7. */
1232 *phNative = (RTHCINTPTR)pThis->Overlapped.hEvent;
1233 return VINF_SUCCESS;
1234}
1235
1236
1237/**
1238 * Checks for pending events.
1239 *
1240 * @returns Event mask or 0.
1241 * @param pThis The pipe handle.
1242 * @param fEvents The desired events.
1243 */
1244static uint32_t rtPipePollCheck(RTPIPEINTERNAL *pThis, uint32_t fEvents)
1245{
1246 uint32_t fRetEvents = 0;
1247 if (pThis->fBrokenPipe)
1248 fRetEvents |= RTPOLL_EVT_ERROR;
1249 else if (pThis->fRead)
1250 {
1251 if (!pThis->fIOPending)
1252 {
1253 DWORD cbAvailable;
1254 if (PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL))
1255 {
1256 if ( (fEvents & RTPOLL_EVT_READ)
1257 && cbAvailable > 0)
1258 fRetEvents |= RTPOLL_EVT_READ;
1259 }
1260 else
1261 {
1262 if (GetLastError() == ERROR_BROKEN_PIPE)
1263 pThis->fBrokenPipe = true;
1264 fRetEvents |= RTPOLL_EVT_ERROR;
1265 }
1266 }
1267 }
1268 else
1269 {
1270 if (pThis->fIOPending)
1271 {
1272 rtPipeWriteCheckCompletion(pThis);
1273 if (pThis->fBrokenPipe)
1274 fRetEvents |= RTPOLL_EVT_ERROR;
1275 }
1276 if ( !pThis->fIOPending
1277 && !fRetEvents)
1278 {
1279 FILE_PIPE_LOCAL_INFORMATION Info;
1280 if (rtPipeQueryNtInfo(pThis, &Info))
1281 {
1282 /* Check for broken pipe. */
1283 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
1284 {
1285 fRetEvents = RTPOLL_EVT_ERROR;
1286 pThis->fBrokenPipe = true;
1287 }
1288
1289 /* Check if there is available buffer space. */
1290 if ( !fRetEvents
1291 && (fEvents & RTPOLL_EVT_WRITE)
1292 && ( Info.WriteQuotaAvailable > 0
1293 || Info.OutboundQuota == 0)
1294 )
1295 fRetEvents |= RTPOLL_EVT_WRITE;
1296 }
1297 else if (fEvents & RTPOLL_EVT_WRITE)
1298 fRetEvents |= RTPOLL_EVT_WRITE;
1299 }
1300 }
1301
1302 return fRetEvents;
1303}
1304
1305
1306/**
1307 * Internal RTPoll helper that polls the pipe handle and, if @a fNoWait is
1308 * clear, starts whatever actions we've got running during the poll call.
1309 *
1310 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1311 * Event mask (in @a fEvents) and no actions if the handle is ready
1312 * already.
1313 * UINT32_MAX (asserted) if the pipe handle is busy in I/O or a
1314 * different poll set.
1315 *
1316 * @param hPipe The pipe handle.
1317 * @param hPollSet The poll set handle (for access checks).
1318 * @param fEvents The events we're polling for.
1319 * @param fFinalEntry Set if this is the final entry for this handle
1320 * in this poll set. This can be used for dealing
1321 * with duplicate entries.
1322 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1323 * we'll wait for an event to occur.
1324 */
1325uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1326{
1327 /** @todo All this polling code could be optimized to make fewer system
1328 * calls; like for instance the ResetEvent calls. */
1329 RTPIPEINTERNAL *pThis = hPipe;
1330 AssertPtrReturn(pThis, UINT32_MAX);
1331 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, UINT32_MAX);
1332 RT_NOREF_PV(fFinalEntry);
1333
1334 int rc = RTCritSectEnter(&pThis->CritSect);
1335 AssertRCReturn(rc, UINT32_MAX);
1336
1337 /* Check that this is the only current use of this pipe. */
1338 uint32_t fRetEvents;
1339 if ( pThis->cUsers == 0
1340 || pThis->hPollSet == hPollSet)
1341 {
1342 /* Check what the current events are. */
1343 fRetEvents = rtPipePollCheck(pThis, fEvents);
1344 if ( !fRetEvents
1345 && !fNoWait)
1346 {
1347 /* Make sure the event semaphore has been reset. */
1348 if (!pThis->fIOPending)
1349 {
1350 rc = ResetEvent(pThis->Overlapped.hEvent);
1351 Assert(rc == TRUE);
1352 }
1353
1354 /* Kick off the zero byte read thing if applicable. */
1355 if ( !pThis->fIOPending
1356 && pThis->fRead
1357 && (fEvents & RTPOLL_EVT_READ)
1358 )
1359 {
1360 DWORD cbRead = 0;
1361 if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped))
1362 fRetEvents = rtPipePollCheck(pThis, fEvents);
1363 else if (GetLastError() == ERROR_IO_PENDING)
1364 {
1365 pThis->fIOPending = true;
1366 pThis->fZeroByteRead = true;
1367 }
1368 else
1369 fRetEvents = RTPOLL_EVT_ERROR;
1370 }
1371
1372 /* If we're still set for the waiting, record the poll set and
1373 mark the pipe used. */
1374 if (!fRetEvents)
1375 {
1376 pThis->cUsers++;
1377 pThis->hPollSet = hPollSet;
1378 }
1379 }
1380 }
1381 else
1382 {
1383 AssertFailed();
1384 fRetEvents = UINT32_MAX;
1385 }
1386
1387 RTCritSectLeave(&pThis->CritSect);
1388 return fRetEvents;
1389}
1390
1391
1392/**
1393 * Called after a WaitForMultipleObjects returned in order to check for pending
1394 * events and stop whatever actions that rtPipePollStart() initiated.
1395 *
1396 * @returns Event mask or 0.
1397 *
1398 * @param hPipe The pipe handle.
1399 * @param fEvents The events we're polling for.
1400 * @param fFinalEntry Set if this is the final entry for this handle
1401 * in this poll set. This can be used for dealing
1402 * with duplicate entries. Only keep in mind that
1403 * this method is called in reverse order, so the
1404 * first call will have this set (when the entire
1405 * set was processed).
1406 * @param fHarvestEvents Set if we should check for pending events.
1407 */
1408uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
1409{
1410 RTPIPEINTERNAL *pThis = hPipe;
1411 AssertPtrReturn(pThis, 0);
1412 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
1413 RT_NOREF_PV(fFinalEntry);
1414 RT_NOREF_PV(fHarvestEvents);
1415
1416 int rc = RTCritSectEnter(&pThis->CritSect);
1417 AssertRCReturn(rc, 0);
1418
1419 Assert(pThis->cUsers > 0);
1420
1421
1422 /* Cancel the zero byte read. */
1423 uint32_t fRetEvents = 0;
1424 if (pThis->fZeroByteRead)
1425 {
1426 CancelIo(pThis->hPipe);
1427 DWORD cbRead = 0;
1428 if ( !GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/)
1429 && GetLastError() != ERROR_OPERATION_ABORTED)
1430 fRetEvents = RTPOLL_EVT_ERROR;
1431
1432 pThis->fIOPending = false;
1433 pThis->fZeroByteRead = false;
1434 }
1435
1436 /* harvest events. */
1437 fRetEvents |= rtPipePollCheck(pThis, fEvents);
1438
1439 /* update counters. */
1440 pThis->cUsers--;
1441 /** @todo This isn't sane, or is it? See OS/2 impl. */
1442 if (!pThis->cUsers)
1443 pThis->hPollSet = NIL_RTPOLLSET;
1444
1445 RTCritSectLeave(&pThis->CritSect);
1446 return fRetEvents;
1447}
1448
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