VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp@ 35650

Last change on this file since 35650 was 35638, checked in by vboxsync, 14 years ago

Main. QT/FE: fix long standing COM issue

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 35638 2011-01-19 19:10:49Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2010 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#include "VirtualBoxClientImpl.h"
19
20#include "AutoCaller.h"
21#include "VBoxEvents.h"
22#include "Logging.h"
23
24#include <iprt/asm.h>
25#include <iprt/thread.h>
26#include <iprt/critsect.h>
27#include <iprt/semaphore.h>
28#include <iprt/cpp/utils.h>
29
30
31/** Waiting time between probing whether VBoxSVC is alive. */
32#define VBOXCLIENT_DEFAULT_INTERVAL 30000
33
34
35/** Initialize instance counter class variable */
36uint32_t VirtualBoxClient::g_cInstances = 0;
37
38
39// constructor / destructor
40/////////////////////////////////////////////////////////////////////////////
41
42HRESULT VirtualBoxClient::FinalConstruct()
43{
44 HRESULT rc = init();
45 BaseFinalConstruct();
46 return rc;
47}
48
49void VirtualBoxClient::FinalRelease()
50{
51 uninit();
52 BaseFinalRelease();
53}
54
55// public initializer/uninitializer for internal purposes only
56/////////////////////////////////////////////////////////////////////////////
57
58/**
59 * Initializes the VirtualBoxClient object.
60 *
61 * @returns COM result indicator
62 */
63HRESULT VirtualBoxClient::init()
64{
65 LogFlowThisFunc(("\n"));
66
67 HRESULT rc;
68 /* Enclose the state transition NotReady->InInit->Ready */
69 AutoInitSpan autoInitSpan(this);
70 AssertReturn(autoInitSpan.isOk(), E_FAIL);
71
72 mData.m_ThreadWatcher = NIL_RTTHREAD;
73 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
74
75 if (ASMAtomicIncU32(&g_cInstances) != 1)
76 AssertFailedReturn(E_FAIL);
77
78 rc = mData.m_pVirtualBox.createLocalObject(CLSID_VirtualBox);
79 AssertComRCReturnRC(rc);
80
81 rc = unconst(mData.m_pEventSource).createObject();
82 AssertComRCReturnRC(rc);
83 rc = mData.m_pEventSource->init(static_cast<IVirtualBoxClient *>(this));
84 AssertComRCReturnRC(rc);
85
86 /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it
87 * is not considered important enough to cause any sort of visible
88 * failure. The monitoring will not be done, but that's all. */
89 int vrc = RTSemEventCreate(&mData.m_SemEvWatcher);
90 AssertRC(vrc);
91 if (RT_SUCCESS(vrc))
92 {
93 vrc = RTThreadCreate(&mData.m_ThreadWatcher, SVCWatcherThread,
94 this, 0, RTTHREADTYPE_INFREQUENT_POLLER,
95 RTTHREADFLAGS_WAITABLE, "VBoxSVCWatcher");
96 AssertRC(vrc);
97 }
98 else
99 {
100 RTSemEventDestroy(mData.m_SemEvWatcher);
101 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
102 }
103
104 /* Confirm a successful initialization */
105 autoInitSpan.setSucceeded();
106
107 return rc;
108}
109
110/**
111 * Uninitializes the instance and sets the ready flag to FALSE.
112 * Called either from FinalRelease() or by the parent when it gets destroyed.
113 */
114void VirtualBoxClient::uninit()
115{
116 LogFlowThisFunc(("\n"));
117
118 /* Enclose the state transition Ready->InUninit->NotReady */
119 AutoUninitSpan autoUninitSpan(this);
120 if (autoUninitSpan.uninitDone())
121 return;
122
123 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
124 {
125 /* Signal the event semaphore and wait for the thread to terminate.
126 * if it hangs for some reason exit anyway, this can cause a crash
127 * though as the object will no longer be available. */
128 RTSemEventSignal(mData.m_SemEvWatcher);
129 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
130 mData.m_ThreadWatcher = NIL_RTTHREAD;
131 RTSemEventDestroy(mData.m_SemEvWatcher);
132 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
133 }
134
135 mData.m_pVirtualBox.setNull();
136
137 ASMAtomicDecU32(&g_cInstances);
138}
139
140// IVirtualBoxClient properties
141/////////////////////////////////////////////////////////////////////////////
142
143/**
144 * Returns a reference to the VirtualBox object.
145 *
146 * @returns COM status code
147 * @param aVirtualBox Address of result variable.
148 */
149STDMETHODIMP VirtualBoxClient::COMGETTER(VirtualBox)(IVirtualBox **aVirtualBox)
150{
151 CheckComArgOutPointerValid(aVirtualBox);
152
153 AutoCaller autoCaller(this);
154 if (FAILED(autoCaller.rc())) return autoCaller.rc();
155
156 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
157 mData.m_pVirtualBox.queryInterfaceTo(aVirtualBox);
158 return S_OK;
159}
160
161/**
162 * Create a new Session object and return a reference to it.
163 *
164 * @returns COM status code
165 * @param aSession Address of result variable.
166 */
167STDMETHODIMP VirtualBoxClient::COMGETTER(Session)(ISession **aSession)
168{
169 HRESULT rc;
170 CheckComArgOutPointerValid(aSession);
171
172 AutoCaller autoCaller(this);
173 if (FAILED(autoCaller.rc())) return autoCaller.rc();
174
175 /* this is not stored in this object, no need to lock */
176 ComPtr<ISession> pSession;
177 rc = pSession.createInprocObject(CLSID_Session);
178 if (SUCCEEDED(rc))
179 pSession.queryInterfaceTo(aSession);
180
181 return rc;
182}
183
184/**
185 * Return reference to the EventSource associated with this object.
186 *
187 * @returns COM status code
188 * @param aEventSource Address of result variable.
189 */
190STDMETHODIMP VirtualBoxClient::COMGETTER(EventSource)(IEventSource **aEventSource)
191{
192 CheckComArgOutPointerValid(aEventSource);
193
194 AutoCaller autoCaller(this);
195 if (FAILED(autoCaller.rc())) return autoCaller.rc();
196
197 /* this is const, no need to lock */
198 mData.m_pEventSource.queryInterfaceTo(aEventSource);
199
200 return mData.m_pEventSource.isNull() ? E_FAIL : S_OK;
201}
202
203// private methods
204/////////////////////////////////////////////////////////////////////////////
205
206/*static*/
207DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
208 void *pvUser)
209{
210 NOREF(ThreadSelf);
211 Assert(pvUser);
212 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
213 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
214 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
215 int vrc;
216
217 /* The likelihood of early crashes are high, so start with a short wait. */
218 vrc = RTSemEventWait(sem, cMillies / 2);
219
220 /* As long as the waiting times out keep retrying the wait. */
221 while (RT_FAILURE(vrc))
222 {
223 {
224 HRESULT rc = S_OK;
225 ComPtr<IVirtualBox> pV;
226 {
227 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
228 pV = pThis->mData.m_pVirtualBox;
229 }
230 if (!pV.isNull())
231 {
232 ULONG rev;
233 rc = pV->COMGETTER(Revision)(&rev);
234 if (FAILED_DEAD_INTERFACE(rc))
235 {
236 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
237 {
238 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
239 /* Throw away the VirtualBox reference, it's no longer
240 * usable as VBoxSVC terminated in the mean time. */
241 pThis->mData.m_pVirtualBox.setNull();
242 }
243 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
244 }
245 }
246 else
247 {
248 /* Try to get a new VirtualBox reference straight away, and if
249 * this fails use an increased waiting time as very frequent
250 * restart attempts in some wedged config can cause high CPU
251 * and disk load. */
252 ComPtr<IVirtualBox> pVBox;
253 rc = pVBox.createLocalObject(CLSID_VirtualBox);
254 if (FAILED(rc))
255 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
256 else
257 {
258 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
259 {
260 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
261 /* Update the VirtualBox reference, there's a working
262 * VBoxSVC again from now on. */
263 pThis->mData.m_pVirtualBox = pVBox;
264 }
265 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
266 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
267 }
268 }
269 }
270 vrc = RTSemEventWait(sem, cMillies);
271 }
272 return 0;
273}
274
275/* 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