VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use