VirtualBox

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

Last change on this file since 69536 was 69536, checked in by vboxsync, 7 years ago

IPRT: Go seriously paranoid on written byte counts returned by WriteFile calls.

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