VirtualBox

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

最後變更 在這個檔案從606是 606,由 vboxsync 提交於 18 年 前

Initial darwin port. (Not tested on linux yet.)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 23.8 KB
 
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.alldomusa.eu.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
253 return S_OK;
254}
255
256STDMETHODIMP Session::GetRemoteConsole (IConsole **aConsole)
257{
258 AssertReturn (aConsole, E_POINTER);
259
260 AutoCaller autoCaller (this);
261 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
262
263 AutoReaderLock alock (this);
264
265 AssertReturn (mState == SessionState_SessionOpen, E_FAIL);
266
267 AssertMsgReturn (mType == SessionType_DirectSession && !!mConsole,
268 ("This is not a direct session!\n"), E_FAIL);
269
270 mConsole.queryInterfaceTo (aConsole);
271
272 return S_OK;
273}
274
275STDMETHODIMP Session::AssignMachine (IMachine *aMachine)
276{
277 LogFlowThisFuncEnter();
278 LogFlowThisFunc (("aMachine=%p\n", aMachine));
279
280 AutoCaller autoCaller (this);
281 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
282
283 AutoLock alock (this);
284
285 AssertReturn (mState == SessionState_SessionClosed, E_FAIL);
286
287 if (!aMachine)
288 {
289 /*
290 * A special case: the server informs us that this session has been
291 * passed to IVirtualBox::OpenRemoteSession() so this session will
292 * become remote (but not existing) when AssignRemoteMachine() is
293 * called.
294 */
295
296 AssertReturn (mType == SessionType_InvalidSessionType, E_FAIL);
297 mType = SessionType_RemoteSession;
298 mState = SessionState_SessionSpawning;
299
300 LogFlowThisFuncLeave();
301 return S_OK;
302 }
303
304 HRESULT rc = E_FAIL;
305
306 /* query IInternalMachineControl interface */
307 mControl = aMachine;
308 AssertReturn (!!mControl, E_FAIL);
309
310 rc = mConsole.createObject();
311 AssertComRCReturn (rc, rc);
312
313 rc = mConsole->init (aMachine, mControl);
314 AssertComRCReturn (rc, rc);
315
316 rc = grabIPCSemaphore();
317
318 /*
319 * Reference the VirtualBox object to ensure the server is up
320 * until the session is closed
321 */
322 if (SUCCEEDED (rc))
323 rc = aMachine->COMGETTER(Parent) (mVirtualBox.asOutParam());
324
325 if (SUCCEEDED (rc))
326 {
327 mType = SessionType_DirectSession;
328 mState = SessionState_SessionOpen;
329 }
330 else
331 {
332 /* some cleanup */
333 mControl.setNull();
334 mConsole->uninit();
335 mConsole.setNull();
336 }
337
338 LogFlowThisFunc (("rc=%08X\n", rc));
339 LogFlowThisFuncLeave();
340
341 return rc;
342}
343
344STDMETHODIMP Session::AssignRemoteMachine (IMachine *aMachine, IConsole *aConsole)
345{
346 LogFlowThisFuncEnter();
347 LogFlowThisFunc (("aMachine=%p, aConsole=%p\n", aMachine, aConsole));
348
349 AssertReturn (aMachine && aConsole, E_INVALIDARG);
350
351 AutoCaller autoCaller (this);
352 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
353
354 AutoLock alock (this);
355
356 AssertReturn (mState == SessionState_SessionClosed ||
357 mState == SessionState_SessionSpawning, E_FAIL);
358
359 HRESULT rc = E_FAIL;
360
361 /* query IInternalMachineControl interface */
362 mControl = aMachine;
363 AssertReturn (!!mControl, E_FAIL);
364
365 /// @todo (dmik)
366 // currently, the remote session returns the same machine and
367 // console objects as the direct session, thus giving the
368 // (remote) client full control over the direct session. For the
369 // console, it is the desired behavior (the ability to control
370 // VM execution is a must for the remote session). What about
371 // the machine object, we may want to prevent the remote client
372 // from modifying machine data. In this case, we must:
373 // 1) assign the Machine object (instead of the SessionMachine
374 // object that is passed to this method) to mRemoteMachine;
375 // 2) remove GetMachine() property from the IConsole interface
376 // because it always returns the SessionMachine object
377 // (alternatively, we can supply a separate IConsole
378 // implementation that will return the Machine object in
379 // response to GetMachine()).
380
381 mRemoteMachine = aMachine;
382 mRemoteConsole = aConsole;
383
384 /*
385 * Reference the VirtualBox object to ensure the server is up
386 * until the session is closed
387 */
388 rc = aMachine->COMGETTER(Parent) (mVirtualBox.asOutParam());
389
390 if (SUCCEEDED (rc))
391 {
392 /*
393 * RemoteSession type can be already set by AssignMachine() when its
394 * argument is NULL (a special case)
395 */
396 if (mType != SessionType_RemoteSession)
397 mType = SessionType_ExistingSession;
398 else
399 Assert (mState == SessionState_SessionSpawning);
400
401 mState = SessionState_SessionOpen;
402 }
403 else
404 {
405 /* some cleanup */
406 mControl.setNull();
407 mRemoteMachine.setNull();
408 mRemoteConsole.setNull();
409 }
410
411 LogFlowThisFunc (("rc=%08X\n", rc));
412 LogFlowThisFuncLeave();
413
414 return rc;
415}
416
417STDMETHODIMP Session::UpdateMachineState (MachineState_T aMachineState)
418{
419 AutoCaller autoCaller (this);
420
421 if (autoCaller.state() != Ready)
422 {
423 /*
424 * We might have already entered Session::uninit() at this point, so
425 * return silently (not interested in the state change during uninit)
426 */
427 LogFlowThisFunc (("Already uninitialized.\n"));
428 return S_OK;
429 }
430
431 AutoReaderLock alock (this);
432
433 if (mState == SessionState_SessionClosing)
434 {
435 LogFlowThisFunc (("Already being closed.\n"));
436 return S_OK;
437 }
438
439 AssertReturn (mState == SessionState_SessionOpen &&
440 mType == SessionType_DirectSession, E_FAIL);
441
442 AssertReturn (!mControl.isNull(), E_FAIL);
443 AssertReturn (!mConsole.isNull(), E_FAIL);
444
445 return mConsole->updateMachineState (aMachineState);
446}
447
448STDMETHODIMP Session::Uninitialize()
449{
450 LogFlowThisFuncEnter();
451
452 AutoCaller autoCaller (this);
453
454 HRESULT rc = S_OK;
455
456 if (autoCaller.state() == Ready)
457 {
458 AutoReaderLock alock (this);
459
460 LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
461
462 if (mState == SessionState_SessionClosing)
463 {
464 LogFlowThisFunc (("Already being closed.\n"));
465 return S_OK;
466 }
467
468 AssertReturn (mState == SessionState_SessionOpen, E_FAIL);
469
470 /* close ourselves */
471 rc = close (false /* aFinalRelease */, true /* aFromServer */);
472 }
473 else if (autoCaller.state() == InUninit)
474 {
475 /*
476 * We might have already entered Session::uninit() at this point,
477 * return silently
478 */
479 LogFlowThisFunc (("Already uninitialized.\n"));
480 }
481 else
482 {
483 LogWarningThisFunc (("UNEXPECTED uninitialization!\n"));
484 rc = autoCaller.rc();
485 }
486
487 LogFlowThisFunc (("rc=%08X\n", rc));
488 LogFlowThisFuncLeave();
489
490 return rc;
491}
492
493STDMETHODIMP Session::OnDVDDriveChange()
494{
495 LogFlowThisFunc (("\n"));
496
497 AutoCaller autoCaller (this);
498 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
499
500 AutoReaderLock alock (this);
501 AssertReturn (mState == SessionState_SessionOpen &&
502 mType == SessionType_DirectSession, E_FAIL);
503
504 return mConsole->onDVDDriveChange();
505}
506
507STDMETHODIMP Session::OnFloppyDriveChange()
508{
509 LogFlowThisFunc (("\n"));
510
511 AutoCaller autoCaller (this);
512 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
513
514 AutoReaderLock alock (this);
515 AssertReturn (mState == SessionState_SessionOpen &&
516 mType == SessionType_DirectSession, E_FAIL);
517
518 return mConsole->onFloppyDriveChange();
519}
520
521STDMETHODIMP Session::OnNetworkAdapterChange(INetworkAdapter *networkAdapter)
522{
523 LogFlowThisFunc (("\n"));
524
525 AutoCaller autoCaller (this);
526 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
527
528 AutoReaderLock alock (this);
529 AssertReturn (mState == SessionState_SessionOpen &&
530 mType == SessionType_DirectSession, E_FAIL);
531
532 return mConsole->onNetworkAdapterChange(networkAdapter);
533}
534
535STDMETHODIMP Session::OnVRDPServerChange()
536{
537 LogFlowThisFunc (("\n"));
538
539 AutoCaller autoCaller (this);
540 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
541
542 AutoReaderLock alock (this);
543 AssertReturn (mState == SessionState_SessionOpen &&
544 mType == SessionType_DirectSession, E_FAIL);
545
546 return mConsole->onVRDPServerChange();
547}
548
549STDMETHODIMP Session::OnUSBControllerChange()
550{
551 LogFlowThisFunc (("\n"));
552
553 AutoCaller autoCaller (this);
554 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
555
556 AutoReaderLock alock (this);
557 AssertReturn (mState == SessionState_SessionOpen &&
558 mType == SessionType_DirectSession, E_FAIL);
559
560 return mConsole->onUSBControllerChange();
561}
562
563STDMETHODIMP Session::OnUSBDeviceAttach (IUSBDevice *aDevice)
564{
565 LogFlowThisFunc (("\n"));
566
567 AutoCaller autoCaller (this);
568 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
569
570 AutoReaderLock alock (this);
571 AssertReturn (mState == SessionState_SessionOpen &&
572 mType == SessionType_DirectSession, E_FAIL);
573
574 return mConsole->onUSBDeviceAttach (aDevice);
575}
576
577STDMETHODIMP Session::OnUSBDeviceDetach (INPTR GUIDPARAM aId)
578{
579 LogFlowThisFunc (("\n"));
580
581 AutoCaller autoCaller (this);
582 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
583
584 AutoReaderLock alock (this);
585 AssertReturn (mState == SessionState_SessionOpen &&
586 mType == SessionType_DirectSession, E_FAIL);
587
588 return mConsole->onUSBDeviceDetach (aId);
589}
590
591// private methods
592///////////////////////////////////////////////////////////////////////////////
593
594/**
595 * Closes the current session.
596 *
597 * @param aFinalRelease called as a result of FinalRelease()
598 * @param aFromServer called as a result of Uninitialize()
599 *
600 * @note To be called only from #uninit(), #Close() or #Uninitialize().
601 * @note Locks this object for writing.
602 */
603HRESULT Session::close (bool aFinalRelease, bool aFromServer)
604{
605 LogFlowThisFuncEnter();
606 LogFlowThisFunc (("aFinalRelease=%d, isFromServer=%d\n",
607 aFinalRelease, aFromServer));
608
609 AutoCaller autoCaller (this);
610 AssertComRCReturnRC (autoCaller.rc());
611
612 AutoLock alock (this);
613
614 LogFlowThisFunc (("mState=%d, mType=%d\n", mState, mType));
615
616 if (mState != SessionState_SessionOpen)
617 {
618 Assert (mState == SessionState_SessionSpawning);
619
620 /* The session object is going to be uninitialized by the client before
621 * it has been assigned a direct console of the machine the client
622 * requested to open a remote session to using IVirtualBox::
623 * openRemoteSession(). Theoretically it should not happen because
624 * openRemoteSession() doesn't return control to the client until the
625 * procedure is fully complete, so assert here. */
626 AssertFailed();
627
628 mState = SessionState_SessionClosed;
629 mType = SessionType_InvalidSessionType;
630#if defined(__WIN32__)
631 Assert (!mIPCSem && !mIPCThreadSem);
632#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
633 Assert (mIPCSem == -1);
634#endif
635 LogFlowThisFuncLeave();
636 return S_OK;
637 }
638
639 /* go to the closing state */
640 mState = SessionState_SessionClosing;
641
642 if (mType == SessionType_DirectSession)
643 {
644 mConsole->uninit();
645 mConsole.setNull();
646 }
647 else
648 {
649 mRemoteMachine.setNull();
650 mRemoteConsole.setNull();
651 }
652
653 ComPtr <IProgress> progress;
654
655 if (!aFinalRelease && !aFromServer)
656 {
657 /*
658 * We trigger OnSessionEnd() only when the session closes itself using
659 * Close(). Note that if isFinalRelease = TRUE here, this means that
660 * the client process has already initialized the termination procedure
661 * without issuing Close() and the IPC channel is no more operational --
662 * so we cannot call the server's method (it will definitely fail). The
663 * server will instead simply detect the abnormal client death (since
664 * OnSessionEnd() is not called) and reset the machine state to Aborted.
665 */
666
667 /*
668 * while waiting for OnSessionEnd() to complete one of our methods
669 * can be called by the server (for example, Uninitialize(), if the
670 * direct session has initiated a closure just a bit before us) so
671 * we need to release the lock to avoid deadlocks. The state is already
672 * SessionState_SessionClosing here, so it's safe.
673 */
674 alock.leave();
675
676 LogFlowThisFunc (("Calling mControl->OnSessionEnd()...\n"));
677 HRESULT rc = mControl->OnSessionEnd (this, progress.asOutParam());
678 LogFlowThisFunc (("mControl->OnSessionEnd()=%08X\n", rc));
679
680 alock.enter();
681
682 /*
683 * If we get E_UNEXPECTED this means that the direct session has already
684 * been closed, we're just too late with our notification and nothing more
685 */
686 if (mType != SessionType_DirectSession && rc == E_UNEXPECTED)
687 rc = S_OK;
688
689 AssertComRC (rc);
690 }
691
692 mControl.setNull();
693
694 if (mType == SessionType_DirectSession)
695 {
696 releaseIPCSemaphore();
697 if (!aFinalRelease && !aFromServer)
698 {
699 /*
700 * Wait for the server to grab the semaphore and destroy the session
701 * machine (allowing us to open a new session with the same machine
702 * once this method returns)
703 */
704 Assert (!!progress);
705 if (progress)
706 progress->WaitForCompletion (-1);
707 }
708 }
709
710 mState = SessionState_SessionClosed;
711 mType = SessionType_InvalidSessionType;
712
713 /* release the VirtualBox instance as the very last step */
714 mVirtualBox.setNull();
715
716 LogFlowThisFuncLeave();
717 return S_OK;
718}
719
720/** @note To be called only from #AssignMachine() */
721HRESULT Session::grabIPCSemaphore()
722{
723 HRESULT rc = E_FAIL;
724
725 /* open the IPC semaphore based on the sessionId and try to grab it */
726 Bstr ipcId;
727 rc = mControl->GetIPCId (ipcId.asOutParam());
728 AssertComRCReturn (rc, rc);
729
730 LogFlowThisFunc (("ipcId: {%ls}\n", ipcId.raw()));
731
732#if defined(__WIN__)
733
734 /*
735 * Since Session is an MTA object, this method can be executed on
736 * any thread, and this thread will not necessarily match the thread on
737 * which close() will be called later. Therefore, we need a separate
738 * thread to hold the IPC mutex and then release it in close().
739 */
740
741 mIPCThreadSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
742 AssertMsgReturn (mIPCThreadSem,
743 ("Cannot create an event sem, err=%d", ::GetLastError()),
744 E_FAIL);
745
746 void *data [3];
747 data [0] = (void *) (BSTR) ipcId;
748 data [1] = (void *) mIPCThreadSem;
749 data [2] = 0; /* will get an output from the thread */
750
751 /* create the thread to hold the IPC mutex until signalled to release it */
752 RTTHREAD tid;
753 int vrc = RTThreadCreate (&tid, IPCMutexHolderThread, (void *) data,
754 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
755 AssertRCReturn (vrc, E_FAIL);
756
757 /* wait until thread init is completed */
758 DWORD wrc = ::WaitForSingleObject (mIPCThreadSem, INFINITE);
759 AssertMsg (wrc == WAIT_OBJECT_0, ("Wait failed, err=%d", ::GetLastError()));
760 Assert (data [2]);
761
762 if (wrc == WAIT_OBJECT_0 && data [2])
763 {
764 /* memorize the event sem we should signal in close() */
765 mIPCSem = (HANDLE) data [2];
766 rc = S_OK;
767 }
768 else
769 {
770 ::CloseHandle (mIPCThreadSem);
771 mIPCThreadSem = NULL;
772 rc = E_FAIL;
773 }
774
775#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
776
777 Utf8Str semName = ipcId;
778 char *pszSemName = NULL;
779 RTStrUtf8ToCurrentCP (&pszSemName, semName);
780 key_t key = ::ftok (pszSemName, 0);
781 RTStrFree (pszSemName);
782
783 mIPCSem = ::semget (key, 0, 0);
784 AssertMsgReturn (mIPCSem >= 0,
785 ("Cannot open IPC semaphore, errno=%d", errno),
786 E_FAIL);
787
788 /* grab the semaphore */
789 ::sembuf sop = { 0, -1, SEM_UNDO };
790 int rv = ::semop (mIPCSem, &sop, 1);
791 AssertMsgReturn (rv == 0,
792 ("Cannot grab IPC semaphore, errno=%d", errno),
793 E_FAIL);
794
795#endif
796
797 return rc;
798}
799
800/** @note To be called only from #close() */
801void Session::releaseIPCSemaphore()
802{
803 /* release the IPC semaphore */
804#if defined(__WIN__)
805 if (mIPCSem && mIPCThreadSem)
806 {
807 /*
808 * say the thread holding the IPC mutex to release it;
809 * it will close mIPCSem handle
810 */
811 ::SetEvent (mIPCSem);
812 /* wait for the thread to finish */
813 ::WaitForSingleObject (mIPCThreadSem, INFINITE);
814 ::CloseHandle (mIPCThreadSem);
815 }
816#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
817 if (mIPCSem >= 0)
818 {
819 ::sembuf sop = { 0, 1, SEM_UNDO };
820 ::semop (mIPCSem, &sop, 1);
821 }
822#endif
823}
824
825#if defined(__WIN__)
826/** VM IPC mutex holder thread */
827DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
828{
829 LogFlowFuncEnter();
830
831 Assert (pvUser);
832 void **data = (void **) pvUser;
833
834 BSTR sessionId = (BSTR) data [0];
835 HANDLE initDoneSem = (HANDLE) data [1];
836
837 HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId);
838 AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%08X\n", ::GetLastError()));
839
840 if (ipcMutex)
841 {
842 /* grab the mutex */
843 DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);
844 AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));
845 if (wrc == WAIT_OBJECT_0)
846 {
847 HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
848 AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));
849 if (finishSem)
850 {
851 data [2] = (void *) finishSem;
852 /* signal we're done with init */
853 ::SetEvent (initDoneSem);
854 /* wait until we're signaled to release the IPC mutex */
855 ::WaitForSingleObject (finishSem, INFINITE);
856 /* release the IPC mutex */
857 LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));
858 BOOL success = ::ReleaseMutex (ipcMutex);
859 AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));
860 ::CloseHandle (ipcMutex);
861 ::CloseHandle (finishSem);
862 }
863 }
864 }
865
866 /* signal we're done */
867 ::SetEvent (initDoneSem);
868
869 LogFlowFuncLeave();
870
871 return 0;
872}
873#endif
874
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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