VirtualBox

source: vbox/trunk/src/VBox/Main/VirtualBoxClientImpl.cpp@ 35061

Last change on this file since 35061 was 34642, checked in by vboxsync, 14 years ago

Main/VirtualBoxClient: Don't use the singleton factory, as the destruction of the objects is done too late (process termination). Use an instance counter approach, and make sure that only the first instance is actually working.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 34642 2010-12-02 18:16:04Z 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 = unconst(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 unconst(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 /* this is const, no need to lock */
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 = pThis->mData.m_pVirtualBox;
223 if (!pV.isNull())
224 {
225 ULONG rev;
226 rc = pV->COMGETTER(Revision)(&rev);
227 if (FAILED_DEAD_INTERFACE(rc))
228 {
229 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
230 fireVBoxSVCUnavailableEvent(pThis->mData.m_pEventSource);
231
232 /* Throw away the VirtualBox reference, it's no longer
233 * usable as VBoxSVC terminated in the mean time. */
234 unconst(pThis->mData.m_pVirtualBox).setNull();
235 }
236 }
237 else
238 {
239 /* Try to get a new VirtualBox reference straight away, and if
240 * this fails use an increased waiting time as very frequent
241 * restart attempts in some wedged config can cause high CPU
242 * and disk load. */
243 rc = unconst(pThis->mData.m_pVirtualBox).createLocalObject(CLSID_VirtualBox);
244 if (FAILED(rc))
245 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
246 else
247 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
248 }
249 }
250 vrc = RTSemEventWait(sem, cMillies);
251 }
252 return 0;
253}
254
255/* 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