VirtualBox

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

Last change on this file since 35553 was 35368, checked in by vboxsync, 14 years ago

Main: source re-org.

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