VirtualBox

source: vbox/trunk/src/VBox/Main/SessionImpl.cpp@ 2463

Last change on this file since 2463 was 2463, checked in by vboxsync, 18 years ago

Main & All Frontends: Prototyped a bunch of Main API changes (IVirtualBoxErrorInfo extension for cascading errors; IMachine/IConsoleCallback extension to properly activate the console window; IVirtualBoxCallback::onExtraDataCanChange() support for error messages; minor IHost::createUSBDeviceFilter/removeUSBDeviceFilter corrections).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.2 KB
Line 
1/** @file
2 *
3 * VBox Client Session COM Class implementation
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#if defined(__WIN__)
23#elif defined(__LINUX__)
24#endif
25
26#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
27# include <errno.h>
28# include <sys/types.h>
29# include <sys/stat.h>
30# include <sys/ipc.h>
31# include <sys/sem.h>
32#endif
33
34#include "SessionImpl.h"
35#include "ConsoleImpl.h"
36
37#include "Logging.h"
38
39#include <VBox/err.h>
40#include <iprt/process.h>
41
42#if defined(__WIN__)
43/** VM IPC mutex holder thread */
44static DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser);
45#endif
46
47/**
48 * Local macro to check whether the session is open and return an error if not.
49 * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this
50 * macro.
51 */
52#define CHECK_OPEN() \
53 do { \
54 if (mState != SessionState_SessionOpen) \
55 return setError (E_UNEXPECTED, \
56 tr ("The session is not open")); \
57 } while (0)
58
59// constructor / destructor
60/////////////////////////////////////////////////////////////////////////////
61
62HRESULT Session::FinalConstruct()
63{
64 LogFlowThisFunc (("\n"));
65
66 return init();
67}
68
69void Session::FinalRelease()
70{
71 LogFlowThisFunc (("\n"));
72
73 uninit (true /* aFinalRelease */);
74}
75
76// public initializer/uninitializer for internal purposes only
77/////////////////////////////////////////////////////////////////////////////
78
79/**
80 * Initializes the Session object.
81 */
82HRESULT Session::init()
83{
84 /* Enclose the state transition NotReady->InInit->Ready */
85 AutoInitSpan autoInitSpan (this);
86 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
87
88 LogFlowThisFuncEnter();
89
90 mState = SessionState_SessionClosed;
91 mType = SessionType_InvalidSessionType;
92
93#if defined(__WIN__)
94 mIPCSem = NULL;
95 mIPCThreadSem = NULL;
96#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
97 mIPCSem = -1;
98#endif
99
100 /* Confirm a successful initialization when it's the case */
101 autoInitSpan.setSucceeded();
102
103 LogFlowThisFuncLeave();
104
105 return S_OK;
106}
107
108/**
109 * Uninitializes the Session object.
110 *
111 * @note Locks this object for writing.
112 */
113void Session::uninit (bool aFinalRelease)
114{
115 LogFlowThisFuncEnter();
116 LogFlowThisFunc (("aFinalRelease=%d\n", aFinalRelease));
117
118 /* Enclose the state transition Ready->InUninit->NotReady */
119 AutoUninitSpan autoUninitSpan (this);
120 if (autoUninitSpan.uninitDone())
121 {
122 LogFlowThisFunc (("Already uninitialized.\n"));
123 LogFlowThisFuncLeave();
124 return;
125 }
126
127 AutoLock alock (this);
128
129 if (mState != SessionState_SessionClosed)
130 {
131 Assert (mState == SessionState_SessionOpen ||
132 mState == SessionState_SessionSpawning);
133
134 HRESULT rc = close (aFinalRelease, false /* aFromServer */);
135 AssertComRC (rc);
136 }
137
138 LogFlowThisFuncLeave();
139}
140
141// ISession properties
142/////////////////////////////////////////////////////////////////////////////
143
144STDMETHODIMP Session::COMGETTER(State) (SessionState_T *aState)
145{
146 if (!aState)
147 return E_POINTER;
148
149 AutoCaller autoCaller (this);
150 CheckComRCReturnRC (autoCaller.rc());
151
152 AutoReaderLock alock (this);
153
154 *aState = mState;
155
156 return S_OK;
157}
158
159STDMETHODIMP Session::COMGETTER(Type) (SessionType_T *aType)
160{
161 if (!aType)
162 return E_POINTER;
163
164 AutoCaller autoCaller (this);
165 CheckComRCReturnRC (autoCaller.rc());
166
167 AutoReaderLock alock (this);
168
169 CHECK_OPEN();
170
171 *aType = mType;
172 return S_OK;
173}
174
175STDMETHODIMP Session::COMGETTER(Machine) (IMachine **aMachine)
176{
177 if (!aMachine)
178 return E_POINTER;
179
180 AutoCaller autoCaller (this);
181 CheckComRCReturnRC (autoCaller.rc());
182
183 AutoReaderLock alock (this);
184
185 CHECK_OPEN();
186
187 HRESULT rc = E_FAIL;
188
189 if (mConsole)
190 rc = mConsole->machine().queryInterfaceTo (aMachine);
191 else
192 rc = mRemoteMachine.queryInterfaceTo (aMachine);
193 ComAssertComRC (rc);
194
195 return rc;
196}
197
198STDMETHODIMP Session::COMGETTER(Console) (IConsole **aConsole)
199{
200 if (!aConsole)
201 return E_POINTER;
202
203 AutoCaller autoCaller (this);
204 CheckComRCReturnRC (autoCaller.rc());
205
206 AutoReaderLock alock (this);
207
208 CHECK_OPEN();
209
210 HRESULT rc = E_FAIL;
211
212 if (mConsole)
213 rc = mConsole.queryInterfaceTo (aConsole);
214 else
215 rc = mRemoteConsole.queryInterfaceTo (aConsole);
216 ComAssertComRC (rc);
217
218 return rc;
219}
220
221// ISession methods
222/////////////////////////////////////////////////////////////////////////////
223
224STDMETHODIMP Session::Close()
225{
226 LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
227
228 AutoCaller autoCaller (this);
229 CheckComRCReturnRC (autoCaller.rc());
230
231 /* close() needs write lock */
232 AutoLock alock (this);
233
234 CHECK_OPEN();
235
236 return close (false /* aFinalRelease */, false /* aFromServer */);
237}
238
239// IInternalSessionControl methods
240/////////////////////////////////////////////////////////////////////////////
241
242STDMETHODIMP Session::GetPID (ULONG *aPid)
243{
244 AssertReturn (aPid, E_POINTER);
245
246 AutoCaller autoCaller (this);
247 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
248
249 AutoReaderLock alock (this);
250
251 *aPid = (ULONG) RTProcSelf();
252 AssertCompile (sizeof (*aPid) == sizeof (RTPROCESS));
253
254 return S_OK;
255}
256
257STDMETHODIMP Session::GetRemoteConsole (IConsole **aConsole)
258{
259 AssertReturn (aConsole, E_POINTER);
260
261 AutoCaller autoCaller (this);
262 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
263
264 AutoReaderLock alock (this);
265
266 AssertReturn (mState == SessionState_SessionOpen, E_FAIL);
267
268 AssertMsgReturn (mType == SessionType_DirectSession && !!mConsole,
269 ("This is not a direct session!\n"), E_FAIL);
270
271 mConsole.queryInterfaceTo (aConsole);
272
273 return S_OK;
274}
275
276STDMETHODIMP Session::AssignMachine (IMachine *aMachine)
277{
278 LogFlowThisFuncEnter();
279 LogFlowThisFunc (("aMachine=%p\n", aMachine));
280
281 AutoCaller autoCaller (this);
282 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
283
284 AutoLock alock (this);
285
286 AssertReturn (mState == SessionState_SessionClosed, E_FAIL);
287
288 if (!aMachine)
289 {
290 /*
291 * A special case: the server informs us that this session has been
292 * passed to IVirtualBox::OpenRemoteSession() so this session will
293 * become remote (but not existing) when AssignRemoteMachine() is
294 * called.
295 */
296
297 AssertReturn (mType == SessionType_InvalidSessionType, E_FAIL);
298 mType = SessionType_RemoteSession;
299 mState = SessionState_SessionSpawning;
300
301 LogFlowThisFuncLeave();
302 return S_OK;
303 }
304
305 HRESULT rc = E_FAIL;
306
307 /* query IInternalMachineControl interface */
308 mControl = aMachine;
309 AssertReturn (!!mControl, E_FAIL);
310
311 rc = mConsole.createObject();
312 AssertComRCReturn (rc, rc);
313
314 rc = mConsole->init (aMachine, mControl);
315 AssertComRCReturn (rc, rc);
316
317 rc = grabIPCSemaphore();
318
319 /*
320 * Reference the VirtualBox object to ensure the server is up
321 * until the session is closed
322 */
323 if (SUCCEEDED (rc))
324 rc = aMachine->COMGETTER(Parent) (mVirtualBox.asOutParam());
325
326 if (SUCCEEDED (rc))
327 {
328 mType = SessionType_DirectSession;
329 mState = SessionState_SessionOpen;
330 }
331 else
332 {
333 /* some cleanup */
334 mControl.setNull();
335 mConsole->uninit();
336 mConsole.setNull();
337 }
338
339 LogFlowThisFunc (("rc=%08X\n", rc));
340 LogFlowThisFuncLeave();
341
342 return rc;
343}
344
345STDMETHODIMP Session::AssignRemoteMachine (IMachine *aMachine, IConsole *aConsole)
346{
347 LogFlowThisFuncEnter();
348 LogFlowThisFunc (("aMachine=%p, aConsole=%p\n", aMachine, aConsole));
349
350 AssertReturn (aMachine && aConsole, E_INVALIDARG);
351
352 AutoCaller autoCaller (this);
353 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
354
355 AutoLock alock (this);
356
357 AssertReturn (mState == SessionState_SessionClosed ||
358 mState == SessionState_SessionSpawning, E_FAIL);
359
360 HRESULT rc = E_FAIL;
361
362 /* query IInternalMachineControl interface */
363 mControl = aMachine;
364 AssertReturn (!!mControl, E_FAIL);
365
366 /// @todo (dmik)
367 // currently, the remote session returns the same machine and
368 // console objects as the direct session, thus giving the
369 // (remote) client full control over the direct session. For the
370 // console, it is the desired behavior (the ability to control
371 // VM execution is a must for the remote session). What about
372 // the machine object, we may want to prevent the remote client
373 // from modifying machine data. In this case, we must:
374 // 1) assign the Machine object (instead of the SessionMachine
375 // object that is passed to this method) to mRemoteMachine;
376 // 2) remove GetMachine() property from the IConsole interface
377 // because it always returns the SessionMachine object
378 // (alternatively, we can supply a separate IConsole
379 // implementation that will return the Machine object in
380 // response to GetMachine()).
381
382 mRemoteMachine = aMachine;
383 mRemoteConsole = aConsole;
384
385 /*
386 * Reference the VirtualBox object to ensure the server is up
387 * until the session is closed
388 */
389 rc = aMachine->COMGETTER(Parent) (mVirtualBox.asOutParam());
390
391 if (SUCCEEDED (rc))
392 {
393 /*
394 * RemoteSession type can be already set by AssignMachine() when its
395 * argument is NULL (a special case)
396 */
397 if (mType != SessionType_RemoteSession)
398 mType = SessionType_ExistingSession;
399 else
400 Assert (mState == SessionState_SessionSpawning);
401
402 mState = SessionState_SessionOpen;
403 }
404 else
405 {
406 /* some cleanup */
407 mControl.setNull();
408 mRemoteMachine.setNull();
409 mRemoteConsole.setNull();
410 }
411
412 LogFlowThisFunc (("rc=%08X\n", rc));
413 LogFlowThisFuncLeave();
414
415 return rc;
416}
417
418STDMETHODIMP Session::UpdateMachineState (MachineState_T aMachineState)
419{
420 AutoCaller autoCaller (this);
421
422 if (autoCaller.state() != Ready)
423 {
424 /*
425 * We might have already entered Session::uninit() at this point, so
426 * return silently (not interested in the state change during uninit)
427 */
428 LogFlowThisFunc (("Already uninitialized.\n"));
429 return S_OK;
430 }
431
432 AutoReaderLock alock (this);
433
434 if (mState == SessionState_SessionClosing)
435 {
436 LogFlowThisFunc (("Already being closed.\n"));
437 return S_OK;
438 }
439
440 AssertReturn (mState == SessionState_SessionOpen &&
441 mType == SessionType_DirectSession, E_FAIL);
442
443 AssertReturn (!mControl.isNull(), E_FAIL);
444 AssertReturn (!mConsole.isNull(), E_FAIL);
445
446 return mConsole->updateMachineState (aMachineState);
447}
448
449STDMETHODIMP Session::Uninitialize()
450{
451 LogFlowThisFuncEnter();
452
453 AutoCaller autoCaller (this);
454
455 HRESULT rc = S_OK;
456
457 if (autoCaller.state() == Ready)
458 {
459 AutoReaderLock alock (this);
460
461 LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
462
463 if (mState == SessionState_SessionClosing)
464 {
465 LogFlowThisFunc (("Already being closed.\n"));
466 return S_OK;
467 }
468
469 AssertReturn (mState == SessionState_SessionOpen, E_FAIL);
470
471 /* close ourselves */
472 rc = close (false /* aFinalRelease */, true /* aFromServer */);
473 }
474 else if (autoCaller.state() == InUninit)
475 {
476 /*
477 * We might have already entered Session::uninit() at this point,
478 * return silently
479 */
480 LogFlowThisFunc (("Already uninitialized.\n"));
481 }
482 else
483 {
484 LogWarningThisFunc (("UNEXPECTED uninitialization!\n"));
485 rc = autoCaller.rc();
486 }
487
488 LogFlowThisFunc (("rc=%08X\n", rc));
489 LogFlowThisFuncLeave();
490
491 return rc;
492}
493
494STDMETHODIMP Session::OnDVDDriveChange()
495{
496 LogFlowThisFunc (("\n"));
497
498 AutoCaller autoCaller (this);
499 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
500
501 AutoReaderLock alock (this);
502 AssertReturn (mState == SessionState_SessionOpen &&
503 mType == SessionType_DirectSession, E_FAIL);
504
505 return mConsole->onDVDDriveChange();
506}
507
508STDMETHODIMP Session::OnFloppyDriveChange()
509{
510 LogFlowThisFunc (("\n"));
511
512 AutoCaller autoCaller (this);
513 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
514
515 AutoReaderLock alock (this);
516 AssertReturn (mState == SessionState_SessionOpen &&
517 mType == SessionType_DirectSession, E_FAIL);
518
519 return mConsole->onFloppyDriveChange();
520}
521
522STDMETHODIMP Session::OnNetworkAdapterChange(INetworkAdapter *networkAdapter)
523{
524 LogFlowThisFunc (("\n"));
525
526 AutoCaller autoCaller (this);
527 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
528
529 AutoReaderLock alock (this);
530 AssertReturn (mState == SessionState_SessionOpen &&
531 mType == SessionType_DirectSession, E_FAIL);
532
533 return mConsole->onNetworkAdapterChange(networkAdapter);
534}
535
536STDMETHODIMP Session::OnVRDPServerChange()
537{
538 LogFlowThisFunc (("\n"));
539
540 AutoCaller autoCaller (this);
541 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
542
543 AutoReaderLock alock (this);
544 AssertReturn (mState == SessionState_SessionOpen &&
545 mType == SessionType_DirectSession, E_FAIL);
546
547 return mConsole->onVRDPServerChange();
548}
549
550STDMETHODIMP Session::OnUSBControllerChange()
551{
552 LogFlowThisFunc (("\n"));
553
554 AutoCaller autoCaller (this);
555 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
556
557 AutoReaderLock alock (this);
558 AssertReturn (mState == SessionState_SessionOpen &&
559 mType == SessionType_DirectSession, E_FAIL);
560
561 return mConsole->onUSBControllerChange();
562}
563
564STDMETHODIMP Session::OnUSBDeviceAttach (IUSBDevice *aDevice)
565{
566 LogFlowThisFunc (("\n"));
567
568 AutoCaller autoCaller (this);
569 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
570
571 AutoReaderLock alock (this);
572 AssertReturn (mState == SessionState_SessionOpen &&
573 mType == SessionType_DirectSession, E_FAIL);
574
575 return mConsole->onUSBDeviceAttach (aDevice);
576}
577
578STDMETHODIMP Session::OnUSBDeviceDetach (INPTR GUIDPARAM aId)
579{
580 LogFlowThisFunc (("\n"));
581
582 AutoCaller autoCaller (this);
583 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
584
585 AutoReaderLock alock (this);
586 AssertReturn (mState == SessionState_SessionOpen &&
587 mType == SessionType_DirectSession, E_FAIL);
588
589 return mConsole->onUSBDeviceDetach (aId);
590}
591
592STDMETHODIMP Session::OnShowWindow (BOOL aCheck, BOOL *aCanShow)
593{
594 AutoCaller autoCaller (this);
595 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
596
597 AutoReaderLock alock (this);
598 AssertReturn (mState == SessionState_SessionOpen &&
599 mType == SessionType_DirectSession, E_FAIL);
600
601 return mConsole->onShowWindow (aCheck, aCanShow);
602}
603
604// private methods
605///////////////////////////////////////////////////////////////////////////////
606
607/**
608 * Closes the current session.
609 *
610 * @param aFinalRelease called as a result of FinalRelease()
611 * @param aFromServer called as a result of Uninitialize()
612 *
613 * @note To be called only from #uninit(), #Close() or #Uninitialize().
614 * @note Locks this object for writing.
615 */
616HRESULT Session::close (bool aFinalRelease, bool aFromServer)
617{
618 LogFlowThisFuncEnter();
619 LogFlowThisFunc (("aFinalRelease=%d, isFromServer=%d\n",
620 aFinalRelease, aFromServer));
621
622 AutoCaller autoCaller (this);
623 AssertComRCReturnRC (autoCaller.rc());
624
625 AutoLock alock (this);
626
627 LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
628
629 if (mState != SessionState_SessionOpen)
630 {
631 Assert (mState == SessionState_SessionSpawning);
632
633 /* The session object is going to be uninitialized by the client before
634 * it has been assigned a direct console of the machine the client
635 * requested to open a remote session to using IVirtualBox::
636 * openRemoteSession(). Theoretically it should not happen because
637 * openRemoteSession() doesn't return control to the client until the
638 * procedure is fully complete, so assert here. */
639 AssertFailed();
640
641 mState = SessionState_SessionClosed;
642 mType = SessionType_InvalidSessionType;
643#if defined(__WIN__)
644 Assert (!mIPCSem && !mIPCThreadSem);
645#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
646 Assert (mIPCSem == -1);
647#endif
648 LogFlowThisFuncLeave();
649 return S_OK;
650 }
651
652 /* go to the closing state */
653 mState = SessionState_SessionClosing;
654
655 if (mType == SessionType_DirectSession)
656 {
657 mConsole->uninit();
658 mConsole.setNull();
659 }
660 else
661 {
662 mRemoteMachine.setNull();
663 mRemoteConsole.setNull();
664 }
665
666 ComPtr <IProgress> progress;
667
668 if (!aFinalRelease && !aFromServer)
669 {
670 /*
671 * We trigger OnSessionEnd() only when the session closes itself using
672 * Close(). Note that if isFinalRelease = TRUE here, this means that
673 * the client process has already initialized the termination procedure
674 * without issuing Close() and the IPC channel is no more operational --
675 * so we cannot call the server's method (it will definitely fail). The
676 * server will instead simply detect the abnormal client death (since
677 * OnSessionEnd() is not called) and reset the machine state to Aborted.
678 */
679
680 /*
681 * while waiting for OnSessionEnd() to complete one of our methods
682 * can be called by the server (for example, Uninitialize(), if the
683 * direct session has initiated a closure just a bit before us) so
684 * we need to release the lock to avoid deadlocks. The state is already
685 * SessionState_SessionClosing here, so it's safe.
686 */
687 alock.leave();
688
689 LogFlowThisFunc (("Calling mControl->OnSessionEnd()...\n"));
690 HRESULT rc = mControl->OnSessionEnd (this, progress.asOutParam());
691 LogFlowThisFunc (("mControl->OnSessionEnd()=%08X\n", rc));
692
693 alock.enter();
694
695 /*
696 * If we get E_UNEXPECTED this means that the direct session has already
697 * been closed, we're just too late with our notification and nothing more
698 */
699 if (mType != SessionType_DirectSession && rc == E_UNEXPECTED)
700 rc = S_OK;
701
702 AssertComRC (rc);
703 }
704
705 mControl.setNull();
706
707 if (mType == SessionType_DirectSession)
708 {
709 releaseIPCSemaphore();
710 if (!aFinalRelease && !aFromServer)
711 {
712 /*
713 * Wait for the server to grab the semaphore and destroy the session
714 * machine (allowing us to open a new session with the same machine
715 * once this method returns)
716 */
717 Assert (!!progress);
718 if (progress)
719 progress->WaitForCompletion (-1);
720 }
721 }
722
723 mState = SessionState_SessionClosed;
724 mType = SessionType_InvalidSessionType;
725
726 /* release the VirtualBox instance as the very last step */
727 mVirtualBox.setNull();
728
729 LogFlowThisFuncLeave();
730 return S_OK;
731}
732
733/** @note To be called only from #AssignMachine() */
734HRESULT Session::grabIPCSemaphore()
735{
736 HRESULT rc = E_FAIL;
737
738 /* open the IPC semaphore based on the sessionId and try to grab it */
739 Bstr ipcId;
740 rc = mControl->GetIPCId (ipcId.asOutParam());
741 AssertComRCReturn (rc, rc);
742
743 LogFlowThisFunc (("ipcId: {%ls}\n", ipcId.raw()));
744
745#if defined(__WIN__)
746
747 /*
748 * Since Session is an MTA object, this method can be executed on
749 * any thread, and this thread will not necessarily match the thread on
750 * which close() will be called later. Therefore, we need a separate
751 * thread to hold the IPC mutex and then release it in close().
752 */
753
754 mIPCThreadSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
755 AssertMsgReturn (mIPCThreadSem,
756 ("Cannot create an event sem, err=%d", ::GetLastError()),
757 E_FAIL);
758
759 void *data [3];
760 data [0] = (void *) (BSTR) ipcId;
761 data [1] = (void *) mIPCThreadSem;
762 data [2] = 0; /* will get an output from the thread */
763
764 /* create the thread to hold the IPC mutex until signalled to release it */
765 RTTHREAD tid;
766 int vrc = RTThreadCreate (&tid, IPCMutexHolderThread, (void *) data,
767 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
768 AssertRCReturn (vrc, E_FAIL);
769
770 /* wait until thread init is completed */
771 DWORD wrc = ::WaitForSingleObject (mIPCThreadSem, INFINITE);
772 AssertMsg (wrc == WAIT_OBJECT_0, ("Wait failed, err=%d", ::GetLastError()));
773 Assert (data [2]);
774
775 if (wrc == WAIT_OBJECT_0 && data [2])
776 {
777 /* memorize the event sem we should signal in close() */
778 mIPCSem = (HANDLE) data [2];
779 rc = S_OK;
780 }
781 else
782 {
783 ::CloseHandle (mIPCThreadSem);
784 mIPCThreadSem = NULL;
785 rc = E_FAIL;
786 }
787
788#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
789
790 Utf8Str semName = ipcId;
791 char *pszSemName = NULL;
792 RTStrUtf8ToCurrentCP (&pszSemName, semName);
793 key_t key = ::ftok (pszSemName, 0);
794 RTStrFree (pszSemName);
795
796 mIPCSem = ::semget (key, 0, 0);
797 AssertMsgReturn (mIPCSem >= 0,
798 ("Cannot open IPC semaphore, errno=%d", errno),
799 E_FAIL);
800
801 /* grab the semaphore */
802 ::sembuf sop = { 0, -1, SEM_UNDO };
803 int rv = ::semop (mIPCSem, &sop, 1);
804 AssertMsgReturn (rv == 0,
805 ("Cannot grab IPC semaphore, errno=%d", errno),
806 E_FAIL);
807
808#endif
809
810 return rc;
811}
812
813/** @note To be called only from #close() */
814void Session::releaseIPCSemaphore()
815{
816 /* release the IPC semaphore */
817#if defined(__WIN__)
818 if (mIPCSem && mIPCThreadSem)
819 {
820 /*
821 * say the thread holding the IPC mutex to release it;
822 * it will close mIPCSem handle
823 */
824 ::SetEvent (mIPCSem);
825 /* wait for the thread to finish */
826 ::WaitForSingleObject (mIPCThreadSem, INFINITE);
827 ::CloseHandle (mIPCThreadSem);
828 }
829#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
830 if (mIPCSem >= 0)
831 {
832 ::sembuf sop = { 0, 1, SEM_UNDO };
833 ::semop (mIPCSem, &sop, 1);
834 }
835#endif
836}
837
838#if defined(__WIN__)
839/** VM IPC mutex holder thread */
840DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
841{
842 LogFlowFuncEnter();
843
844 Assert (pvUser);
845 void **data = (void **) pvUser;
846
847 BSTR sessionId = (BSTR) data [0];
848 HANDLE initDoneSem = (HANDLE) data [1];
849
850 HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId);
851 AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%08X\n", ::GetLastError()));
852
853 if (ipcMutex)
854 {
855 /* grab the mutex */
856 DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);
857 AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));
858 if (wrc == WAIT_OBJECT_0)
859 {
860 HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
861 AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));
862 if (finishSem)
863 {
864 data [2] = (void *) finishSem;
865 /* signal we're done with init */
866 ::SetEvent (initDoneSem);
867 /* wait until we're signaled to release the IPC mutex */
868 ::WaitForSingleObject (finishSem, INFINITE);
869 /* release the IPC mutex */
870 LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));
871 BOOL success = ::ReleaseMutex (ipcMutex);
872 AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));
873 ::CloseHandle (ipcMutex);
874 ::CloseHandle (finishSem);
875 }
876 }
877 }
878
879 /* signal we're done */
880 ::SetEvent (initDoneSem);
881
882 LogFlowFuncLeave();
883
884 return 0;
885}
886#endif
887
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette