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