VBoxServicePipeBuf.cpp revision 396ad8a2e743a2181c333d433b303ff25f7d11a6
/* $Id$ */
/** @file
* VBoxServicePipeBuf - Pipe buffering.
*/
/*
* Copyright (C) 2010-2011 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/semaphore.h>
#include "VBoxServicePipeBuf.h"
/**
* Initializes a pipe buffer.
*
* @returns IPRT status code.
* @param pBuf The pipe buffer to initialize.
* @param uId The pipe's ID handle.
* @param fNeedNotificationPipe Whether the buffer needs a notification
* pipe or not.
*/
int VBoxServicePipeBufInit(PVBOXSERVICECTRLEXECPIPEBUF pBuf, uint8_t uId, bool fNeedNotificationPipe)
{
/** @todo Add allocation size as function parameter! */
pBuf->fPendingClose = false;
if (RT_SUCCESS(rc))
{
}
if (RT_FAILURE(rc))
{
}
return rc;
}
/**
* Reads out data from a specififed pipe buffer.
*
* @return IPRT status code.
* @param pBuf Pointer to pipe buffer to read the data from.
* @param pbBuffer Pointer to buffer to store the read out data.
* @param cbBuffer Size (in bytes) of the buffer where to store the data.
* @param pcbToRead Pointer to desired amount (in bytes) of data to read,
* will reflect the actual amount read on return.
*/
{
if (RT_SUCCESS(rc))
{
if (cbToRead)
{
#ifdef DEBUG_andy
pBuf->uPID, pBuf->uPipeId, pBuf, pBuf->fEnabled ? "EN" : "DIS", cbToRead, pBuf->cbSize, pBuf->cbAllocated, pBuf->cbOffset);
#endif
{
}
}
else
{
*pcbToRead = 0;
}
if (RT_SUCCESS(rc))
}
return rc;
}
/**
* Peeks for buffer data without moving the buffer's offset
* or touching any other internal data.
*
* @return IPRT status code.
* @param pBuf Pointer to pipe buffer to read the data from.
* @param pbBuffer Pointer to buffer to store the read out data.
* @param cbBuffer Size (in bytes) of the buffer where to store the data.
* @param cbOffset Offset (in bytes) where to start reading.
* @param pcbRead Pointer to desired amount (in bytes) of data to read,
* will reflect the actual amount read on return.
* @param pcbLeft Pointer to bytes left in buffer after the current read
* operation.
*/
{
if (RT_SUCCESS(rc))
{
if (cbToRead)
{
}
if (pcbRead)
if (pcbLeft)
if (RT_SUCCESS(rc))
}
return rc;
}
/**
* Writes data into a specififed pipe buffer.
*
* @return IPRT status code.
* @param pBuf Pointer to pipe buffer to write data into.
* @param pbData Pointer to byte data to write.
* @param cbData Data size (in bytes) to write.
* @param fPendingClose Needs the pipe (buffer) to be closed next time we have the chance to?
* @param pcbWritten Pointer to where the amount of written bytes get stored. Optional.
*/
{
if (RT_SUCCESS(rc))
{
{
/* Rewind the buffer if it's empty. */
if (fAddToSet)
/* Try and see if we can simply append the data. */
{
}
else
{
/* Move any buffered data to the front. */
if (cbInBuf == 0)
{
}
/* Do we need to grow the buffer? */
{
if (pvNew)
{
}
else
rc = VERR_NO_MEMORY;
}
/* Finally, copy the data. */
if (RT_SUCCESS(rc))
{
{
}
else
}
}
if (RT_SUCCESS(rc))
{
/*
* next time we have the chance to.
*/
if (fPendingClose)
/*
* Wake up the thread servicing the process so it can feed it
* (if we have a notification helper pipe).
*/
if (pBuf->fNeedNotification)
{
/* Disable notification until it is set again on successful write. */
}
/* Report back written bytes (if wanted). */
if (pcbWritten)
*pcbWritten = cbData;
/* Only trigger signal if we really wrote something. */
if ( cbData
{
}
#ifdef DEBUG_andy
pBuf->uPID, pBuf->uPipeId, pBuf, pBuf->fEnabled ? "EN" : "DIS", cbData, pBuf->cbSize, pBuf->cbAllocated, pBuf->cbOffset);
#endif
}
}
else
rc = VERR_BAD_PIPE;
if (RT_SUCCESS(rc))
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
/* Set current bytes left in pipe buffer. It's okay
* to have no data in yet ... */
&& cbToWrite)
{
if (RT_SUCCESS(rc))
{
pBuf->fNeedNotification = true;
if (rc != VINF_TRY_AGAIN)
/* Did somebody tell us that we should come to an end,
* e.g. no more data coming in? */
if (pBuf->fPendingClose)
{
/* Is there more data to write out? */
{
/* We have a pending close, but there's more data that we can write out
* from buffer to pipe ... */
if (pBuf->fNeedNotification)
{
/* Still data to push out - so we need another
* poll round! Write something into the notification pipe. */
/* Disable notification until it is set again on successful write. */
}
}
}
/* Set new bytes left in pipe buffer afer we wrote to the pipe above. */
}
else
{
*pcbWritten = 0;
/* Don't set pBuf->fEnabled to false here! We just didn't write
* anything -- that doesn't mean this buffer is disabled (again). */
}
}
else
{
*pcbWritten = 0;
}
if (RT_SUCCESS(rc))
}
return rc;
}
/**
* Returns whether a pipe buffer is active or not.
*
* @return bool True if pipe buffer is active, false if not.
* @param pBuf The pipe buffer.
*/
{
AssertPtrReturn(pBuf, false);
bool fEnabled = false;
if (RT_SUCCESS(rc))
{
}
return fEnabled;
}
/**
* Returns whether a pipe buffer is in a pending close state or
* not. This means that someone has written the last chunk into
* the pipe buffer with the fPendingClose flag set.
*
* @return bool True if pipe buffer is in pending
* close state, false if not.
* @param pBuf The pipe buffer.
*/
{
AssertPtrReturn(pBuf, false);
return false;
bool fClosing = false;
{
}
return fClosing;
}
/**
*
* @return IPRT status code.
* @param pBuf The pipe buffer.
* @param fEnabled Pipe buffer status to set.
*/
{
if (RT_SUCCESS(rc))
{
{
/* Let waiter know that something has changed ... */
}
}
return rc;
}
/**
* Assigns a PID to the specified pipe buffer. Does not allow
* setting a new PID after a PID already was set.
*
* @return IPRT status code.
* @param pBuf The pipe buffer.
* @param uPID PID to assign.
*/
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* Waits for the pipe buffer to get notified when something changed, like
* new data was written to or the buffer was disabled, i.e. not used anymore.
*
* @return IPRT status code.
* @param pBuf The pipe buffer.
* @param cMillies The maximum time (in ms) to wait for the event.
*/
{
/* Don't enter the critical section here; someone else could signal the event semaphore
* and this will deadlock then ... */
}
/**
* Deletes a pipe buffer.
*
* @note Not thread safe -- only call this when nobody is relying on the
* data anymore!
*
* @param pBuf The pipe buffer.
*/
{
{
pBuf->cbAllocated = 0;
}
}