VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp@ 35263

Last change on this file since 35263 was 35060, checked in by vboxsync, 13 years ago

Comment typos.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/* $Id: VBoxServiceControl.cpp 35060 2010-12-14 10:26:12Z vboxsync $ */
2/** @file
3 * VBoxServiceControl - Host-driven Guest Control.
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
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/asm.h>
23#include <iprt/assert.h>
24#include <iprt/getopt.h>
25#include <iprt/mem.h>
26#include <iprt/semaphore.h>
27#include <iprt/thread.h>
28#include <VBox/VBoxGuestLib.h>
29#include <VBox/HostServices/GuestControlSvc.h>
30#include "VBoxServiceInternal.h"
31#include "VBoxServiceUtils.h"
32
33using namespace guestControl;
34
35/*******************************************************************************
36* Global Variables *
37*******************************************************************************/
38/** The control interval (milliseconds). */
39uint32_t g_ControlInterval = 0;
40/** The semaphore we're blocking on. */
41static RTSEMEVENTMULTI g_hControlEvent = NIL_RTSEMEVENTMULTI;
42/** The Guest Control service client ID. */
43static uint32_t g_GuestControlSvcClientID = 0;
44/** List of spawned processes */
45RTLISTNODE g_GuestControlExecThreads;
46
47
48/** @copydoc VBOXSERVICE::pfnPreInit */
49static DECLCALLBACK(int) VBoxServiceControlPreInit(void)
50{
51 return VINF_SUCCESS;
52}
53
54
55/** @copydoc VBOXSERVICE::pfnOption */
56static DECLCALLBACK(int) VBoxServiceControlOption(const char **ppszShort, int argc, char **argv, int *pi)
57{
58 int rc = -1;
59 if (ppszShort)
60 /* no short options */;
61 else if (!strcmp(argv[*pi], "--control-interval"))
62 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
63 &g_ControlInterval, 1, UINT32_MAX - 1);
64 return rc;
65}
66
67
68/** @copydoc VBOXSERVICE::pfnInit */
69static DECLCALLBACK(int) VBoxServiceControlInit(void)
70{
71 /*
72 * If not specified, find the right interval default.
73 * Then create the event sem to block on.
74 */
75 if (!g_ControlInterval)
76 g_ControlInterval = 1000;
77
78 int rc = RTSemEventMultiCreate(&g_hControlEvent);
79 AssertRCReturn(rc, rc);
80
81 rc = VbglR3GuestCtrlConnect(&g_GuestControlSvcClientID);
82 if (RT_SUCCESS(rc))
83 {
84 VBoxServiceVerbose(3, "Control: Service Client ID: %#x\n", g_GuestControlSvcClientID);
85
86 /* Init thread list. */
87 RTListInit(&g_GuestControlExecThreads);
88 }
89 else
90 {
91 /* If the service was not found, we disable this service without
92 causing VBoxService to fail. */
93 if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
94 {
95 VBoxServiceVerbose(0, "Control: Guest control service is not available\n");
96 rc = VERR_SERVICE_DISABLED;
97 }
98 else
99 VBoxServiceError("Control: Failed to connect to the guest control service! Error: %Rrc\n", rc);
100 RTSemEventMultiDestroy(g_hControlEvent);
101 g_hControlEvent = NIL_RTSEMEVENTMULTI;
102 }
103 return rc;
104}
105
106
107/** @copydoc VBOXSERVICE::pfnWorker */
108DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
109{
110 /*
111 * Tell the control thread that it can continue
112 * spawning services.
113 */
114 RTThreadUserSignal(RTThreadSelf());
115 Assert(g_GuestControlSvcClientID > 0);
116
117 int rc = VINF_SUCCESS;
118
119 /*
120 * Execution loop.
121 *
122 * @todo
123 */
124 for (;;)
125 {
126 uint32_t uMsg;
127 uint32_t uNumParms;
128 VBoxServiceVerbose(3, "Control: Waiting for host msg ...\n");
129 rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms);
130 if (RT_FAILURE(rc))
131 {
132 if (rc == VERR_TOO_MUCH_DATA)
133 {
134 VBoxServiceVerbose(4, "Control: Message requires %ld parameters, but only 2 supplied -- retrying request (no error!)...\n", uNumParms);
135 rc = VINF_SUCCESS; /* Try to get "real" message in next block below. */
136 }
137 else
138 VBoxServiceVerbose(3, "Control: Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran into timeout. */
139 }
140
141 if (RT_SUCCESS(rc))
142 {
143 VBoxServiceVerbose(3, "Control: Msg=%u (%u parms) retrieved\n", uMsg, uNumParms);
144 switch(uMsg)
145 {
146 case HOST_CANCEL_PENDING_WAITS:
147 VBoxServiceVerbose(3, "Control: Host asked us to quit ...\n");
148 break;
149
150 case HOST_EXEC_CMD:
151 rc = VBoxServiceControlExecHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
152 break;
153
154 case HOST_EXEC_SET_INPUT:
155 /** @todo Make buffer size configurable via guest properties/argv! */
156 rc = VBoxServiceControlExecHandleCmdSetInput(g_GuestControlSvcClientID, uNumParms, _1M /* Buffer size */);
157 break;
158
159 case HOST_EXEC_GET_OUTPUT:
160 rc = VBoxServiceControlExecHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms);
161 break;
162
163 default:
164 VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%u\n", uMsg);
165 /* Don't terminate here; just wait for the next message. */
166 break;
167 }
168
169 if (RT_FAILURE(rc))
170 VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc);
171 }
172
173 /* Do we need to shutdown? */
174 if ( *pfShutdown
175 || uMsg == HOST_CANCEL_PENDING_WAITS)
176 {
177 rc = VINF_SUCCESS;
178 break;
179 }
180
181 /* Let's sleep for a bit and let others run ... */
182 RTThreadYield();
183 }
184
185 RTSemEventMultiDestroy(g_hControlEvent);
186 g_hControlEvent = NIL_RTSEMEVENTMULTI;
187 return rc;
188}
189
190
191/** @copydoc VBOXSERVICE::pfnStop */
192static DECLCALLBACK(void) VBoxServiceControlStop(void)
193{
194 VBoxServiceVerbose(3, "Control: Stopping ...\n");
195
196 /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
197 * annoying call since doesn't support timeouts in the posix world. */
198 RTSemEventMultiSignal(g_hControlEvent);
199
200 /*
201 * Ask the host service to cancel all pending requests so that we can
202 * shutdown properly here.
203 */
204 if (g_GuestControlSvcClientID)
205 {
206 int rc = VbglR3GuestCtrlCancelPendingWaits(g_GuestControlSvcClientID);
207 if (RT_FAILURE(rc))
208 VBoxServiceError("Control: Cancelling pending waits failed; rc=%Rrc\n", rc);
209 }
210}
211
212
213/** @copydoc VBOXSERVICE::pfnTerm */
214static DECLCALLBACK(void) VBoxServiceControlTerm(void)
215{
216 VBoxServiceVerbose(3, "Control: Terminating ...\n");
217
218 /* Signal all threads that we want to shutdown. */
219 PVBOXSERVICECTRLTHREAD pNode;
220 RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
221 ASMAtomicXchgBool(&pNode->fShutdown, true);
222
223 /* Wait for threads to shutdown. */
224 RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
225 {
226 if (pNode->Thread != NIL_RTTHREAD)
227 {
228 /* Wait a bit ... */
229 int rc2 = RTThreadWait(pNode->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL);
230 if (RT_FAILURE(rc2))
231 VBoxServiceError("Control: Thread failed to stop; rc2=%Rrc\n", rc2);
232 }
233
234 /* Destroy thread specific data. */
235 switch (pNode->enmType)
236 {
237 case kVBoxServiceCtrlThreadDataExec:
238 VBoxServiceControlExecDestroyThreadData((PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData);
239 break;
240
241 default:
242 break;
243 }
244 }
245
246 /* Finally destroy thread list. */
247 pNode = RTListGetFirst(&g_GuestControlExecThreads, VBOXSERVICECTRLTHREAD, Node);
248 while (pNode)
249 {
250 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node);
251 bool fLast = RTListNodeIsLast(&g_GuestControlExecThreads, &pNode->Node);
252
253 RTListNodeRemove(&pNode->Node);
254 RTMemFree(pNode);
255
256 if (fLast)
257 break;
258
259 pNode = pNext;
260 }
261
262 VbglR3GuestCtrlDisconnect(g_GuestControlSvcClientID);
263 g_GuestControlSvcClientID = 0;
264
265 if (g_hControlEvent != NIL_RTSEMEVENTMULTI)
266 {
267 RTSemEventMultiDestroy(g_hControlEvent);
268 g_hControlEvent = NIL_RTSEMEVENTMULTI;
269 }
270}
271
272
273/**
274 * The 'vminfo' service description.
275 */
276VBOXSERVICE g_Control =
277{
278 /* pszName. */
279 "control",
280 /* pszDescription. */
281 "Host-driven Guest Control",
282 /* pszUsage. */
283 " [--control-interval <ms>]"
284 ,
285 /* pszOptions. */
286 " --control-interval Specifies the interval at which to check for\n"
287 " new control commands. The default is 1000 ms.\n"
288 ,
289 /* methods */
290 VBoxServiceControlPreInit,
291 VBoxServiceControlOption,
292 VBoxServiceControlInit,
293 VBoxServiceControlWorker,
294 VBoxServiceControlStop,
295 VBoxServiceControlTerm
296};
297
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use