VirtualBox

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

最後變更 在這個檔案從60060是 59996,由 vboxsync 提交於 9 年 前

Main/VirtualBox: postpone the error reporting from VirtualBox object creation to the method calls of the object. COM loses the error (replaces it by REGDB_E_CLASSNOTREG), making troubleshooting very difficult. XPCOM wouldn't need this, but it is applied everywhere for maximum consistency. Many changes elsewhere to propagate the information correctly, and also fixes many outdated comments.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 9.2 KB
 
1/* $Id: VirtualBoxClientImpl.cpp 59996 2016-03-11 15:27:55Z 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.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 (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 LogFlowThisFunc(("\n"));
67
68 HRESULT rc;
69 /* Enclose the state transition NotReady->InInit->Ready */
70 AutoInitSpan autoInitSpan(this);
71 AssertReturn(autoInitSpan.isOk(), E_FAIL);
72
73 mData.m_ThreadWatcher = NIL_RTTHREAD;
74 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
75
76 if (ASMAtomicIncU32(&g_cInstances) != 1)
77 AssertFailedReturn(E_FAIL);
78
79 rc = mData.m_pVirtualBox.createLocalObject(CLSID_VirtualBox);
80 if (FAILED(rc))
81 return rc;
82
83 /* Error return is postponed to method calls, fetch info now. */
84 ULONG rev;
85 rc = mData.m_pVirtualBox->COMGETTER(Revision)(&rev);
86 if (FAILED(rc))
87 return rc;
88
89 rc = unconst(mData.m_pEventSource).createObject();
90 AssertComRCReturnRC(rc);
91 rc = mData.m_pEventSource->init();
92 AssertComRCReturnRC(rc);
93
94 /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it
95 * is not considered important enough to cause any sort of visible
96 * failure. The monitoring will not be done, but that's all. */
97 int vrc = RTSemEventCreate(&mData.m_SemEvWatcher);
98 AssertRC(vrc);
99 if (RT_SUCCESS(vrc))
100 {
101 vrc = RTThreadCreate(&mData.m_ThreadWatcher, SVCWatcherThread,
102 this, 0, RTTHREADTYPE_INFREQUENT_POLLER,
103 RTTHREADFLAGS_WAITABLE, "VBoxSVCWatcher");
104 AssertRC(vrc);
105 }
106 else
107 {
108 RTSemEventDestroy(mData.m_SemEvWatcher);
109 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
110 }
111
112 /* Confirm a successful initialization */
113 autoInitSpan.setSucceeded();
114
115 return rc;
116}
117
118/**
119 * Uninitializes the instance and sets the ready flag to FALSE.
120 * Called either from FinalRelease() or by the parent when it gets destroyed.
121 */
122void VirtualBoxClient::uninit()
123{
124 LogFlowThisFunc(("\n"));
125
126 /* Enclose the state transition Ready->InUninit->NotReady */
127 AutoUninitSpan autoUninitSpan(this);
128 if (autoUninitSpan.uninitDone())
129 return;
130
131 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
132 {
133 /* Signal the event semaphore and wait for the thread to terminate.
134 * if it hangs for some reason exit anyway, this can cause a crash
135 * though as the object will no longer be available. */
136 RTSemEventSignal(mData.m_SemEvWatcher);
137 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
138 mData.m_ThreadWatcher = NIL_RTTHREAD;
139 RTSemEventDestroy(mData.m_SemEvWatcher);
140 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
141 }
142
143 mData.m_pVirtualBox.setNull();
144
145 ASMAtomicDecU32(&g_cInstances);
146}
147
148// IVirtualBoxClient properties
149/////////////////////////////////////////////////////////////////////////////
150
151/**
152 * Returns a reference to the VirtualBox object.
153 *
154 * @returns COM status code
155 * @param aVirtualBox Address of result variable.
156 */
157HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
158{
159 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
160 aVirtualBox = mData.m_pVirtualBox;
161 return S_OK;
162}
163
164/**
165 * Create a new Session object and return a reference to it.
166 *
167 * @returns COM status code
168 * @param aSession Address of result variable.
169 */
170HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
171{
172 /* this is not stored in this object, no need to lock */
173 ComPtr<ISession> pSession;
174 HRESULT rc = pSession.createInprocObject(CLSID_Session);
175 if (SUCCEEDED(rc))
176 aSession = pSession;
177 return rc;
178}
179
180/**
181 * Return reference to the EventSource associated with this object.
182 *
183 * @returns COM status code
184 * @param aEventSource Address of result variable.
185 */
186HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
187{
188 /* this is const, no need to lock */
189 aEventSource = mData.m_pEventSource;
190 return aEventSource.isNull() ? E_FAIL : S_OK;
191}
192
193// IVirtualBoxClient methods
194/////////////////////////////////////////////////////////////////////////////
195
196/**
197 * Checks a Machine object for any pending errors.
198 *
199 * @returns COM status code
200 * @param aMachine Machine object to check.
201 */
202HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
203{
204 BOOL fAccessible = FALSE;
205 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
206 if (FAILED(rc))
207 return setError(rc, tr("Could not check the accessibility status of the VM"));
208 else if (!fAccessible)
209 {
210 ComPtr<IVirtualBoxErrorInfo> pAccessError;
211 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
212 if (FAILED(rc))
213 return setError(rc, tr("Could not get the access error message of the VM"));
214 else
215 {
216 ErrorInfo info(pAccessError);
217 ErrorInfoKeeper eik(info);
218 return info.getResultCode();
219 }
220 }
221 return S_OK;
222}
223
224// private methods
225/////////////////////////////////////////////////////////////////////////////
226
227/*static*/
228DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
229 void *pvUser)
230{
231 NOREF(ThreadSelf);
232 Assert(pvUser);
233 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
234 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
235 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
236 int vrc;
237
238 /* The likelihood of early crashes are high, so start with a short wait. */
239 vrc = RTSemEventWait(sem, cMillies / 2);
240
241 /* As long as the waiting times out keep retrying the wait. */
242 while (RT_FAILURE(vrc))
243 {
244 {
245 HRESULT rc = S_OK;
246 ComPtr<IVirtualBox> pV;
247 {
248 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
249 pV = pThis->mData.m_pVirtualBox;
250 }
251 if (!pV.isNull())
252 {
253 ULONG rev;
254 rc = pV->COMGETTER(Revision)(&rev);
255 if (FAILED_DEAD_INTERFACE(rc))
256 {
257 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
258 {
259 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
260 /* Throw away the VirtualBox reference, it's no longer
261 * usable as VBoxSVC terminated in the mean time. */
262 pThis->mData.m_pVirtualBox.setNull();
263 }
264 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
265 }
266 }
267 else
268 {
269 /* Try to get a new VirtualBox reference straight away, and if
270 * this fails use an increased waiting time as very frequent
271 * restart attempts in some wedged config can cause high CPU
272 * and disk load. */
273 ComPtr<IVirtualBox> pVirtualBox;
274 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
275 if (FAILED(rc))
276 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
277 else
278 {
279 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
280 {
281 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
282 /* Update the VirtualBox reference, there's a working
283 * VBoxSVC again from now on. */
284 pThis->mData.m_pVirtualBox = pVirtualBox;
285 }
286 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
287 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
288 }
289 }
290 }
291 vrc = RTSemEventWait(sem, cMillies);
292 }
293 return 0;
294}
295
296/* vi: set tabstop=4 shiftwidth=4 expandtab: */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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