VirtualBox

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

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

scm --update-copyright-year

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