SessionImpl.cpp revision 240f7d7012a5f64bcde850bcf048531a710d81cf
70N/A * VBox Client Session COM Class implementation 70N/A * Copyright (C) 2006-2007 Sun Microsystems, Inc. 70N/A * This file is part of VirtualBox Open Source Edition (OSE), as 70N/A * you can redistribute it and/or modify it under the terms of the GNU 70N/A * General Public License (GPL) as published by the Free Software 70N/A * Foundation, in version 2 as it comes in the "COPYING" file of the 70N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 70N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 70N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa 70N/A * additional information or have any questions. 70N/A/** VM IPC mutex holder thread */ 70N/A * Local macro to check whether the session is open and return an error if not. 70N/A * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this 70N/A tr (
"The session is not open")); \
70N/A// constructor / destructor ///////////////////////////////////////////////////////////////////////////// uninit (
true /* aFinalRelease */);
///////////////////////////////////////////////////////////////////////////// * Initializes the Session object. /* Enclose the state transition NotReady->InInit->Ready */ /* Confirm a successful initialization when it's the case */ * Uninitializes the Session object. * @note Locks this object for writing. /* Enclose the state transition Ready->InUninit->NotReady */ /* close() needs write lock */ ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// /* close() needs write lock */ return close (
false /* aFinalRelease */,
false /* aFromServer */);
// IInternalSessionControl methods ///////////////////////////////////////////////////////////////////////////// (
"This is not a direct session!\n"),
E_FAIL);
/* return a failure if the session already transitioned to Closing * but the server hasn't processed Machine::OnSessionEnd() yet. */ * A special case: the server informs us that this session has been * passed to IVirtualBox::OpenRemoteSession() so this session will * become remote (but not existing) when AssignRemoteMachine() is /* query IInternalMachineControl interface */ * Reference the VirtualBox object to ensure the server is up * until the session is closed /* query IInternalMachineControl interface */ // currently, the remote session returns the same machine and // console objects as the direct session, thus giving the // (remote) client full control over the direct session. For the // console, it is the desired behavior (the ability to control // VM execution is a must for the remote session). What about // the machine object, we may want to prevent the remote client // from modifying machine data. In this case, we must: // 1) assign the Machine object (instead of the SessionMachine // object that is passed to this method) to mRemoteMachine; // 2) remove GetMachine() property from the IConsole interface // because it always returns the SessionMachine object // (alternatively, we can supply a separate IConsole // implementation that will return the Machine object in // response to GetMachine()). * Reference the VirtualBox object to ensure the server is up * until the session is closed * RemoteSession type can be already set by AssignMachine() when its * argument is NULL (a special case) * We might have already entered Session::uninit() at this point, so * return silently (not interested in the state change during uninit) /* close() needs write lock */ rc =
close (
false /* aFinalRelease */,
true /* aFromServer */);
* We might have already entered Session::uninit() at this point, /* the call from Machine issued when the session is open can arrive * after the session starts closing or gets closed. Note that when * aCheck is false, we return E_FAIL to indicate that aWinId we return tr (
"Machine session is not open (session state: %d)."),
/* aValue can be NULL for a setter call if the property is to be deleted. */ /* aFlags can be null if it is to be left as is */ #
else /* VBOX_WITH_GUEST_PROPS not defined */#
endif /* VBOX_WITH_GUEST_PROPS not defined */ tr (
"Machine session is not open (session state: %d)."),
#
else /* VBOX_WITH_GUEST_PROPS not defined */#
endif /* VBOX_WITH_GUEST_PROPS not defined *//////////////////////////////////////////////////////////////////////////////// * Closes the current session. * @param aFinalRelease called as a result of FinalRelease() * @param aFromServer called as a result of Uninitialize() * @note To be called only from #uninit(), #Close() or #Uninitialize(). * @note Locks this object for writing. /* The session object is going to be uninitialized before it has been * assigned a direct console of the machine the client requested to open * a remote session to using IVirtualBox:: openRemoteSession(). It is OK * only if this close reqiest comes from the server (for example, it * detected that the VM process it started terminated before opening a * direct session). Otherwise, it means that the client is too fast and * trying to close the session before waiting for the progress object it * got from IVirtualBox:: openRemoteSession() to complete, so assert. */ /* go to the closing state */ * We trigger OnSessionEnd() only when the session closes itself using * Close(). Note that if isFinalRelease = TRUE here, this means that * the client process has already initialized the termination procedure * without issuing Close() and the IPC channel is no more operational -- * so we cannot call the server's method (it will definitely fail). The * server will instead simply detect the abnormal client death (since * OnSessionEnd() is not called) and reset the machine state to Aborted. * while waiting for OnSessionEnd() to complete one of our methods * can be called by the server (for example, Uninitialize(), if the * direct session has initiated a closure just a bit before us) so * we need to release the lock to avoid deadlocks. The state is already * SessionState_Closing here, so it's safe. * If we get E_UNEXPECTED this means that the direct session has already * been closed, we're just too late with our notification and nothing more * Wait for the server to grab the semaphore and destroy the session * machine (allowing us to open a new session with the same machine * once this method returns) /* release the VirtualBox instance as the very last step */ /** @note To be called only from #AssignMachine() */ /* open the IPC semaphore based on the sessionId and try to grab it */ * Since Session is an MTA object, this method can be executed on * any thread, and this thread will not necessarily match the thread on * which close() will be called later. Therefore, we need a separate * thread to hold the IPC mutex and then release it in close(). data [
2] = 0;
/* will get an output from the thread */ /* create a thread to hold the IPC mutex until signalled to release it */ /* wait until thread init is completed */ /* memorize the event sem we should signal in close() */ /* We use XPCOM where any message (including close()) can arrive on any * worker thread (which will not necessarily match this thread that opens * the mutex). Therefore, we need a separate thread to hold the IPC mutex * and then release it in close(). */ data [
2] = (
void *)
false;
/* will get the thread result here */ /* create a thread to hold the IPC mutex until signalled to release it */ /* wait until thread init is completed */ /* the thread must succeed */ (
"Cannot open IPC semaphore, errno=%d",
errno),
(
"Cannot grab IPC semaphore, errno=%d",
errno),
/** @note To be called only from #close() */ /* release the IPC semaphore */ * tell the thread holding the IPC mutex to release it; * it will close mIPCSem handle /* wait for the thread to finish */ /* tell the thread holding the IPC mutex to release it */ /* wait for the thread to finish */ /** VM IPC mutex holder thread */ /* signal we're done with init */ /* wait until we're signaled to release the IPC mutex */ /* release the IPC mutex */ LogFlow ((
"IPCMutexHolderThread(): releasing IPC mutex...\n"));
/** VM IPC mutex holder thread */ data [
2] = (
void *)
true;
/* wait until we're signaled to release the IPC mutex */ /* release the IPC mutex */ data [
1] = (
void *)
false;