/* $Id: pdmasynccompletion.h 31263 2008-05-26 20:14:14Z aeichner $ */
/** @file
 * PDM - Pluggable Device Manager, Async I/O Completion.
 */

/*
 * Copyright (C) 2007 Sun Microsystems, Inc.
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * 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.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 * additional information or have any questions.
 */

#ifndef ___VBox_pdmasynccompletion_h
#define ___VBox_pdmasynccompletion_h

#include <VBox/types.h>
#include <VBox/err.h>
#include <iprt/assert.h>

__BEGIN_DECLS

/** @defgroup grp_pdm_async_completion  Async I/O Completion
 * @ingroup grp_pdm
 * @{
 */

/** Pointer to a PDM async completion template handle. */
typedef struct PDMASYNCCOMPLETIONTEMPLATE *PPDMASYNCCOMPLETIONTEMPLATE;
/** Pointer to a PDM async completion template handle pointer. */
typedef PPDMASYNCCOMPLETIONTEMPLATE *PPPDMASYNCCOMPLETIONTEMPLATE;

/** Pointer to a PDM async completion task handle. */
typedef struct PDMASYNCCOMPLETIONTASK *PPDMASYNCCOMPLETIONTASK;
/** Pointer to a PDM async completion task handle pointer. */
typedef PPDMASYNCCOMPLETIONTASK *PPPDMASYNCCOMPLETIONTASK;


/**
 * Completion callback for devices.
 *
 * @param   pDevIns     The device instance.
 * @param   pTask       Pointer to the completion task.
 *                      The task is at the time of the call setup to be resumed. So, the callback must
 *                      call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
 *                      action is wanted upon return.
 * @param   pvCtx       Pointer to any additional, OS specific, completion context. TBD.
 * @param   pvUser      User argument.
 */
typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEDEV(PPDMDEVINS pDevIns, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser);
/** Pointer to a FNPDMASYNCCOMPLETEDEV(). */
typedef FNPDMASYNCCOMPLETEDEV *PFNPDMASYNCCOMPLETEDEV;


/**
 * Completion callback for drivers.
 *
 * @param   pDrvIns     The driver instance.
 * @param   pTask       Pointer to the completion task.
 *                      The task is at the time of the call setup to be resumed. So, the callback must
 *                      call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
 *                      action is wanted upon return.
 * @param   pvCtx       Pointer to any additional, OS specific, completion context. TBD.
 * @param   pvUser      User argument.
 */
typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEDRV(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser);
/** Pointer to a FNPDMASYNCCOMPLETEDRV(). */
typedef FNPDMASYNCCOMPLETEDRV *PFNPDMASYNCCOMPLETEDRV;


/**
 * Completion callback for USB devices.
 *
 * @param   pUsbIns     The USB device instance.
 * @param   pTask       Pointer to the completion task.
 *                      The task is at the time of the call setup to be resumed. So, the callback must
 *                      call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
 *                      action is wanted upon return.
 * @param   pvCtx       Pointer to any additional, OS specific, completion context. TBD.
 * @param   pvUser      User argument.
 */
typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEUSB(PPDMUSBINS pUsbIns, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser);
/** Pointer to a FNPDMASYNCCOMPLETEUSB(). */
typedef FNPDMASYNCCOMPLETEUSB *PFNPDMASYNCCOMPLETEUSB;


/**
 * Completion callback for internal.
 *
 * @param   pVM         Pointer to the shared VM structure.
 * @param   pTask       Pointer to the completion task.
 *                      The task is at the time of the call setup to be resumed. So, the callback must
 *                      call PDMR3AsyncCompletionSuspend or PDMR3AsyncCompletionDestroy if any other
 *                      action is wanted upon return.
 * @param   pvCtx       Pointer to any additional, OS specific, completion context. TBD.
 * @param   pvUser      User argument for the task.
 * @param   pvUser2     User argument for the template.
 */
typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEINT(PVM pVM, PPDMASYNCCOMPLETIONTASK pTask, void *pvCtx, void *pvUser, void *pvUser2);
/** Pointer to a FNPDMASYNCCOMPLETEINT(). */
typedef FNPDMASYNCCOMPLETEINT *PFNPDMASYNCCOMPLETEINT;


/**
 * Creates a async completion template for a device instance.
 *
 * The template is used when creating new completion tasks.
 *
 * @returns VBox status code.
 * @param   pVM             Pointer to the shared VM structure.
 * @param   pDevIns         The device instance.
 * @param   ppTemplate      Where to store the template pointer on success.
 * @param   pfnCompleted    The completion callback routine.
 * @param   pszDesc         Description.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDEV pfnCompleted, const char *pszDesc);

/**
 * Creates a async completion template for a driver instance.
 *
 * The template is used when creating new completion tasks.
 *
 * @returns VBox status code.
 * @param   pVM             Pointer to the shared VM structure.
 * @param   pDrvIns         The driver instance.
 * @param   ppTemplate      Where to store the template pointer on success.
 * @param   pfnCompleted    The completion callback routine.
 * @param   pszDesc         Description.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDRV pfnCompleted, const char *pszDesc);

/**
 * Creates a async completion template for a USB device instance.
 *
 * The template is used when creating new completion tasks.
 *
 * @returns VBox status code.
 * @param   pVM             Pointer to the shared VM structure.
 * @param   pUsbIns         The USB device instance.
 * @param   ppTemplate      Where to store the template pointer on success.
 * @param   pfnCompleted    The completion callback routine.
 * @param   pszDesc         Description.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEUSB pfnCompleted, const char *pszDesc);

/**
 * Creates a async completion template for internally by the VMM.
 *
 * The template is used when creating new completion tasks.
 *
 * @returns VBox status code.
 * @param   pVM             Pointer to the shared VM structure.
 * @param   ppTemplate      Where to store the template pointer on success.
 * @param   pfnCompleted    The completion callback routine.
 * @param   pvUser2         The 2nd user argument for the callback.
 * @param   pszDesc         Description.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc);

/**
 * Destroys the specified async completion template.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use.
 *
 * @param   pTemplate       The template in question.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate);

/**
 * Destroys all the specified async completion templates for the given device instance.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
 *
 * @param   pVM             Pointer to the shared VM structure.
 * @param   pDevIns         The device instance.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDevice(PVM pVM, PPDMDEVINS pDevIns);

/**
 * Destroys all the specified async completion templates for the given driver instance.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
 *
 * @param   pVM             Pointer to the shared VM structure.
 * @param   pDrvIns         The driver instance.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns);

/**
 * Destroys all the specified async completion templates for the given USB device instance.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
 *
 * @param   pVM             Pointer to the shared VM structure.
 * @param   pUsbIns         The USB device instance.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns);

/**
 * Async completion task type
 */
typedef enum PDMASYNCCOMPLETIONTASKTYPE
{
    /** Socket. */
    PDMASYNCCOMPLETIONTASKTYPE_SOCKET = 0,
    /** Host OS specific. */
    PDMASYNCCOMPLETIONTASKTYPE_HOST,
    /** Number of supported backends. This has to be last entry! */
    PDMASYNCCOMPLETIONTASKTYPE_SUPPORTED
} PDMASYNCCOMPLETIONTASKTYPE;

/**
 * Get the backend name of a task type.
 *
 * @returns Name of the backend.
 * @param   enmTaskType    The task type to get the backend name from.
 */
PDMR3DECL(const char *) PDMR3AsyncCompletionGetBackendName(PDMASYNCCOMPLETIONTASKTYPE enmTaskType);

/**
 * Creates a completion task.
 *
 * @returns VBox status code.
 * @param   ppTask          Where to store the task handle on success.
 * @param   pTemplate       The async completion template.
 * @param   enmType         The type of the task.
 * @param   pvCtx           The task specific context.
 * @param   pvUser          The user argument for the callback.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskCreate(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, PDMASYNCCOMPLETIONTASKTYPE enmType, void *pvCtx, void *pvUser);

/**
 * Submit an array of tasks for processing
 * The tasks must have a type specific context.
 *
 * @returns VBox status code.
 * @param   apTasks  Array of tasks which should be processed.
 * @param   cTasks   Number of tasks in the array which should be processed.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskSubmit(PPDMASYNCCOMPLETIONTASK apTasks[], unsigned cTasks);

/**
 * Sets the user argument of a completion task.
 *
 * @returns VBox status code.
 * @param   pTask           The async completion task.
 * @param   pvUser          The user argument for the callback.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskSetUserArg(PPDMASYNCCOMPLETIONTASK pTask, void *pvUser);

/**
 * Suspends a async completion task.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_PDM_ASYNC_COMPLETION_ALREADY_SUSPENDED if already suspended.
 * @retval  VERR_INVALID_HANDLE if pTask is invalid (asserts).
 * @param   pTask           The async completion task.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskSuspend(PPDMASYNCCOMPLETIONTASK pTask);

/**
 * Suspends a async completion task.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_PDM_ASYNC_COMPLETION_NOT_SUSPENDED if not suspended.
 * @retval  VERR_INVALID_HANDLE if pTask is invalid (asserts).
 * @param   pTask           The async completion task.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskResume(PPDMASYNCCOMPLETIONTASK pTask);

/**
 * Cancels a async completion task.
 * The task doesn't have to be suspended.
 *
 * @returns VBox status code
 * @param   pTask The Task to cancel.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask);

/**
 * Destroys a async completion task.
 *
 * The task doesn't have to be suspended or anything.
 *
 * @returns VBox status codes:
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_INVALID_HANDLE if pTask is invalid but not NIL (asserts).
 * @param   pTask           The async completion task.
 */
PDMR3DECL(int) PDMR3AsyncCompletionTaskDestroy(PPDMASYNCCOMPLETIONTASK pTask);

/*
 * Host specific wrapper functions for the above API
 */
#if defined(RT_OS_LINUX)

struct iocb;

/**
 * Creates a completion task for an IO operation on Linux.
 *
 * The pvCtx callback argument will be pIoCB.
 *
 * @returns VBox status code.
 * @param   ppTask          Where to store the task handle on success.
 * @param   pTemplate       The async completion template.
 * @param   pIoCB           The asynchronous I/O control block to wait for.
 * @param   pvUser          The user argument for the callback.
 */
DECLINLINE(int) PDMR3AsyncCompletionCreateLnxIO(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, const struct iocb *pIoCB, void *pvUser)
{
    int rc = VINF_SUCCESS;
    PPDMASYNCCOMPLETIONTASK pTask;

    rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)pIoCB, pvUser);
    if (VBOX_FAILURE(rc))
    {
        AssertMsgFailed(("Creating Linux task failed\n"));
        return rc;
    }

    *ppTask = pTask;

    return rc;
}
#endif /* RT_OS_LINUX */

#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX)

struct aiocb;

/**
 * Creates a completion task for an AIO operation on Unix like systems like Solaris, Darwin or FreeBSD.
 * This method must be used too on Linux if the real asynchronous solution is not available.
 *
 * The pvCtx callback argument will be pAioCB.
 *
 * @returns VBox status code.
 * @param   ppTask          Where to store the task handle on success.
 * @param   pTemplate       The async completion template.
 * @param   pIoCB           The asynchronous I/O control block to wait for.
 * @param   pvUser          The user argument for the callback.
 */
DECLINLINE(int) PDMR3AsyncCompletionCreateUnxAIO(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, const struct aiocb *pAioCB, void *pvUser)
{
    int rc = VINF_SUCCESS;
    PPDMASYNCCOMPLETIONTASK pTask;

    rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)pAioCB, pvUser);
    if (VBOX_FAILURE(rc))
    {
        AssertMsgFailed(("Creating AIO task failed\n"));
        return rc;
    }

    *ppTask = pTask;

    return rc;
}
#endif /* RT_OS_SOLARIS || RT_OS_DARWIN || RT_OS_FREEBSD || RT_OS_LINUX */

#ifdef RT_OS_OS2
/**
 * Creates a completion task for an event semaphore on OS/2.
 *
 * The pvCtx callback argument will be hev.
 *
 * @returns VBox status code.
 * @param   ppTask          Where to store the task handle on success.
 * @param   pTemplate       The async completion template.
 * @param   hev             The handle of the event semaphore to wait on.
 * @param   pvUser          The user argument for the callback.
 */
DECLINLINE(int) PDMR3AsyncCompletionCreateOs2Event(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, unsigned long hev, void *pvUser)
{
    int rc = VINF_SUCCESS;
    PPDMASYNCCOMPLETIONTASK pTask;

    rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)&hev, pvUser);
    if (VBOX_FAILURE(rc))
    {
        AssertMsgFailed(("Creating OS/2 task failed\n"));
        return rc;
    }

    *ppTask = pTask;

    return rc;
}
#endif /* RT_OS_OS2 */

#ifdef RT_OS_WINDOWS
/**
 * Creates a completion task for an object on Windows.
 *
 * The pvCtx callback argument will be hObject.
 *
 * @returns VBox status code.
 * @param   ppTask          Where to store the task handle on success.
 * @param   pTemplate       The async completion template.
 * @param   hObject         The object to wait for.
 * @param   pvUser          The user argument for the callback.
 */
DECLINLINE(int) PDMR3AsyncCompletionCreateWinObject(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, void *hObject, void *pvUser)
{
    int rc = VINF_SUCCESS;
    PPDMASYNCCOMPLETIONTASK pTask;

    rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_HOST, (void *)hObject, pvUser);
    if (VBOX_FAILURE(rc))
    {
        AssertMsgFailed(("Creating Windows task failed\n"));
        return rc;
    }

    *ppTask = pTask;

    return rc;
}
#endif /* RT_OS_WINDOWS */

/**
 * Socket completion context (pvCtx).
 */
typedef struct PDMASYNCCOMPLETIONSOCKET
{
    /** The socket. */
    RTSOCKET        Socket;
    /** Readable. */
    bool            fReadable;
    /** Writable. */
    bool            fWriteable;
    /** Exceptions. */
    bool            fXcpt;
} PDMASYNCCOMPLETIONSOCKET;
/** Pointer to a socket completion context. */
typedef PDMASYNCCOMPLETIONSOCKET *PPDMASYNCCOMPLETIONSOCKET;

/**
 * Creates a completion task for a socket.
 *
 * The pvCtx callback argument will be pointing to a PDMASYNCCOMPLETIONSOCKET structure.
 *
 * @returns VBox status code.
 * @param   ppTask          Where to store the task handle on success.
 * @param   pTemplate       The async completion template.
 * @param   Socket          The socket.
 * @param   fReadable       Whether to callback when the socket becomes readable.
 * @param   fWriteable      Whether to callback when the socket becomes writable.
 * @param   fXcpt           Whether to callback on exception.
 * @param   pvUser          The user argument for the callback.
 */
DECLINLINE(int) PDMR3AsyncCompletionCreateSocket(PPPDMASYNCCOMPLETIONTASK ppTask, PPDMASYNCCOMPLETIONTEMPLATE pTemplate, RTSOCKET Socket, bool fReadable, bool fWriteable, bool fXcpt, void *pvUser)
{
    int rc = VINF_SUCCESS;
    PPDMASYNCCOMPLETIONTASK pTask;
    PDMASYNCCOMPLETIONSOCKET SocketContext;

    SocketContext.Socket     = Socket;
    SocketContext.fReadable  = fReadable;
    SocketContext.fWriteable = fWriteable;
    SocketContext.fXcpt      = fXcpt;

    rc = PDMR3AsyncCompletionTaskCreate(&pTask, pTemplate, PDMASYNCCOMPLETIONTASKTYPE_SOCKET, (void *)&SocketContext, pvUser);
    if (VBOX_FAILURE(rc))
    {
        AssertMsgFailed(("Creating Socket task failed\n"));
        return rc;
    }

    *ppTask = pTask;

    return rc;
}

#if 0
/**
 * Modifies a socket completion task.
 *
 * @returns VBox status code.
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_NOT_SUPPORTED if the task isn't a socket task.
 * @param   pTemplate       The async completion template.
 * @param   Socket          The socket
 * @param   fReadable       Whether to callback when the socket becomes readable.
 * @param   fWriteable      Whether to callback when the socket becomes writable.
 * @param   fXcpt           Whether to callback on exception.
 */
DECLINLINE(int) PDMR3AsyncCompletionModifySocket(PPDMASYNCCOMPLETIONTASK pTask, RTSOCKET Socket, bool fReadable, bool fWriteable, bool fXcpt)
{
    int rc = VINF_SUCCESS;
    PDMASYNCCOMPLETIONSOCKET SocketContext;

    SocketContext.Socket     = Socket;
    SocketContext.fReadable  = fReadable;
    SocketContext.fWriteable = fWriteable;
    SocketContext.fXcpt      = fXcpt;

    rc = PDMR3AsyncCompletionTaskAssociate(pTask, &SocketContext);
    if (VBOX_FAILURE(rc))
    {
        AssertMsgFailed(("Modifying Socket task failed\n"));
        return rc;
    }

    return rc;
}
#endif

/** @} */

__END_DECLS

#endif



