VirtualBox

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

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

WIN32 -> WIN.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.8 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
592// private methods
593///////////////////////////////////////////////////////////////////////////////
594
595/**
596 * Closes the current session.
597 *
598 * @param aFinalRelease called as a result of FinalRelease()
599 * @param aFromServer called as a result of Uninitialize()
600 *
601 * @note To be called only from #uninit(), #Close() or #Uninitialize().
602 * @note Locks this object for writing.
603 */
604HRESULT Session::close (bool aFinalRelease, bool aFromServer)
605{
606 LogFlowThisFuncEnter();
607 LogFlowThisFunc (("aFinalRelease=%d, isFromServer=%d\n",
608 aFinalRelease, aFromServer));
609
610 AutoCaller autoCaller (this);
611 AssertComRCReturnRC (autoCaller.rc());
612
613 AutoLock alock (this);
614
615 LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
616
617 if (mState != SessionState_SessionOpen)
618 {
619 Assert (mState == SessionState_SessionSpawning);
620
621 /* The session object is going to be uninitialized by the client before
622 * it has been assigned a direct console of the machine the client
623 * requested to open a remote session to using IVirtualBox::
624 * openRemoteSession(). Theoretically it should not happen because
625 * openRemoteSession() doesn't return control to the client until the
626 * procedure is fully complete, so assert here. */
627 AssertFailed();
628
629 mState = SessionState_SessionClosed;
630 mType = SessionType_InvalidSessionType;
631#if defined(__WIN__)
632 Assert (!mIPCSem && !mIPCThreadSem);
633#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
634 Assert (mIPCSem == -1);
635#endif
636 LogFlowThisFuncLeave();
637 return S_OK;
638 }
639
640 /* go to the closing state */
641 mState = SessionState_SessionClosing;
642
643 if (mType == SessionType_DirectSession)
644 {
645 mConsole->uninit();
646 mConsole.setNull();
647 }
648 else
649 {
650 mRemoteMachine.setNull();
651 mRemoteConsole.setNull();
652 }
653
654 ComPtr <IProgress> progress;
655
656 if (!aFinalRelease && !aFromServer)
657 {
658 /*
659 * We trigger OnSessionEnd() only when the session closes itself using
660 * Close(). Note that if isFinalRelease = TRUE here, this means that
661 * the client process has already initialized the termination procedure
662 * without issuing Close() and the IPC channel is no more operational --
663 * so we cannot call the server's method (it will definitely fail). The
664 * server will instead simply detect the abnormal client death (since
665 * OnSessionEnd() is not called) and reset the machine state to Aborted.
666 */
667
668 /*
669 * while waiting for OnSessionEnd() to complete one of our methods
670 * can be called by the server (for example, Uninitialize(), if the
671 * direct session has initiated a closure just a bit before us) so
672 * we need to release the lock to avoid deadlocks. The state is already
673 * SessionState_SessionClosing here, so it's safe.
674 */
675 alock.leave();
676
677 LogFlowThisFunc (("Calling mControl->OnSessionEnd()...\n"));
678 HRESULT rc = mControl->OnSessionEnd (this, progress.asOutParam());
679 LogFlowThisFunc (("mControl->OnSessionEnd()=%08X\n", rc));
680
681 alock.enter();
682
683 /*
684 * If we get E_UNEXPECTED this means that the direct session has already
685 * been closed, we're just too late with our notification and nothing more
686 */
687 if (mType != SessionType_DirectSession && rc == E_UNEXPECTED)
688 rc = S_OK;
689
690 AssertComRC (rc);
691 }
692
693 mControl.setNull();
694
695 if (mType == SessionType_DirectSession)
696 {
697 releaseIPCSemaphore();
698 if (!aFinalRelease && !aFromServer)
699 {
700 /*
701 * Wait for the server to grab the semaphore and destroy the session
702 * machine (allowing us to open a new session with the same machine
703 * once this method returns)
704 */
705 Assert (!!progress);
706 if (progress)
707 progress->WaitForCompletion (-1);
708 }
709 }
710
711 mState = SessionState_SessionClosed;
712 mType = SessionType_InvalidSessionType;
713
714 /* release the VirtualBox instance as the very last step */
715 mVirtualBox.setNull();
716
717 LogFlowThisFuncLeave();
718 return S_OK;
719}
720
721/** @note To be called only from #AssignMachine() */
722HRESULT Session::grabIPCSemaphore()
723{
724 HRESULT rc = E_FAIL;
725
726 /* open the IPC semaphore based on the sessionId and try to grab it */
727 Bstr ipcId;
728 rc = mControl->GetIPCId (ipcId.asOutParam());
729 AssertComRCReturn (rc, rc);
730
731 LogFlowThisFunc (("ipcId: {%ls}\n", ipcId.raw()));
732
733#if defined(__WIN__)
734
735 /*
736 * Since Session is an MTA object, this method can be executed on
737 * any thread, and this thread will not necessarily match the thread on
738 * which close() will be called later. Therefore, we need a separate
739 * thread to hold the IPC mutex and then release it in close().
740 */
741
742 mIPCThreadSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
743 AssertMsgReturn (mIPCThreadSem,
744 ("Cannot create an event sem, err=%d", ::GetLastError()),
745 E_FAIL);
746
747 void *data [3];
748 data [0] = (void *) (BSTR) ipcId;
749 data [1] = (void *) mIPCThreadSem;
750 data [2] = 0; /* will get an output from the thread */
751
752 /* create the thread to hold the IPC mutex until signalled to release it */
753 RTTHREAD tid;
754 int vrc = RTThreadCreate (&tid, IPCMutexHolderThread, (void *) data,
755 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
756 AssertRCReturn (vrc, E_FAIL);
757
758 /* wait until thread init is completed */
759 DWORD wrc = ::WaitForSingleObject (mIPCThreadSem, INFINITE);
760 AssertMsg (wrc == WAIT_OBJECT_0, ("Wait failed, err=%d", ::GetLastError()));
761 Assert (data [2]);
762
763 if (wrc == WAIT_OBJECT_0 && data [2])
764 {
765 /* memorize the event sem we should signal in close() */
766 mIPCSem = (HANDLE) data [2];
767 rc = S_OK;
768 }
769 else
770 {
771 ::CloseHandle (mIPCThreadSem);
772 mIPCThreadSem = NULL;
773 rc = E_FAIL;
774 }
775
776#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
777
778 Utf8Str semName = ipcId;
779 char *pszSemName = NULL;
780 RTStrUtf8ToCurrentCP (&pszSemName, semName);
781 key_t key = ::ftok (pszSemName, 0);
782 RTStrFree (pszSemName);
783
784 mIPCSem = ::semget (key, 0, 0);
785 AssertMsgReturn (mIPCSem >= 0,
786 ("Cannot open IPC semaphore, errno=%d", errno),
787 E_FAIL);
788
789 /* grab the semaphore */
790 ::sembuf sop = { 0, -1, SEM_UNDO };
791 int rv = ::semop (mIPCSem, &sop, 1);
792 AssertMsgReturn (rv == 0,
793 ("Cannot grab IPC semaphore, errno=%d", errno),
794 E_FAIL);
795
796#endif
797
798 return rc;
799}
800
801/** @note To be called only from #close() */
802void Session::releaseIPCSemaphore()
803{
804 /* release the IPC semaphore */
805#if defined(__WIN__)
806 if (mIPCSem && mIPCThreadSem)
807 {
808 /*
809 * say the thread holding the IPC mutex to release it;
810 * it will close mIPCSem handle
811 */
812 ::SetEvent (mIPCSem);
813 /* wait for the thread to finish */
814 ::WaitForSingleObject (mIPCThreadSem, INFINITE);
815 ::CloseHandle (mIPCThreadSem);
816 }
817#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
818 if (mIPCSem >= 0)
819 {
820 ::sembuf sop = { 0, 1, SEM_UNDO };
821 ::semop (mIPCSem, &sop, 1);
822 }
823#endif
824}
825
826#if defined(__WIN__)
827/** VM IPC mutex holder thread */
828DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
829{
830 LogFlowFuncEnter();
831
832 Assert (pvUser);
833 void **data = (void **) pvUser;
834
835 BSTR sessionId = (BSTR) data [0];
836 HANDLE initDoneSem = (HANDLE) data [1];
837
838 HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId);
839 AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%08X\n", ::GetLastError()));
840
841 if (ipcMutex)
842 {
843 /* grab the mutex */
844 DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);
845 AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));
846 if (wrc == WAIT_OBJECT_0)
847 {
848 HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
849 AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));
850 if (finishSem)
851 {
852 data [2] = (void *) finishSem;
853 /* signal we're done with init */
854 ::SetEvent (initDoneSem);
855 /* wait until we're signaled to release the IPC mutex */
856 ::WaitForSingleObject (finishSem, INFINITE);
857 /* release the IPC mutex */
858 LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));
859 BOOL success = ::ReleaseMutex (ipcMutex);
860 AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));
861 ::CloseHandle (ipcMutex);
862 ::CloseHandle (finishSem);
863 }
864 }
865 }
866
867 /* signal we're done */
868 ::SetEvent (initDoneSem);
869
870 LogFlowFuncLeave();
871
872 return 0;
873}
874#endif
875
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