VirtualBox

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

Last change on this file since 400 was 1, checked in by vboxsync, 55 years ago

import

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