VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/os2/pipe-os2.cpp@ 57643

Last change on this file since 57643 was 57643, checked in by vboxsync, 9 years ago

IPRT: Added RTVfsIoStrmFromRTPipe (and RTPipeQueryInfo) for the purpose of making RTVfsIoStrmFromStdHandle be able to work with pipes. Mostly untested.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.5 KB
Line 
1/* $Id: pipe-os2.cpp 57643 2015-09-07 13:47:08Z vboxsync $ */
2/** @file
3 * IPRT - Anonymous Pipes, OS/2 Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2015 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#define INCL_ERRORS
32#define INCL_DOSSEMAPHORES
33#include <os2.h>
34
35#include <iprt/pipe.h>
36#include "internal/iprt.h"
37
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/critsect.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43#include <iprt/string.h>
44#include <iprt/poll.h>
45#include <iprt/process.h>
46#include <iprt/thread.h>
47#include <iprt/time.h>
48#include "internal/pipe.h"
49#include "internal/magics.h"
50
51
52/*********************************************************************************************************************************
53* Defined Constants And Macros *
54*********************************************************************************************************************************/
55/** The pipe buffer size we prefer. */
56#define RTPIPE_OS2_SIZE _32K
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62typedef struct RTPIPEINTERNAL
63{
64 /** Magic value (RTPIPE_MAGIC). */
65 uint32_t u32Magic;
66 /** The pipe handle. */
67 HPIPE hPipe;
68 /** Set if this is the read end, clear if it's the write end. */
69 bool fRead;
70 /** Whether the pipe is in blocking or non-blocking mode. */
71 bool fBlocking;
72 /** Set if the pipe is broken. */
73 bool fBrokenPipe;
74 /** Usage counter. */
75 uint32_t cUsers;
76
77 /** The event semaphore associated with the pipe. */
78 HEV hev;
79 /** The handle of the poll set currently polling on this pipe.
80 * We can only have one poller at the time (lazy bird). */
81 RTPOLLSET hPollSet;
82 /** Critical section protecting the above members.
83 * (Taking the lazy/simple approach.) */
84 RTCRITSECT CritSect;
85
86} RTPIPEINTERNAL;
87
88
89/**
90 * Ensures that the pipe has a semaphore associated with it.
91 *
92 * @returns VBox status code.
93 * @param pThis The pipe.
94 */
95static int rtPipeOs2EnsureSem(RTPIPEINTERNAL *pThis)
96{
97 if (pThis->hev != NULLHANDLE)
98 return VINF_SUCCESS;
99
100 HEV hev;
101 APIRET orc = DosCreateEventSem(NULL, &hev, DC_SEM_SHARED, FALSE);
102 if (orc == NO_ERROR)
103 {
104 orc = DosSetNPipeSem(pThis->hPipe, (HSEM)hev, 1);
105 if (orc == NO_ERROR)
106 {
107 pThis->hev = hev;
108 return VINF_SUCCESS;
109 }
110
111 DosCloseEventSem(hev);
112 }
113 return RTErrConvertFromOS2(orc);
114}
115
116
117RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags)
118{
119 AssertPtrReturn(phPipeRead, VERR_INVALID_POINTER);
120 AssertPtrReturn(phPipeWrite, VERR_INVALID_POINTER);
121 AssertReturn(!(fFlags & ~RTPIPE_C_VALID_MASK), VERR_INVALID_PARAMETER);
122
123 /*
124 * Try create and connect a pipe pair.
125 */
126 APIRET orc;
127 HPIPE hPipeR;
128 HFILE hPipeW;
129 int rc;
130 for (;;)
131 {
132 static volatile uint32_t g_iNextPipe = 0;
133 char szName[128];
134 RTStrPrintf(szName, sizeof(szName), "\\pipe\\iprt-pipe-%u-%u", RTProcSelf(), ASMAtomicIncU32(&g_iNextPipe));
135
136 /*
137 * Create the read end of the pipe.
138 */
139 ULONG fPipeMode = 1 /*instance*/ | NP_TYPE_BYTE | NP_READMODE_BYTE | NP_NOWAIT;
140 ULONG fOpenMode = NP_ACCESS_DUPLEX | NP_WRITEBEHIND;
141 if (fFlags & RTPIPE_C_INHERIT_READ)
142 fOpenMode |= NP_INHERIT;
143 else
144 fOpenMode |= NP_NOINHERIT;
145 orc = DosCreateNPipe((PSZ)szName, &hPipeR, fOpenMode, fPipeMode, RTPIPE_OS2_SIZE, RTPIPE_OS2_SIZE, NP_DEFAULT_WAIT);
146 if (orc == NO_ERROR)
147 {
148 orc = DosConnectNPipe(hPipeR);
149 if (orc == ERROR_PIPE_NOT_CONNECTED || orc == NO_ERROR)
150 {
151 /*
152 * Connect to the pipe (the write end), attach sem below.
153 */
154 ULONG ulAction = 0;
155 ULONG fOpenW = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
156 ULONG fModeW = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_FAIL_ON_ERROR;
157 if (!(fFlags & RTPIPE_C_INHERIT_WRITE))
158 fModeW |= OPEN_FLAGS_NOINHERIT;
159 orc = DosOpen((PSZ)szName, &hPipeW, &ulAction, 0 /*cbFile*/, FILE_NORMAL,
160 fOpenW, fModeW, NULL /*peaop2*/);
161 if (orc == NO_ERROR)
162 break;
163 }
164 DosClose(hPipeR);
165 }
166 if ( orc != ERROR_PIPE_BUSY /* already exist - compatible */
167 && orc != ERROR_ACCESS_DENIED /* already exist - incompatible (?) */)
168 return RTErrConvertFromOS2(orc);
169 /* else: try again with a new name */
170 }
171
172 /*
173 * Create the two handles.
174 */
175 RTPIPEINTERNAL *pThisR = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
176 if (pThisR)
177 {
178 RTPIPEINTERNAL *pThisW = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
179 if (pThisW)
180 {
181 /* Crit sects. */
182 rc = RTCritSectInit(&pThisR->CritSect);
183 if (RT_SUCCESS(rc))
184 {
185 rc = RTCritSectInit(&pThisW->CritSect);
186 if (RT_SUCCESS(rc))
187 {
188 /* Initialize the structures. */
189 pThisR->u32Magic = RTPIPE_MAGIC;
190 pThisW->u32Magic = RTPIPE_MAGIC;
191 pThisR->hPipe = hPipeR;
192 pThisW->hPipe = hPipeW;
193 pThisR->hev = NULLHANDLE;
194 pThisW->hev = NULLHANDLE;
195 pThisR->fRead = true;
196 pThisW->fRead = false;
197 pThisR->fBlocking = false;
198 pThisW->fBlocking = true;
199 //pThisR->fBrokenPipe = false;
200 //pThisW->fBrokenPipe = false;
201 //pThisR->cUsers = 0;
202 //pThisW->cUsers = 0;
203 pThisR->hPollSet = NIL_RTPOLLSET;
204 pThisW->hPollSet = NIL_RTPOLLSET;
205
206 *phPipeRead = pThisR;
207 *phPipeWrite = pThisW;
208 return VINF_SUCCESS;
209 }
210
211 RTCritSectDelete(&pThisR->CritSect);
212 }
213 RTMemFree(pThisW);
214 }
215 else
216 rc = VERR_NO_MEMORY;
217 RTMemFree(pThisR);
218 }
219 else
220 rc = VERR_NO_MEMORY;
221
222 /* Don't call DosDisConnectNPipe! */
223 DosClose(hPipeW);
224 DosClose(hPipeR);
225 return rc;
226}
227
228
229RTDECL(int) RTPipeClose(RTPIPE hPipe)
230{
231 RTPIPEINTERNAL *pThis = hPipe;
232 if (pThis == NIL_RTPIPE)
233 return VINF_SUCCESS;
234 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
235 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
236
237 /*
238 * Do the cleanup.
239 */
240 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE);
241 RTCritSectEnter(&pThis->CritSect);
242 Assert(pThis->cUsers == 0);
243
244 /* Don't call DosDisConnectNPipe! */
245 DosClose(pThis->hPipe);
246 pThis->hPipe = (HPIPE)-1;
247
248 if (pThis->hev != NULLHANDLE)
249 {
250 DosCloseEventSem(pThis->hev);
251 pThis->hev = NULLHANDLE;
252 }
253
254 RTCritSectLeave(&pThis->CritSect);
255 RTCritSectDelete(&pThis->CritSect);
256
257 RTMemFree(pThis);
258
259 return VINF_SUCCESS;
260}
261
262
263RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags)
264{
265 AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
266 AssertReturn(!(fFlags & ~RTPIPE_N_VALID_MASK), VERR_INVALID_PARAMETER);
267 AssertReturn(!!(fFlags & RTPIPE_N_READ) != !!(fFlags & RTPIPE_N_WRITE), VERR_INVALID_PARAMETER);
268
269 /*
270 * Get and validate the pipe handle info.
271 */
272 HPIPE hNative = (HPIPE)hNativePipe;
273 ULONG ulType = 0;
274 ULONG ulAttr = 0;
275 APIRET orc = DosQueryHType(hNative, &ulType, &ulAttr);
276 AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), RTErrConvertFromOS2(orc));
277 AssertReturn((ulType & 0x7) == HANDTYPE_PIPE, VERR_INVALID_HANDLE);
278
279#if 0
280 union
281 {
282 PIPEINFO PipeInfo;
283 uint8_t abPadding[sizeof(PIPEINFO) + 127];
284 } Buf;
285 orc = DosQueryNPipeInfo(hNative, 1, &Buf, sizeof(Buf));
286 if (orc != NO_ERROR)
287 {
288 /* Sorry, anonymous pips are not supported. */
289 AssertMsgFailed(("%d\n", orc));
290 return VERR_INVALID_HANDLE;
291 }
292 AssertReturn(Buf.PipeInfo.cbMaxInst == 1, VERR_INVALID_HANDLE);
293#endif
294
295 ULONG fPipeState = 0;
296 orc = DosQueryNPHState(hNative, &fPipeState);
297 if (orc != NO_ERROR)
298 {
299 /* Sorry, anonymous pips are not supported. */
300 AssertMsgFailed(("%d\n", orc));
301 return VERR_INVALID_HANDLE;
302 }
303 AssertReturn(!(fPipeState & NP_TYPE_MESSAGE), VERR_INVALID_HANDLE);
304 AssertReturn(!(fPipeState & NP_READMODE_MESSAGE), VERR_INVALID_HANDLE);
305 AssertReturn((fPipeState & 0xff) == 1, VERR_INVALID_HANDLE);
306
307 ULONG fFileState = 0;
308 orc = DosQueryFHState(hNative, &fFileState);
309 AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), VERR_INVALID_HANDLE);
310 AssertMsgReturn( (fFileState & 0x3) == (fFlags & RTPIPE_N_READ ? OPEN_ACCESS_READONLY : OPEN_ACCESS_WRITEONLY)
311 || (fFileState & 0x3) == OPEN_ACCESS_READWRITE
312 , ("%#x\n", fFileState), VERR_INVALID_HANDLE);
313
314 /*
315 * Looks kind of OK. Fix the inherit flag.
316 */
317 orc = DosSetFHState(hNative, (fFileState & (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE))
318 | (fFlags & RTPIPE_N_INHERIT ? 0 : OPEN_FLAGS_NOINHERIT));
319 AssertMsgReturn(orc == NO_ERROR, ("%d\n", orc), RTErrConvertFromOS2(orc));
320
321
322 /*
323 * Create a handle so we can try rtPipeQueryInfo on it
324 * and see if we need to duplicate it to make that call work.
325 */
326 RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL));
327 if (!pThis)
328 return VERR_NO_MEMORY;
329 int rc = RTCritSectInit(&pThis->CritSect);
330 if (RT_SUCCESS(rc))
331 {
332 pThis->u32Magic = RTPIPE_MAGIC;
333 pThis->hPipe = hNative;
334 pThis->hev = NULLHANDLE;
335 pThis->fRead = !!(fFlags & RTPIPE_N_READ);
336 pThis->fBlocking = !(fPipeState & NP_NOWAIT);
337 //pThis->fBrokenPipe = false;
338 //pThis->cUsers = 0;
339 pThis->hPollSet = NIL_RTPOLLSET;
340
341 *phPipe = pThis;
342 return VINF_SUCCESS;
343
344 //RTCritSectDelete(&pThis->CritSect);
345 }
346 RTMemFree(pThis);
347 return rc;
348}
349
350RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe)
351{
352 RTPIPEINTERNAL *pThis = hPipe;
353 AssertPtrReturn(pThis, -1);
354 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, -1);
355
356 return (RTHCINTPTR)pThis->hPipe;
357}
358
359/**
360 * Prepare blocking mode.
361 *
362 * @returns IPRT status code.
363 * @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is
364 * attempted.
365 *
366 * @param pThis The pipe handle.
367 *
368 * @remarks Caller owns the critical section.
369 */
370static int rtPipeTryBlocking(RTPIPEINTERNAL *pThis)
371{
372 if (!pThis->fBlocking)
373 {
374 if (pThis->cUsers != 0)
375 return VERR_WRONG_ORDER;
376
377 APIRET orc = DosSetNPHState(pThis->hPipe, NP_WAIT | NP_READMODE_BYTE);
378 if (orc != NO_ERROR)
379 {
380 if (orc != ERROR_BROKEN_PIPE && orc != ERROR_PIPE_NOT_CONNECTED)
381 return RTErrConvertFromOS2(orc);
382 pThis->fBrokenPipe = true;
383 }
384 pThis->fBlocking = true;
385 }
386
387 pThis->cUsers++;
388 return VINF_SUCCESS;
389}
390
391
392/**
393 * Prepare non-blocking mode.
394 *
395 * @returns IPRT status code.
396 * @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is
397 * attempted.
398 *
399 * @param pThis The pipe handle.
400 */
401static int rtPipeTryNonBlocking(RTPIPEINTERNAL *pThis)
402{
403 if (pThis->fBlocking)
404 {
405 if (pThis->cUsers != 0)
406 return VERR_WRONG_ORDER;
407
408 APIRET orc = DosSetNPHState(pThis->hPipe, NP_NOWAIT | NP_READMODE_BYTE);
409 if (orc != NO_ERROR)
410 {
411 if (orc != ERROR_BROKEN_PIPE && orc != ERROR_PIPE_NOT_CONNECTED)
412 return RTErrConvertFromOS2(orc);
413 pThis->fBrokenPipe = true;
414 }
415 pThis->fBlocking = false;
416 }
417
418 pThis->cUsers++;
419 return VINF_SUCCESS;
420}
421
422
423/**
424 * Checks if the read pipe has been broken.
425 *
426 * @returns true if broken, false if no.
427 * @param pThis The pipe handle (read).
428 */
429static bool rtPipeOs2IsBroken(RTPIPEINTERNAL *pThis)
430{
431 Assert(pThis->fRead);
432
433#if 0
434 /*
435 * Query it via the semaphore. Not sure how fast this is...
436 */
437 PIPESEMSTATE aStates[3]; RT_ZERO(aStates);
438 APIRET orc = DosQueryNPipeSemState(pThis->hev, &aStates[0], sizeof(aStates));
439 if (orc == NO_ERROR)
440 {
441 if (aStates[0].fStatus == NPSS_CLOSE)
442 return true;
443 if (aStates[0].fStatus == NPSS_RDATA)
444 return false;
445 }
446 AssertMsgFailed(("%d / %d\n", orc, aStates[0].fStatus));
447
448 /*
449 * Fall back / alternative method.
450 */
451#endif
452 ULONG cbActual = 0;
453 ULONG ulState = 0;
454 AVAILDATA Avail = { 0, 0 };
455 APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
456 if (orc != NO_ERROR)
457 {
458 if (orc != ERROR_PIPE_BUSY)
459 AssertMsgFailed(("%d\n", orc));
460 return false;
461 }
462
463 return ulState != NP_STATE_CONNECTED;
464}
465
466
467RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
468{
469 RTPIPEINTERNAL *pThis = hPipe;
470 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
471 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
472 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
473 AssertPtr(pcbRead);
474 AssertPtr(pvBuf);
475
476 int rc = RTCritSectEnter(&pThis->CritSect);
477 if (RT_SUCCESS(rc))
478 {
479 rc = rtPipeTryNonBlocking(pThis);
480 if (RT_SUCCESS(rc))
481 {
482 RTCritSectLeave(&pThis->CritSect);
483
484 ULONG cbActual = 0;
485 APIRET orc = DosRead(pThis->hPipe, pvBuf, cbToRead, &cbActual);
486 if (orc == NO_ERROR)
487 {
488 if (cbActual || !cbToRead || !rtPipeOs2IsBroken(pThis))
489 *pcbRead = cbActual;
490 else
491 rc = VERR_BROKEN_PIPE;
492 }
493 else if (orc == ERROR_NO_DATA)
494 {
495 *pcbRead = 0;
496 rc = VINF_TRY_AGAIN;
497 }
498 else
499 rc = RTErrConvertFromOS2(orc);
500
501 RTCritSectEnter(&pThis->CritSect);
502 if (rc == VERR_BROKEN_PIPE)
503 pThis->fBrokenPipe = true;
504 pThis->cUsers--;
505 }
506 else
507 rc = VERR_WRONG_ORDER;
508 RTCritSectLeave(&pThis->CritSect);
509 }
510 return rc;
511}
512
513
514RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
515{
516 RTPIPEINTERNAL *pThis = hPipe;
517 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
518 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
519 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
520 AssertPtr(pvBuf);
521
522 int rc = RTCritSectEnter(&pThis->CritSect);
523 if (RT_SUCCESS(rc))
524 {
525 rc = rtPipeTryBlocking(pThis);
526 if (RT_SUCCESS(rc))
527 {
528 RTCritSectLeave(&pThis->CritSect);
529
530 size_t cbTotalRead = 0;
531 while (cbToRead > 0)
532 {
533 ULONG cbActual = 0;
534 APIRET orc = DosRead(pThis->hPipe, pvBuf, cbToRead, &cbActual);
535 if (orc != NO_ERROR)
536 {
537 rc = RTErrConvertFromOS2(orc);
538 break;
539 }
540 if (!cbActual && rtPipeOs2IsBroken(pThis))
541 {
542 rc = VERR_BROKEN_PIPE;
543 break;
544 }
545
546 /* advance */
547 pvBuf = (char *)pvBuf + cbActual;
548 cbTotalRead += cbActual;
549 cbToRead -= cbActual;
550 }
551
552 if (pcbRead)
553 {
554 *pcbRead = cbTotalRead;
555 if ( RT_FAILURE(rc)
556 && cbTotalRead)
557 rc = VINF_SUCCESS;
558 }
559
560 RTCritSectEnter(&pThis->CritSect);
561 if (rc == VERR_BROKEN_PIPE)
562 pThis->fBrokenPipe = true;
563 pThis->cUsers--;
564 }
565 else
566 rc = VERR_WRONG_ORDER;
567 RTCritSectLeave(&pThis->CritSect);
568 }
569 return rc;
570}
571
572
573/**
574 * Gets the available write buffer size of the pipe.
575 *
576 * @returns Number of bytes, 1 on failure.
577 * @param pThis The pipe handle.
578 */
579static ULONG rtPipeOs2GetSpace(RTPIPEINTERNAL *pThis)
580{
581 Assert(!pThis->fRead);
582
583#if 0 /* Not sure which is more efficient, neither are really optimal, I fear. */
584 /*
585 * Query via semaphore state.
586 * This will walk the list of active named pipes...
587 */
588 /** @todo Check how hev and hpipe are associated, if complicated, use the
589 * alternative method below. */
590 PIPESEMSTATE aStates[3]; RT_ZERO(aStates);
591 APIRET orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates));
592 if (orc == NO_ERROR)
593 {
594 if (aStates[0].fStatus == NPSS_WSPACE)
595 return aStates[0].usAvail;
596 if (aStates[1].fStatus == NPSS_WSPACE)
597 return aStates[1].usAvail;
598 return 0;
599 }
600 AssertMsgFailed(("%d / %d\n", orc, aStates[0].fStatus));
601
602#else
603 /*
604 * Query via the pipe info.
605 * This will have to lookup and store the pipe name.
606 */
607 union
608 {
609 PIPEINFO PipeInfo;
610 uint8_t abPadding[sizeof(PIPEINFO) + 127];
611 } Buf;
612 APIRET orc = DosQueryNPipeInfo(pThis->hPipe, 1, &Buf, sizeof(Buf));
613 if (orc == NO_ERROR)
614 return Buf.PipeInfo.cbOut;
615 AssertMsgFailed(("%d\n", orc));
616#endif
617
618 return 1;
619}
620
621
622RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
623{
624 RTPIPEINTERNAL *pThis = hPipe;
625 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
626 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
627 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
628 AssertPtr(pcbWritten);
629 AssertPtr(pvBuf);
630
631 int rc = RTCritSectEnter(&pThis->CritSect);
632 if (RT_SUCCESS(rc))
633 {
634 rc = rtPipeTryNonBlocking(pThis);
635 if (RT_SUCCESS(rc))
636 {
637 if (cbToWrite > 0)
638 {
639 ULONG cbActual = 0;
640 APIRET orc = DosWrite(pThis->hPipe, pvBuf, cbToWrite, &cbActual);
641 if (orc == NO_ERROR && cbActual == 0)
642 {
643 /* Retry with the request adjusted to the available buffer space. */
644 ULONG cbAvail = rtPipeOs2GetSpace(pThis);
645 orc = DosWrite(pThis->hPipe, pvBuf, RT_MIN(cbAvail, cbToWrite), &cbActual);
646 }
647
648 if (orc == NO_ERROR)
649 {
650 *pcbWritten = cbActual;
651 if (cbActual == 0)
652 rc = VINF_TRY_AGAIN;
653 }
654 else
655 {
656 rc = RTErrConvertFromOS2(orc);
657 if (rc == VERR_PIPE_NOT_CONNECTED)
658 rc = VERR_BROKEN_PIPE;
659 }
660 }
661 else
662 *pcbWritten = 0;
663
664 if (rc == VERR_BROKEN_PIPE)
665 pThis->fBrokenPipe = true;
666 pThis->cUsers--;
667 }
668 else
669 rc = VERR_WRONG_ORDER;
670 RTCritSectLeave(&pThis->CritSect);
671 }
672 return rc;
673}
674
675
676RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
677{
678 RTPIPEINTERNAL *pThis = hPipe;
679 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
680 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
681 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
682 AssertPtr(pvBuf);
683 AssertPtrNull(pcbWritten);
684
685 int rc = RTCritSectEnter(&pThis->CritSect);
686 if (RT_SUCCESS(rc))
687 {
688 rc = rtPipeTryBlocking(pThis);
689 if (RT_SUCCESS(rc))
690 {
691 RTCritSectLeave(&pThis->CritSect);
692
693 size_t cbTotalWritten = 0;
694 while (cbToWrite > 0)
695 {
696 ULONG cbActual = 0;
697 APIRET orc = DosWrite(pThis->hPipe, pvBuf, cbToWrite, &cbActual);
698 if (orc != NO_ERROR)
699 {
700 rc = RTErrConvertFromOS2(orc);
701 if (rc == VERR_PIPE_NOT_CONNECTED)
702 rc = VERR_BROKEN_PIPE;
703 break;
704 }
705 pvBuf = (char const *)pvBuf + cbActual;
706 cbToWrite -= cbActual;
707 cbTotalWritten += cbActual;
708 }
709
710 if (pcbWritten)
711 {
712 *pcbWritten = cbTotalWritten;
713 if ( RT_FAILURE(rc)
714 && cbTotalWritten)
715 rc = VINF_SUCCESS;
716 }
717
718 RTCritSectEnter(&pThis->CritSect);
719 if (rc == VERR_BROKEN_PIPE)
720 pThis->fBrokenPipe = true;
721 pThis->cUsers--;
722 }
723 else
724 rc = VERR_WRONG_ORDER;
725 RTCritSectLeave(&pThis->CritSect);
726 }
727 return rc;
728}
729
730
731RTDECL(int) RTPipeFlush(RTPIPE hPipe)
732{
733 RTPIPEINTERNAL *pThis = hPipe;
734 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
735 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
736 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
737
738 APIRET orc = DosResetBuffer(pThis->hPipe);
739 if (orc != NO_ERROR)
740 {
741 int rc = RTErrConvertFromOS2(orc);
742 if (rc == VERR_BROKEN_PIPE)
743 {
744 RTCritSectEnter(&pThis->CritSect);
745 pThis->fBrokenPipe = true;
746 RTCritSectLeave(&pThis->CritSect);
747 }
748 return rc;
749 }
750 return VINF_SUCCESS;
751}
752
753
754RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies)
755{
756 RTPIPEINTERNAL *pThis = hPipe;
757 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
758 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
759
760 uint64_t const StartMsTS = RTTimeMilliTS();
761
762 int rc = RTCritSectEnter(&pThis->CritSect);
763 if (RT_FAILURE(rc))
764 return rc;
765
766 rc = rtPipeOs2EnsureSem(pThis);
767 if (RT_SUCCESS(rc) && cMillies > 0)
768 {
769 /* Stop polling attempts if we might block. */
770 if (pThis->hPollSet == NIL_RTPOLLSET)
771 pThis->hPollSet = (RTPOLLSET)(uintptr_t)0xbeef0042;
772 else
773 rc = VERR_WRONG_ORDER;
774 }
775 if (RT_SUCCESS(rc))
776 {
777 for (unsigned iLoop = 0;; iLoop++)
778 {
779 /*
780 * Check the handle state.
781 */
782 APIRET orc;
783 if (cMillies > 0)
784 {
785 ULONG ulIgnore;
786 orc = DosResetEventSem(pThis->hev, &ulIgnore);
787 AssertMsg(orc == NO_ERROR || orc == ERROR_ALREADY_RESET, ("%d\n", orc));
788 }
789
790 PIPESEMSTATE aStates[4]; RT_ZERO(aStates);
791 orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates));
792 if (orc != NO_ERROR)
793 {
794 rc = RTErrConvertFromOS2(orc);
795 break;
796 }
797 int i = 0;
798 if (pThis->fRead)
799 while (aStates[i].fStatus == NPSS_WSPACE)
800 i++;
801 else
802 while (aStates[i].fStatus == NPSS_RDATA)
803 i++;
804 if (aStates[i].fStatus == NPSS_CLOSE)
805 break;
806 Assert(aStates[i].fStatus == NPSS_WSPACE || aStates[i].fStatus == NPSS_RDATA || aStates[i].fStatus == NPSS_EOI);
807 if ( aStates[i].fStatus != NPSS_EOI
808 && aStates[i].usAvail > 0)
809 break;
810
811 /*
812 * Check for timeout.
813 */
814 ULONG cMsMaxWait = SEM_INDEFINITE_WAIT;
815 if (cMillies != RT_INDEFINITE_WAIT)
816 {
817 uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
818 if (cElapsed >= cMillies)
819 {
820 rc = VERR_TIMEOUT;
821 break;
822 }
823 cMsMaxWait = cMillies - (uint32_t)cElapsed;
824 }
825
826 /*
827 * Wait.
828 */
829 RTCritSectLeave(&pThis->CritSect);
830 orc = DosWaitEventSem(pThis->hev, cMsMaxWait);
831 RTCritSectEnter(&pThis->CritSect);
832 if (orc != NO_ERROR && orc != ERROR_TIMEOUT && orc != ERROR_SEM_TIMEOUT )
833 {
834 rc = RTErrConvertFromOS2(orc);
835 break;
836 }
837 }
838
839 if (rc == VERR_BROKEN_PIPE)
840 pThis->fBrokenPipe = true;
841 if (cMillies > 0)
842 pThis->hPollSet = NIL_RTPOLLSET;
843 }
844
845 RTCritSectLeave(&pThis->CritSect);
846 return rc;
847}
848
849
850RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
851{
852 RTPIPEINTERNAL *pThis = hPipe;
853 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
854 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
855 AssertReturn(pThis->fRead, VERR_PIPE_NOT_READ);
856 AssertPtrReturn(pcbReadable, VERR_INVALID_POINTER);
857
858 int rc = RTCritSectEnter(&pThis->CritSect);
859 if (RT_FAILURE(rc))
860 return rc;
861
862 ULONG cbActual = 0;
863 ULONG ulState = 0;
864 AVAILDATA Avail = { 0, 0 };
865 APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
866 if (orc == NO_ERROR)
867 {
868 if (Avail.cbpipe > 0 || ulState == NP_STATE_CONNECTED)
869 *pcbReadable = Avail.cbpipe;
870 else
871 rc = VERR_PIPE_NOT_CONNECTED; /*??*/
872 }
873 else
874 rc = RTErrConvertFromOS2(orc);
875
876 RTCritSectLeave(&pThis->CritSect);
877 return rc;
878}
879
880
881RTDECL(int) RTPipeQueryInfo(RTPIPE hPipe, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
882{
883 RTPIPEINTERNAL *pThis = hPipe;
884 AssertPtrReturn(pThis, 0);
885 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
886
887 int rc = RTCritSectEnter(&pThis->CritSect);
888 AssertRCReturn(rc, 0);
889
890 rtPipeFakeQueryInfo(pObjInfo, enmAddAttr, pThis->fRead);
891
892 if (pThis->fRead)
893 {
894 ULONG cbActual = 0;
895 ULONG ulState = 0;
896 AVAILDATA Avail = { 0, 0 };
897 APIRET orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
898 if (orc == NO_ERROR && (Avail.cbpipe > 0 || ulState == NP_STATE_CONNECTED))
899 pObjInfo->cbObject = Avail.cbpipe;
900 }
901 else
902 pObjInfo->cbObject = rtPipeOs2GetSpace(pThis)
903 pObjInfo->cbAllocated = RTPIPE_OS2_SIZE; /** @todo this isn't necessarily true if we didn't create it... but, whatever */
904
905 RTCritSectLeave(&pThis->CritSect);
906 return VINF_SUCCESS;
907}
908
909
910int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
911{
912 RTPIPEINTERNAL *pThis = hPipe;
913 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
914 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
915
916 AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
917 AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
918
919 int rc = RTCritSectEnter(&pThis->CritSect);
920 if (RT_SUCCESS(rc))
921 {
922 rc = rtPipeOs2EnsureSem(pThis);
923 if (RT_SUCCESS(rc))
924 *phNative = (RTHCINTPTR)pThis->hev;
925 RTCritSectLeave(&pThis->CritSect);
926 }
927 return rc;
928}
929
930
931/**
932 * Checks for pending events.
933 *
934 * @returns Event mask or 0.
935 * @param pThis The pipe handle.
936 * @param fEvents The desired events.
937 * @param fResetEvtSem Whether to reset the event semaphore.
938 */
939static uint32_t rtPipePollCheck(RTPIPEINTERNAL *pThis, uint32_t fEvents, bool fResetEvtSem)
940{
941 /*
942 * Reset the event semaphore if we're gonna wait.
943 */
944 APIRET orc;
945 ULONG ulIgnore;
946 if (fResetEvtSem)
947 {
948 orc = DosResetEventSem(pThis->hev, &ulIgnore);
949 AssertMsg(orc == NO_ERROR || orc == ERROR_ALREADY_RESET, ("%d\n", orc));
950 }
951
952 /*
953 * Check for events.
954 */
955 uint32_t fRetEvents = 0;
956 if (pThis->fBrokenPipe)
957 fRetEvents |= RTPOLL_EVT_ERROR;
958 else if (pThis->fRead)
959 {
960 ULONG cbActual = 0;
961 ULONG ulState = 0;
962 AVAILDATA Avail = { 0, 0 };
963 orc = DosPeekNPipe(pThis->hPipe, NULL, 0, &cbActual, &Avail, &ulState);
964 if (orc != NO_ERROR)
965 {
966 fRetEvents |= RTPOLL_EVT_ERROR;
967 if (orc == ERROR_BROKEN_PIPE || orc == ERROR_PIPE_NOT_CONNECTED)
968 pThis->fBrokenPipe = true;
969 }
970 else if (Avail.cbpipe > 0)
971 fRetEvents |= RTPOLL_EVT_READ;
972 else if (ulState != NP_STATE_CONNECTED)
973 {
974 fRetEvents |= RTPOLL_EVT_ERROR;
975 pThis->fBrokenPipe = true;
976 }
977 }
978 else
979 {
980 PIPESEMSTATE aStates[4]; RT_ZERO(aStates);
981 orc = DosQueryNPipeSemState((HSEM)pThis->hev, &aStates[0], sizeof(aStates));
982 if (orc == NO_ERROR)
983 {
984 int i = 0;
985 while (aStates[i].fStatus == NPSS_RDATA)
986 i++;
987 if (aStates[i].fStatus == NPSS_CLOSE)
988 {
989 fRetEvents |= RTPOLL_EVT_ERROR;
990 pThis->fBrokenPipe = true;
991 }
992 else if ( aStates[i].fStatus == NPSS_WSPACE
993 && aStates[i].usAvail > 0)
994 fRetEvents |= RTPOLL_EVT_WRITE;
995 }
996 else
997 {
998 fRetEvents |= RTPOLL_EVT_ERROR;
999 if (orc == ERROR_BROKEN_PIPE || orc == ERROR_PIPE_NOT_CONNECTED)
1000 pThis->fBrokenPipe = true;
1001 }
1002 }
1003
1004 return fRetEvents & (fEvents | RTPOLL_EVT_ERROR);
1005}
1006
1007
1008uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1009{
1010 RTPIPEINTERNAL *pThis = hPipe;
1011 AssertPtrReturn(pThis, UINT32_MAX);
1012 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, UINT32_MAX);
1013
1014 int rc = RTCritSectEnter(&pThis->CritSect);
1015 AssertRCReturn(rc, UINT32_MAX);
1016
1017 /* Check that this is the only current use of this pipe. */
1018 uint32_t fRetEvents;
1019 if ( pThis->cUsers == 0
1020 || pThis->hPollSet == NIL_RTPOLLSET)
1021 {
1022 fRetEvents = rtPipePollCheck(pThis, fEvents, fNoWait);
1023 if (!fRetEvents && !fNoWait)
1024 {
1025 /* Mark the set busy while waiting. */
1026 pThis->cUsers++;
1027 pThis->hPollSet = hPollSet;
1028 }
1029 }
1030 else
1031 {
1032 AssertFailed();
1033 fRetEvents = UINT32_MAX;
1034 }
1035
1036 RTCritSectLeave(&pThis->CritSect);
1037 return fRetEvents;
1038}
1039
1040
1041uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
1042{
1043 RTPIPEINTERNAL *pThis = hPipe;
1044 AssertPtrReturn(pThis, 0);
1045 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
1046
1047 int rc = RTCritSectEnter(&pThis->CritSect);
1048 AssertRCReturn(rc, 0);
1049
1050 Assert(pThis->cUsers > 0);
1051
1052 /* harvest events. */
1053 uint32_t fRetEvents = rtPipePollCheck(pThis, fEvents, false);
1054
1055 /* update counters. */
1056 pThis->cUsers--;
1057 pThis->hPollSet = NIL_RTPOLLSET;
1058
1059 RTCritSectLeave(&pThis->CritSect);
1060 return fRetEvents;
1061}
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