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