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