SessionState never unlocked
Posted: 21. Apr 2022, 14:21
Hello,
I have used the VirtualBox COM interface for a while with VirtualBox 6.0. Now I am having troubles with 6.1.
The following code works well on 6.0.
* I start a VM in "headless"
* When the state is Running I stop it
* Then I wait until the session state is unlocked again
* I redo the previous steps 10 times.
This simple test works fine on VirtualBox 6.0 but on 6.1 the machine state change correctly to PowerOff but the session is never unlocked and the VBoxHeadless.exe process is not killed and I need to kill it from task manager.
If I use a "gui" session type than all works as exepected also in 6.1.
I think that the problem is caused by the event loop of VBoxHeadless because I see that it is started after I triggrer PowerDown command from the console.
Question: do you think that I am doing some errors? Or this is a bug on VirtualBox 6.1.
Attached the code and the log.
Thanks.
I have used the VirtualBox COM interface for a while with VirtualBox 6.0. Now I am having troubles with 6.1.
The following code works well on 6.0.
* I start a VM in "headless"
* When the state is Running I stop it
* Then I wait until the session state is unlocked again
* I redo the previous steps 10 times.
Code: Select all
#include "VirtualBox.h"
#include <chrono>
#include <string>
#include <thread>
#define SAFE_RELEASE(x) \
if (x) \
{ \
x->Release(); \
x = NULL; \
}
void printErrorInfo()
{
IErrorInfo *errorInfo;
HRESULT rc = GetErrorInfo(0, &errorInfo);
if (FAILED(rc))
{
printf("Failed to get error info! rc = 0x%x\n", rc);
return;
}
BSTR errorDescription = NULL;
rc = errorInfo->GetDescription(&errorDescription);
if (FAILED(rc) || !errorDescription)
{
printf("Error getting error description! rc = 0x%x\n", rc);
return;
}
printf("Successfully retrieved error description: %S\n", errorDescription);
SysFreeString(errorDescription);
SAFE_RELEASE(errorInfo);
}
int testStartVM(IVirtualBox *virtualBox, const wchar_t *name, const wchar_t *sessionTypeName)
{
HRESULT rc;
/* Try to start a VM called "WinXP SP2". */
IMachine *machine = NULL;
BSTR machineName = SysAllocString(name);
rc = virtualBox->FindMachine(machineName, &machine);
if (FAILED(rc))
{
printErrorInfo();
}
else
{
ISession *session = NULL;
IConsole *console = NULL;
IProgress *progress = NULL;
BSTR sessiontype = SysAllocString(sessionTypeName);
BSTR guid;
do
{
rc = machine->get_Id(&guid); /* Get the GUID of the machine. */
if (!SUCCEEDED(rc))
{
printf("Error retrieving machine ID! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Create the session object. */
rc = CoCreateInstance(CLSID_Session, /* the VirtualBox base object */
NULL, /* no aggregation */
CLSCTX_INPROC_SERVER, /* the object lives in the current process */
IID_ISession, /* IID of the interface */
(void **)&session);
if (!SUCCEEDED(rc))
{
printf("Error creating Session instance! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Start a VM session using the delivered VBox GUI. */
rc = machine->LaunchVMProcess(session, sessiontype, NULL, &progress);
if (!SUCCEEDED(rc))
{
printf("Could not open remote session! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Wait until VM is running. */
printf("Starting VM, please wait ...\n");
rc = progress->WaitForCompletion(-1);
if (!SUCCEEDED(rc))
{
printf("Progress wait for LaunchVMProcess completion fail! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Get console object. */
session->get_Console(&console);
/* Bring console window to front. */
machine->ShowConsoleWindow(0);
while (true)
{
MachineState state;
rc = machine->get_State(&state);
if (FAILED(rc))
{
printf("Faile to get machine state! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
printf("Machine state == %d\n", state);
if (state == MachineState_Running)
{
break;
}
}
/* Power down the machine. */
rc = console->PowerDown(&progress);
if (!SUCCEEDED(rc))
{
printf("Console PowerDown fail! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Wait until VM is powered down. */
printf("Powering off VM, please wait ...\n");
rc = progress->WaitForCompletion(-1);
if (!SUCCEEDED(rc))
{
printf("Progress wait for PowerDown fail! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Close the session. */
rc = session->UnlockMachine();
if (!SUCCEEDED(rc))
{
printf("Cannot unlock machine! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
} while (0);
SAFE_RELEASE(console);
SAFE_RELEASE(progress);
SAFE_RELEASE(session);
SysFreeString(guid);
SysFreeString(sessiontype);
// wait for unlocked
printf("Wait for machine unlocked ...\n");
while (true)
{
SessionState sessionState;
rc = machine->get_SessionState(&sessionState);
if (FAILED(rc))
{
printf("Cannot get session state! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
if (sessionState == SessionState_Unlocked)
{
break;
}
}
SAFE_RELEASE(machine);
}
SysFreeString(machineName);
return 0;
}
int main(int argc, char **argv)
{
/* Initialize the COM subsystem. */
CoInitialize(NULL);
/* Instantiate the VirtualBox root object. */
IVirtualBoxClient *virtualBoxClient;
HRESULT rc = CoCreateInstance(CLSID_VirtualBoxClient, /* the VirtualBoxClient object */
NULL, /* no aggregation */
CLSCTX_INPROC_SERVER, /* the object lives in the current process */
IID_IVirtualBoxClient, /* IID of the interface */
(void **)&virtualBoxClient);
if (SUCCEEDED(rc))
{
IVirtualBox *virtualBox;
rc = virtualBoxClient->get_VirtualBox(&virtualBox);
if (SUCCEEDED(rc))
{
for (int i = 0; i < 10; ++i)
{
printf("Test run %d\n", i);
testStartVM(virtualBox, L"TESTING", L"headless");
}
/* Release the VirtualBox object. */
virtualBox->Release();
virtualBoxClient->Release();
}
else
{
printf("Error creating VirtualBox instance! rc = 0x%x\n", rc);
printErrorInfo();
}
}
CoUninitialize();
return 0;
}
If I use a "gui" session type than all works as exepected also in 6.1.
I think that the problem is caused by the event loop of VBoxHeadless because I see that it is started after I triggrer PowerDown command from the console.
Code: Select all
00:00:01.819978 Changing the VM state from 'DESTROYING' to 'TERMINATED'
00:00:01.824010 Console: Machine state changed to 'PoweredOff'
00:00:01.937393 VBoxHeadless: starting event loop
Attached the code and the log.
Thanks.