VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/pipe-posix.cpp@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.3 KB
Line 
1/* $Id: pipe-posix.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Anonymous Pipes, POSIX Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2022 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/pipe.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/mem.h>
38#include <iprt/poll.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include "internal/magics.h"
42
43#include <errno.h>
44#include <fcntl.h>
45#include <limits.h>
46#include <unistd.h>
47#include <sys/ioctl.h>
48#include <sys/poll.h>
49#include <sys/stat.h>
50#include <signal.h>
51#ifdef RT_OS_LINUX
52# include <sys/syscall.h>
53#endif
54#ifdef RT_OS_SOLARIS
55# include <sys/filio.h>
56#endif
57
58#include "internal/pipe.h"
59
60
61/*********************************************************************************************************************************
62* Structures and Typedefs *
63*********************************************************************************************************************************/
64typedef struct RTPIPEINTERNAL
65{
66 /** Magic value (RTPIPE_MAGIC). */
67 uint32_t u32Magic;
68 /** The file descriptor. */
69 int fd;
70 /** Set if this is the read end, clear if it's the write end. */
71 bool fRead;
72 /** RTPipeFromNative: Leave it open on RTPipeClose. */
73 bool fLeaveOpen;
74 /** Atomically operated state variable.
75 *
76 * - Bits 0 thru 29 - Users of the new mode.
77 * - Bit 30 - The pipe mode, set indicates blocking.
78 * - Bit 31 - Set when we're switching the mode.
79 */
80 uint32_t volatile u32State;
81} RTPIPEINTERNAL;
82
83
84/*********************************************************************************************************************************
85* Defined Constants And Macros *
86*********************************************************************************************************************************/
87/** @name RTPIPEINTERNAL::u32State defines
88 * @{ */
89#define RTPIPE_POSIX_BLOCKING UINT32_C(0x40000000)
90#define RTPIPE_POSIX_SWITCHING UINT32_C(0x80000000)
91#define RTPIPE_POSIX_SWITCHING_BIT 31
92#define RTPIPE_POSIX_USERS_MASK UINT32_C(0x3fffffff)
93/** @} */
94
95
96
97/**
98 * Wrapper for calling pipe2() or pipe().
99 *
100 * When using pipe2() the returned handles are marked close-on-exec and does
101 * not risk racing process creation calls on other threads.
102 *
103 * @returns See pipe().
104 * @param paFds See pipe().
105 * @param piNewPipeSyscall Where to cache which call we should used. -1 if
106 * pipe(), 1 if pipe2(), 0 if not yet decided.
107 */
108static int my_pipe_wrapper(int *paFds, int *piNewPipeSyscall)
109{
110 if (*piNewPipeSyscall >= 0)
111 {
112#if defined(RT_OS_LINUX) && defined(__NR_pipe2) && defined(O_CLOEXEC)
113 long rc = syscall(__NR_pipe2, paFds, O_CLOEXEC);
114 if (rc >= 0)
115 {
116 if (*piNewPipeSyscall == 0)
117 *piNewPipeSyscall = 1;
118 return (int)rc;
119 }
120#endif
121 *piNewPipeSyscall = -1;
122 }
123
124 return pipe(paFds);
125}
126
127
128RTDECL(int) RTPipeCreate(PRTPIPE phPipeRead, PRTPIPE phPipeWrite, uint32_t fFlags)
129{
130 AssertPtrReturn(phPipeRead, VERR_INVALID_POINTER);
131 AssertPtrReturn(phPipeWrite, VERR_INVALID_POINTER);
132 AssertReturn(!(fFlags & ~RTPIPE_C_VALID_MASK), VERR_INVALID_PARAMETER);
133
134 /*
135 * Create the pipe and clear/set the close-on-exec flag as required.
136 */
137 int aFds[2] = {-1, -1};
138 static int s_iNewPipeSyscall = 0;
139 if (my_pipe_wrapper(aFds, &s_iNewPipeSyscall))
140 return RTErrConvertFromErrno(errno);
141
142 int rc = VINF_SUCCESS;
143 if (s_iNewPipeSyscall > 0)
144 {
145 /* created with close-on-exec set. */
146 if (fFlags & RTPIPE_C_INHERIT_READ)
147 {
148 if (fcntl(aFds[0], F_SETFD, 0))
149 rc = RTErrConvertFromErrno(errno);
150 }
151
152 if (fFlags & RTPIPE_C_INHERIT_WRITE)
153 {
154 if (fcntl(aFds[1], F_SETFD, 0))
155 rc = RTErrConvertFromErrno(errno);
156 }
157 }
158 else
159 {
160 /* created with close-on-exec cleared. */
161 if (!(fFlags & RTPIPE_C_INHERIT_READ))
162 {
163 if (fcntl(aFds[0], F_SETFD, FD_CLOEXEC))
164 rc = RTErrConvertFromErrno(errno);
165 }
166
167 if (!(fFlags & RTPIPE_C_INHERIT_WRITE))
168 {
169 if (fcntl(aFds[1], F_SETFD, FD_CLOEXEC))
170 rc = RTErrConvertFromErrno(errno);
171 }
172 }
173
174 if (RT_SUCCESS(rc))
175 {
176 /*
177 * Create the two handles.
178 */
179 RTPIPEINTERNAL *pThisR = (RTPIPEINTERNAL *)RTMemAlloc(sizeof(RTPIPEINTERNAL));
180 if (pThisR)
181 {
182 RTPIPEINTERNAL *pThisW = (RTPIPEINTERNAL *)RTMemAlloc(sizeof(RTPIPEINTERNAL));
183 if (pThisW)
184 {
185 pThisR->u32Magic = RTPIPE_MAGIC;
186 pThisW->u32Magic = RTPIPE_MAGIC;
187 pThisR->fd = aFds[0];
188 pThisW->fd = aFds[1];
189 pThisR->fRead = true;
190 pThisW->fRead = false;
191 pThisR->fLeaveOpen = false;
192 pThisW->fLeaveOpen = false;
193 pThisR->u32State = RTPIPE_POSIX_BLOCKING;
194 pThisW->u32State = RTPIPE_POSIX_BLOCKING;
195
196 *phPipeRead = pThisR;
197 *phPipeWrite = pThisW;
198
199 /*
200 * Before we leave, make sure to shut up SIGPIPE.
201 */
202 signal(SIGPIPE, SIG_IGN);
203 return VINF_SUCCESS;
204 }
205
206 RTMemFree(pThisR);
207 rc = VERR_NO_MEMORY;
208 }
209 else
210 rc = VERR_NO_MEMORY;
211 }
212
213 close(aFds[0]);
214 close(aFds[1]);
215 return rc;
216}
217
218
219RTDECL(int) RTPipeCloseEx(RTPIPE hPipe, bool fLeaveOpen)
220{
221 RTPIPEINTERNAL *pThis = hPipe;
222 if (pThis == NIL_RTPIPE)
223 return VINF_SUCCESS;
224 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
225 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
226
227 /*
228 * Do the cleanup.
229 */
230 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE);
231
232 int fd = pThis->fd;
233 pThis->fd = -1;
234 if (!fLeaveOpen && !pThis->fLeaveOpen)
235 close(fd);
236
237 if (ASMAtomicReadU32(&pThis->u32State) & RTPIPE_POSIX_USERS_MASK)
238 {
239 AssertFailed();
240 RTThreadSleep(1);
241 }
242
243 RTMemFree(pThis);
244
245 return VINF_SUCCESS;
246}
247
248
249RTDECL(int) RTPipeClose(RTPIPE hPipe)
250{
251 return RTPipeCloseEx(hPipe, false /*fLeaveOpen*/);
252}
253
254
255RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags)
256{
257 AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
258 AssertReturn(!(fFlags & ~RTPIPE_N_VALID_MASK_FN), VERR_INVALID_PARAMETER);
259 AssertReturn(!!(fFlags & RTPIPE_N_READ) != !!(fFlags & RTPIPE_N_WRITE), VERR_INVALID_PARAMETER);
260
261 /*
262 * Get and validate the pipe handle info.
263 */
264 int hNative = (int)hNativePipe;
265 struct stat st;
266 AssertReturn(fstat(hNative, &st) == 0, RTErrConvertFromErrno(errno));
267 AssertMsgReturn(S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode), ("%#x (%o)\n", st.st_mode, st.st_mode), VERR_INVALID_HANDLE);
268
269 int fFd = fcntl(hNative, F_GETFL, 0);
270 AssertReturn(fFd != -1, VERR_INVALID_HANDLE);
271 AssertMsgReturn( (fFd & O_ACCMODE) == (fFlags & RTPIPE_N_READ ? O_RDONLY : O_WRONLY)
272 || (fFd & O_ACCMODE) == O_RDWR /* Solaris creates bi-directional pipes. */
273 , ("%#x\n", fFd), VERR_INVALID_HANDLE);
274
275 /*
276 * Create the handle.
277 */
278 RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAlloc(sizeof(RTPIPEINTERNAL));
279 if (!pThis)
280 return VERR_NO_MEMORY;
281
282 pThis->u32Magic = RTPIPE_MAGIC;
283 pThis->fd = hNative;
284 pThis->fRead = RT_BOOL(fFlags & RTPIPE_N_READ);
285 pThis->fLeaveOpen = RT_BOOL(fFlags & RTPIPE_N_LEAVE_OPEN);
286 pThis->u32State = fFd & O_NONBLOCK ? 0 : RTPIPE_POSIX_BLOCKING;
287
288 /*
289 * Fix up inheritability and shut up SIGPIPE and we're done.
290 */
291 if (fcntl(hNative, F_SETFD, fFlags & RTPIPE_N_INHERIT ? 0 : FD_CLOEXEC) == 0)
292 {
293 signal(SIGPIPE, SIG_IGN);
294 *phPipe = pThis;
295 return VINF_SUCCESS;
296 }
297
298 int rc = RTErrConvertFromErrno(errno);
299 RTMemFree(pThis);
300 return rc;
301}
302
303
304RTDECL(RTHCINTPTR) RTPipeToNative(RTPIPE hPipe)
305{
306 RTPIPEINTERNAL *pThis = hPipe;
307 AssertPtrReturn(pThis, -1);
308 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, -1);
309
310 return pThis->fd;
311}
312
313
314/**
315 * Prepare blocking mode.
316 *
317 * @returns VINF_SUCCESS
318 * @retval VERR_WRONG_ORDER
319 * @retval VERR_INTERNAL_ERROR_4
320 *
321 * @param pThis The pipe handle.
322 */
323static int rtPipeTryBlocking(RTPIPEINTERNAL *pThis)
324{
325 /*
326 * Update the state.
327 */
328 for (;;)
329 {
330 uint32_t u32State = ASMAtomicReadU32(&pThis->u32State);
331 uint32_t const u32StateOld = u32State;
332 uint32_t const cUsers = (u32State & RTPIPE_POSIX_USERS_MASK);
333
334 if (u32State & RTPIPE_POSIX_BLOCKING)
335 {
336 AssertReturn(cUsers < RTPIPE_POSIX_USERS_MASK / 2, VERR_INTERNAL_ERROR_4);
337 u32State &= ~RTPIPE_POSIX_USERS_MASK;
338 u32State |= cUsers + 1;
339 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32StateOld))
340 {
341 if (u32State & RTPIPE_POSIX_SWITCHING)
342 break;
343 return VINF_SUCCESS;
344 }
345 }
346 else if (cUsers == 0)
347 {
348 u32State = 1 | RTPIPE_POSIX_SWITCHING | RTPIPE_POSIX_BLOCKING;
349 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32StateOld))
350 break;
351 }
352 else
353 return VERR_WRONG_ORDER;
354 ASMNopPause();
355 }
356
357 /*
358 * Do the switching.
359 */
360 int fFlags = fcntl(pThis->fd, F_GETFL, 0);
361 if (fFlags != -1)
362 {
363 if ( !(fFlags & O_NONBLOCK)
364 || fcntl(pThis->fd, F_SETFL, fFlags & ~O_NONBLOCK) != -1)
365 {
366 ASMAtomicBitClear(&pThis->u32State, RTPIPE_POSIX_SWITCHING_BIT);
367 return VINF_SUCCESS;
368 }
369 }
370
371 ASMAtomicDecU32(&pThis->u32State);
372 return RTErrConvertFromErrno(errno);
373}
374
375
376/**
377 * Prepare non-blocking mode.
378 *
379 * @returns VINF_SUCCESS
380 * @retval VERR_WRONG_ORDER
381 * @retval VERR_INTERNAL_ERROR_4
382 *
383 * @param pThis The pipe handle.
384 */
385static int rtPipeTryNonBlocking(RTPIPEINTERNAL *pThis)
386{
387 /*
388 * Update the state.
389 */
390 for (;;)
391 {
392 uint32_t u32State = ASMAtomicReadU32(&pThis->u32State);
393 uint32_t const u32StateOld = u32State;
394 uint32_t const cUsers = (u32State & RTPIPE_POSIX_USERS_MASK);
395
396 if (!(u32State & RTPIPE_POSIX_BLOCKING))
397 {
398 AssertReturn(cUsers < RTPIPE_POSIX_USERS_MASK / 2, VERR_INTERNAL_ERROR_4);
399 u32State &= ~RTPIPE_POSIX_USERS_MASK;
400 u32State |= cUsers + 1;
401 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32StateOld))
402 {
403 if (u32State & RTPIPE_POSIX_SWITCHING)
404 break;
405 return VINF_SUCCESS;
406 }
407 }
408 else if (cUsers == 0)
409 {
410 u32State = 1 | RTPIPE_POSIX_SWITCHING;
411 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32StateOld))
412 break;
413 }
414 else
415 return VERR_WRONG_ORDER;
416 ASMNopPause();
417 }
418
419 /*
420 * Do the switching.
421 */
422 int fFlags = fcntl(pThis->fd, F_GETFL, 0);
423 if (fFlags != -1)
424 {
425 if ( (fFlags & O_NONBLOCK)
426 || fcntl(pThis->fd, F_SETFL, fFlags | O_NONBLOCK) != -1)
427 {
428 ASMAtomicBitClear(&pThis->u32State, RTPIPE_POSIX_SWITCHING_BIT);
429 return VINF_SUCCESS;
430 }
431 }
432
433 ASMAtomicDecU32(&pThis->u32State);
434 return RTErrConvertFromErrno(errno);
435}
436
437
438/**
439 * Checks if the read pipe has a HUP condition.
440 *
441 * @returns true if HUP, false if no.
442 * @param pThis The pipe handle (read).
443 */
444static bool rtPipePosixHasHup(RTPIPEINTERNAL *pThis)
445{
446 Assert(pThis->fRead);
447
448 struct pollfd PollFd;
449 RT_ZERO(PollFd);
450 PollFd.fd = pThis->fd;
451 PollFd.events = POLLHUP;
452 return poll(&PollFd, 1, 0) >= 1
453 && (PollFd.revents & POLLHUP);
454}
455
456
457RTDECL(int) RTPipeRead(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
458{
459 RTPIPEINTERNAL *pThis = hPipe;
460 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
461 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
462 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
463 AssertPtr(pcbRead);
464 AssertPtr(pvBuf);
465
466 int rc = rtPipeTryNonBlocking(pThis);
467 if (RT_SUCCESS(rc))
468 {
469 ssize_t cbRead = read(pThis->fd, pvBuf, RT_MIN(cbToRead, SSIZE_MAX));
470 if (cbRead >= 0)
471 {
472 if (cbRead || !cbToRead || !rtPipePosixHasHup(pThis))
473 *pcbRead = cbRead;
474 else
475 rc = VERR_BROKEN_PIPE;
476 }
477 else if (errno == EAGAIN)
478 {
479 *pcbRead = 0;
480 rc = VINF_TRY_AGAIN;
481 }
482 else
483 rc = RTErrConvertFromErrno(errno);
484
485 ASMAtomicDecU32(&pThis->u32State);
486 }
487 return rc;
488}
489
490
491RTDECL(int) RTPipeReadBlocking(RTPIPE hPipe, void *pvBuf, size_t cbToRead, size_t *pcbRead)
492{
493 RTPIPEINTERNAL *pThis = hPipe;
494 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
495 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
496 AssertReturn(pThis->fRead, VERR_ACCESS_DENIED);
497 AssertPtr(pvBuf);
498
499 int rc = rtPipeTryBlocking(pThis);
500 if (RT_SUCCESS(rc))
501 {
502 size_t cbTotalRead = 0;
503 while (cbToRead > 0)
504 {
505 ssize_t cbRead = read(pThis->fd, pvBuf, RT_MIN(cbToRead, SSIZE_MAX));
506 if (cbRead < 0)
507 {
508 rc = RTErrConvertFromErrno(errno);
509 break;
510 }
511 if (!cbRead && rtPipePosixHasHup(pThis))
512 {
513 rc = VERR_BROKEN_PIPE;
514 break;
515 }
516
517 /* advance */
518 pvBuf = (char *)pvBuf + cbRead;
519 cbTotalRead += cbRead;
520 cbToRead -= cbRead;
521 }
522
523 if (pcbRead)
524 {
525 *pcbRead = cbTotalRead;
526 if ( RT_FAILURE(rc)
527 && cbTotalRead
528 && rc != VERR_INVALID_POINTER)
529 rc = VINF_SUCCESS;
530 }
531
532 ASMAtomicDecU32(&pThis->u32State);
533 }
534 return rc;
535}
536
537
538RTDECL(int) RTPipeWrite(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
539{
540 RTPIPEINTERNAL *pThis = hPipe;
541 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
542 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
543 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
544 AssertPtr(pcbWritten);
545 AssertPtr(pvBuf);
546
547 int rc = rtPipeTryNonBlocking(pThis);
548 if (RT_SUCCESS(rc))
549 {
550 if (cbToWrite)
551 {
552 ssize_t cbWritten = write(pThis->fd, pvBuf, RT_MIN(cbToWrite, SSIZE_MAX));
553 if (cbWritten >= 0)
554 *pcbWritten = cbWritten;
555 else if (errno == EAGAIN)
556 {
557 *pcbWritten = 0;
558 rc = VINF_TRY_AGAIN;
559 }
560 else
561 rc = RTErrConvertFromErrno(errno);
562 }
563 else
564 *pcbWritten = 0;
565
566 ASMAtomicDecU32(&pThis->u32State);
567 }
568 return rc;
569}
570
571
572RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
573{
574 RTPIPEINTERNAL *pThis = hPipe;
575 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
576 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
577 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
578 AssertPtr(pvBuf);
579 AssertPtrNull(pcbWritten);
580
581 int rc = rtPipeTryBlocking(pThis);
582 if (RT_SUCCESS(rc))
583 {
584 size_t cbTotalWritten = 0;
585 while (cbToWrite > 0)
586 {
587 ssize_t cbWritten = write(pThis->fd, pvBuf, RT_MIN(cbToWrite, SSIZE_MAX));
588 if (cbWritten < 0)
589 {
590 rc = RTErrConvertFromErrno(errno);
591 break;
592 }
593
594 /* advance */
595 pvBuf = (char const *)pvBuf + cbWritten;
596 cbTotalWritten += cbWritten;
597 cbToWrite -= cbWritten;
598 }
599
600 if (pcbWritten)
601 {
602 *pcbWritten = cbTotalWritten;
603 if ( RT_FAILURE(rc)
604 && cbTotalWritten
605 && rc != VERR_INVALID_POINTER)
606 rc = VINF_SUCCESS;
607 }
608
609 ASMAtomicDecU32(&pThis->u32State);
610 }
611 return rc;
612}
613
614
615RTDECL(int) RTPipeFlush(RTPIPE hPipe)
616{
617 RTPIPEINTERNAL *pThis = hPipe;
618 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
619 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
620 AssertReturn(!pThis->fRead, VERR_ACCESS_DENIED);
621
622 if (fsync(pThis->fd))
623 {
624 if (errno == EINVAL || errno == ENOTSUP)
625 return VERR_NOT_SUPPORTED;
626 return RTErrConvertFromErrno(errno);
627 }
628 return VINF_SUCCESS;
629}
630
631
632RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies)
633{
634 RTPIPEINTERNAL *pThis = hPipe;
635 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
636 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
637
638 struct pollfd PollFd;
639 RT_ZERO(PollFd);
640 PollFd.fd = pThis->fd;
641 PollFd.events = POLLHUP | POLLERR;
642 if (pThis->fRead)
643 PollFd.events |= POLLIN | POLLPRI;
644 else
645 PollFd.events |= POLLOUT;
646
647 int timeout;
648 if ( cMillies == RT_INDEFINITE_WAIT
649 || cMillies >= INT_MAX /* lazy bird */)
650 timeout = -1;
651 else
652 timeout = cMillies;
653
654 int rc = poll(&PollFd, 1, timeout);
655 if (rc == -1)
656 return RTErrConvertFromErrno(errno);
657 return rc > 0 ? VINF_SUCCESS : VERR_TIMEOUT;
658}
659
660
661RTDECL(int) RTPipeQueryReadable(RTPIPE hPipe, size_t *pcbReadable)
662{
663 RTPIPEINTERNAL *pThis = hPipe;
664 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
665 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
666 AssertReturn(pThis->fRead, VERR_PIPE_NOT_READ);
667 AssertPtrReturn(pcbReadable, VERR_INVALID_POINTER);
668
669 int cb = 0;
670 int rc = ioctl(pThis->fd, FIONREAD, &cb);
671 if (rc != -1)
672 {
673 AssertStmt(cb >= 0, cb = 0);
674 *pcbReadable = cb;
675 return VINF_SUCCESS;
676 }
677
678 rc = errno;
679 if (rc == ENOTTY)
680 rc = VERR_NOT_SUPPORTED;
681 else
682 rc = RTErrConvertFromErrno(rc);
683 return rc;
684}
685
686
687RTDECL(int) RTPipeQueryInfo(RTPIPE hPipe, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
688{
689 RTPIPEINTERNAL *pThis = hPipe;
690 AssertPtrReturn(pThis, 0);
691 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0);
692
693 rtPipeFakeQueryInfo(pObjInfo, enmAddAttr, pThis->fRead);
694
695 if (pThis->fRead)
696 {
697 int cb = 0;
698 int rc = ioctl(pThis->fd, FIONREAD, &cb);
699 if (rc >= 0)
700 pObjInfo->cbObject = cb;
701 }
702#ifdef FIONSPACE
703 else
704 {
705 int cb = 0;
706 int rc = ioctl(pThis->fd, FIONSPACE, &cb);
707 if (rc >= 0)
708 pObjInfo->cbObject = cb;
709 }
710#endif
711
712 /** @todo Check this out on linux, solaris and darwin... (Currently going by a
713 * FreeBSD manpage.) */
714 struct stat St;
715 if (fstat(pThis->fd, &St))
716 {
717 pObjInfo->cbAllocated = St.st_blksize;
718 if ( enmAddAttr == RTFSOBJATTRADD_NOTHING
719 || enmAddAttr == RTFSOBJATTRADD_UNIX)
720 {
721 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
722 pObjInfo->Attr.u.Unix.INodeId = St.st_ino;
723 pObjInfo->Attr.u.Unix.INodeIdDevice = St.st_dev;
724 }
725 }
726 /** @todo error handling? */
727
728 return VINF_SUCCESS;
729}
730
731
732int rtPipePollGetHandle(RTPIPE hPipe, uint32_t fEvents, PRTHCINTPTR phNative)
733{
734 RTPIPEINTERNAL *pThis = hPipe;
735 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
736 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);
737
738 AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER);
739 AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER);
740
741 *phNative = pThis->fd;
742 return VINF_SUCCESS;
743}
744
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