Changeset 47561 in vbox for trunk/src/VBox/Main/src-client
- Timestamp:
- Aug 6, 2013 3:18:17 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 87761
- Location:
- trunk/src/VBox/Main/src-client
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/ClientTokenHolder.cpp
r47555 r47561 1 /* $Id$ */2 1 /** @file 3 * VBox Client Session COM Class implementation in VBoxC. 2 * 3 * VirtualBox API client token holder (in the client process) 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-201 2Oracle Corporation7 * Copyright (C) 2006-2013 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 #include <iprt/asm.h> 19 #include <iprt/assert.h> 20 #include <iprt/log.h> 21 #include <iprt/semaphore.h> 22 #include <iprt/process.h> 23 18 24 #ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER 19 # include <errno.h> 20 # include <sys/types.h> 21 # include <sys/stat.h> 22 # include <sys/ipc.h> 23 # include <sys/sem.h> 24 #endif 25 25 # include <errno.h> 26 # include <sys/types.h> 27 # include <sys/stat.h> 28 # include <sys/ipc.h> 29 # include <sys/sem.h> 30 #endif 31 32 #include <VBox/com/defs.h> 33 34 #include "ClientTokenHolder.h" 26 35 #include "SessionImpl.h" 27 #include "ConsoleImpl.h" 28 #include "Global.h" 29 30 #include "AutoCaller.h" 31 #include "Logging.h" 32 33 #include <VBox/err.h> 34 #include <iprt/process.h> 35 36 #if defined(RT_OS_WINDOWS) || defined (RT_OS_OS2) 37 /** VM IPC mutex holder thread */ 38 static DECLCALLBACK(int) IPCMutexHolderThread(RTTHREAD Thread, void *pvUser); 39 #endif 40 41 /** 42 * Local macro to check whether the session is open and return an error if not. 43 * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this 44 * macro. 45 */ 46 #define CHECK_OPEN() \ 47 do { \ 48 if (mState != SessionState_Locked) \ 49 return setError(E_UNEXPECTED, tr ("The session is not locked (session state: %s)"), Global::stringifySessionState(mState)); \ 50 } while (0) 51 52 // constructor / destructor 53 ///////////////////////////////////////////////////////////////////////////// 54 55 HRESULT Session::FinalConstruct() 56 { 57 LogFlowThisFunc(("\n")); 58 59 HRESULT rc = init(); 60 61 BaseFinalConstruct(); 62 63 return rc; 64 } 65 66 void Session::FinalRelease() 67 { 68 LogFlowThisFunc(("\n")); 69 70 uninit(); 71 72 BaseFinalRelease(); 73 } 74 75 // public initializer/uninitializer for internal purposes only 76 ///////////////////////////////////////////////////////////////////////////// 77 78 /** 79 * Initializes the Session object. 80 */ 81 HRESULT Session::init() 82 { 83 /* Enclose the state transition NotReady->InInit->Ready */ 84 AutoInitSpan autoInitSpan(this); 85 AssertReturn(autoInitSpan.isOk(), E_FAIL); 86 87 LogFlowThisFuncEnter(); 88 89 mState = SessionState_Unlocked; 90 mType = SessionType_Null; 91 36 37 38 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 39 /** client token holder thread */ 40 static DECLCALLBACK(int) ClientTokenHolderThread(RTTHREAD Thread, void *pvUser); 41 #endif 42 43 44 Session::ClientTokenHolder::ClientTokenHolder() 45 { 46 AssertReleaseFailed(); 47 } 48 49 Session::ClientTokenHolder::~ClientTokenHolder() 50 { 51 /* release the client token */ 92 52 #if defined(RT_OS_WINDOWS) 93 mIPCSem = NULL; 94 mIPCThreadSem = NULL; 53 54 if (mSem && mThreadSem) 55 { 56 /* 57 * tell the thread holding the token to release it; 58 * it will close mSem handle 59 */ 60 ::SetEvent(mSem); 61 /* wait for the thread to finish */ 62 ::WaitForSingleObject(mThreadSem, INFINITE); 63 ::CloseHandle(mThreadSem); 64 65 mThreadSem = NULL; 66 mSem = NULL; 67 mThread = NIL_RTTHREAD; 68 } 69 95 70 #elif defined(RT_OS_OS2) 96 mIPCThread = NIL_RTTHREAD; 97 mIPCThreadSem = NIL_RTSEMEVENT; 71 72 if (mThread != NIL_RTTHREAD) 73 { 74 Assert(mSem != NIL_RTSEMEVENT); 75 76 /* tell the thread holding the token to release it */ 77 int vrc = RTSemEventSignal(mSem); 78 AssertRC(vrc == NO_ERROR); 79 80 /* wait for the thread to finish */ 81 vrc = RTThreadUserWait(mThread, RT_INDEFINITE_WAIT); 82 Assert(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); 83 84 mThread = NIL_RTTHREAD; 85 } 86 87 if (mSem != NIL_RTSEMEVENT) 88 { 89 RTSemEventDestroy(mSem); 90 mSem = NIL_RTSEMEVENT; 91 } 92 98 93 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) 99 mIPCSem = -1; 94 95 if (mSem >= 0) 96 { 97 ::sembuf sop = { 0, 1, SEM_UNDO }; 98 ::semop(mSem, &sop, 1); 99 100 mSem = -1; 101 } 102 100 103 #else 101 104 # error "Port me!" 102 105 #endif 103 104 /* Confirm a successful initialization when it's the case */ 105 autoInitSpan.setSucceeded(); 106 107 LogFlowThisFuncLeave(); 108 109 return S_OK; 110 } 111 112 /** 113 * Uninitializes the Session object. 114 * 115 * @note Locks this object for writing. 116 */ 117 void Session::uninit() 118 { 119 LogFlowThisFuncEnter(); 120 121 /* Enclose the state transition Ready->InUninit->NotReady */ 122 AutoUninitSpan autoUninitSpan(this); 123 if (autoUninitSpan.uninitDone()) 124 { 125 LogFlowThisFunc(("Already uninitialized.\n")); 126 LogFlowThisFuncLeave(); 127 return; 128 } 129 130 /* close() needs write lock */ 131 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 132 133 if (mState != SessionState_Unlocked) 134 { 135 Assert(mState == SessionState_Locked || 136 mState == SessionState_Spawning); 137 138 HRESULT rc = unlockMachine(true /* aFinalRelease */, false /* aFromServer */); 139 AssertComRC(rc); 140 } 141 142 LogFlowThisFuncLeave(); 143 } 144 145 // ISession properties 146 ///////////////////////////////////////////////////////////////////////////// 147 148 STDMETHODIMP Session::COMGETTER(State)(SessionState_T *aState) 149 { 150 CheckComArgOutPointerValid(aState); 151 152 AutoCaller autoCaller(this); 153 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 154 155 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 156 157 *aState = mState; 158 159 return S_OK; 160 } 161 162 STDMETHODIMP Session::COMGETTER(Type)(SessionType_T *aType) 163 { 164 CheckComArgOutPointerValid(aType); 165 166 AutoCaller autoCaller(this); 167 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 168 169 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 170 171 CHECK_OPEN(); 172 173 *aType = mType; 174 return S_OK; 175 } 176 177 STDMETHODIMP Session::COMGETTER(Machine)(IMachine **aMachine) 178 { 179 CheckComArgOutPointerValid(aMachine); 180 181 AutoCaller autoCaller(this); 182 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 183 184 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 185 186 CHECK_OPEN(); 187 188 HRESULT rc; 189 if (mConsole) 190 rc = mConsole->machine().queryInterfaceTo(aMachine); 106 } 107 108 Session::ClientTokenHolder::ClientTokenHolder(const Utf8Str &strTokenId) : 109 mClientTokenId(strTokenId) 110 { 111 mSem = CTHSEMARG; 112 mThread = NIL_RTTHREAD; 113 114 #if defined(RT_OS_WINDOWS) 115 mThreadSem = CTHTHREADSEMARG; 116 117 Bstr bstrTokenId(strTokenId); 118 119 /* 120 * Since there is no guarantee that the constructor and destructor will be 121 * called in the same thread, we need a separate thread to hold the token. 122 */ 123 124 mThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); 125 AssertMsgReturnVoid(mThreadSem, 126 ("Cannot create an event sem, err=%d", ::GetLastError())); 127 128 void *data[3]; 129 data[0] = (void*)(BSTR)bstrTokenId.raw(); 130 data[1] = (void*)mThreadSem; 131 data[2] = 0; /* will get an output from the thread */ 132 133 /* create a thread to hold the token until signalled to release it */ 134 int vrc = RTThreadCreate(&mThread, ClientTokenHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); 135 AssertRCReturnVoid(vrc); 136 137 /* wait until thread init is completed */ 138 DWORD wrc = ::WaitForSingleObject(mThreadSem, INFINITE); 139 AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError())); 140 Assert(data[2]); 141 142 if (wrc == WAIT_OBJECT_0 && data[2]) 143 { 144 /* memorize the event sem we should signal in close() */ 145 mSem = (HANDLE)data[2]; 146 } 191 147 else 192 rc = mRemoteMachine.queryInterfaceTo(aMachine); 193 if (FAILED(rc)) 194 { 195 /** @todo VBox 3.3: replace E_FAIL with rc here. */ 196 if (mConsole) 197 setError(E_FAIL, tr("Failed to query the session machine (%Rhrc)"), rc); 198 else if (FAILED_DEAD_INTERFACE(rc)) 199 setError(E_FAIL, tr("Peer process crashed")); 200 else 201 setError(E_FAIL, tr("Failed to query the remote session machine (%Rhrc)"), rc); 202 } 203 204 return rc; 205 } 206 207 STDMETHODIMP Session::COMGETTER(Console)(IConsole **aConsole) 208 { 209 CheckComArgOutPointerValid(aConsole); 210 211 AutoCaller autoCaller(this); 212 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 213 214 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 215 216 CHECK_OPEN(); 217 218 HRESULT rc; 219 if (mConsole) 220 rc = mConsole.queryInterfaceTo(aConsole); 221 else 222 rc = mRemoteConsole.queryInterfaceTo(aConsole); 223 224 if (FAILED(rc)) 225 { 226 /** @todo VBox 3.3: replace E_FAIL with rc here. */ 227 if (mConsole) 228 setError(E_FAIL, tr("Failed to query the console (%Rhrc)"), rc); 229 else if (FAILED_DEAD_INTERFACE(rc)) 230 setError(E_FAIL, tr("Peer process crashed")); 231 else 232 setError(E_FAIL, tr("Failed to query the remote console (%Rhrc)"), rc); 233 } 234 235 return rc; 236 } 237 238 // ISession methods 239 ///////////////////////////////////////////////////////////////////////////// 240 241 STDMETHODIMP Session::UnlockMachine() 242 { 243 LogFlowThisFunc(("mState=%d, mType=%d\n", mState, mType)); 244 245 AutoCaller autoCaller(this); 246 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 247 248 /* close() needs write lock */ 249 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 250 251 CHECK_OPEN(); 252 253 return unlockMachine(false /* aFinalRelease */, false /* aFromServer */); 254 } 255 256 // IInternalSessionControl methods 257 ///////////////////////////////////////////////////////////////////////////// 258 259 STDMETHODIMP Session::GetPID(ULONG *aPid) 260 { 261 AssertReturn(aPid, E_POINTER); 262 263 AutoCaller autoCaller(this); 264 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 265 266 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 267 268 *aPid = (ULONG)RTProcSelf(); 269 AssertCompile(sizeof(*aPid) == sizeof(RTPROCESS)); 270 271 return S_OK; 272 } 273 274 STDMETHODIMP Session::GetRemoteConsole(IConsole **aConsole) 275 { 276 LogFlowThisFuncEnter(); 277 AssertReturn(aConsole, E_POINTER); 278 279 AutoCaller autoCaller(this); 280 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 281 282 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 283 284 AssertReturn(mState != SessionState_Unlocked, VBOX_E_INVALID_VM_STATE); 285 286 AssertMsgReturn(mType == SessionType_WriteLock && !!mConsole, 287 ("This is not a direct session!\n"), 288 VBOX_E_INVALID_OBJECT_STATE); 289 290 /* return a failure if the session already transitioned to Closing 291 * but the server hasn't processed Machine::OnSessionEnd() yet. */ 292 if (mState != SessionState_Locked) 293 return VBOX_E_INVALID_VM_STATE; 294 295 mConsole.queryInterfaceTo(aConsole); 296 297 LogFlowThisFuncLeave(); 298 299 return S_OK; 300 } 301 302 STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType) 303 { 304 LogFlowThisFuncEnter(); 305 LogFlowThisFunc(("aMachine=%p\n", aMachine)); 306 307 AutoCaller autoCaller(this); 308 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 309 310 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 311 312 AssertReturn(mState == SessionState_Unlocked, VBOX_E_INVALID_VM_STATE); 313 314 if (!aMachine) 315 { 316 /* 317 * A special case: the server informs us that this session has been 318 * passed to IMachine::launchVMProcess() so this session will become 319 * remote (but not existing) when AssignRemoteMachine() is called. 320 */ 321 322 AssertReturn(mType == SessionType_Null, VBOX_E_INVALID_OBJECT_STATE); 323 mType = SessionType_Remote; 324 mState = SessionState_Spawning; 325 326 LogFlowThisFuncLeave(); 327 return S_OK; 328 } 329 330 HRESULT rc = E_FAIL; 331 332 /* query IInternalMachineControl interface */ 333 mControl = aMachine; 334 AssertReturn(!!mControl, E_FAIL); 335 336 rc = mConsole.createObject(); 337 AssertComRCReturn(rc, rc); 338 339 rc = mConsole->init(aMachine, mControl, aLockType); 340 AssertComRCReturn(rc, rc); 341 342 rc = grabIPCSemaphore(); 148 { 149 ::CloseHandle(mThreadSem); 150 mThreadSem = NULL; 151 } 152 #elif defined(RT_OS_OS2) 153 Bstr bstrTokenId(strTokenId); 343 154 344 155 /* 345 * Reference the VirtualBox object to ensure the server is up346 * until the session is closed156 * Since there is no guarantee that the constructor and destructor will be 157 * called in the same thread, we need a separate thread to hold the token. 347 158 */ 348 if (SUCCEEDED(rc)) 349 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam()); 350 351 if (SUCCEEDED(rc)) 352 { 353 mType = SessionType_WriteLock; 354 mState = SessionState_Locked; 355 } 356 else 357 { 358 /* some cleanup */ 359 mControl.setNull(); 360 if (!mConsole.isNull()) 361 { 362 mConsole->uninit(); 363 mConsole.setNull(); 364 } 365 } 366 367 LogFlowThisFunc(("rc=%08X\n", rc)); 368 LogFlowThisFuncLeave(); 369 370 return rc; 371 } 372 373 STDMETHODIMP Session::AssignRemoteMachine(IMachine *aMachine, IConsole *aConsole) 374 { 375 LogFlowThisFuncEnter(); 376 LogFlowThisFunc(("aMachine=%p, aConsole=%p\n", aMachine, aConsole)); 377 378 AssertReturn(aMachine && aConsole, E_INVALIDARG); 379 380 AutoCaller autoCaller(this); 381 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 382 383 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 384 385 AssertReturn(mState == SessionState_Unlocked || 386 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE); 387 388 HRESULT rc = E_FAIL; 389 390 /* query IInternalMachineControl interface */ 391 mControl = aMachine; 392 AssertReturn(!!mControl, E_FAIL); 393 394 /// @todo (dmik) 395 // currently, the remote session returns the same machine and 396 // console objects as the direct session, thus giving the 397 // (remote) client full control over the direct session. For the 398 // console, it is the desired behavior (the ability to control 399 // VM execution is a must for the remote session). What about 400 // the machine object, we may want to prevent the remote client 401 // from modifying machine data. In this case, we must: 402 // 1) assign the Machine object (instead of the SessionMachine 403 // object that is passed to this method) to mRemoteMachine; 404 // 2) remove GetMachine() property from the IConsole interface 405 // because it always returns the SessionMachine object 406 // (alternatively, we can supply a separate IConsole 407 // implementation that will return the Machine object in 408 // response to GetMachine()). 409 410 mRemoteMachine = aMachine; 411 mRemoteConsole = aConsole; 412 413 /* 414 * Reference the VirtualBox object to ensure the server is up 415 * until the session is closed 416 */ 417 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam()); 418 419 if (SUCCEEDED(rc)) 420 { 421 /* 422 * RemoteSession type can be already set by AssignMachine() when its 423 * argument is NULL (a special case) 424 */ 425 if (mType != SessionType_Remote) 426 mType = SessionType_Shared; 427 else 428 Assert(mState == SessionState_Spawning); 429 430 mState = SessionState_Locked; 431 } 432 else 433 { 434 /* some cleanup */ 435 mControl.setNull(); 436 mRemoteMachine.setNull(); 437 mRemoteConsole.setNull(); 438 } 439 440 LogFlowThisFunc(("rc=%08X\n", rc)); 441 LogFlowThisFuncLeave(); 442 443 return rc; 444 } 445 446 STDMETHODIMP Session::UpdateMachineState(MachineState_T aMachineState) 447 { 448 AutoCaller autoCaller(this); 449 450 if (autoCaller.state() != Ready) 451 { 452 /* 453 * We might have already entered Session::uninit() at this point, so 454 * return silently (not interested in the state change during uninit) 455 */ 456 LogFlowThisFunc(("Already uninitialized.\n")); 457 return S_OK; 458 } 459 460 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 461 462 if (mState == SessionState_Unlocking) 463 { 464 LogFlowThisFunc(("Already being unlocked.\n")); 465 return S_OK; 466 } 467 468 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 469 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 470 471 AssertReturn(!mControl.isNull(), E_FAIL); 472 AssertReturn(!mConsole.isNull(), E_FAIL); 473 474 return mConsole->updateMachineState(aMachineState); 475 } 476 477 STDMETHODIMP Session::Uninitialize() 478 { 479 LogFlowThisFuncEnter(); 480 481 AutoCaller autoCaller(this); 482 483 HRESULT rc = S_OK; 484 485 if (autoCaller.state() == Ready) 486 { 487 /* close() needs write lock */ 488 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 489 490 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType)); 491 492 if (mState == SessionState_Unlocking) 493 { 494 LogFlowThisFunc(("Already being unlocked.\n")); 495 return S_OK; 496 } 497 498 #ifndef DEBUG_andy /* Don't bug me -- now time to fix this at the moment. */ 499 AssertReturn(mState == SessionState_Locked || 500 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE); 501 #endif 502 503 /* close ourselves */ 504 rc = unlockMachine(false /* aFinalRelease */, true /* aFromServer */); 505 } 506 else if (autoCaller.state() == InUninit) 507 { 508 /* 509 * We might have already entered Session::uninit() at this point, 510 * return silently 511 */ 512 LogFlowThisFunc(("Already uninitialized.\n")); 513 } 514 else 515 { 516 LogWarningThisFunc(("UNEXPECTED uninitialization!\n")); 517 rc = autoCaller.rc(); 518 } 519 520 LogFlowThisFunc(("rc=%08X\n", rc)); 521 LogFlowThisFuncLeave(); 522 523 return rc; 524 } 525 526 STDMETHODIMP Session::OnNetworkAdapterChange(INetworkAdapter *networkAdapter, BOOL changeAdapter) 527 { 528 LogFlowThisFunc(("\n")); 529 530 AutoCaller autoCaller(this); 531 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 532 533 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 534 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 535 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 536 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 537 538 return mConsole->onNetworkAdapterChange(networkAdapter, changeAdapter); 539 } 540 541 STDMETHODIMP Session::OnSerialPortChange(ISerialPort *serialPort) 542 { 543 LogFlowThisFunc(("\n")); 544 545 AutoCaller autoCaller(this); 546 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 547 548 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 549 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 550 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 551 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 552 553 return mConsole->onSerialPortChange(serialPort); 554 } 555 556 STDMETHODIMP Session::OnParallelPortChange(IParallelPort *parallelPort) 557 { 558 LogFlowThisFunc(("\n")); 559 560 AutoCaller autoCaller(this); 561 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 562 563 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 564 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 565 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 566 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 567 568 return mConsole->onParallelPortChange(parallelPort); 569 } 570 571 STDMETHODIMP Session::OnStorageControllerChange() 572 { 573 LogFlowThisFunc(("\n")); 574 575 AutoCaller autoCaller(this); 576 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 577 578 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 579 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 580 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 581 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 582 583 return mConsole->onStorageControllerChange(); 584 } 585 586 STDMETHODIMP Session::OnMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForce) 587 { 588 LogFlowThisFunc(("\n")); 589 590 AutoCaller autoCaller(this); 591 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 592 593 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 594 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 595 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 596 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 597 598 return mConsole->onMediumChange(aMediumAttachment, aForce); 599 } 600 601 STDMETHODIMP Session::OnCPUChange(ULONG aCPU, BOOL aRemove) 602 { 603 LogFlowThisFunc(("\n")); 604 605 AutoCaller autoCaller(this); 606 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 607 608 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 609 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 610 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 611 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 612 613 return mConsole->onCPUChange(aCPU, aRemove); 614 } 615 616 STDMETHODIMP Session::OnCPUExecutionCapChange(ULONG aExecutionCap) 617 { 618 LogFlowThisFunc(("\n")); 619 620 AutoCaller autoCaller(this); 621 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 622 623 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 624 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 625 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 626 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 627 628 return mConsole->onCPUExecutionCapChange(aExecutionCap); 629 } 630 631 STDMETHODIMP Session::OnVRDEServerChange(BOOL aRestart) 632 { 633 LogFlowThisFunc(("\n")); 634 635 AutoCaller autoCaller(this); 636 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 637 638 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 639 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 640 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 641 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 642 643 return mConsole->onVRDEServerChange(aRestart); 644 } 645 646 STDMETHODIMP Session::OnVideoCaptureChange() 647 { 648 LogFlowThisFunc(("\n")); 649 650 AutoCaller autoCaller(this); 651 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 652 653 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 654 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 655 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 656 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 657 658 return mConsole->onVideoCaptureChange(); 659 } 660 661 STDMETHODIMP Session::OnUSBControllerChange() 662 { 663 LogFlowThisFunc(("\n")); 664 665 AutoCaller autoCaller(this); 666 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 667 668 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 669 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 670 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 671 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 672 673 return mConsole->onUSBControllerChange(); 674 } 675 676 STDMETHODIMP Session::OnSharedFolderChange(BOOL aGlobal) 677 { 678 LogFlowThisFunc(("\n")); 679 680 AutoCaller autoCaller(this); 681 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 682 683 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 684 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 685 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 686 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 687 688 return mConsole->onSharedFolderChange(aGlobal); 689 } 690 691 STDMETHODIMP Session::OnClipboardModeChange(ClipboardMode_T aClipboardMode) 692 { 693 LogFlowThisFunc(("\n")); 694 695 AutoCaller autoCaller(this); 696 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 697 698 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 699 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 700 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 701 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 702 703 return mConsole->onClipboardModeChange(aClipboardMode); 704 } 705 706 STDMETHODIMP Session::OnDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode) 707 { 708 LogFlowThisFunc(("\n")); 709 710 AutoCaller autoCaller(this); 711 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 712 713 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 714 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 715 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 716 717 return mConsole->onDragAndDropModeChange(aDragAndDropMode); 718 } 719 720 STDMETHODIMP Session::OnUSBDeviceAttach(IUSBDevice *aDevice, 721 IVirtualBoxErrorInfo *aError, 722 ULONG aMaskedIfs) 723 { 724 LogFlowThisFunc(("\n")); 725 726 AutoCaller autoCaller(this); 727 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 728 729 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 730 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 731 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 732 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 733 734 return mConsole->onUSBDeviceAttach(aDevice, aError, aMaskedIfs); 735 } 736 737 STDMETHODIMP Session::OnUSBDeviceDetach(IN_BSTR aId, 738 IVirtualBoxErrorInfo *aError) 739 { 740 LogFlowThisFunc(("\n")); 741 742 AutoCaller autoCaller(this); 743 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 744 745 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 746 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 747 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 748 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 749 750 return mConsole->onUSBDeviceDetach(aId, aError); 751 } 752 753 STDMETHODIMP Session::OnShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId) 754 { 755 AutoCaller autoCaller(this); 756 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 757 758 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 759 760 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 761 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 762 763 if (mState != SessionState_Locked) 764 { 765 /* the call from Machine issued when the session is open can arrive 766 * after the session starts closing or gets closed. Note that when 767 * aCheck is false, we return E_FAIL to indicate that aWinId we return 768 * is not valid */ 769 *aCanShow = FALSE; 770 *aWinId = 0; 771 return aCheck ? S_OK : E_FAIL; 772 } 773 774 return mConsole->onShowWindow(aCheck, aCanShow, aWinId); 775 } 776 777 STDMETHODIMP Session::OnBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) 778 { 779 LogFlowThisFunc(("\n")); 780 781 AutoCaller autoCaller(this); 782 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 783 784 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 785 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 786 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 787 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 788 789 return mConsole->onBandwidthGroupChange(aBandwidthGroup); 790 } 791 792 STDMETHODIMP Session::OnStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent) 793 { 794 LogFlowThisFunc(("\n")); 795 796 AutoCaller autoCaller(this); 797 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 798 799 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 800 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 801 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 802 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 803 804 return mConsole->onStorageDeviceChange(aMediumAttachment, aRemove, aSilent); 805 } 806 807 STDMETHODIMP Session::AccessGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags, 808 BOOL aIsSetter, BSTR *aRetValue, LONG64 *aRetTimestamp, BSTR *aRetFlags) 809 { 810 #ifdef VBOX_WITH_GUEST_PROPS 811 AutoCaller autoCaller(this); 812 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 813 814 if (mState != SessionState_Locked) 815 return setError(VBOX_E_INVALID_VM_STATE, 816 tr("Machine is not locked by session (session state: %s)."), 817 Global::stringifySessionState(mState)); 818 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 819 CheckComArgStrNotEmptyOrNull(aName); 820 if (!aIsSetter && !VALID_PTR(aRetValue)) 821 return E_POINTER; 822 if (!aIsSetter && !VALID_PTR(aRetTimestamp)) 823 return E_POINTER; 824 if (!aIsSetter && !VALID_PTR(aRetFlags)) 825 return E_POINTER; 826 /* aValue can be NULL for a setter call if the property is to be deleted. */ 827 if (aIsSetter && (aValue != NULL) && !VALID_PTR(aValue)) 828 return setError(E_INVALIDARG, tr("Invalid value pointer")); 829 /* aFlags can be null if it is to be left as is */ 830 if (aIsSetter && (aFlags != NULL) && !VALID_PTR(aFlags)) 831 return setError(E_INVALIDARG, tr("Invalid flags pointer")); 832 833 /* If this session is not in a VM process fend off the call. The caller 834 * handles this correctly, by doing the operation in VBoxSVC. */ 835 if (!mConsole) 836 return E_ACCESSDENIED; 837 838 if (!aIsSetter) 839 return mConsole->getGuestProperty(aName, aRetValue, aRetTimestamp, aRetFlags); 840 else 841 return mConsole->setGuestProperty(aName, aValue, aFlags); 842 #else /* VBOX_WITH_GUEST_PROPS not defined */ 843 ReturnComNotImplemented(); 844 #endif /* VBOX_WITH_GUEST_PROPS not defined */ 845 } 846 847 STDMETHODIMP Session::EnumerateGuestProperties(IN_BSTR aPatterns, 848 ComSafeArrayOut(BSTR, aNames), 849 ComSafeArrayOut(BSTR, aValues), 850 ComSafeArrayOut(LONG64, aTimestamps), 851 ComSafeArrayOut(BSTR, aFlags)) 852 { 853 #ifdef VBOX_WITH_GUEST_PROPS 854 AutoCaller autoCaller(this); 855 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 856 857 if (mState != SessionState_Locked) 858 return setError(VBOX_E_INVALID_VM_STATE, 859 tr("Machine is not locked by session (session state: %s)."), 860 Global::stringifySessionState(mState)); 861 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 862 if (!VALID_PTR(aPatterns) && (aPatterns != NULL)) 863 return E_POINTER; 864 if (ComSafeArrayOutIsNull(aNames)) 865 return E_POINTER; 866 if (ComSafeArrayOutIsNull(aValues)) 867 return E_POINTER; 868 if (ComSafeArrayOutIsNull(aTimestamps)) 869 return E_POINTER; 870 if (ComSafeArrayOutIsNull(aFlags)) 871 return E_POINTER; 872 873 /* If this session is not in a VM process fend off the call. The caller 874 * handles this correctly, by doing the operation in VBoxSVC. */ 875 if (!mConsole) 876 return E_ACCESSDENIED; 877 878 return mConsole->enumerateGuestProperties(aPatterns, 879 ComSafeArrayOutArg(aNames), 880 ComSafeArrayOutArg(aValues), 881 ComSafeArrayOutArg(aTimestamps), 882 ComSafeArrayOutArg(aFlags)); 883 #else /* VBOX_WITH_GUEST_PROPS not defined */ 884 ReturnComNotImplemented(); 885 #endif /* VBOX_WITH_GUEST_PROPS not defined */ 886 } 887 888 STDMETHODIMP Session::OnlineMergeMedium(IMediumAttachment *aMediumAttachment, 889 ULONG aSourceIdx, ULONG aTargetIdx, 890 IMedium *aSource, IMedium *aTarget, 891 BOOL aMergeForward, 892 IMedium *aParentForTarget, 893 ComSafeArrayIn(IMedium *, aChildrenToReparent), 894 IProgress *aProgress) 895 { 896 AutoCaller autoCaller(this); 897 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 898 899 if (mState != SessionState_Locked) 900 return setError(VBOX_E_INVALID_VM_STATE, 901 tr("Machine is not locked by session (session state: %s)."), 902 Global::stringifySessionState(mState)); 903 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 904 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 905 CheckComArgNotNull(aMediumAttachment); 906 CheckComArgSafeArrayNotNull(aChildrenToReparent); 907 908 return mConsole->onlineMergeMedium(aMediumAttachment, aSourceIdx, 909 aTargetIdx, aSource, aTarget, 910 aMergeForward, aParentForTarget, 911 ComSafeArrayInArg(aChildrenToReparent), 912 aProgress); 913 } 914 915 STDMETHODIMP Session::EnableVMMStatistics(BOOL aEnable) 916 { 917 AutoCaller autoCaller(this); 918 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 919 920 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 921 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 922 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 923 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 924 925 mConsole->enableVMMStatistics(aEnable); 926 927 return S_OK; 928 } 929 930 STDMETHODIMP Session::PauseWithReason(Reason_T aReason) 931 { 932 AutoCaller autoCaller(this); 933 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 934 935 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 936 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 937 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 938 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 939 940 return mConsole->pause(aReason); 941 } 942 943 STDMETHODIMP Session::ResumeWithReason(Reason_T aReason) 944 { 945 AutoCaller autoCaller(this); 946 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 947 948 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 949 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 950 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 951 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 952 953 return mConsole->resume(aReason); 954 } 955 956 STDMETHODIMP Session::SaveStateWithReason(Reason_T aReason, IProgress **aProgress) 957 { 958 AutoCaller autoCaller(this); 959 AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); 960 961 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 962 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); 963 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); 964 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); 965 966 return mConsole->saveState(aReason, aProgress); 967 } 968 969 // private methods 970 /////////////////////////////////////////////////////////////////////////////// 971 972 /** 973 * Unlocks a machine associated with the current session. 974 * 975 * @param aFinalRelease called as a result of FinalRelease() 976 * @param aFromServer called as a result of Uninitialize() 977 * 978 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize(). 979 * @note Locks this object for writing. 980 */ 981 HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer) 982 { 983 LogFlowThisFuncEnter(); 984 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n", 985 aFinalRelease, aFromServer)); 986 987 AutoCaller autoCaller(this); 988 AssertComRCReturnRC(autoCaller.rc()); 989 990 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 991 992 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType)); 993 994 if (mState != SessionState_Locked) 995 { 996 Assert(mState == SessionState_Spawning); 997 998 /* The session object is going to be uninitialized before it has been 999 * assigned a direct console of the machine the client requested to open 1000 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK 1001 * only if this close request comes from the server (for example, it 1002 * detected that the VM process it started terminated before opening a 1003 * direct session). Otherwise, it means that the client is too fast and 1004 * trying to close the session before waiting for the progress object it 1005 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */ 1006 Assert(aFromServer); 1007 1008 mState = SessionState_Unlocked; 1009 mType = SessionType_Null; 1010 #if defined(RT_OS_WINDOWS) 1011 Assert(!mIPCSem && !mIPCThreadSem); 1012 #elif defined(RT_OS_OS2) 1013 Assert(mIPCThread == NIL_RTTHREAD && 1014 mIPCThreadSem == NIL_RTSEMEVENT); 159 160 int vrc = RTSemEventCreate(&mSem); 161 AssertRCReturnVoid(vrc); 162 163 void *data[3]; 164 data[0] = (void*)bstrTokenId.raw(); 165 data[1] = (void*)mSem; 166 data[2] = (void*)false; /* will get the thread result here */ 167 168 /* create a thread to hold the token until signalled to release it */ 169 vrc = RTThreadCreate(&mThread, ClientTokenHolderThread, (void *) data, 170 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); 171 AssertRCReturnVoid(vrc); 172 /* wait until thread init is completed */ 173 vrc = RTThreadUserWait(mThread, RT_INDEFINITE_WAIT); 174 AssertReturnVoid(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); 175 176 /* the thread must succeed */ 177 AssertReturnVoid((bool)data[2]); 178 1015 179 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) 1016 Assert(mIPCSem == -1); 180 181 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN 182 key_t key = RTStrToUInt32(strTokenId.c_str()); 183 AssertMsgReturnVoid(key != 0, 184 ("Key value of 0 is not valid for client token")); 185 # else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ 186 char *pszSemName = NULL; 187 RTStrUtf8ToCurrentCP(&pszSemName, strTokenId); 188 key_t key = ::ftok(pszSemName, 'V'); 189 RTStrFree(pszSemName); 190 # endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ 191 int s = ::semget(key, 0, 0); 192 AssertMsgReturnVoid(s >= 0, 193 ("Cannot open semaphore, errno=%d", errno)); 194 195 /* grab the semaphore */ 196 ::sembuf sop = { 0, -1, SEM_UNDO }; 197 int rv = ::semop(s, &sop, 1); 198 AssertMsgReturnVoid(rv == 0, 199 ("Cannot grab semaphore, errno=%d", errno)); 200 mSem = s; 201 1017 202 #else 1018 203 # error "Port me!" 1019 204 #endif 1020 LogFlowThisFuncLeave(); 1021 return S_OK; 1022 } 1023 1024 /* go to the closing state */ 1025 mState = SessionState_Unlocking; 1026 1027 if (mType == SessionType_WriteLock) 1028 { 1029 if (!mConsole.isNull()) 1030 { 1031 mConsole->uninit(); 1032 mConsole.setNull(); 1033 } 1034 } 1035 else 1036 { 1037 mRemoteMachine.setNull(); 1038 mRemoteConsole.setNull(); 1039 } 1040 1041 ComPtr<IProgress> progress; 1042 1043 if (!aFinalRelease && !aFromServer) 1044 { 1045 /* 1046 * We trigger OnSessionEnd() only when the session closes itself using 1047 * Close(). Note that if isFinalRelease = TRUE here, this means that 1048 * the client process has already initialized the termination procedure 1049 * without issuing Close() and the IPC channel is no more operational -- 1050 * so we cannot call the server's method (it will definitely fail). The 1051 * server will instead simply detect the abnormal client death (since 1052 * OnSessionEnd() is not called) and reset the machine state to Aborted. 1053 */ 1054 1055 /* 1056 * while waiting for OnSessionEnd() to complete one of our methods 1057 * can be called by the server (for example, Uninitialize(), if the 1058 * direct session has initiated a closure just a bit before us) so 1059 * we need to release the lock to avoid deadlocks. The state is already 1060 * SessionState_Closing here, so it's safe. 1061 */ 1062 alock.release(); 1063 1064 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n")); 1065 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam()); 1066 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc)); 1067 1068 alock.acquire(); 1069 1070 /* 1071 * If we get E_UNEXPECTED this means that the direct session has already 1072 * been closed, we're just too late with our notification and nothing more 1073 * 1074 * bird: Seems E_ACCESSDENIED is what gets returned these days; see 1075 * VirtualBoxBase::addCaller. 1076 */ 1077 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED)) 1078 rc = S_OK; 1079 1080 #ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */ 1081 AssertComRC(rc); 1082 #endif 1083 } 1084 1085 mControl.setNull(); 1086 1087 if (mType == SessionType_WriteLock) 1088 { 1089 releaseIPCSemaphore(); 1090 if (!aFinalRelease && !aFromServer) 1091 { 1092 /* 1093 * Wait for the server to grab the semaphore and destroy the session 1094 * machine (allowing us to open a new session with the same machine 1095 * once this method returns) 1096 */ 1097 Assert(!!progress); 1098 if (progress) 1099 progress->WaitForCompletion(-1); 1100 } 1101 } 1102 1103 mState = SessionState_Unlocked; 1104 mType = SessionType_Null; 1105 1106 /* release the VirtualBox instance as the very last step */ 1107 mVirtualBox.setNull(); 1108 1109 LogFlowThisFuncLeave(); 1110 return S_OK; 1111 } 1112 1113 /** @note To be called only from #AssignMachine() */ 1114 HRESULT Session::grabIPCSemaphore() 1115 { 1116 HRESULT rc = E_FAIL; 1117 1118 /* open the IPC semaphore based on the sessionId and try to grab it */ 1119 Bstr ipcId; 1120 rc = mControl->GetIPCId(ipcId.asOutParam()); 1121 AssertComRCReturnRC(rc); 1122 1123 LogFlowThisFunc(("ipcId='%ls'\n", ipcId.raw())); 1124 1125 #if defined(RT_OS_WINDOWS) 1126 1127 /* 1128 * Since Session is an MTA object, this method can be executed on 1129 * any thread, and this thread will not necessarily match the thread on 1130 * which close() will be called later. Therefore, we need a separate 1131 * thread to hold the IPC mutex and then release it in close(). 1132 */ 1133 1134 mIPCThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); 1135 AssertMsgReturn(mIPCThreadSem, 1136 ("Cannot create an event sem, err=%d", ::GetLastError()), 1137 E_FAIL); 1138 1139 void *data[3]; 1140 data[0] = (void*)(BSTR)ipcId.raw(); 1141 data[1] = (void*)mIPCThreadSem; 1142 data[2] = 0; /* will get an output from the thread */ 1143 1144 /* create a thread to hold the IPC mutex until signalled to release it */ 1145 RTTHREAD tid; 1146 int vrc = RTThreadCreate(&tid, IPCMutexHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); 1147 AssertRCReturn(vrc, E_FAIL); 1148 1149 /* wait until thread init is completed */ 1150 DWORD wrc = ::WaitForSingleObject(mIPCThreadSem, INFINITE); 1151 AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError())); 1152 Assert(data[2]); 1153 1154 if (wrc == WAIT_OBJECT_0 && data[2]) 1155 { 1156 /* memorize the event sem we should signal in close() */ 1157 mIPCSem = (HANDLE)data[2]; 1158 rc = S_OK; 1159 } 1160 else 1161 { 1162 ::CloseHandle(mIPCThreadSem); 1163 mIPCThreadSem = NULL; 1164 rc = E_FAIL; 1165 } 1166 1167 #elif defined(RT_OS_OS2) 1168 1169 /* We use XPCOM where any message (including close()) can arrive on any 1170 * worker thread (which will not necessarily match this thread that opens 1171 * the mutex). Therefore, we need a separate thread to hold the IPC mutex 1172 * and then release it in close(). */ 1173 1174 int vrc = RTSemEventCreate(&mIPCThreadSem); 1175 AssertRCReturn(vrc, E_FAIL); 1176 1177 void *data[3]; 1178 data[0] = (void*)ipcId.raw(); 1179 data[1] = (void*)mIPCThreadSem; 1180 data[2] = (void*)false; /* will get the thread result here */ 1181 1182 /* create a thread to hold the IPC mutex until signalled to release it */ 1183 vrc = RTThreadCreate(&mIPCThread, IPCMutexHolderThread, (void *) data, 1184 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); 1185 AssertRCReturn(vrc, E_FAIL); 1186 1187 /* wait until thread init is completed */ 1188 vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT); 1189 AssertReturn(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED, E_FAIL); 1190 1191 /* the thread must succeed */ 1192 AssertReturn((bool)data[2], E_FAIL); 1193 1194 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) 1195 1196 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN 1197 Utf8Str ipcKey = ipcId; 1198 key_t key = RTStrToUInt32(ipcKey.c_str()); 1199 AssertMsgReturn (key != 0, 1200 ("Key value of 0 is not valid for IPC semaphore"), 1201 E_FAIL); 1202 # else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ 1203 Utf8Str semName = ipcId; 1204 char *pszSemName = NULL; 1205 RTStrUtf8ToCurrentCP (&pszSemName, semName); 1206 key_t key = ::ftok (pszSemName, 'V'); 1207 RTStrFree (pszSemName); 1208 # endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ 1209 1210 mIPCSem = ::semget (key, 0, 0); 1211 AssertMsgReturn (mIPCSem >= 0, 1212 ("Cannot open IPC semaphore, errno=%d", errno), 1213 E_FAIL); 1214 1215 /* grab the semaphore */ 1216 ::sembuf sop = { 0, -1, SEM_UNDO }; 1217 int rv = ::semop (mIPCSem, &sop, 1); 1218 AssertMsgReturn (rv == 0, 1219 ("Cannot grab IPC semaphore, errno=%d", errno), 1220 E_FAIL); 1221 1222 #else 1223 # error "Port me!" 1224 #endif 1225 1226 return rc; 1227 } 1228 1229 /** @note To be called only from #close() */ 1230 void Session::releaseIPCSemaphore() 1231 { 1232 /* release the IPC semaphore */ 1233 #if defined(RT_OS_WINDOWS) 1234 1235 if (mIPCSem && mIPCThreadSem) 1236 { 1237 /* 1238 * tell the thread holding the IPC mutex to release it; 1239 * it will close mIPCSem handle 1240 */ 1241 ::SetEvent (mIPCSem); 1242 /* wait for the thread to finish */ 1243 ::WaitForSingleObject (mIPCThreadSem, INFINITE); 1244 ::CloseHandle (mIPCThreadSem); 1245 1246 mIPCThreadSem = NULL; 1247 mIPCSem = NULL; 1248 } 1249 1250 #elif defined(RT_OS_OS2) 1251 1252 if (mIPCThread != NIL_RTTHREAD) 1253 { 1254 Assert (mIPCThreadSem != NIL_RTSEMEVENT); 1255 1256 /* tell the thread holding the IPC mutex to release it */ 1257 int vrc = RTSemEventSignal (mIPCThreadSem); 1258 AssertRC(vrc == NO_ERROR); 1259 1260 /* wait for the thread to finish */ 1261 vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT); 1262 Assert (RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); 1263 1264 mIPCThread = NIL_RTTHREAD; 1265 } 1266 1267 if (mIPCThreadSem != NIL_RTSEMEVENT) 1268 { 1269 RTSemEventDestroy (mIPCThreadSem); 1270 mIPCThreadSem = NIL_RTSEMEVENT; 1271 } 1272 1273 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) 1274 1275 if (mIPCSem >= 0) 1276 { 1277 ::sembuf sop = { 0, 1, SEM_UNDO }; 1278 ::semop (mIPCSem, &sop, 1); 1279 1280 mIPCSem = -1; 1281 } 1282 1283 #else 1284 # error "Port me!" 1285 #endif 1286 } 1287 1288 #if defined(RT_OS_WINDOWS) 1289 /** VM IPC mutex holder thread */ 1290 DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser) 205 } 206 207 bool Session::ClientTokenHolder::isReady() 208 { 209 return mSem != CTHSEMARG; 210 } 211 212 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 213 /** client token holder thread */ 214 DECLCALLBACK(int) ClientTokenHolderThread(RTTHREAD Thread, void *pvUser) 1291 215 { 1292 216 LogFlowFuncEnter(); 1293 217 1294 Assert (pvUser); 1295 void **data = (void **) pvUser; 1296 218 Assert(pvUser); 219 220 void **data = (void **)pvUser; 221 222 # if defined(RT_OS_WINDOWS) 1297 223 BSTR sessionId = (BSTR)data[0]; 1298 224 HANDLE initDoneSem = (HANDLE)data[1]; 1299 225 1300 HANDLE ipcMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, sessionId);1301 AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%d\n", ::GetLastError()));1302 1303 if ( ipcMutex)1304 { 1305 /* grab the mutex*/1306 DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);1307 AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));226 HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, sessionId); 227 AssertMsg(mutex, ("cannot open token, err=%d\n", ::GetLastError())); 228 229 if (mutex) 230 { 231 /* grab the token */ 232 DWORD wrc = ::WaitForSingleObject(mutex, 0); 233 AssertMsg(wrc == WAIT_OBJECT_0, ("cannot grab token, err=%d\n", wrc)); 1308 234 if (wrc == WAIT_OBJECT_0) 1309 235 { 1310 HANDLE finishSem = ::CreateEvent 1311 AssertMsg 236 HANDLE finishSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); 237 AssertMsg(finishSem, ("cannot create event sem, err=%d\n", ::GetLastError())); 1312 238 if (finishSem) 1313 239 { 1314 240 data[2] = (void*)finishSem; 1315 241 /* signal we're done with init */ 1316 ::SetEvent 1317 /* wait until we're signaled to release the IPC mutex*/1318 ::WaitForSingleObject 1319 /* release the IPC mutex*/1320 LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));1321 BOOL success = ::ReleaseMutex (ipcMutex);1322 AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));1323 ::CloseHandle (ipcMutex);1324 ::CloseHandle 242 ::SetEvent(initDoneSem); 243 /* wait until we're signaled to release the token */ 244 ::WaitForSingleObject(finishSem, INFINITE); 245 /* release the token */ 246 LogFlow(("ClientTokenHolderThread(): releasing token...\n")); 247 BOOL success = ::ReleaseMutex(mutex); 248 AssertMsg(success, ("cannot release token, err=%d\n", ::GetLastError())); 249 ::CloseHandle(mutex); 250 ::CloseHandle(finishSem); 1325 251 } 1326 252 } … … 1328 254 1329 255 /* signal we're done */ 1330 ::SetEvent (initDoneSem); 1331 1332 LogFlowFuncLeave(); 1333 1334 return 0; 1335 } 1336 #endif 1337 1338 #if defined(RT_OS_OS2) 1339 /** VM IPC mutex holder thread */ 1340 DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser) 1341 { 1342 LogFlowFuncEnter(); 1343 1344 Assert (pvUser); 1345 void **data = (void **) pvUser; 1346 1347 Utf8Str ipcId = (BSTR)data[0]; 256 ::SetEvent(initDoneSem); 257 # elif defined(RT_OS_OS2) 258 Utf8Str sessionId = (BSTR)data[0]; 1348 259 RTSEMEVENT finishSem = (RTSEMEVENT)data[1]; 1349 260 1350 LogFlowFunc (("ipcId='%s', finishSem=%p\n", ipcId.raw(), finishSem));1351 1352 HMTX ipcMutex = NULLHANDLE;1353 APIRET arc = ::DosOpenMutexSem ((PSZ) ipcId.raw(), &ipcMutex);1354 AssertMsg (arc == NO_ERROR, ("cannot open IPC mutex, arc=%ld\n", arc));261 LogFlowFunc(("sessionId='%s', finishSem=%p\n", sessionId.raw(), finishSem)); 262 263 HMTX mutex = NULLHANDLE; 264 APIRET arc = ::DosOpenMutexSem((PSZ)sessionId.raw(), &mutex); 265 AssertMsg(arc == NO_ERROR, ("cannot open token, arc=%ld\n", arc)); 1355 266 1356 267 if (arc == NO_ERROR) 1357 268 { 1358 /* grab the mutex*/1359 LogFlowFunc (("grabbing IPC mutex...\n"));1360 arc = ::DosRequestMutexSem (ipcMutex, SEM_IMMEDIATE_RETURN);1361 AssertMsg (arc == NO_ERROR, ("cannot grab IPC mutex, arc=%ld\n", arc));269 /* grab the token */ 270 LogFlowFunc(("grabbing token...\n")); 271 arc = ::DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN); 272 AssertMsg(arc == NO_ERROR, ("cannot grab token, arc=%ld\n", arc)); 1362 273 if (arc == NO_ERROR) 1363 274 { … … 1365 276 data[2] = (void*)true; 1366 277 /* signal we're done */ 1367 int vrc = RTThreadUserSignal 278 int vrc = RTThreadUserSignal(Thread); 1368 279 AssertRC(vrc); 1369 280 1370 /* wait until we're signaled to release the IPC mutex*/1371 LogFlowFunc 1372 vrc = RTSemEventWait 1373 Assert 1374 1375 /* release the IPC mutex*/1376 LogFlowFunc (("releasing IPC mutex...\n"));1377 arc = ::DosReleaseMutexSem (ipcMutex);1378 AssertMsg (arc == NO_ERROR, ("cannot release mutex, arc=%ld\n", arc));281 /* wait until we're signaled to release the token */ 282 LogFlowFunc(("waiting for termination signal..\n")); 283 vrc = RTSemEventWait(finishSem, RT_INDEFINITE_WAIT); 284 Assert(arc == ERROR_INTERRUPT || ERROR_TIMEOUT); 285 286 /* release the token */ 287 LogFlowFunc(("releasing token...\n")); 288 arc = ::DosReleaseMutexSem(mutex); 289 AssertMsg(arc == NO_ERROR, ("cannot release token, arc=%ld\n", arc)); 1379 290 } 1380 1381 ::DosCloseMutexSem (ipcMutex); 291 ::DosCloseMutexSem(mutex); 1382 292 } 1383 293 … … 1385 295 data[1] = (void*)false; 1386 296 /* signal we're done */ 1387 int vrc = RTThreadUserSignal 297 int vrc = RTThreadUserSignal(Thread); 1388 298 AssertRC(vrc); 299 # else 300 # error "Port me!" 301 # endif 1389 302 1390 303 LogFlowFuncLeave(); … … 1393 306 } 1394 307 #endif 308 1395 309 /* vi: set tabstop=4 shiftwidth=4 expandtab: */ -
trunk/src/VBox/Main/src-client/SessionImpl.cpp
r46775 r47561 5 5 6 6 /* 7 * Copyright (C) 2006-201 2Oracle Corporation7 * Copyright (C) 2006-2013 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 #ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER19 # include <errno.h>20 # include <sys/types.h>21 # include <sys/stat.h>22 # include <sys/ipc.h>23 # include <sys/sem.h>24 #endif25 26 18 #include "SessionImpl.h" 27 19 #include "ConsoleImpl.h" 28 20 #include "Global.h" 21 #include "ClientTokenHolder.h" 29 22 30 23 #include "AutoCaller.h" … … 33 26 #include <VBox/err.h> 34 27 #include <iprt/process.h> 35 36 #if defined(RT_OS_WINDOWS) || defined (RT_OS_OS2)37 /** VM IPC mutex holder thread */38 static DECLCALLBACK(int) IPCMutexHolderThread(RTTHREAD Thread, void *pvUser);39 #endif40 28 41 29 /** … … 90 78 mType = SessionType_Null; 91 79 92 #if defined(RT_OS_WINDOWS) 93 mIPCSem = NULL; 94 mIPCThreadSem = NULL; 95 #elif defined(RT_OS_OS2) 96 mIPCThread = NIL_RTTHREAD; 97 mIPCThreadSem = NIL_RTSEMEVENT; 98 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) 99 mIPCSem = -1; 100 #else 101 # error "Port me!" 102 #endif 80 mClientTokenHolder = NULL; 103 81 104 82 /* Confirm a successful initialization when it's the case */ … … 300 278 } 301 279 302 STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType) 280 STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType, 281 IN_BSTR aTokenId) 303 282 { 304 283 LogFlowThisFuncEnter(); … … 340 319 AssertComRCReturn(rc, rc); 341 320 342 rc = grabIPCSemaphore(); 321 Utf8Str strTokenId(aTokenId); 322 Assert(!strTokenId.isEmpty()); 323 /* create the machine client token */ 324 try 325 { 326 mClientTokenHolder = new ClientTokenHolder(strTokenId); 327 if (!mClientTokenHolder->isReady()) 328 { 329 delete mClientTokenHolder; 330 mClientTokenHolder = NULL; 331 rc = E_FAIL; 332 } 333 } 334 catch (std::bad_alloc &) 335 { 336 rc = E_OUTOFMEMORY; 337 } 343 338 344 339 /* … … 1008 1003 mState = SessionState_Unlocked; 1009 1004 mType = SessionType_Null; 1010 #if defined(RT_OS_WINDOWS) 1011 Assert(!mIPCSem && !mIPCThreadSem); 1012 #elif defined(RT_OS_OS2) 1013 Assert(mIPCThread == NIL_RTTHREAD && 1014 mIPCThreadSem == NIL_RTSEMEVENT); 1015 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) 1016 Assert(mIPCSem == -1); 1017 #else 1018 # error "Port me!" 1019 #endif 1005 1006 Assert(!mClientTokenHolder); 1007 1020 1008 LogFlowThisFuncLeave(); 1021 1009 return S_OK; … … 1087 1075 if (mType == SessionType_WriteLock) 1088 1076 { 1089 releaseIPCSemaphore(); 1077 if (mClientTokenHolder) 1078 { 1079 delete mClientTokenHolder; 1080 mClientTokenHolder = NULL; 1081 } 1082 1090 1083 if (!aFinalRelease && !aFromServer) 1091 1084 { … … 1111 1104 } 1112 1105 1113 /** @note To be called only from #AssignMachine() */1114 HRESULT Session::grabIPCSemaphore()1115 {1116 HRESULT rc = E_FAIL;1117 1118 /* open the IPC semaphore based on the sessionId and try to grab it */1119 Bstr ipcId;1120 rc = mControl->GetIPCId(ipcId.asOutParam());1121 AssertComRCReturnRC(rc);1122 1123 LogFlowThisFunc(("ipcId='%ls'\n", ipcId.raw()));1124 1125 #if defined(RT_OS_WINDOWS)1126 1127 /*1128 * Since Session is an MTA object, this method can be executed on1129 * any thread, and this thread will not necessarily match the thread on1130 * which close() will be called later. Therefore, we need a separate1131 * thread to hold the IPC mutex and then release it in close().1132 */1133 1134 mIPCThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL);1135 AssertMsgReturn(mIPCThreadSem,1136 ("Cannot create an event sem, err=%d", ::GetLastError()),1137 E_FAIL);1138 1139 void *data[3];1140 data[0] = (void*)(BSTR)ipcId.raw();1141 data[1] = (void*)mIPCThreadSem;1142 data[2] = 0; /* will get an output from the thread */1143 1144 /* create a thread to hold the IPC mutex until signalled to release it */1145 RTTHREAD tid;1146 int vrc = RTThreadCreate(&tid, IPCMutexHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");1147 AssertRCReturn(vrc, E_FAIL);1148 1149 /* wait until thread init is completed */1150 DWORD wrc = ::WaitForSingleObject(mIPCThreadSem, INFINITE);1151 AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError()));1152 Assert(data[2]);1153 1154 if (wrc == WAIT_OBJECT_0 && data[2])1155 {1156 /* memorize the event sem we should signal in close() */1157 mIPCSem = (HANDLE)data[2];1158 rc = S_OK;1159 }1160 else1161 {1162 ::CloseHandle(mIPCThreadSem);1163 mIPCThreadSem = NULL;1164 rc = E_FAIL;1165 }1166 1167 #elif defined(RT_OS_OS2)1168 1169 /* We use XPCOM where any message (including close()) can arrive on any1170 * worker thread (which will not necessarily match this thread that opens1171 * the mutex). Therefore, we need a separate thread to hold the IPC mutex1172 * and then release it in close(). */1173 1174 int vrc = RTSemEventCreate(&mIPCThreadSem);1175 AssertRCReturn(vrc, E_FAIL);1176 1177 void *data[3];1178 data[0] = (void*)ipcId.raw();1179 data[1] = (void*)mIPCThreadSem;1180 data[2] = (void*)false; /* will get the thread result here */1181 1182 /* create a thread to hold the IPC mutex until signalled to release it */1183 vrc = RTThreadCreate(&mIPCThread, IPCMutexHolderThread, (void *) data,1184 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");1185 AssertRCReturn(vrc, E_FAIL);1186 1187 /* wait until thread init is completed */1188 vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT);1189 AssertReturn(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED, E_FAIL);1190 1191 /* the thread must succeed */1192 AssertReturn((bool)data[2], E_FAIL);1193 1194 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)1195 1196 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN1197 Utf8Str ipcKey = ipcId;1198 key_t key = RTStrToUInt32(ipcKey.c_str());1199 AssertMsgReturn (key != 0,1200 ("Key value of 0 is not valid for IPC semaphore"),1201 E_FAIL);1202 # else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */1203 Utf8Str semName = ipcId;1204 char *pszSemName = NULL;1205 RTStrUtf8ToCurrentCP (&pszSemName, semName);1206 key_t key = ::ftok (pszSemName, 'V');1207 RTStrFree (pszSemName);1208 # endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */1209 1210 mIPCSem = ::semget (key, 0, 0);1211 AssertMsgReturn (mIPCSem >= 0,1212 ("Cannot open IPC semaphore, errno=%d", errno),1213 E_FAIL);1214 1215 /* grab the semaphore */1216 ::sembuf sop = { 0, -1, SEM_UNDO };1217 int rv = ::semop (mIPCSem, &sop, 1);1218 AssertMsgReturn (rv == 0,1219 ("Cannot grab IPC semaphore, errno=%d", errno),1220 E_FAIL);1221 1222 #else1223 # error "Port me!"1224 #endif1225 1226 return rc;1227 }1228 1229 /** @note To be called only from #close() */1230 void Session::releaseIPCSemaphore()1231 {1232 /* release the IPC semaphore */1233 #if defined(RT_OS_WINDOWS)1234 1235 if (mIPCSem && mIPCThreadSem)1236 {1237 /*1238 * tell the thread holding the IPC mutex to release it;1239 * it will close mIPCSem handle1240 */1241 ::SetEvent (mIPCSem);1242 /* wait for the thread to finish */1243 ::WaitForSingleObject (mIPCThreadSem, INFINITE);1244 ::CloseHandle (mIPCThreadSem);1245 1246 mIPCThreadSem = NULL;1247 mIPCSem = NULL;1248 }1249 1250 #elif defined(RT_OS_OS2)1251 1252 if (mIPCThread != NIL_RTTHREAD)1253 {1254 Assert (mIPCThreadSem != NIL_RTSEMEVENT);1255 1256 /* tell the thread holding the IPC mutex to release it */1257 int vrc = RTSemEventSignal (mIPCThreadSem);1258 AssertRC(vrc == NO_ERROR);1259 1260 /* wait for the thread to finish */1261 vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT);1262 Assert (RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED);1263 1264 mIPCThread = NIL_RTTHREAD;1265 }1266 1267 if (mIPCThreadSem != NIL_RTSEMEVENT)1268 {1269 RTSemEventDestroy (mIPCThreadSem);1270 mIPCThreadSem = NIL_RTSEMEVENT;1271 }1272 1273 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)1274 1275 if (mIPCSem >= 0)1276 {1277 ::sembuf sop = { 0, 1, SEM_UNDO };1278 ::semop (mIPCSem, &sop, 1);1279 1280 mIPCSem = -1;1281 }1282 1283 #else1284 # error "Port me!"1285 #endif1286 }1287 1288 #if defined(RT_OS_WINDOWS)1289 /** VM IPC mutex holder thread */1290 DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)1291 {1292 LogFlowFuncEnter();1293 1294 Assert (pvUser);1295 void **data = (void **) pvUser;1296 1297 BSTR sessionId = (BSTR)data[0];1298 HANDLE initDoneSem = (HANDLE)data[1];1299 1300 HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId);1301 AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%d\n", ::GetLastError()));1302 1303 if (ipcMutex)1304 {1305 /* grab the mutex */1306 DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);1307 AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));1308 if (wrc == WAIT_OBJECT_0)1309 {1310 HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);1311 AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));1312 if (finishSem)1313 {1314 data[2] = (void*)finishSem;1315 /* signal we're done with init */1316 ::SetEvent (initDoneSem);1317 /* wait until we're signaled to release the IPC mutex */1318 ::WaitForSingleObject (finishSem, INFINITE);1319 /* release the IPC mutex */1320 LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));1321 BOOL success = ::ReleaseMutex (ipcMutex);1322 AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));1323 ::CloseHandle (ipcMutex);1324 ::CloseHandle (finishSem);1325 }1326 }1327 }1328 1329 /* signal we're done */1330 ::SetEvent (initDoneSem);1331 1332 LogFlowFuncLeave();1333 1334 return 0;1335 }1336 #endif1337 1338 #if defined(RT_OS_OS2)1339 /** VM IPC mutex holder thread */1340 DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)1341 {1342 LogFlowFuncEnter();1343 1344 Assert (pvUser);1345 void **data = (void **) pvUser;1346 1347 Utf8Str ipcId = (BSTR)data[0];1348 RTSEMEVENT finishSem = (RTSEMEVENT)data[1];1349 1350 LogFlowFunc (("ipcId='%s', finishSem=%p\n", ipcId.raw(), finishSem));1351 1352 HMTX ipcMutex = NULLHANDLE;1353 APIRET arc = ::DosOpenMutexSem ((PSZ) ipcId.raw(), &ipcMutex);1354 AssertMsg (arc == NO_ERROR, ("cannot open IPC mutex, arc=%ld\n", arc));1355 1356 if (arc == NO_ERROR)1357 {1358 /* grab the mutex */1359 LogFlowFunc (("grabbing IPC mutex...\n"));1360 arc = ::DosRequestMutexSem (ipcMutex, SEM_IMMEDIATE_RETURN);1361 AssertMsg (arc == NO_ERROR, ("cannot grab IPC mutex, arc=%ld\n", arc));1362 if (arc == NO_ERROR)1363 {1364 /* store the answer */1365 data[2] = (void*)true;1366 /* signal we're done */1367 int vrc = RTThreadUserSignal (Thread);1368 AssertRC(vrc);1369 1370 /* wait until we're signaled to release the IPC mutex */1371 LogFlowFunc (("waiting for termination signal..\n"));1372 vrc = RTSemEventWait (finishSem, RT_INDEFINITE_WAIT);1373 Assert (arc == ERROR_INTERRUPT || ERROR_TIMEOUT);1374 1375 /* release the IPC mutex */1376 LogFlowFunc (("releasing IPC mutex...\n"));1377 arc = ::DosReleaseMutexSem (ipcMutex);1378 AssertMsg (arc == NO_ERROR, ("cannot release mutex, arc=%ld\n", arc));1379 }1380 1381 ::DosCloseMutexSem (ipcMutex);1382 }1383 1384 /* store the answer */1385 data[1] = (void*)false;1386 /* signal we're done */1387 int vrc = RTThreadUserSignal (Thread);1388 AssertRC(vrc);1389 1390 LogFlowFuncLeave();1391 1392 return 0;1393 }1394 #endif1395 1106 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note:
See TracChangeset
for help on using the changeset viewer.