pipe-os2.cpp revision 625fbb1328649ec29bf92374a6a980cdcd163726
/* $Id$ */
/** @file
* IPRT - Anonymous Pipes, OS/2 Implementation.
*/
/*
* Copyright (C) 2010-2013 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 *
*******************************************************************************/
#define INCL_ERRORS
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include <iprt/critsect.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The pipe buffer size we prefer. */
#define RTPIPE_OS2_SIZE _32K
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct RTPIPEINTERNAL
{
/** Magic value (RTPIPE_MAGIC). */
/** The pipe handle. */
/** Set if this is the read end, clear if it's the write end. */
bool fRead;
/** Whether the pipe is in blocking or non-blocking mode. */
bool fBlocking;
/** Set if the pipe is broken. */
bool fBrokenPipe;
/** Usage counter. */
/** The event semaphore associated with the pipe. */
/** The handle of the poll set currently polling on this pipe.
* We can only have one poller at the time (lazy bird). */
/** Critical section protecting the above members.
/**
* Ensures that the pipe has a semaphore associated with it.
*
* @returns VBox status code.
* @param pThis The pipe.
*/
{
return VINF_SUCCESS;
{
{
return VINF_SUCCESS;
}
}
return RTErrConvertFromOS2(orc);
}
{
/*
* Try create and connect a pipe pair.
*/
int rc;
for (;;)
{
static volatile uint32_t g_iNextPipe = 0;
char szName[128];
RTStrPrintf(szName, sizeof(szName), "\\pipe\\iprt-pipe-%u-%u", RTProcSelf(), ASMAtomicIncU32(&g_iNextPipe));
/*
* Create the read end of the pipe.
*/
if (fFlags & RTPIPE_C_INHERIT_READ)
fOpenMode |= NP_INHERIT;
else
orc = DosCreateNPipe((PSZ)szName, &hPipeR, fOpenMode, fPipeMode, RTPIPE_OS2_SIZE, RTPIPE_OS2_SIZE, NP_DEFAULT_WAIT);
{
{
/*
* Connect to the pipe (the write end), attach sem below.
*/
if (!(fFlags & RTPIPE_C_INHERIT_WRITE))
break;
}
}
return RTErrConvertFromOS2(orc);
/* else: try again with a new name */
}
/*
* Create the two handles.
*/
if (pThisR)
{
if (pThisW)
{
/* Crit sects. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* Initialize the structures. */
//pThisR->fBrokenPipe = false;
//pThisW->fBrokenPipe = false;
//pThisR->cUsers = 0;
//pThisW->cUsers = 0;
*phPipeRead = pThisR;
*phPipeWrite = pThisW;
return VINF_SUCCESS;
}
}
}
else
rc = VERR_NO_MEMORY;
}
else
rc = VERR_NO_MEMORY;
/* Don't call DosDisConnectNPipe! */
return rc;
}
{
if (pThis == NIL_RTPIPE)
return VINF_SUCCESS;
/*
* Do the cleanup.
*/
AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTPIPE_MAGIC, RTPIPE_MAGIC), VERR_INVALID_HANDLE);
/* Don't call DosDisConnectNPipe! */
{
}
return VINF_SUCCESS;
}
{
/*
* Get and validate the pipe handle info.
*/
#if 0
union
{
} Buf;
{
/* Sorry, anonymous pips are not supported. */
return VERR_INVALID_HANDLE;
}
#endif
ULONG fPipeState = 0;
{
/* Sorry, anonymous pips are not supported. */
return VERR_INVALID_HANDLE;
}
ULONG fFileState = 0;
AssertMsgReturn( (fFileState & 0x3) == (fFlags & RTPIPE_N_READ ? OPEN_ACCESS_READONLY : OPEN_ACCESS_WRITEONLY)
/*
* Looks kind of OK. Fix the inherit flag.
*/
orc = DosSetFHState(hNative, (fFileState & (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE))
/*
* Create a handle so we can try rtPipeQueryInfo on it
* and see if we need to duplicate it to make that call work.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
//pThis->fBrokenPipe = false;
//pThis->cUsers = 0;
return VINF_SUCCESS;
//RTCritSectDelete(&pThis->CritSect);
}
return rc;
}
{
}
/**
* Prepare blocking mode.
*
* @returns IPRT status code.
* @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is
* attempted.
*
* @param pThis The pipe handle.
*
* @remarks Caller owns the critical section.
*/
{
{
return VERR_WRONG_ORDER;
{
return RTErrConvertFromOS2(orc);
pThis->fBrokenPipe = true;
}
}
return VINF_SUCCESS;
}
/**
* Prepare non-blocking mode.
*
* @returns IPRT status code.
* @retval VERR_WRONG_ORDER if simultaneous non-blocking and blocking access is
* attempted.
*
* @param pThis The pipe handle.
*/
{
{
return VERR_WRONG_ORDER;
{
return RTErrConvertFromOS2(orc);
pThis->fBrokenPipe = true;
}
}
return VINF_SUCCESS;
}
/**
* Checks if the read pipe has been broken.
*
* @returns true if broken, false if no.
* @param pThis The pipe handle (read).
*/
{
#if 0
/*
* Query it via the semaphore. Not sure how fast this is...
*/
{
return true;
return false;
}
/*
* Fall back / alternative method.
*/
#endif
{
if (orc != ERROR_PIPE_BUSY)
return false;
}
return ulState != NP_STATE_CONNECTED;
}
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
{
else
}
else if (orc == ERROR_NO_DATA)
{
*pcbRead = 0;
rc = VINF_TRY_AGAIN;
}
else
if (rc == VERR_BROKEN_PIPE)
pThis->fBrokenPipe = true;
}
else
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
size_t cbTotalRead = 0;
while (cbToRead > 0)
{
{
break;
}
{
break;
}
/* advance */
cbTotalRead += cbActual;
}
if (pcbRead)
{
*pcbRead = cbTotalRead;
if ( RT_FAILURE(rc)
&& cbTotalRead)
rc = VINF_SUCCESS;
}
if (rc == VERR_BROKEN_PIPE)
pThis->fBrokenPipe = true;
}
else
}
return rc;
}
/**
* Gets the available write buffer size of the pipe.
*
* @returns Number of bytes, 1 on failure.
* @param pThis The pipe handle.
*/
{
#if 0 /* Not sure which is more efficient, neither are really optimal, I fear. */
/*
* Query via semaphore state.
* This will walk the list of active named pipes...
*/
/** @todo Check how hev and hpipe are associated, if complicated, use the
* alternative method below. */
{
return 0;
}
#else
/*
* Query via the pipe info.
* This will have to lookup and store the pipe name.
*/
union
{
} Buf;
#endif
return 1;
}
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (cbToWrite > 0)
{
{
/* Retry with the request adjusted to the available buffer space. */
}
{
*pcbWritten = cbActual;
if (cbActual == 0)
rc = VINF_TRY_AGAIN;
}
else
{
if (rc == VERR_PIPE_NOT_CONNECTED)
}
}
else
*pcbWritten = 0;
if (rc == VERR_BROKEN_PIPE)
pThis->fBrokenPipe = true;
}
else
}
return rc;
}
RTDECL(int) RTPipeWriteBlocking(RTPIPE hPipe, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
size_t cbTotalWritten = 0;
while (cbToWrite > 0)
{
{
if (rc == VERR_PIPE_NOT_CONNECTED)
break;
}
}
if (pcbWritten)
{
if ( RT_FAILURE(rc)
&& cbTotalWritten)
rc = VINF_SUCCESS;
}
if (rc == VERR_BROKEN_PIPE)
pThis->fBrokenPipe = true;
}
else
}
return rc;
}
{
{
if (rc == VERR_BROKEN_PIPE)
{
pThis->fBrokenPipe = true;
}
return rc;
}
return VINF_SUCCESS;
}
{
if (RT_FAILURE(rc))
return rc;
{
/* Stop polling attempts if we might block. */
else
}
if (RT_SUCCESS(rc))
{
{
/*
* Check the handle state.
*/
if (cMillies > 0)
{
}
{
break;
}
int i = 0;
i++;
else
i++;
break;
Assert(aStates[i].fStatus == NPSS_WSPACE || aStates[i].fStatus == NPSS_RDATA || aStates[i].fStatus == NPSS_EOI);
break;
/*
* Check for timeout.
*/
if (cMillies != RT_INDEFINITE_WAIT)
{
{
rc = VERR_TIMEOUT;
break;
}
}
/*
* Wait.
*/
{
break;
}
}
if (rc == VERR_BROKEN_PIPE)
pThis->fBrokenPipe = true;
if (cMillies > 0)
}
return rc;
}
{
if (RT_FAILURE(rc))
return rc;
{
else
}
else
return rc;
}
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
return rc;
}
/**
* Checks for pending events.
*
* @returns Event mask or 0.
* @param pThis The pipe handle.
* @param fEvents The desired events.
* @param fResetEvtSem Whether to reset the event semaphore.
*/
{
/*
* Reset the event semaphore if we're gonna wait.
*/
if (fResetEvtSem)
{
}
/*
* Check for events.
*/
uint32_t fRetEvents = 0;
if (pThis->fBrokenPipe)
{
{
pThis->fBrokenPipe = true;
}
else if (ulState != NP_STATE_CONNECTED)
{
pThis->fBrokenPipe = true;
}
}
else
{
{
int i = 0;
i++;
{
pThis->fBrokenPipe = true;
}
}
else
{
pThis->fBrokenPipe = true;
}
}
}
uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
{
/* Check that this is the only current use of this pipe. */
{
if (!fRetEvents && !fNoWait)
{
/* Mark the set busy while waiting. */
}
}
else
{
AssertFailed();
}
return fRetEvents;
}
{
AssertPtrReturn(pThis, 0);
AssertRCReturn(rc, 0);
/* harvest events. */
/* update counters. */
return fRetEvents;
}