tstPDMAsyncCompletion.cpp revision 8bed792bc65abd39393889351f22263ce6c289bf
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync/* $Id$ */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync/** @file
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * PDM Asynchronous Completion Testcase.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync *
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * This testcase is for testing the async completion interface.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * It implements a file copy program which uses the interface to copy the data.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync *
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Use: ./tstPDMAsyncCompletion <source> <destination>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync/*
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Copyright (C) 2008-2009 Sun Microsystems, Inc.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync *
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * available from http://www.virtualbox.org. This file is free software;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * General Public License (GPL) as published by the Free Software
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync *
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * additional information or have any questions.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync/*******************************************************************************
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync* Header Files *
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync*******************************************************************************/
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#define LOG_GROUP LOG_GROUP_PDM_ASYNC_COMPLETION
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include "../VMInternal.h" /* UVM */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/vm.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/uvm.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/pdmasynccompletion.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/vmm.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/cpum.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/err.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/log.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <VBox/pdmapi.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/alloc.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/asm.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/assert.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/file.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/initterm.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/semaphore.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/stream.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/string.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#include <iprt/thread.h>
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#define TESTCASE "tstPDMAsyncCompletion"
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync/*
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Number of simultaneous active tasks.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#define NR_TASKS 80
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync#define BUFFER_SIZE (64*_1K)
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync/* Buffers to store data in .*/
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsyncuint8_t *g_AsyncCompletionTasksBuffer[NR_TASKS];
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsyncPPDMASYNCCOMPLETIONTASK g_AsyncCompletionTasks[NR_TASKS];
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsyncvolatile uint32_t g_cTasksLeft;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsyncRTSEMEVENT g_FinishedEventSem;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsyncvoid pfnAsyncTaskCompleted(PVM pVM, void *pvUser, void *pvUser2)
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync{
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync LogFlow((TESTCASE ": %s: pVM=%p pvUser=%p pvUser2=%p\n", __FUNCTION__, pVM, pvUser, pvUser2));
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync uint32_t cTasksStillLeft = ASMAtomicDecU32(&g_cTasksLeft);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync if (!cTasksStillLeft)
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync {
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync /* All tasks processed. Wakeup main. */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync RTSemEventSignal(g_FinishedEventSem);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync }
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync}
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsyncint main(int argc, char *argv[])
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync{
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync int rcRet = 0; /* error count */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync int rc = VINF_SUCCESS;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync PPDMASYNCCOMPLETIONENDPOINT pEndpointSrc, pEndpointDst;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync RTR3InitAndSUPLib();
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync if (argc != 3)
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync {
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync RTPrintf(TESTCASE ": Usage is ./tstPDMAsyncCompletion <source> <dest>\n");
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync return 1;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync }
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync PVM pVM;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync rc = VMR3Create(1, NULL, NULL, NULL, NULL, &pVM);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync if (RT_SUCCESS(rc))
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync {
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync /*
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Little hack to avoid the VM_ASSERT_EMT assertion.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync RTTlsSet(pVM->pUVM->vm.s.idxTLS, &pVM->pUVM->aCpus[0]);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync pVM->pUVM->aCpus[0].pUVM = pVM->pUVM;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync pVM->pUVM->aCpus[0].vm.s.NativeThreadEMT = RTThreadNativeSelf();
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync /*
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Create the template.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync rc = PDMR3AsyncCompletionTemplateCreateInternal(pVM, &pTemplate, pfnAsyncTaskCompleted, NULL, "Test");
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync if (RT_FAILURE(rc))
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync {
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync RTPrintf(TESTCASE ": Error while creating the template!! rc=%d\n", rc);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync return 1;
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync }
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync /*
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync * Create event semaphor.
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync */
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync rc = RTSemEventCreate(&g_FinishedEventSem);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync AssertRC(rc);
9fc464631dc4a68fbb5eb6419d61fbe91b6b16bdvboxsync
/*
* Create the temporary buffers.
*/
int i;
for (i=0; i < NR_TASKS; i++)
{
g_AsyncCompletionTasksBuffer[i] = (uint8_t *)RTMemAllocZ(BUFFER_SIZE);
if (!g_AsyncCompletionTasksBuffer[i])
{
RTPrintf(TESTCASE ": out of memory!\n");
rcRet++;
return rcRet;
}
}
/* Create the destination as the async completion API can't do this. */
RTFILE FileTmp;
rc = RTFileOpen(&FileTmp, argv[2], RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_NONE);
if (RT_FAILURE(rc))
{
RTPrintf(TESTCASE ": Error while creating the destination!! rc=%d\n", rc);
return 1;
rcRet++;
return rcRet;
}
RTFileClose(FileTmp);
/* Create our file endpoint */
rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointSrc, argv[1], 0, pTemplate);
if (RT_SUCCESS(rc))
{
rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointDst, argv[2], 0, pTemplate);
if (RT_SUCCESS(rc))
{
PDMR3PowerOn(pVM);
/* Wait for all threads to finish initialization. */
RTThreadSleep(100);
int fReadPass = true;
uint64_t cbSrc, cbLeft;
size_t offSrc = 0;
size_t offDst = 0;
uint32_t cTasksUsed = 0;
rc = PDMR3AsyncCompletionEpGetSize(pEndpointSrc, &cbSrc);
if (RT_SUCCESS(rc))
{
/* Copy the data. */
for (;;)
{
if (fReadPass)
{
cTasksUsed = (BUFFER_SIZE * NR_TASKS) <= (cbSrc - offSrc)
? NR_TASKS
: ((cbSrc - offSrc) / BUFFER_SIZE)
+ ((cbSrc - offSrc) % BUFFER_SIZE) > 0
? 1
: 0;
g_cTasksLeft = cTasksUsed;
for (uint32_t i = 0; i < cTasksUsed; i++)
{
size_t cbRead = ((size_t)offSrc + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offSrc;
PDMDATASEG DataSeg;
DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i];
DataSeg.cbSeg = cbRead;
rc = PDMR3AsyncCompletionEpRead(pEndpointSrc, offSrc, &DataSeg, 1, cbRead, NULL,
&g_AsyncCompletionTasks[i]);
AssertRC(rc);
offSrc += cbRead;
if (offSrc == cbSrc)
break;
}
}
else
{
g_cTasksLeft = cTasksUsed;
for (uint32_t i = 0; i < cTasksUsed; i++)
{
size_t cbWrite = (offDst + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offDst;
PDMDATASEG DataSeg;
DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i];
DataSeg.cbSeg = cbWrite;
rc = PDMR3AsyncCompletionEpWrite(pEndpointDst, offDst, &DataSeg, 1, cbWrite, NULL,
&g_AsyncCompletionTasks[i]);
AssertRC(rc);
offDst += cbWrite;
if (offDst == cbSrc)
break;
}
}
rc = RTSemEventWait(g_FinishedEventSem, RT_INDEFINITE_WAIT);
AssertRC(rc);
if (!fReadPass && (offDst == cbSrc))
break;
else if (fReadPass)
fReadPass = false;
else
{
cTasksUsed = 0;
fReadPass = true;
}
}
}
else
{
RTPrintf(TESTCASE ": Error querying size of the endpoint!! rc=%d\n", rc);
rcRet++;
}
PDMR3PowerOff(pVM);
PDMR3AsyncCompletionEpClose(pEndpointDst);
}
PDMR3AsyncCompletionEpClose(pEndpointSrc);
}
rc = VMR3Destroy(pVM);
AssertMsg(rc == VINF_SUCCESS, ("%s: Destroying VM failed rc=%Rrc!!\n", __FUNCTION__, rc));
/*
* Clean up.
*/
for (uint32_t i = 0; i < NR_TASKS; i++)
{
RTMemFree(g_AsyncCompletionTasksBuffer[i]);
}
}
else
{
RTPrintf(TESTCASE ": failed to create VM!! rc=%Rrc\n", rc);
rcRet++;
}
return rcRet;
}