[11725] | 1 | /* $Id: SUPSvcGrant.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * VirtualBox Support Service - The Grant Service.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2008-2023 Oracle and/or its affiliates.
|
---|
[11725] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[11725] | 11 | *
|
---|
[96407] | 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 | *
|
---|
[11725] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 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
|
---|
[11725] | 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.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[11725] | 35 | */
|
---|
| 36 |
|
---|
[57358] | 37 |
|
---|
| 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Header Files *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[11725] | 41 | #define LOG_GROUP LOG_GROUP_SUP
|
---|
| 42 | #include "SUPSvcInternal.h"
|
---|
| 43 |
|
---|
| 44 | #include <VBox/log.h>
|
---|
| 45 | #include <iprt/asm.h>
|
---|
[76474] | 46 | #include <iprt/errcore.h>
|
---|
[11725] | 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 |
|
---|
[57358] | 56 | /*********************************************************************************************************************************
|
---|
| 57 | * Structures and Typedefs *
|
---|
| 58 | *********************************************************************************************************************************/
|
---|
[11725] | 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 |
|
---|
[57358] | 158 | /*********************************************************************************************************************************
|
---|
| 159 | * Internal Functions *
|
---|
| 160 | *********************************************************************************************************************************/
|
---|
[11725] | 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 | /*
|
---|
[33540] | 181 | * Process client requests until it quits or we're cancelled on termination.
|
---|
[11725] | 182 | */
|
---|
| 183 | while (!ASMAtomicUoReadBool(&pThis->fTerminate))
|
---|
| 184 | {
|
---|
| 185 | RTThreadSleep(1000);
|
---|
| 186 | /** @todo */
|
---|
| 187 | }
|
---|
| 188 |
|
---|
| 189 | /*
|
---|
| 190 | * Clean up the session.
|
---|
| 191 | */
|
---|
[30111] | 192 | PSUPSVCGRANT pParent = ASMAtomicReadPtrT(&pThis->pParent, PSUPSVCGRANT);
|
---|
[11725] | 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 | /*
|
---|
[33540] | 265 | * Iterate until be make it all the way thru the list.
|
---|
[11725] | 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);
|
---|
[69046] | 507 | RT_FALL_THRU();
|
---|
[11725] | 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);
|
---|
[69046] | 522 | RT_FALL_THRU();
|
---|
[11725] | 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)
|
---|
[30112] | 988 | ASMAtomicWriteNullPtr(&pCur->pParent);
|
---|
[11725] | 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 |
|
---|