1 | /* $Id: SUPSvcGrant.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VirtualBox Support Service - The Grant Service.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2008-2024 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * The contents of this file may alternatively be used under the terms
|
---|
26 | * of the Common Development and Distribution License Version 1.0
|
---|
27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
29 | * CDDL are applicable instead of those of the GPL.
|
---|
30 | *
|
---|
31 | * You may elect to license modified versions of this file under the
|
---|
32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
33 | *
|
---|
34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
35 | */
|
---|
36 |
|
---|
37 |
|
---|
38 | /*********************************************************************************************************************************
|
---|
39 | * Header Files *
|
---|
40 | *********************************************************************************************************************************/
|
---|
41 | #define LOG_GROUP LOG_GROUP_SUP
|
---|
42 | #include "SUPSvcInternal.h"
|
---|
43 |
|
---|
44 | #include <VBox/log.h>
|
---|
45 | #include <iprt/asm.h>
|
---|
46 | #include <iprt/errcore.h>
|
---|
47 | #include <iprt/assert.h>
|
---|
48 | #include <iprt/critsect.h>
|
---|
49 | #include <iprt/mem.h>
|
---|
50 | #include <iprt/semaphore.h>
|
---|
51 | #include <iprt/thread.h>
|
---|
52 | #include <iprt/time.h>
|
---|
53 | #include <iprt/localipc.h>
|
---|
54 |
|
---|
55 |
|
---|
56 | /*********************************************************************************************************************************
|
---|
57 | * Structures and Typedefs *
|
---|
58 | *********************************************************************************************************************************/
|
---|
59 | /** Pointer to a client instance. */
|
---|
60 | typedef struct SUPSVCGRANTSESSION *PSUPSVCGRANTSESSION;
|
---|
61 | /** Pointer to a Grant service instance. */
|
---|
62 | typedef struct SUPSVCGRANT *PSUPSVCGRANT;
|
---|
63 |
|
---|
64 |
|
---|
65 | /**
|
---|
66 | * Grant service session data.
|
---|
67 | */
|
---|
68 | typedef struct SUPSVCGRANTSESSION
|
---|
69 | {
|
---|
70 | /** Pointer to the next client in the list. */
|
---|
71 | PSUPSVCGRANTSESSION pNext;
|
---|
72 | /** Pointer to the previous client in the list. */
|
---|
73 | PSUPSVCGRANTSESSION pPrev;
|
---|
74 | /** Pointer to the parent (the service instance). */
|
---|
75 | PSUPSVCGRANT volatile pParent;
|
---|
76 | /** The local ipc client handle. */
|
---|
77 | RTLOCALIPCSESSION volatile hSession;
|
---|
78 | /** Indicate that the thread should terminate ASAP. */
|
---|
79 | bool volatile fTerminate;
|
---|
80 | /** The thread handle. */
|
---|
81 | RTTHREAD hThread;
|
---|
82 |
|
---|
83 | } SUPSVCGRANTSESSION;
|
---|
84 |
|
---|
85 |
|
---|
86 | /**
|
---|
87 | * State grant service machine.
|
---|
88 | */
|
---|
89 | typedef enum SUPSVCGRANTSTATE
|
---|
90 | {
|
---|
91 | /** The invalid zero entry. */
|
---|
92 | kSupSvcGrantState_Invalid = 0,
|
---|
93 | /** Creating - the thread is being started.
|
---|
94 | * Next: Paused or Butchered. */
|
---|
95 | kSupSvcGrantState_Creating,
|
---|
96 | /** Paused - the thread is blocked on it's user event semaphore.
|
---|
97 | * Next: Resuming, Terminating or Butchered.
|
---|
98 | * Prev: Creating, Pausing */
|
---|
99 | kSupSvcGrantState_Paused,
|
---|
100 | /** Resuming - the thread is being unblocked and ushered into RTLocalIpcServiceListen.
|
---|
101 | * Next: Listen or Butchered.
|
---|
102 | * Prev: Paused */
|
---|
103 | kSupSvcGrantState_Resuming,
|
---|
104 | /** Listen - the thread is in RTLocalIpcServerListen or setting up an incoming session.
|
---|
105 | * Next: Pausing or Butchered.
|
---|
106 | * Prev: Resuming */
|
---|
107 | kSupSvcGrantState_Listen,
|
---|
108 | /** Pausing - Cancelling the listen and dropping any incoming sessions.
|
---|
109 | * Next: Paused or Butchered.
|
---|
110 | * Prev: Listen */
|
---|
111 | kSupSvcGrantState_Pausing,
|
---|
112 | /** Butchered - The thread has quit because something when terribly wrong.
|
---|
113 | * Next: Destroyed
|
---|
114 | * Prev: Any. */
|
---|
115 | kSupSvcGrantState_Butchered,
|
---|
116 | /** Pausing - Cancelling the listen and dropping any incoming sessions.
|
---|
117 | * Next: Destroyed
|
---|
118 | * Prev: Paused */
|
---|
119 | kSupSvcGrantState_Terminating,
|
---|
120 | /** Destroyed - the instance is invalid.
|
---|
121 | * Prev: Butchered or Terminating */
|
---|
122 | kSupSvcGrantState_Destroyed,
|
---|
123 | /** The end of valid state values. */
|
---|
124 | kSupSvcGrantState_End,
|
---|
125 | /** The usual 32-bit blowup hack. */
|
---|
126 | kSupSvcGrantState_32BitHack = 0x7fffffff
|
---|
127 | } SUPSVCGRANTSTATE;
|
---|
128 |
|
---|
129 |
|
---|
130 | /**
|
---|
131 | * Grant service instance data.
|
---|
132 | */
|
---|
133 | typedef struct SUPSVCGRANT
|
---|
134 | {
|
---|
135 | /** The local ipc server handle. */
|
---|
136 | RTLOCALIPCSERVER hServer;
|
---|
137 |
|
---|
138 | /** Critical section serializing access to the session list, the state,
|
---|
139 | * the response event, the session event, and the thread event. */
|
---|
140 | RTCRITSECT CritSect;
|
---|
141 | /** The service thread will signal this event when it has changed to
|
---|
142 | * the 'paused' or 'running' state. */
|
---|
143 | RTSEMEVENT hResponseEvent;
|
---|
144 | /** Event that's signaled on session termination. */
|
---|
145 | RTSEMEVENT hSessionEvent;
|
---|
146 | /** The handle to the service thread. */
|
---|
147 | RTTHREAD hThread;
|
---|
148 | /** Head of the session list. */
|
---|
149 | PSUPSVCGRANTSESSION volatile pSessionHead;
|
---|
150 | /** The service state. */
|
---|
151 | SUPSVCGRANTSTATE volatile enmState;
|
---|
152 |
|
---|
153 | /** Critical section serializing access to the SUPR3HardenedVerify APIs. */
|
---|
154 | RTCRITSECT VerifyCritSect;
|
---|
155 | } SUPSVCGRANT;
|
---|
156 |
|
---|
157 |
|
---|
158 | /*********************************************************************************************************************************
|
---|
159 | * Internal Functions *
|
---|
160 | *********************************************************************************************************************************/
|
---|
161 | static const char *supSvcGrantStateName(SUPSVCGRANTSTATE enmState);
|
---|
162 |
|
---|
163 |
|
---|
164 |
|
---|
165 |
|
---|
166 | /**
|
---|
167 | * Services a client session.
|
---|
168 | *
|
---|
169 | * @returns VINF_SUCCESS.
|
---|
170 | *
|
---|
171 | * @param hThread The thread handle.
|
---|
172 | * @param pvSession Pointer to the session instance data.
|
---|
173 | */
|
---|
174 | static DECLCALLBACK(int) supSvcGrantSessionThread(RTTHREAD hThread, void *pvSession)
|
---|
175 | {
|
---|
176 | PSUPSVCGRANTSESSION pThis = (PSUPSVCGRANTSESSION)pvSession;
|
---|
177 | RTLOCALIPCSESSION hSession = pThis->hSession;
|
---|
178 | Log(("supSvcGrantSessionThread(%p):\n", pThis));
|
---|
179 |
|
---|
180 | /*
|
---|
181 | * Process client requests until it quits or we're cancelled on termination.
|
---|
182 | */
|
---|
183 | while (!ASMAtomicUoReadBool(&pThis->fTerminate))
|
---|
184 | {
|
---|
185 | RTThreadSleep(1000);
|
---|
186 | /** @todo */
|
---|
187 | }
|
---|
188 |
|
---|
189 | /*
|
---|
190 | * Clean up the session.
|
---|
191 | */
|
---|
192 | PSUPSVCGRANT pParent = ASMAtomicReadPtrT(&pThis->pParent, PSUPSVCGRANT);
|
---|
193 | if (pParent)
|
---|
194 | RTCritSectEnter(&pParent->CritSect);
|
---|
195 | else
|
---|
196 | Log(("supSvcGrantSessionThread(%p): No parent\n", pThis));
|
---|
197 |
|
---|
198 | ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
|
---|
199 | if (hSession != NIL_RTLOCALIPCSESSION)
|
---|
200 | RTLocalIpcSessionClose(hSession);
|
---|
201 | else
|
---|
202 | Log(("supSvcGrantSessionThread(%p): No session handle\n", pThis));
|
---|
203 |
|
---|
204 | if (pParent)
|
---|
205 | {
|
---|
206 | RTSemEventSignal(pParent->hSessionEvent);
|
---|
207 | RTCritSectLeave(&pParent->CritSect);
|
---|
208 | }
|
---|
209 | Log(("supSvcGrantSessionThread(%p): exits\n"));
|
---|
210 | return VINF_SUCCESS;
|
---|
211 | }
|
---|
212 |
|
---|
213 |
|
---|
214 | /**
|
---|
215 | * Cleans up a session.
|
---|
216 | *
|
---|
217 | * This is called while inside the grant service critical section.
|
---|
218 | *
|
---|
219 | * @param pThis The session to destroy.
|
---|
220 | * @param pParent The parent.
|
---|
221 | */
|
---|
222 | static void supSvcGrantSessionDestroy(PSUPSVCGRANTSESSION pThis, PSUPSVCGRANT pParent)
|
---|
223 | {
|
---|
224 | /*
|
---|
225 | * Unlink it.
|
---|
226 | */
|
---|
227 | if (pThis->pNext)
|
---|
228 | {
|
---|
229 | Assert(pThis->pNext->pPrev == pThis);
|
---|
230 | pThis->pNext->pPrev = pThis->pPrev;
|
---|
231 | }
|
---|
232 |
|
---|
233 | if (pThis->pPrev)
|
---|
234 | {
|
---|
235 | Assert(pThis->pPrev->pNext == pThis);
|
---|
236 | pThis->pPrev->pNext = pThis->pNext;
|
---|
237 | }
|
---|
238 | else if (pParent->pSessionHead == pThis)
|
---|
239 | pParent->pSessionHead = pThis->pNext;
|
---|
240 |
|
---|
241 | /*
|
---|
242 | * Free the resources associated with it.
|
---|
243 | */
|
---|
244 | pThis->hThread = NIL_RTTHREAD;
|
---|
245 | pThis->pNext = NULL;
|
---|
246 | pThis->pPrev = NULL;
|
---|
247 |
|
---|
248 | RTLOCALIPCSESSION hSession;
|
---|
249 | ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
|
---|
250 | if (hSession != NIL_RTLOCALIPCSESSION)
|
---|
251 | RTLocalIpcSessionClose(hSession);
|
---|
252 |
|
---|
253 | RTMemFree(pThis);
|
---|
254 | }
|
---|
255 |
|
---|
256 |
|
---|
257 | /**
|
---|
258 | * Cleans up zombie sessions, locked.
|
---|
259 | *
|
---|
260 | * @param pThis Pointer to the grant service instance data.
|
---|
261 | */
|
---|
262 | static void supSvcGrantCleanUpSessionsLocked(PSUPSVCGRANT pThis)
|
---|
263 | {
|
---|
264 | /*
|
---|
265 | * Iterate until be make it all the way thru the list.
|
---|
266 | *
|
---|
267 | * Only use the thread state as and indicator on whether we can destroy
|
---|
268 | * the session or not.
|
---|
269 | */
|
---|
270 | PSUPSVCGRANTSESSION pCur;
|
---|
271 | do
|
---|
272 | {
|
---|
273 | for (pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
|
---|
274 | {
|
---|
275 | int rc = RTThreadWait(pCur->hThread, 0, NULL);
|
---|
276 | if (RT_SUCCESS(rc))
|
---|
277 | {
|
---|
278 | supSvcGrantSessionDestroy(pCur, pThis);
|
---|
279 | break;
|
---|
280 | }
|
---|
281 |
|
---|
282 | Assert(rc == VERR_TIMEOUT);
|
---|
283 | Assert(pCur->hThread != NIL_RTTHREAD);
|
---|
284 | Assert(pCur->pNext != pThis->pSessionHead);
|
---|
285 | }
|
---|
286 | } while (pCur);
|
---|
287 | }
|
---|
288 |
|
---|
289 |
|
---|
290 | /**
|
---|
291 | * Cleans up zombie sessions.
|
---|
292 | *
|
---|
293 | * @returns VINF_SUCCESS, VBox error code on internal error.
|
---|
294 | *
|
---|
295 | * @param pThis Pointer to the grant service instance data.
|
---|
296 | * @param fOwnCritSect Whether we own the crit sect already. The state is preserved.
|
---|
297 | */
|
---|
298 | static int supSvcGrantCleanUpSessions(PSUPSVCGRANT pThis, bool fOwnCritSect)
|
---|
299 | {
|
---|
300 | int rc = RTCritSectEnter(&pThis->CritSect);
|
---|
301 | if (RT_FAILURE(rc))
|
---|
302 | {
|
---|
303 | supSvcLogError("supSvcGrantCleanUpSessions: RTCritSectEnter returns %Rrc", rc);
|
---|
304 | return rc;
|
---|
305 | }
|
---|
306 |
|
---|
307 | supSvcGrantCleanUpSessionsLocked(pThis);
|
---|
308 |
|
---|
309 | RTCritSectLeave(&pThis->CritSect);
|
---|
310 | return VINF_SUCCESS;
|
---|
311 | }
|
---|
312 |
|
---|
313 |
|
---|
314 | /**
|
---|
315 | * Gets the state name.
|
---|
316 | *
|
---|
317 | * @returns The state name string (read only).
|
---|
318 | * @param enmState The state.
|
---|
319 | */
|
---|
320 | static const char *supSvcGrantStateName(SUPSVCGRANTSTATE enmState)
|
---|
321 | {
|
---|
322 | switch (enmState)
|
---|
323 | {
|
---|
324 | case kSupSvcGrantState_Invalid: return "Invalid";
|
---|
325 | case kSupSvcGrantState_Creating: return "Creating";
|
---|
326 | case kSupSvcGrantState_Paused: return "Paused";
|
---|
327 | case kSupSvcGrantState_Resuming: return "Resuming";
|
---|
328 | case kSupSvcGrantState_Listen: return "Listen";
|
---|
329 | case kSupSvcGrantState_Pausing: return "Pausing";
|
---|
330 | case kSupSvcGrantState_Butchered: return "Butchered";
|
---|
331 | case kSupSvcGrantState_Terminating: return "Terminating";
|
---|
332 | case kSupSvcGrantState_Destroyed: return "Destroyed";
|
---|
333 | default: return "?Unknown?";
|
---|
334 | }
|
---|
335 | }
|
---|
336 |
|
---|
337 |
|
---|
338 | /**
|
---|
339 | * Attempts to flip into the butchered state.
|
---|
340 | *
|
---|
341 | * @returns rc.
|
---|
342 | * @param pThis The instance data.
|
---|
343 | * @param fOwnCritSect Whether we own the crit sect already.
|
---|
344 | * @param pszFailed What failed.
|
---|
345 | * @param rc What to return (lazy bird).
|
---|
346 | */
|
---|
347 | static int supSvcGrantThreadButchered(PSUPSVCGRANT pThis, bool fOwnCritSect, const char *pszFailed, int rc)
|
---|
348 | {
|
---|
349 | int rc2 = VINF_SUCCESS;
|
---|
350 | if (!fOwnCritSect)
|
---|
351 | rc2 = RTCritSectEnter(&pThis->CritSect);
|
---|
352 | if (RT_SUCCESS(rc2))
|
---|
353 | {
|
---|
354 | supSvcLogError("supSvcGrantThread(%s): Butchered; %Rrc: %s",
|
---|
355 | supSvcGrantStateName(pThis->enmState), rc, pszFailed);
|
---|
356 | pThis->enmState = kSupSvcGrantState_Butchered;
|
---|
357 |
|
---|
358 | RTCritSectLeave(&pThis->CritSect);
|
---|
359 | }
|
---|
360 | return rc;
|
---|
361 | }
|
---|
362 |
|
---|
363 |
|
---|
364 | /**
|
---|
365 | * Creates a new session.
|
---|
366 | *
|
---|
367 | * @returns VINF_SUCCESS on success, VBox error code on internal error.
|
---|
368 | *
|
---|
369 | * @param pThis Pointer to the grant service instance data.
|
---|
370 | * @param hSession The client session handle.
|
---|
371 | */
|
---|
372 | static int supSvcGrantThreadCreateSession(PSUPSVCGRANT pThis, RTLOCALIPCSESSION hSession)
|
---|
373 | {
|
---|
374 | /*
|
---|
375 | * Allocate and initialize a new session instance before entering the critsect.
|
---|
376 | */
|
---|
377 | PSUPSVCGRANTSESSION pSession = (PSUPSVCGRANTSESSION)RTMemAlloc(sizeof(*pSession));
|
---|
378 | if (!pSession)
|
---|
379 | {
|
---|
380 | supSvcLogError("supSvcGrantThreadListen: failed to allocate session");
|
---|
381 | return VINF_SUCCESS; /* not fatal? */
|
---|
382 | }
|
---|
383 | pSession->pPrev = NULL;
|
---|
384 | pSession->pNext = NULL;
|
---|
385 | pSession->pParent = pThis;
|
---|
386 | pSession->hSession = hSession;
|
---|
387 | pSession->fTerminate = false;
|
---|
388 | pSession->hThread = NIL_RTTHREAD;
|
---|
389 |
|
---|
390 | /*
|
---|
391 | * Enter the critsect, check the state, link it and fire off the session thread.
|
---|
392 | */
|
---|
393 | int rc = RTCritSectEnter(&pThis->CritSect);
|
---|
394 | if (RT_SUCCESS(rc))
|
---|
395 | {
|
---|
396 | /* check the state */
|
---|
397 | SUPSVCGRANTSTATE enmState = pThis->enmState;
|
---|
398 | if (enmState == kSupSvcGrantState_Listen)
|
---|
399 | {
|
---|
400 | /* link it */
|
---|
401 | pSession->pNext = pThis->pSessionHead;
|
---|
402 | if (pThis->pSessionHead)
|
---|
403 | pThis->pSessionHead->pPrev = pSession;
|
---|
404 | pThis->pSessionHead = pSession;
|
---|
405 |
|
---|
406 | /* fire up the thread */
|
---|
407 | Log(("supSvcGrantThreadListen: starting session %p\n", pSession));
|
---|
408 | rc = RTThreadCreate(&pSession->hThread, supSvcGrantSessionThread, pSession, 0,
|
---|
409 | RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "SESSION");
|
---|
410 | if (RT_SUCCESS(rc))
|
---|
411 | {
|
---|
412 | rc = RTCritSectLeave(&pThis->CritSect);
|
---|
413 | if (RT_FAILURE(rc))
|
---|
414 | return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTCritSectLeave", rc);
|
---|
415 |
|
---|
416 | /*
|
---|
417 | * Successfully handled the client.
|
---|
418 | */
|
---|
419 | return VINF_SUCCESS;
|
---|
420 | }
|
---|
421 |
|
---|
422 | /* bail out */
|
---|
423 | supSvcLogError("supSvcGrantThreadListen: RTThreadCreate returns %Rrc", rc);
|
---|
424 | }
|
---|
425 | else
|
---|
426 | Log(("supSvcGrantThreadListen: dropping connection, state %s\n", supSvcGrantStateName(enmState)));
|
---|
427 |
|
---|
428 | RTCritSectLeave(&pThis->CritSect);
|
---|
429 | rc = VINF_SUCCESS;
|
---|
430 | }
|
---|
431 | else
|
---|
432 | supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTCritSectEnter", rc);
|
---|
433 | RTLocalIpcSessionClose(hSession);
|
---|
434 | RTMemFree(pSession);
|
---|
435 | return rc;
|
---|
436 | }
|
---|
437 |
|
---|
438 |
|
---|
439 | /**
|
---|
440 | * Listen for a client session and kicks off the service thread for it.
|
---|
441 | *
|
---|
442 | * @returns VINF_SUCCESS on normal state change, failure if something gets screwed up.
|
---|
443 | *
|
---|
444 | * @param pThis Pointer to the grant service instance data.
|
---|
445 | */
|
---|
446 | static int supSvcGrantThreadListen(PSUPSVCGRANT pThis)
|
---|
447 | {
|
---|
448 | /*
|
---|
449 | * Wait for a client to connect and create a new session.
|
---|
450 | */
|
---|
451 | RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
|
---|
452 | int rc = RTLocalIpcServerListen(pThis->hServer, &hClientSession);
|
---|
453 | if (RT_FAILURE(rc))
|
---|
454 | {
|
---|
455 | if (rc == VERR_CANCELLED)
|
---|
456 | LogFlow(("supSvcGrantThreadListen: cancelled\n"));
|
---|
457 | else if (rc == VERR_TRY_AGAIN)
|
---|
458 | /* for testing */;
|
---|
459 | else
|
---|
460 | return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTLocalIpcServerListen", rc);
|
---|
461 | return VINF_SUCCESS;
|
---|
462 | }
|
---|
463 |
|
---|
464 | return supSvcGrantThreadCreateSession(pThis, hClientSession);
|
---|
465 | }
|
---|
466 |
|
---|
467 |
|
---|
468 | /**
|
---|
469 | * Grant service thread.
|
---|
470 | *
|
---|
471 | * This thread is the one listening for clients and kicks off
|
---|
472 | * the session threads and stuff.
|
---|
473 | *
|
---|
474 | * @returns VINF_SUCCESS on normal exit, VBox error status on failure.
|
---|
475 | * @param hThread The thread handle.
|
---|
476 | * @param pvThis Pointer to the grant service instance data.
|
---|
477 | */
|
---|
478 | static DECLCALLBACK(int) supSvcGrantThread(RTTHREAD hThread, void *pvThis)
|
---|
479 | {
|
---|
480 | PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvThis;
|
---|
481 |
|
---|
482 | /*
|
---|
483 | * The state loop.
|
---|
484 | */
|
---|
485 | for (;;)
|
---|
486 | {
|
---|
487 | /*
|
---|
488 | * Switch on the current state (requires critsect).
|
---|
489 | */
|
---|
490 | int rc = RTCritSectEnter(&pThis->CritSect);
|
---|
491 | if (RT_FAILURE(rc))
|
---|
492 | {
|
---|
493 | supSvcLogError("supSvcGrantThread - RTCritSectEnter returns %Rrc", rc);
|
---|
494 | return rc;
|
---|
495 | }
|
---|
496 |
|
---|
497 | SUPSVCGRANTSTATE enmState = pThis->enmState;
|
---|
498 | LogFlow(("supSvcGrantThread: switching %s\n", supSvcGrantStateName(enmState)));
|
---|
499 | switch (enmState)
|
---|
500 | {
|
---|
501 | case kSupSvcGrantState_Creating:
|
---|
502 | case kSupSvcGrantState_Pausing:
|
---|
503 | pThis->enmState = kSupSvcGrantState_Paused;
|
---|
504 | rc = RTSemEventSignal(pThis->hResponseEvent);
|
---|
505 | if (RT_FAILURE(rc))
|
---|
506 | return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "RTSemEventSignal", rc);
|
---|
507 | RT_FALL_THRU();
|
---|
508 |
|
---|
509 | case kSupSvcGrantState_Paused:
|
---|
510 | RTCritSectLeave(&pThis->CritSect);
|
---|
511 |
|
---|
512 | rc = RTThreadUserWait(hThread, 60*1000); /* wake up once in a while (paranoia) */
|
---|
513 | if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
|
---|
514 | return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect*/, "RTThreadUserWait", rc);
|
---|
515 | break;
|
---|
516 |
|
---|
517 | case kSupSvcGrantState_Resuming:
|
---|
518 | pThis->enmState = kSupSvcGrantState_Listen;
|
---|
519 | rc = RTSemEventSignal(pThis->hResponseEvent);
|
---|
520 | if (RT_FAILURE(rc))
|
---|
521 | return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "RTSemEventSignal", rc);
|
---|
522 | RT_FALL_THRU();
|
---|
523 |
|
---|
524 | case kSupSvcGrantState_Listen:
|
---|
525 | RTCritSectLeave(&pThis->CritSect);
|
---|
526 | rc = supSvcGrantThreadListen(pThis);
|
---|
527 | if (RT_FAILURE(rc))
|
---|
528 | {
|
---|
529 | Log(("supSvcGrantThread: supSvcGrantDoListening returns %Rrc, exiting\n", rc));
|
---|
530 | return rc;
|
---|
531 | }
|
---|
532 | break;
|
---|
533 |
|
---|
534 | case kSupSvcGrantState_Terminating:
|
---|
535 | RTCritSectLeave(&pThis->CritSect);
|
---|
536 | Log(("supSvcGrantThread: Done\n"));
|
---|
537 | return VINF_SUCCESS;
|
---|
538 |
|
---|
539 | case kSupSvcGrantState_Butchered:
|
---|
540 | default:
|
---|
541 | return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "Bad state", VERR_INTERNAL_ERROR);
|
---|
542 | }
|
---|
543 |
|
---|
544 | /*
|
---|
545 | * Massage the session list between clients and states.
|
---|
546 | */
|
---|
547 | rc = supSvcGrantCleanUpSessions(pThis, false /* fOwnCritSect */);
|
---|
548 | if (RT_FAILURE(rc))
|
---|
549 | return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "supSvcGrantCleanUpSessions", rc);
|
---|
550 | }
|
---|
551 | }
|
---|
552 |
|
---|
553 |
|
---|
554 | /**
|
---|
555 | * Waits for the service thread to respond to a state change.
|
---|
556 | *
|
---|
557 | * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time, other error code on internal error.
|
---|
558 | *
|
---|
559 | * @param pThis Pointer to the grant service instance data.
|
---|
560 | * @param enmCurState The current state.
|
---|
561 | * @param enmNewState The new state we're waiting for it to enter.
|
---|
562 | */
|
---|
563 | static int supSvcGrantWait(PSUPSVCGRANT pThis, SUPSVCGRANTSTATE enmCurState, SUPSVCGRANTSTATE enmNewState)
|
---|
564 | {
|
---|
565 | LogFlow(("supSvcGrantWait(,%s,%s): enter\n",
|
---|
566 | supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState)));
|
---|
567 |
|
---|
568 | /*
|
---|
569 | * Wait a short while for the response event to be set.
|
---|
570 | */
|
---|
571 | RTSemEventWait(pThis->hResponseEvent, 1000);
|
---|
572 | int rc = RTCritSectEnter(&pThis->CritSect);
|
---|
573 | if (RT_SUCCESS(rc))
|
---|
574 | {
|
---|
575 | if (pThis->enmState == enmNewState)
|
---|
576 | {
|
---|
577 | RTCritSectLeave(&pThis->CritSect);
|
---|
578 | rc = VINF_SUCCESS;
|
---|
579 | }
|
---|
580 | else if (pThis->enmState == enmCurState)
|
---|
581 | {
|
---|
582 | /*
|
---|
583 | * Wait good while longer.
|
---|
584 | */
|
---|
585 | RTCritSectLeave(&pThis->CritSect);
|
---|
586 | rc = RTSemEventWait(pThis->hResponseEvent, 59*1000); /* 59 sec */
|
---|
587 | if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT)
|
---|
588 | {
|
---|
589 | rc = RTCritSectEnter(&pThis->CritSect);
|
---|
590 | if (RT_SUCCESS(rc))
|
---|
591 | {
|
---|
592 | /*
|
---|
593 | * Check the state whether we've succeeded.
|
---|
594 | */
|
---|
595 | SUPSVCGRANTSTATE enmState = pThis->enmState;
|
---|
596 | if (enmState == enmNewState)
|
---|
597 | rc = VINF_SUCCESS;
|
---|
598 | else if (enmState == enmCurState)
|
---|
599 | {
|
---|
600 | supSvcLogError("supSvcGrantWait(,%s,%s) - the thread doesn't respond in a timely manner, failing.",
|
---|
601 | supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
|
---|
602 | rc = VERR_TIMEOUT;
|
---|
603 | }
|
---|
604 | else
|
---|
605 | {
|
---|
606 | supSvcLogError("supSvcGrantWait(,%s,%s) - wrong state %s!", supSvcGrantStateName(enmCurState),
|
---|
607 | supSvcGrantStateName(enmNewState), supSvcGrantStateName(enmState));
|
---|
608 | AssertMsgFailed(("%s\n", supSvcGrantStateName(enmState)));
|
---|
609 | rc = VERR_INTERNAL_ERROR;
|
---|
610 | }
|
---|
611 |
|
---|
612 | RTCritSectLeave(&pThis->CritSect);
|
---|
613 | }
|
---|
614 | else
|
---|
615 | supSvcLogError("supSvcGrantWait(,%s,%s) - RTCritSectEnter returns %Rrc",
|
---|
616 | supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
|
---|
617 | }
|
---|
618 | else
|
---|
619 | supSvcLogError("supSvcGrantWait(,%s,%s) - RTSemEventWait returns %Rrc",
|
---|
620 | supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
|
---|
621 | }
|
---|
622 | else
|
---|
623 | {
|
---|
624 | supSvcLogError("supSvcGrantWait(,%s,%s) - wrong state %s!", supSvcGrantStateName(enmCurState),
|
---|
625 | supSvcGrantStateName(enmNewState), supSvcGrantStateName(pThis->enmState));
|
---|
626 | AssertMsgFailed(("%s\n", supSvcGrantStateName(pThis->enmState)));
|
---|
627 | RTCritSectLeave(&pThis->CritSect);
|
---|
628 | rc = VERR_INTERNAL_ERROR;
|
---|
629 | }
|
---|
630 | }
|
---|
631 | else
|
---|
632 | supSvcLogError("supSvcGrantWait(,%s,%s) - RTCritSectEnter returns %Rrc",
|
---|
633 | supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
|
---|
634 |
|
---|
635 | Log(("supSvcGrantWait(,%s,%s): returns %Rrc\n",
|
---|
636 | supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState), rc));
|
---|
637 | return rc;
|
---|
638 | }
|
---|
639 |
|
---|
640 |
|
---|
641 | /** @copydoc SUPSVCSERVICE::pfnCreate */
|
---|
642 | DECLCALLBACK(int) supSvcGrantCreate(void **ppvInstance)
|
---|
643 | {
|
---|
644 | LogFlowFuncEnter();
|
---|
645 |
|
---|
646 | /*
|
---|
647 | * Allocate and initialize the session data.
|
---|
648 | */
|
---|
649 | PSUPSVCGRANT pThis = (PSUPSVCGRANT)RTMemAlloc(sizeof(*pThis));
|
---|
650 | if (!pThis)
|
---|
651 | {
|
---|
652 | supSvcLogError("supSvcGrantCreate - no memory");
|
---|
653 | return VERR_NO_MEMORY;
|
---|
654 | }
|
---|
655 | bool fFreeIt = true;
|
---|
656 | pThis->pSessionHead = NULL;
|
---|
657 | pThis->enmState = kSupSvcGrantState_Creating;
|
---|
658 | int rc = RTCritSectInit(&pThis->VerifyCritSect);
|
---|
659 | if (RT_SUCCESS(rc))
|
---|
660 | {
|
---|
661 | rc = RTCritSectInit(&pThis->CritSect);
|
---|
662 | if (RT_SUCCESS(rc))
|
---|
663 | {
|
---|
664 | rc = RTSemEventCreate(&pThis->hResponseEvent);
|
---|
665 | if (RT_SUCCESS(rc))
|
---|
666 | {
|
---|
667 | rc = RTSemEventCreate(&pThis->hSessionEvent);
|
---|
668 | if (RT_SUCCESS(rc))
|
---|
669 | {
|
---|
670 | /*
|
---|
671 | * Create the local IPC instance and then finally fire up the thread.
|
---|
672 | */
|
---|
673 | rc = RTLocalIpcServerCreate(&pThis->hServer, SUPSVC_GRANT_SERVICE_NAME, RTLOCALIPC_FLAGS_MULTI_SESSION);
|
---|
674 | if (RT_SUCCESS(rc))
|
---|
675 | {
|
---|
676 | rc = RTThreadCreate(&pThis->hThread, supSvcGrantThread, pThis, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "GRANT");
|
---|
677 | if (RT_SUCCESS(rc))
|
---|
678 | {
|
---|
679 | rc = supSvcGrantWait(pThis, kSupSvcGrantState_Creating, kSupSvcGrantState_Paused);
|
---|
680 | if (RT_SUCCESS(rc))
|
---|
681 | {
|
---|
682 | /*
|
---|
683 | * Successfully created the grant service!
|
---|
684 | */
|
---|
685 | Log(("supSvcGrantCreate: returns VINF_SUCCESS (pThis=%p)\n", pThis));
|
---|
686 | *ppvInstance = pThis;
|
---|
687 | return VINF_SUCCESS;
|
---|
688 | }
|
---|
689 |
|
---|
690 | /*
|
---|
691 | * The thread FAILED to start in a timely manner!
|
---|
692 | */
|
---|
693 | RTCritSectEnter(&pThis->CritSect);
|
---|
694 | pThis->enmState = kSupSvcGrantState_Terminating;
|
---|
695 | RTCritSectLeave(&pThis->CritSect);
|
---|
696 |
|
---|
697 | RTThreadUserSignal(pThis->hThread);
|
---|
698 |
|
---|
699 | int cTries = 10;
|
---|
700 | int rc2 = RTThreadWait(pThis->hThread, 20000, NULL);
|
---|
701 | if (RT_FAILURE(rc2))
|
---|
702 | {
|
---|
703 | /* poke it a few more times before giving up. */
|
---|
704 | while (--cTries > 0)
|
---|
705 | {
|
---|
706 | RTThreadUserSignal(pThis->hThread);
|
---|
707 | RTLocalIpcServerCancel(pThis->hServer);
|
---|
708 | if (RTThreadWait(pThis->hThread, 1000, NULL) != VERR_TIMEOUT)
|
---|
709 | break;
|
---|
710 | }
|
---|
711 | }
|
---|
712 | fFreeIt = cTries <= 0;
|
---|
713 | }
|
---|
714 | else
|
---|
715 | supSvcLogError("supSvcGrantCreate - RTThreadCreate returns %Rrc", rc);
|
---|
716 | RTLocalIpcServerDestroy(pThis->hServer);
|
---|
717 | pThis->hServer = NIL_RTLOCALIPCSERVER;
|
---|
718 | }
|
---|
719 | else
|
---|
720 | supSvcLogError("supSvcGrantCreate - RTLocalIpcServiceCreate returns %Rrc", rc);
|
---|
721 | RTSemEventDestroy(pThis->hSessionEvent);
|
---|
722 | pThis->hSessionEvent = NIL_RTSEMEVENT;
|
---|
723 | }
|
---|
724 | else
|
---|
725 | supSvcLogError("supSvcGrantCreate - RTSemEventCreate returns %Rrc", rc);
|
---|
726 | RTSemEventDestroy(pThis->hResponseEvent);
|
---|
727 | pThis->hResponseEvent = NIL_RTSEMEVENT;
|
---|
728 | }
|
---|
729 | else
|
---|
730 | supSvcLogError("supSvcGrantCreate - RTSemEventCreate returns %Rrc", rc);
|
---|
731 | RTCritSectDelete(&pThis->CritSect);
|
---|
732 | }
|
---|
733 | else
|
---|
734 | supSvcLogError("supSvcGrantCreate - RTCritSectInit returns %Rrc", rc);
|
---|
735 | RTCritSectDelete(&pThis->VerifyCritSect);
|
---|
736 | }
|
---|
737 | else
|
---|
738 | supSvcLogError("supSvcGrantCreate - RTCritSectInit returns %Rrc", rc);
|
---|
739 | if (fFreeIt)
|
---|
740 | RTMemFree(pThis);
|
---|
741 | Log(("supSvcGrantCreate: returns %Rrc\n", rc));
|
---|
742 | return rc;
|
---|
743 | }
|
---|
744 |
|
---|
745 |
|
---|
746 | /** @copydoc SUPSVCSERVICE::pfnStart */
|
---|
747 | DECLCALLBACK(void) supSvcGrantStart(void *pvInstance)
|
---|
748 | {
|
---|
749 | PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvInstance;
|
---|
750 |
|
---|
751 | /*
|
---|
752 | * Change the state and signal the thread.
|
---|
753 | */
|
---|
754 | int rc = RTCritSectEnter(&pThis->CritSect);
|
---|
755 | if (RT_SUCCESS(rc))
|
---|
756 | {
|
---|
757 | bool fInCritSect = true;
|
---|
758 | SUPSVCGRANTSTATE enmState = pThis->enmState;
|
---|
759 | if (enmState == kSupSvcGrantState_Paused)
|
---|
760 | {
|
---|
761 | pThis->enmState = kSupSvcGrantState_Resuming;
|
---|
762 | rc = RTThreadUserSignal(pThis->hThread);
|
---|
763 | if (RT_SUCCESS(rc))
|
---|
764 | {
|
---|
765 | /*
|
---|
766 | * Wait for the bugger to respond (no need to bitch here).
|
---|
767 | */
|
---|
768 | RTCritSectLeave(&pThis->CritSect);
|
---|
769 | supSvcGrantWait(pThis, kSupSvcGrantState_Resuming, kSupSvcGrantState_Listen);
|
---|
770 | fInCritSect = false;
|
---|
771 | }
|
---|
772 | }
|
---|
773 | else
|
---|
774 | supSvcLogError("supSvcGrantStart - Incorrect state %s!", supSvcGrantStateName(enmState));
|
---|
775 | if (fInCritSect)
|
---|
776 | RTCritSectLeave(&pThis->CritSect);
|
---|
777 | }
|
---|
778 | else
|
---|
779 | {
|
---|
780 | supSvcLogError("supSvcGrantStart - RTCritSectEnter returns %Rrc!", rc);
|
---|
781 | AssertRCReturnVoid(rc);
|
---|
782 | }
|
---|
783 | }
|
---|
784 |
|
---|
785 |
|
---|
786 | /** @copydoc SUPSVCSERVICE::pfnTryStop */
|
---|
787 | DECLCALLBACK(int) supSvcGrantTryStop(void *pvInstance)
|
---|
788 | {
|
---|
789 | PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvInstance;
|
---|
790 |
|
---|
791 | /*
|
---|
792 | * Don't give up immediately.
|
---|
793 | */
|
---|
794 | uint64_t u64StartTS = RTTimeMilliTS();
|
---|
795 | int rc;
|
---|
796 | for (;;)
|
---|
797 | {
|
---|
798 | /*
|
---|
799 | * First check the state to make sure the thing is actually running.
|
---|
800 | * If the critsect is butchered, just pretend success.
|
---|
801 | */
|
---|
802 | rc = RTCritSectEnter(&pThis->CritSect);
|
---|
803 | if (RT_FAILURE(rc))
|
---|
804 | {
|
---|
805 | supSvcLogError("supSvcGrantTryStop - RTCritSectEnter returns %Rrc", rc);
|
---|
806 | AssertRC(rc);
|
---|
807 | return VINF_SUCCESS;
|
---|
808 | }
|
---|
809 | SUPSVCGRANTSTATE enmState = pThis->enmState;
|
---|
810 | if (enmState != kSupSvcGrantState_Listen)
|
---|
811 | {
|
---|
812 | supSvcLogError("supSvcGrantTryStop - Not running, state: %s", supSvcGrantStateName(enmState));
|
---|
813 | RTCritSectLeave(&pThis->CritSect);
|
---|
814 | return VINF_SUCCESS;
|
---|
815 | }
|
---|
816 |
|
---|
817 | /*
|
---|
818 | * If there are no clients, usher the thread into the paused state.
|
---|
819 | */
|
---|
820 | supSvcGrantCleanUpSessionsLocked(pThis);
|
---|
821 | if (!pThis->pSessionHead)
|
---|
822 | {
|
---|
823 | rc = RTThreadUserReset(pThis->hThread);
|
---|
824 | pThis->enmState = kSupSvcGrantState_Pausing;
|
---|
825 | int rc2 = RTLocalIpcServerCancel(pThis->hServer);
|
---|
826 | int rc3 = RTCritSectLeave(&pThis->CritSect);
|
---|
827 | if (RT_SUCCESS(rc) && RT_SUCCESS(rc2) && RT_SUCCESS(rc3))
|
---|
828 | supSvcGrantWait(pThis, kSupSvcGrantState_Pausing, kSupSvcGrantState_Paused);
|
---|
829 | else
|
---|
830 | {
|
---|
831 | if (RT_FAILURE(rc))
|
---|
832 | supSvcLogError("supSvcGrantTryStop - RTThreadUserReset returns %Rrc", rc);
|
---|
833 | if (RT_FAILURE(rc2))
|
---|
834 | supSvcLogError("supSvcGrantTryStop - RTLocalIpcServerCancel returns %Rrc", rc);
|
---|
835 | if (RT_FAILURE(rc3))
|
---|
836 | supSvcLogError("supSvcGrantTryStop - RTCritSectLeave returns %Rrc", rc);
|
---|
837 | }
|
---|
838 | return VINF_SUCCESS;
|
---|
839 | }
|
---|
840 |
|
---|
841 | /*
|
---|
842 | * Check the time limit, otherwise wait for a client event.
|
---|
843 | */
|
---|
844 | uint64_t u64Elapsed = RTTimeMilliTS() - u64StartTS;
|
---|
845 | if (u64Elapsed >= 60*1000) /* 1 min */
|
---|
846 | {
|
---|
847 | unsigned cSessions = 0;
|
---|
848 | for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
|
---|
849 | cSessions++;
|
---|
850 | RTCritSectLeave(&pThis->CritSect);
|
---|
851 |
|
---|
852 | supSvcLogError("supSvcGrantTryStop - %u active sessions after waiting %u ms", cSessions, (unsigned)u64Elapsed);
|
---|
853 | return VERR_TRY_AGAIN;
|
---|
854 | }
|
---|
855 |
|
---|
856 | rc = RTCritSectLeave(&pThis->CritSect);
|
---|
857 | if (RT_FAILURE(rc))
|
---|
858 | {
|
---|
859 | supSvcLogError("supSvcGrantTryStop - RTCritSectLeave returns %Rrc", rc);
|
---|
860 | return VINF_SUCCESS;
|
---|
861 | }
|
---|
862 |
|
---|
863 | rc = RTSemEventWait(pThis->hSessionEvent, 60*1000 - u64Elapsed);
|
---|
864 | if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
|
---|
865 | {
|
---|
866 | supSvcLogError("supSvcGrantTryStop - RTSemEventWait returns %Rrc", rc);
|
---|
867 | return VINF_SUCCESS;
|
---|
868 | }
|
---|
869 | }
|
---|
870 | }
|
---|
871 |
|
---|
872 |
|
---|
873 | /** @copydoc SUPSVCSERVICE::pfnStopAndDestroy */
|
---|
874 | DECLCALLBACK(void) supSvcGrantStopAndDestroy(void *pvInstance, bool fRunning)
|
---|
875 | {
|
---|
876 | PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvInstance;
|
---|
877 | int rc;
|
---|
878 |
|
---|
879 | /*
|
---|
880 | * Attempt to stop the service, cancelling blocked server and client calls.
|
---|
881 | */
|
---|
882 | RTCritSectEnter(&pThis->CritSect);
|
---|
883 |
|
---|
884 | SUPSVCGRANTSTATE enmState = pThis->enmState;
|
---|
885 | AssertMsg(fRunning == (pThis->enmState == kSupSvcGrantState_Listen),
|
---|
886 | ("%RTbool %s\n", fRunning, supSvcGrantStateName(enmState)));
|
---|
887 |
|
---|
888 | if (enmState == kSupSvcGrantState_Listen)
|
---|
889 | {
|
---|
890 | RTThreadUserReset(pThis->hThread);
|
---|
891 | pThis->enmState = kSupSvcGrantState_Paused;
|
---|
892 | for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
|
---|
893 | ASMAtomicWriteBool(&pCur->fTerminate, true);
|
---|
894 |
|
---|
895 | /* try cancel local ipc operations that might be pending */
|
---|
896 | RTLocalIpcServerCancel(pThis->hServer);
|
---|
897 | for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
|
---|
898 | {
|
---|
899 | RTLOCALIPCSESSION hSession;
|
---|
900 | ASMAtomicReadHandle(&pCur->hSession, &hSession);
|
---|
901 | if (hSession != NIL_RTLOCALIPCSESSION)
|
---|
902 | RTLocalIpcSessionCancel(hSession);
|
---|
903 | }
|
---|
904 |
|
---|
905 | /*
|
---|
906 | * Wait for the thread to respond (outside the crit sect).
|
---|
907 | */
|
---|
908 | RTCritSectLeave(&pThis->CritSect);
|
---|
909 | supSvcGrantWait(pThis, kSupSvcGrantState_Pausing, kSupSvcGrantState_Paused);
|
---|
910 | RTCritSectEnter(&pThis->CritSect);
|
---|
911 |
|
---|
912 | /*
|
---|
913 | * Wait for any lingering sessions to exit.
|
---|
914 | */
|
---|
915 | supSvcGrantCleanUpSessionsLocked(pThis);
|
---|
916 | if (pThis->pSessionHead)
|
---|
917 | {
|
---|
918 | uint64_t u64StartTS = RTTimeMilliTS();
|
---|
919 | do
|
---|
920 | {
|
---|
921 | /* Destroy the sessions since cancelling didn't do the trick. */
|
---|
922 | for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
|
---|
923 | {
|
---|
924 | RTLOCALIPCSESSION hSession;
|
---|
925 | ASMAtomicXchgHandle(&pCur->hSession, NIL_RTLOCALIPCSESSION, &hSession);
|
---|
926 | if (hSession != NIL_RTLOCALIPCSESSION)
|
---|
927 | {
|
---|
928 | rc = RTLocalIpcSessionClose(hSession);
|
---|
929 | AssertRC(rc);
|
---|
930 | if (RT_FAILURE(rc))
|
---|
931 | supSvcLogError("supSvcGrantStopAndDestroy: RTLocalIpcSessionClose(%p) returns %Rrc",
|
---|
932 | (uintptr_t)hSession, rc);
|
---|
933 | }
|
---|
934 | }
|
---|
935 |
|
---|
936 | /* Check the time. */
|
---|
937 | uint64_t u64Elapsed = RTTimeMilliTS() - u64StartTS;
|
---|
938 | if (u64Elapsed >= 60*1000) /* 1 min */
|
---|
939 | break;
|
---|
940 |
|
---|
941 | /* wait */
|
---|
942 | RTCritSectLeave(&pThis->CritSect);
|
---|
943 | rc = RTSemEventWait(pThis->hSessionEvent, 60*1000 - u64Elapsed);
|
---|
944 | RTCritSectEnter(&pThis->CritSect);
|
---|
945 | if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
|
---|
946 | break;
|
---|
947 |
|
---|
948 | /* cleanup and check again */
|
---|
949 | supSvcGrantCleanUpSessionsLocked(pThis);
|
---|
950 | } while (pThis->pSessionHead);
|
---|
951 | }
|
---|
952 | }
|
---|
953 |
|
---|
954 | /*
|
---|
955 | * Tell the service thread to terminate and wait for it to do so.
|
---|
956 | */
|
---|
957 | pThis->enmState = kSupSvcGrantState_Terminating;
|
---|
958 | RTLOCALIPCSERVER hServer;
|
---|
959 | ASMAtomicXchgHandle(&pThis->hServer, NIL_RTLOCALIPCSERVER, &hServer);
|
---|
960 | RTThreadUserSignal(pThis->hThread);
|
---|
961 |
|
---|
962 | RTCritSectLeave(&pThis->CritSect);
|
---|
963 |
|
---|
964 | rc = RTThreadWait(pThis->hThread, 20*1000, NULL);
|
---|
965 | if (RT_FAILURE(rc) && rc == VERR_TIMEOUT)
|
---|
966 | {
|
---|
967 | RTThreadUserSignal(pThis->hThread);
|
---|
968 | RTLocalIpcServerDestroy(hServer);
|
---|
969 | hServer = NIL_RTLOCALIPCSERVER;
|
---|
970 |
|
---|
971 | rc = RTThreadWait(pThis->hThread, 40*1000, NULL);
|
---|
972 | if (RT_FAILURE(rc))
|
---|
973 | supSvcLogError("supSvcGrantStopAndDestroy - RTThreadWait(40 sec) returns %Rrc", rc);
|
---|
974 | }
|
---|
975 | else if (RT_FAILURE(rc))
|
---|
976 | supSvcLogError("supSvcGrantStopAndDestroy - RTThreadWait(20 sec) returns %Rrc", rc);
|
---|
977 | pThis->hThread = NIL_RTTHREAD;
|
---|
978 |
|
---|
979 | /*
|
---|
980 | * Kill the parent pointers of any lingering sessions.
|
---|
981 | */
|
---|
982 | RTCritSectEnter(&pThis->CritSect);
|
---|
983 | pThis->enmState = kSupSvcGrantState_Destroyed;
|
---|
984 |
|
---|
985 | supSvcGrantCleanUpSessionsLocked(pThis);
|
---|
986 | unsigned cSessions = 0;
|
---|
987 | for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
|
---|
988 | ASMAtomicWriteNullPtr(&pCur->pParent);
|
---|
989 |
|
---|
990 | RTCritSectLeave(&pThis->CritSect);
|
---|
991 | if (cSessions)
|
---|
992 | supSvcLogError("supSvcGrantStopAndDestroy: %d session failed to terminate!", cSessions);
|
---|
993 |
|
---|
994 | /*
|
---|
995 | * Free the resource.
|
---|
996 | */
|
---|
997 | RTLocalIpcServerDestroy(hServer);
|
---|
998 |
|
---|
999 | RTSemEventDestroy(pThis->hResponseEvent);
|
---|
1000 | pThis->hResponseEvent = NIL_RTSEMEVENT;
|
---|
1001 |
|
---|
1002 | RTSemEventDestroy(pThis->hSessionEvent);
|
---|
1003 | pThis->hSessionEvent = NIL_RTSEMEVENT;
|
---|
1004 |
|
---|
1005 | RTCritSectDelete(&pThis->VerifyCritSect);
|
---|
1006 | RTCritSectDelete(&pThis->CritSect);
|
---|
1007 |
|
---|
1008 | RTMemFree(pThis);
|
---|
1009 |
|
---|
1010 | Log(("supSvcGrantStopAndDestroy: done (rc=%Rrc)\n", rc));
|
---|
1011 | }
|
---|
1012 |
|
---|