VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/SessionImpl.cpp@ 42261

Last change on this file since 42261 was 42261, checked in by vboxsync, 12 years ago

enabled shared clipboard support for Linux hosts (guest=>host only)

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