VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp@ 107958

最後變更 在這個檔案從107958是 107958,由 vboxsync 提交於 7 週 前

VBoxTray/IPC: Unified logging to also use the VBoxTray logging facilities, back off a little in the main worker thread if something has failed, to not hog the CPU too much. Note: This does not fix the actual issue yet but only fixes the symptom. ticketref:22123

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 21.1 KB
 
1/* $Id: VBoxIPC.cpp 107958 2025-01-28 09:28:51Z vboxsync $ */
2/** @file
3 * VBoxIPC - IPC thread, acts as a (purely) local IPC server.
4 * Multiple sessions are supported, whereas every session
5 * has its own thread for processing requests.
6 */
7
8/*
9 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.alldomusa.eu.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/critsect.h>
37#include <iprt/errcore.h>
38#include <iprt/ldr.h>
39#include <iprt/list.h>
40#include <iprt/localipc.h>
41#include <iprt/log.h>
42#include <iprt/mem.h>
43#include <iprt/process.h>
44#include <iprt/win/windows.h>
45
46#include "VBoxTray.h"
47#include "VBoxTrayInternal.h"
48#include "VBoxTrayMsg.h"
49#include "VBoxHelpers.h"
50#include "VBoxIPC.h"
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * IPC context data.
58 */
59typedef struct VBOXIPCCONTEXT
60{
61 /** Pointer to the service environment. */
62 const VBOXTRAYSVCENV *pEnv;
63 /** Handle for the local IPC server. */
64 RTLOCALIPCSERVER hServer;
65 /** Critical section serializing access to the session list, the state,
66 * the response event, the session event, and the thread event. */
67 RTCRITSECT CritSect;
68 /** List of all active IPC sessions. */
69 RTLISTANCHOR SessionList;
70
71} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
72
73/** Function pointer for GetLastInputInfo(). */
74typedef BOOL (WINAPI *PFNGETLASTINPUTINFO)(PLASTINPUTINFO);
75
76/**
77 * IPC per-session thread data.
78 */
79typedef struct VBOXIPCSESSION
80{
81 /** The list node required to be part of the
82 * IPC session list. */
83 RTLISTNODE Node;
84 /** Pointer to the IPC context data. */
85 PVBOXIPCCONTEXT volatile pCtx;
86 /** The local ipc client handle. */
87 RTLOCALIPCSESSION volatile hSession;
88 /** Indicate that the thread should terminate ASAP. */
89 bool volatile fTerminate;
90 /** The thread handle. */
91 RTTHREAD hThread;
92
93} VBOXIPCSESSION, *PVBOXIPCSESSION;
94
95
96/*********************************************************************************************************************************
97* Global Variables *
98*********************************************************************************************************************************/
99static VBOXIPCCONTEXT g_Ctx = { NULL, NIL_RTLOCALIPCSERVER };
100static PFNGETLASTINPUTINFO g_pfnGetLastInputInfo = NULL;
101
102
103/*********************************************************************************************************************************
104* Internal Functions *
105*********************************************************************************************************************************/
106static int vboxIPCSessionStop(PVBOXIPCSESSION pSession);
107
108
109
110/**
111 * Handles VBOXTRAYIPCMSGTYPE_RESTART.
112 */
113static int vboxIPCHandleVBoxTrayRestart(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
114{
115 RT_NOREF(pSession, pHdr);
116
117 /** @todo Not implemented yet; don't return an error here. */
118 return VINF_SUCCESS;
119}
120
121/**
122 * Handles VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG.
123 */
124static int vboxIPCHandleShowBalloonMsg(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
125{
126 /*
127 * Unmarshal and validate the data.
128 */
129 union
130 {
131 uint8_t abBuf[_4K];
132 VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T s;
133 } Payload;
134 AssertReturn(pHdr->cbPayload >= RT_UOFFSETOF_DYN(VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T, szzStrings[2]), VERR_INVALID_PARAMETER);
135 AssertReturn(pHdr->cbPayload < sizeof(Payload), VERR_BUFFER_OVERFLOW);
136
137 int rc = RTLocalIpcSessionRead(pSession->hSession, &Payload, pHdr->cbPayload, NULL /*pcbRead - exact, blocking*/);
138 if (RT_FAILURE(rc))
139 return rc;
140
141 /* String lengths: */
142 AssertReturn( Payload.s.cchMsg + 1 + Payload.s.cchTitle + 1 + RT_UOFFSETOF(VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T, szzStrings)
143 <= pHdr->cbPayload, VERR_INVALID_PARAMETER);
144
145 /* Message text: */
146 const char *pszMsg = Payload.s.szzStrings;
147 rc = RTStrValidateEncodingEx(pszMsg, Payload.s.cchMsg + 1,
148 RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
149 AssertRCReturn(rc, rc);
150
151 /* Title text: */
152 const char *pszTitle = &Payload.s.szzStrings[Payload.s.cchMsg + 1];
153 rc = RTStrValidateEncodingEx(pszMsg, Payload.s.cchTitle + 1,
154 RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
155 AssertRCReturn(rc, rc);
156
157 /* Type/dwInfoFlags: */
158 AssertReturn( Payload.s.uType == NIIF_NONE
159 || Payload.s.uType == NIIF_INFO
160 || Payload.s.uType == NIIF_WARNING
161 || Payload.s.uType == NIIF_ERROR,
162 VERR_WRONG_TYPE);
163
164 /* Timeout: */
165 if (!Payload.s.cMsTimeout)
166 Payload.s.cMsTimeout = RT_MS_5SEC;
167 AssertStmt(Payload.s.cMsTimeout >= RT_MS_1SEC, Payload.s.cMsTimeout = RT_MS_1SEC);
168 AssertStmt(Payload.s.cMsTimeout <= RT_MS_1MIN, Payload.s.cMsTimeout = RT_MS_1MIN);
169
170 /*
171 * Showing the balloon tooltip is not critical.
172 */
173 VBoxTrayHlpShowBalloonTipEx(g_hInstance, g_hwndToolWindow, ID_TRAYICON,
174 pszMsg, pszTitle, Payload.s.cMsTimeout, Payload.s.uType);
175
176 return VINF_SUCCESS;
177}
178
179/**
180 * Handles VBOXTRAYIPCMSGTYPE_USER_LAST_INPUT.
181 */
182static int vboxIPCHandleUserLastInput(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
183{
184 RT_NOREF(pHdr);
185
186 int rc = VINF_SUCCESS;
187 VBOXTRAYIPCREPLY_USER_LAST_INPUT_T Reply = { UINT32_MAX };
188 if (g_pfnGetLastInputInfo)
189 {
190 /* Note: This only works up to 49.7 days (= 2^32, 32-bit counter) since Windows was started. */
191 LASTINPUTINFO LastInput;
192 LastInput.cbSize = sizeof(LastInput);
193 if (g_pfnGetLastInputInfo(&LastInput))
194 Reply.cSecSinceLastInput = (GetTickCount() - LastInput.dwTime) / 1000;
195 else
196 rc = RTErrConvertFromWin32(GetLastError());
197 }
198
199 int rc2 = RTLocalIpcSessionWrite(pSession->hSession, &Reply, sizeof(Reply));
200 if (RT_SUCCESS(rc))
201 rc = rc2;
202
203 return rc;
204}
205
206/**
207 * @interface_method_impl{VBOXTRAYSVCDESC,pfnPreInit}
208 */
209static DECLCALLBACK(int) vbtrIPCPreInit(void)
210{
211 return VINF_SUCCESS;
212}
213
214
215/**
216 * @interface_method_impl{VBOXTRAYSVCDESC,pfnOption}
217 */
218static DECLCALLBACK(int) vbtrIPCOption(const char **ppszShort, int argc, char **argv, int *pi)
219{
220 RT_NOREF(ppszShort, argc, argv, pi);
221
222 return -1;
223}
224
225/**
226 * @interface_method_impl{VBOXTRAYSVCDESC,pfnInit}
227 */
228DECLCALLBACK(int) vbtrIPCInit(const PVBOXTRAYSVCENV pEnv, void **ppvInstance)
229{
230 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
231 AssertPtrReturn(ppvInstance, VERR_INVALID_POINTER);
232
233 LogFlowFuncEnter();
234
235 PVBOXIPCCONTEXT pCtx = &g_Ctx; /* Only one instance at the moment. */
236 AssertPtr(pCtx);
237
238 int rc = RTCritSectInit(&pCtx->CritSect);
239 if (RT_SUCCESS(rc))
240 {
241 char szPipeName[512 + sizeof(VBOXTRAY_IPC_PIPE_PREFIX)];
242 memcpy(szPipeName, VBOXTRAY_IPC_PIPE_PREFIX, sizeof(VBOXTRAY_IPC_PIPE_PREFIX));
243 rc = RTProcQueryUsername(NIL_RTPROCESS,
244 &szPipeName[sizeof(VBOXTRAY_IPC_PIPE_PREFIX) - 1],
245 sizeof(szPipeName) - sizeof(VBOXTRAY_IPC_PIPE_PREFIX) + 1,
246 NULL /*pcbUser*/);
247 AssertRC(rc);
248 if (RT_SUCCESS(rc))
249 {
250 rc = RTLocalIpcServerCreate(&pCtx->hServer, szPipeName, RTLOCALIPC_FLAGS_NATIVE_NAME);
251 AssertRC(rc);
252 if (RT_SUCCESS(rc))
253 {
254 pCtx->pEnv = pEnv;
255 RTListInit(&pCtx->SessionList);
256
257 *ppvInstance = pCtx;
258
259 /* GetLastInputInfo only is available starting at Windows 2000 -- might fail. */
260 g_pfnGetLastInputInfo = (PFNGETLASTINPUTINFO)RTLdrGetSystemSymbol("User32.dll", "GetLastInputInfo");
261
262 LogRelFunc(("Local IPC server now running at \"%s\"\n", szPipeName));
263 return VINF_SUCCESS;
264 }
265
266 }
267
268 RTCritSectDelete(&pCtx->CritSect);
269 }
270
271 LogRelFunc(("Creating local IPC server failed with rc=%Rrc\n", rc));
272 return rc;
273}
274
275/**
276 * @interface_method_impl{VBOXTRAYSVCDESC,pfnStop}
277 */
278DECLCALLBACK(void) VBoxIPCStop(void *pvInstance)
279{
280 /* Can be NULL if VBoxIPCInit failed. */
281 if (!pvInstance)
282 return;
283 AssertPtrReturnVoid(pvInstance);
284
285 VBoxTrayInfo("IPC: Stopping worker thread ...\n");
286
287 /* Shut down local IPC server. */
288 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pvInstance;
289 AssertPtr(pCtx);
290
291 if (pCtx->hServer != NIL_RTLOCALIPCSERVER)
292 {
293 int rc2 = RTLocalIpcServerCancel(pCtx->hServer);
294 if (RT_FAILURE(rc2))
295 LogFlowFunc(("Cancelling current listening call failed with rc=%Rrc\n", rc2));
296 }
297
298 /* Stop all remaining session threads. */
299 int rc = RTCritSectEnter(&pCtx->CritSect);
300 if (RT_SUCCESS(rc))
301 {
302 PVBOXIPCSESSION pSession;
303 RTListForEach(&pCtx->SessionList, pSession, VBOXIPCSESSION, Node)
304 {
305 int rc2 = vboxIPCSessionStop(pSession);
306 if (RT_FAILURE(rc2))
307 {
308 LogFlowFunc(("Stopping IPC session %p failed with rc=%Rrc\n",
309 pSession, rc2));
310 /* Keep going. */
311 }
312 }
313 }
314}
315
316/**
317 * @interface_method_impl{VBOXTRAYSVCDESC,pfnDestroy}
318 */
319DECLCALLBACK(void) vbtrIPCDestroy(void *pvInstance)
320{
321 AssertPtrReturnVoid(pvInstance);
322
323 LogFlowFunc(("Destroying pvInstance=%p\n", pvInstance));
324
325 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pvInstance;
326 AssertPtr(pCtx);
327
328 /* Shut down local IPC server. */
329 int rc = RTCritSectEnter(&pCtx->CritSect);
330 if (RT_SUCCESS(rc))
331 {
332 rc = RTLocalIpcServerDestroy(pCtx->hServer);
333 if (RT_FAILURE(rc))
334 VBoxTrayError("IPC: Unable to destroy IPC server, rc=%Rrc\n", rc);
335
336 int rc2 = RTCritSectLeave(&pCtx->CritSect);
337 if (RT_SUCCESS(rc))
338 rc = rc2;
339 }
340
341 VBoxTrayInfo("IPC: Waiting for remaining IPC sessions to shut down ...\n");
342
343 /* Wait for all IPC session threads to shut down. */
344 bool fListIsEmpty = true;
345 do
346 {
347 int rc2 = RTCritSectEnter(&pCtx->CritSect);
348 if (RT_SUCCESS(rc2))
349 {
350 fListIsEmpty = RTListIsEmpty(&pCtx->SessionList);
351 rc2 = RTCritSectLeave(&pCtx->CritSect);
352
353 if (!fListIsEmpty) /* Don't hog CPU while waiting. */
354 RTThreadSleep(100);
355 }
356
357 if (RT_FAILURE(rc2))
358 break;
359
360 } while (!fListIsEmpty);
361
362 AssertMsg(fListIsEmpty, ("Session thread list is not empty when it should\n"));
363 VBoxTrayInfo("IPC: All remaining IPC sessions shut down\n");
364
365 int rc2 = RTCritSectDelete(&pCtx->CritSect);
366 if (RT_SUCCESS(rc))
367 rc = rc2;
368
369 LogFlowFunc(("Destroyed pvInstance=%p, rc=%Rrc\n", pvInstance, rc));
370}
371
372/**
373 * Services a client session.
374 *
375 * @returns VINF_SUCCESS.
376 * @param hThreadSelf The thread handle.
377 * @param pvSession Pointer to the session instance data.
378 */
379static DECLCALLBACK(int) vboxIPCSessionThread(RTTHREAD hThreadSelf, void *pvSession)
380{
381 RT_NOREF(hThreadSelf);
382 PVBOXIPCSESSION pThis = (PVBOXIPCSESSION)pvSession;
383 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
384 RTLOCALIPCSESSION hSession = pThis->hSession;
385 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
386
387 VBoxTrayVerbose(1, "IPC: Session thread %#x started\n", hSession);
388
389 int rc = VINF_SUCCESS;
390
391 /*
392 * Process client requests until it quits or we're cancelled on termination.
393 */
394 while ( !ASMAtomicUoReadBool(&pThis->fTerminate)
395 && RT_SUCCESS(rc))
396 {
397 /* The next call will be cancelled via VBoxIPCStop if needed. */
398 rc = RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT);
399 if (RT_SUCCESS(rc))
400 {
401 /*
402 * Read the message header.
403 */
404 VBOXTRAYIPCHEADER Hdr = {0};
405 rc = RTLocalIpcSessionRead(hSession, &Hdr, sizeof(Hdr), NULL /*pcbRead - exact, blocking*/);
406 if (RT_FAILURE(rc))
407 break;
408
409 /*
410 * Validate the message header.
411 *
412 * Disconnecting the client if invalid or something we don't grok.
413 * Currently all clients are one-shots, so there is no need to get
414 * in complicated recovery code if we don't understand one another.
415 */
416 if ( Hdr.uMagic != VBOXTRAY_IPC_HDR_MAGIC
417 || Hdr.uVersion != VBOXTRAY_IPC_HDR_VERSION)
418 {
419 VBoxTrayVerbose(1, "IPC: Session %#x: Invalid header magic/version: %#x, %#x, %#x, %#x\n",
420 hSession, Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload);
421 rc = VERR_INVALID_MAGIC;
422 break;
423 }
424 if (Hdr.cbPayload > VBOXTRAY_IPC_MAX_PAYLOAD)
425 {
426 VBoxTrayVerbose(1, "IPC: Session %#x: Payload too big: %#x, %#x, %#x, %#x - max %#x\n",
427 hSession, Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload, VBOXTRAY_IPC_MAX_PAYLOAD);
428 rc = VERR_TOO_MUCH_DATA;
429 break;
430 }
431 if ( Hdr.enmMsgType <= VBOXTRAYIPCMSGTYPE_INVALID
432 || Hdr.enmMsgType >= VBOXTRAYIPCMSGTYPE_END)
433 {
434 VBoxTrayVerbose(1, "IPC: Session %#x: Unknown message: %#x, %#x, %#x, %#x\n",
435 hSession, Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload);
436 rc = VERR_INVALID_FUNCTION;
437 break;
438 }
439
440 /*
441 * Handle the message.
442 */
443 switch (Hdr.enmMsgType)
444 {
445 case VBOXTRAYIPCMSGTYPE_RESTART:
446 rc = vboxIPCHandleVBoxTrayRestart(pThis, &Hdr);
447 break;
448
449 case VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG:
450 rc = vboxIPCHandleShowBalloonMsg(pThis, &Hdr);
451 break;
452
453 case VBOXTRAYIPCMSGTYPE_USER_LAST_INPUT:
454 rc = vboxIPCHandleUserLastInput(pThis, &Hdr);
455 break;
456
457 default:
458 AssertFailedBreakStmt(rc = VERR_IPE_NOT_REACHED_DEFAULT_CASE);
459 }
460 if (RT_FAILURE(rc))
461 VBoxTrayVerbose(1, "IPC: Session %#x: Handling command %RU32 failed with rc=%Rrc\n",
462 hSession, Hdr.enmMsgType, rc);
463 }
464 else if (rc == VERR_CANCELLED)
465 {
466 VBoxTrayVerbose(1, "IPC: Session %#x: Waiting for data cancelled\n", hSession);
467 rc = VINF_SUCCESS;
468 break;
469 }
470 else
471 VBoxTrayError("IPC: Session %#x: Waiting for session data failed with rc=%Rrc\n", hSession, rc);
472 }
473
474 VBoxTrayVerbose(1, "IPC: Session thread %#x ended with rc=%Rrc\n", hSession, rc);
475
476 /*
477 * Close the session.
478 */
479 int rc2 = RTLocalIpcSessionClose(hSession);
480 if (RT_FAILURE(rc2))
481 VBoxTrayError("IPC: Failed closing session %#x, rc=%Rrc\n", hSession, rc);
482
483 /*
484 * Clean up the session.
485 */
486 PVBOXIPCCONTEXT pCtx = ASMAtomicReadPtrT(&pThis->pCtx, PVBOXIPCCONTEXT);
487 AssertMsg(pCtx, ("Session %#x: No context found\n", hSession));
488 rc2 = RTCritSectEnter(&pCtx->CritSect);
489 if (RT_SUCCESS(rc2))
490 {
491 /* Remove this session from the session list. */
492 RTListNodeRemove(&pThis->Node);
493
494 rc2 = RTCritSectLeave(&pCtx->CritSect);
495 if (RT_SUCCESS(rc))
496 rc = rc2;
497 }
498
499 VBoxTrayVerbose(1, "IPC: Session thread %#x terminated with rc=%Rrc\n", hSession, rc);
500
501 RTMemFree(pThis);
502 pThis = NULL;
503
504 return rc;
505}
506
507static int vboxIPCSessionCreate(PVBOXIPCCONTEXT pCtx, RTLOCALIPCSESSION hSession)
508{
509 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
510 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
511
512 int rc = RTCritSectEnter(&pCtx->CritSect);
513 if (RT_SUCCESS(rc))
514 {
515 PVBOXIPCSESSION pSession = (PVBOXIPCSESSION)RTMemAllocZ(sizeof(VBOXIPCSESSION));
516 if (pSession)
517 {
518 pSession->pCtx = pCtx;
519 pSession->hSession = hSession;
520 pSession->fTerminate = false;
521 pSession->hThread = NIL_RTTHREAD;
522
523 /* Start IPC session thread. */
524 LogFlowFunc(("Creating thread for session %p ...\n", pSession));
525 rc = RTThreadCreate(&pSession->hThread, vboxIPCSessionThread,
526 pSession /* pvUser */, 0 /* Default stack size */,
527 RTTHREADTYPE_DEFAULT, 0 /* Flags */, "IPCSESSION");
528 if (RT_SUCCESS(rc))
529 {
530 /* Add session thread to session IPC list. */
531 RTListAppend(&pCtx->SessionList, &pSession->Node);
532 }
533 else
534 {
535 int rc2 = RTLocalIpcSessionClose(hSession);
536 if (RT_FAILURE(rc2))
537 VBoxTrayError("IPC: Failed closing client session %#x with rc=%Rrc\n", hSession, rc2);
538 RTMemFree(pSession);
539 }
540 }
541 else
542 rc = VERR_NO_MEMORY;
543
544 int rc2 = RTCritSectLeave(&pCtx->CritSect);
545 AssertRC(rc2);
546 }
547
548 return rc;
549}
550
551static int vboxIPCSessionStop(PVBOXIPCSESSION pSession)
552{
553 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
554
555 ASMAtomicWriteBool(&pSession->fTerminate, true);
556
557 VBoxTrayInfo("IPC: Stopping worker thread ...\n");
558
559 RTLOCALIPCSESSION hSession;
560 ASMAtomicXchgHandle(&pSession->hSession, NIL_RTLOCALIPCSESSION, &hSession);
561 if (hSession)
562 return RTLocalIpcSessionClose(hSession);
563
564 return VINF_SUCCESS;
565}
566
567/**
568 * Thread worker for the IPC handling code.
569 */
570DECLCALLBACK(int) vbtrIPCWorker(void *pvInstance, bool volatile *pfShutdown)
571{
572 AssertPtrReturn(pvInstance, VERR_INVALID_PARAMETER);
573 LogFunc(("pvInstance=%p\n", pvInstance));
574
575 /*
576 * Tell the control thread that it can continue
577 * spawning services.
578 */
579 RTThreadUserSignal(RTThreadSelf());
580
581 VBoxTrayInfo("IPC: Worker thread started\n");
582
583 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pvInstance;
584 AssertPtr(pCtx);
585
586 int rc;
587
588 for (;;)
589 {
590 RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
591 rc = RTLocalIpcServerListen(pCtx->hServer, &hClientSession);
592 if (RT_FAILURE(rc))
593 {
594 if (rc == VERR_CANCELLED)
595 {
596 VBoxTrayInfo("IPC: Worker thread cancelled\n");
597 rc = VINF_SUCCESS;
598 break;
599 }
600 else
601 VBoxTrayError("IPC: Listening failed with rc=%Rrc\n", rc);
602 }
603 else
604 {
605 VBoxTrayVerbose(1, "IPC: New client connected with session %#x\n", hClientSession);
606
607 rc = vboxIPCSessionCreate(pCtx, hClientSession);
608 if (RT_FAILURE(rc))
609 {
610 VBoxTrayError("IPC: Creating session %#x failed with rc=%Rrc\n", hClientSession, rc);
611 /* Keep going. */
612 }
613 }
614
615 if (*pfShutdown)
616 break;
617
618 /* Back off a little to not hog the CPU too much. */
619 RTThreadSleep(100 /* ms */);
620 }
621
622 VBoxTrayInfo("IPC: Worker thread stopped with %Rrc\n", rc);
623 return rc;
624}
625
626/**
627 * The service description.
628 */
629VBOXTRAYSVCDESC g_SvcDescIPC =
630{
631 /* pszName. */
632 "IPC",
633 /* pszDescription. */
634 "Inter-Process Communication",
635 /* pszUsage. */
636 NULL,
637 /* pszOptions. */
638 NULL,
639 /* methods */
640 vbtrIPCPreInit,
641 vbtrIPCOption,
642 vbtrIPCInit,
643 vbtrIPCWorker,
644 NULL /* pfnStop */,
645 vbtrIPCDestroy
646};
647
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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