VirtualBox

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

Last change on this file since 61572 was 61117, checked in by vboxsync, 9 years ago

Main: fixed two format specifiers in Log/Assert statements

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 61117 2016-05-23 09:10:42Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2010-2016 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#include "VBox/com/ErrorInfo.h"
24
25#include <iprt/asm.h>
26#include <iprt/thread.h>
27#include <iprt/critsect.h>
28#include <iprt/semaphore.h>
29#include <iprt/cpp/utils.h>
30
31
32/** Waiting time between probing whether VBoxSVC is alive. */
33#define VBOXCLIENT_DEFAULT_INTERVAL 30000
34
35
36/** Initialize instance counter class variable */
37uint32_t VirtualBoxClient::g_cInstances = 0;
38
39
40// constructor / destructor
41/////////////////////////////////////////////////////////////////////////////
42
43HRESULT VirtualBoxClient::FinalConstruct()
44{
45 HRESULT rc = init();
46 BaseFinalConstruct();
47 return rc;
48}
49
50void VirtualBoxClient::FinalRelease()
51{
52 uninit();
53 BaseFinalRelease();
54}
55
56// public initializer/uninitializer for internal purposes only
57/////////////////////////////////////////////////////////////////////////////
58
59/**
60 * Initializes the VirtualBoxClient object.
61 *
62 * @returns COM result indicator
63 */
64HRESULT VirtualBoxClient::init()
65{
66 LogFlowThisFuncEnter();
67
68 /* Enclose the state transition NotReady->InInit->Ready */
69 AutoInitSpan autoInitSpan(this);
70 AssertReturn(autoInitSpan.isOk(), E_FAIL);
71
72 /* Important: DO NOT USE any kind of "early return" (except the single
73 * one above, checking the init span success) in this method. It is vital
74 * for correct error handling that it has only one point of return, which
75 * does all the magic on COM to signal object creation success and
76 * reporting the error later for every API method. COM translates any
77 * unsuccessful object creation to REGDB_E_CLASSNOTREG errors or similar
78 * unhelpful ones which cause us a lot of grief with troubleshooting. */
79
80 HRESULT rc = S_OK;
81 try
82 {
83 if (ASMAtomicIncU32(&g_cInstances) != 1)
84 AssertFailedStmt(throw setError(E_FAIL,
85 tr("Attempted to create more than one VirtualBoxClient instance")));
86
87 mData.m_ThreadWatcher = NIL_RTTHREAD;
88 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
89
90 rc = mData.m_pVirtualBox.createLocalObject(CLSID_VirtualBox);
91 if (FAILED(rc))
92 throw rc;
93
94 /* VirtualBox error return is postponed to method calls, fetch it. */
95 ULONG rev;
96 rc = mData.m_pVirtualBox->COMGETTER(Revision)(&rev);
97 if (FAILED(rc))
98 throw rc;
99
100 rc = unconst(mData.m_pEventSource).createObject();
101 AssertComRCThrow(rc, setError(rc,
102 tr("Could not create EventSource for VirtualBoxClient")));
103 rc = mData.m_pEventSource->init();
104 AssertComRCThrow(rc, setError(rc,
105 tr("Could not initialize EventSource for VirtualBoxClient")));
106
107 /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it
108 * is not considered important enough to cause any sort of visible
109 * failure. The monitoring will not be done, but that's all. */
110 int vrc = RTSemEventCreate(&mData.m_SemEvWatcher);
111 if (RT_FAILURE(vrc))
112 {
113 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
114 AssertRCStmt(vrc, throw setError(VBOX_E_IPRT_ERROR,
115 tr("Failed to create semaphore (rc=%Rrc)"),
116 vrc));
117 }
118
119 vrc = RTThreadCreate(&mData.m_ThreadWatcher, SVCWatcherThread, this, 0,
120 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "VBoxSVCWatcher");
121 if (RT_FAILURE(vrc))
122 {
123 RTSemEventDestroy(mData.m_SemEvWatcher);
124 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
125 AssertRCStmt(vrc, throw setError(VBOX_E_IPRT_ERROR,
126 tr("Failed to create watcher thread (rc=%Rrc)"),
127 vrc));
128 }
129 }
130 catch (HRESULT err)
131 {
132 /* we assume that error info is set by the thrower */
133 rc = err;
134 }
135 catch (...)
136 {
137 rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS);
138 }
139
140 /* Confirm a successful initialization when it's the case. Must be last,
141 * as on failure it will uninitialize the object. */
142 if (SUCCEEDED(rc))
143 autoInitSpan.setSucceeded();
144 else
145 autoInitSpan.setFailed(rc);
146
147 LogFlowThisFunc(("rc=%Rhrc\n", rc));
148 LogFlowThisFuncLeave();
149 /* Unconditionally return success, because the error return is delayed to
150 * the attribute/method calls through the InitFailed object state. */
151 return S_OK;
152}
153
154/**
155 * Uninitializes the instance and sets the ready flag to FALSE.
156 * Called either from FinalRelease() or by the parent when it gets destroyed.
157 */
158void VirtualBoxClient::uninit()
159{
160 LogFlowThisFunc(("\n"));
161
162 /* Enclose the state transition Ready->InUninit->NotReady */
163 AutoUninitSpan autoUninitSpan(this);
164 if (autoUninitSpan.uninitDone())
165 return;
166
167 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
168 {
169 /* Signal the event semaphore and wait for the thread to terminate.
170 * if it hangs for some reason exit anyway, this can cause a crash
171 * though as the object will no longer be available. */
172 RTSemEventSignal(mData.m_SemEvWatcher);
173 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
174 mData.m_ThreadWatcher = NIL_RTTHREAD;
175 RTSemEventDestroy(mData.m_SemEvWatcher);
176 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
177 }
178
179 mData.m_pVirtualBox.setNull();
180
181 ASMAtomicDecU32(&g_cInstances);
182}
183
184// IVirtualBoxClient properties
185/////////////////////////////////////////////////////////////////////////////
186
187/**
188 * Returns a reference to the VirtualBox object.
189 *
190 * @returns COM status code
191 * @param aVirtualBox Address of result variable.
192 */
193HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
194{
195 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
196 aVirtualBox = mData.m_pVirtualBox;
197 return S_OK;
198}
199
200/**
201 * Create a new Session object and return a reference to it.
202 *
203 * @returns COM status code
204 * @param aSession Address of result variable.
205 */
206HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
207{
208 /* this is not stored in this object, no need to lock */
209 ComPtr<ISession> pSession;
210 HRESULT rc = pSession.createInprocObject(CLSID_Session);
211 if (SUCCEEDED(rc))
212 aSession = pSession;
213 return rc;
214}
215
216/**
217 * Return reference to the EventSource associated with this object.
218 *
219 * @returns COM status code
220 * @param aEventSource Address of result variable.
221 */
222HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
223{
224 /* this is const, no need to lock */
225 aEventSource = mData.m_pEventSource;
226 return aEventSource.isNull() ? E_FAIL : S_OK;
227}
228
229// IVirtualBoxClient methods
230/////////////////////////////////////////////////////////////////////////////
231
232/**
233 * Checks a Machine object for any pending errors.
234 *
235 * @returns COM status code
236 * @param aMachine Machine object to check.
237 */
238HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
239{
240 BOOL fAccessible = FALSE;
241 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
242 if (FAILED(rc))
243 return setError(rc, tr("Could not check the accessibility status of the VM"));
244 else if (!fAccessible)
245 {
246 ComPtr<IVirtualBoxErrorInfo> pAccessError;
247 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
248 if (FAILED(rc))
249 return setError(rc, tr("Could not get the access error message of the VM"));
250 else
251 {
252 ErrorInfo info(pAccessError);
253 ErrorInfoKeeper eik(info);
254 return info.getResultCode();
255 }
256 }
257 return S_OK;
258}
259
260// private methods
261/////////////////////////////////////////////////////////////////////////////
262
263/*static*/
264DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
265 void *pvUser)
266{
267 NOREF(ThreadSelf);
268 Assert(pvUser);
269 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
270 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
271 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
272 int vrc;
273
274 /* The likelihood of early crashes are high, so start with a short wait. */
275 vrc = RTSemEventWait(sem, cMillies / 2);
276
277 /* As long as the waiting times out keep retrying the wait. */
278 while (RT_FAILURE(vrc))
279 {
280 {
281 HRESULT rc = S_OK;
282 ComPtr<IVirtualBox> pV;
283 {
284 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
285 pV = pThis->mData.m_pVirtualBox;
286 }
287 if (!pV.isNull())
288 {
289 ULONG rev;
290 rc = pV->COMGETTER(Revision)(&rev);
291 if (FAILED_DEAD_INTERFACE(rc))
292 {
293 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
294 {
295 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
296 /* Throw away the VirtualBox reference, it's no longer
297 * usable as VBoxSVC terminated in the mean time. */
298 pThis->mData.m_pVirtualBox.setNull();
299 }
300 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
301 }
302 }
303 else
304 {
305 /* Try to get a new VirtualBox reference straight away, and if
306 * this fails use an increased waiting time as very frequent
307 * restart attempts in some wedged config can cause high CPU
308 * and disk load. */
309 ComPtr<IVirtualBox> pVirtualBox;
310 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
311 if (FAILED(rc))
312 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
313 else
314 {
315 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
316 {
317 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
318 /* Update the VirtualBox reference, there's a working
319 * VBoxSVC again from now on. */
320 pThis->mData.m_pVirtualBox = pVirtualBox;
321 }
322 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
323 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
324 }
325 }
326 }
327 vrc = RTSemEventWait(sem, cMillies);
328 }
329 return 0;
330}
331
332/* 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