pipe-posix.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
/* $Id$ */
/** @file
* IPRT - Anonymous Pipes, POSIX Implementation.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <signal.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct RTPIPEINTERNAL
{
/** Magic value (RTPIPE_MAGIC). */
/** The file descriptor. */
int fd;
/** Set if this is the read end, clear if it's the write end. */
bool fRead;
/** Atomically operated state variable.
*
* - Bits 0 thru 29 - Users of the new mode.
* - Bit 30 - The pipe mode, set indicates blocking.
* - Bit 31 - Set when we're switching the mode.
*/
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** @name RTPIPEINTERNAL::u32State defines
* @{ */
#define RTPIPE_POSIX_SWITCHING_BIT 31
/** @} */
{
/*
* Create the pipe and set the close-on-exec flag if requested.
*/
return RTErrConvertFromErrno(errno);
int rc = VINF_SUCCESS;
if (!(fFlags & RTPIPE_C_INHERIT_READ))
{
}
if (!(fFlags & RTPIPE_C_INHERIT_WRITE))
{
}
if (RT_SUCCESS(rc))
{
/*
* Create the two handles.
*/
if (pThisR)
{
if (pThisW)
{
*phPipeRead = pThisR;
*phPipeWrite = pThisW;
/*
* Before we leave, make sure to shut up SIGPIPE.
*/
return VINF_SUCCESS;
}
rc = VERR_NO_MEMORY;
}
else
rc = VERR_NO_MEMORY;
}
return rc;
}
{
if (pThis == NIL_RTPIPE)
return VINF_SUCCESS;
/*
* Do the cleanup.
*/
AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE);
{
AssertFailed();
RTThreadSleep(1);
}
return VINF_SUCCESS;
}
{
/*
* Get and validate the pipe handle info.
*/
int hNative = (int)hNativePipe;
AssertMsgReturn(S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode), ("%#x (%o)\n", st.st_mode, st.st_mode), VERR_INVALID_HANDLE);
/*
* Create the handle.
*/
if (!pThis)
return VERR_NO_MEMORY;
/*
* Fix up inheritability and shut up SIGPIPE and we're done.
*/
{
return VINF_SUCCESS;
}
return rc;
}
{
}
/**
* Prepare blocking mode.
*
* @returns VINF_SUCCESS
* @retval VERR_WRONG_ORDER
* @retval VERR_INTERNAL_ERROR_4
*
* @param pThis The pipe handle.
*/
{
/*
* Update the state.
*/
for (;;)
{
if (u32State & RTPIPE_POSIX_BLOCKING)
{
{
if (u32State & RTPIPE_POSIX_SWITCHING)
break;
return VINF_SUCCESS;
}
}
else if (cUsers == 0)
{
break;
}
else
return VERR_WRONG_ORDER;
ASMNopPause();
}
/*
* Do the switching.
*/
if (fFlags != -1)
{
if ( !(fFlags & O_NONBLOCK)
{
return VINF_SUCCESS;
}
}
return RTErrConvertFromErrno(errno);
}
/**
* Prepare non-blocking mode.
*
* @returns VINF_SUCCESS
* @retval VERR_WRONG_ORDER
* @retval VERR_INTERNAL_ERROR_4
*
* @param pThis The pipe handle.
*/
{
/*
* Update the state.
*/
for (;;)
{
if (!(u32State & RTPIPE_POSIX_BLOCKING))
{
{
if (u32State & RTPIPE_POSIX_SWITCHING)
break;
return VINF_SUCCESS;
}
}
else if (cUsers == 0)
{
break;
}
else
return VERR_WRONG_ORDER;
ASMNopPause();
}
/*
* Do the switching.
*/
if (fFlags != -1)
{
if ( (fFlags & O_NONBLOCK)
{
return VINF_SUCCESS;
}
}
return RTErrConvertFromErrno(errno);
}
/**
* Checks if the read pipe has a HUP condition.
*
* @returns true if HUP, false if no.
* @param pThis The pipe handle (read).
*/
{
}
{
if (RT_SUCCESS(rc))
{
if (cbRead >= 0)
{
else
}
{
*pcbRead = 0;
rc = VINF_TRY_AGAIN;
}
else
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
size_t cbTotalRead = 0;;
while (cbToRead > 0)
{
if (cbRead < 0)
{
break;
}
{
break;
}
/* advance */
cbTotalRead += cbRead;
}
if (pcbRead)
{
*pcbRead = cbTotalRead;
if ( RT_FAILURE(rc)
&& cbTotalRead
&& rc != VERR_INVALID_POINTER)
rc = VINF_SUCCESS;
}
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
if (cbToWrite)
{
if (cbWritten >= 0)
*pcbWritten = cbWritten;
{
*pcbWritten = 0;
rc = VINF_TRY_AGAIN;
}
else
}
else
*pcbWritten = 0;
}
return rc;
}
RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
{
if (RT_SUCCESS(rc))
{
size_t cbTotalWritten = 0;
while (cbToWrite > 0)
{
if (cbWritten < 0)
{
break;
}
/* advance */
}
if (pcbWritten)
{
if ( RT_FAILURE(rc)
&& rc != VERR_INVALID_POINTER)
rc = VINF_SUCCESS;
}
}
return rc;
}
{
{
return VERR_NOT_SUPPORTED;
return RTErrConvertFromErrno(errno);
}
return VINF_SUCCESS;
}
{
else
int timeout;
if ( cMillies == RT_INDEFINITE_WAIT
timeout = -1;
else
if (rc == -1)
return RTErrConvertFromErrno(errno);
}