SUPSvcGrant.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox Support Service - The Grant Service.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2008 Oracle Corporation
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * available from http://www.virtualbox.org. This file is free software;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * you can redistribute it and/or modify it under the terms of the GNU
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * General Public License (GPL) as published by the Free Software
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * The contents of this file may alternatively be used under the terms
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * of the Common Development and Distribution License Version 1.0
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox OSE distribution, in which case the provisions of the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * CDDL are applicable instead of those of the GPL.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * You may elect to license modified versions of this file under the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * terms and conditions of either the GPL or the CDDL or both.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Header Files *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Structures and Typedefs *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** Pointer to a client instance. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsynctypedef struct SUPSVCGRANTSESSION *PSUPSVCGRANTSESSION;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** Pointer to a Grant service instance. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Grant service session data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Pointer to the next client in the list. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Pointer to the previous client in the list. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Pointer to the parent (the service instance). */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The local ipc client handle. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Indicate that the thread should terminate ASAP. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync bool volatile fTerminate;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The thread handle. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * State grant service machine.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The invalid zero entry. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Creating - the thread is being started.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Paused or Butchered. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Paused - the thread is blocked on it's user event semaphore.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Resuming, Terminating or Butchered.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Creating, Pausing */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Resuming - the thread is being unblocked and ushered into RTLocalIpcServiceListen.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Listen or Butchered.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Paused */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Listen - the thread is in RTLocalIpcServerListen or setting up an incoming session.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Pausing or Butchered.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Resuming */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Pausing - Cancelling the listen and dropping any incoming sessions.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Paused or Butchered.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Listen */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Butchered - The thread has quit because something when terribly wrong.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Destroyed
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Any. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Pausing - Cancelling the listen and dropping any incoming sessions.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Next: Destroyed
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Paused */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Destroyed - the instance is invalid.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Prev: Butchered or Terminating */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The end of valid state values. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The usual 32-bit blowup hack. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsynctypedef struct SUPSVCGRANT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The local ipc server handle. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Critical section serializing access to the session list, the state,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * the response event, the session event, and the thread event. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The service thread will signal this event when it has changed to
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * the 'paused' or 'running' state. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Event that's signaled on session termination. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The handle to the service thread. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Head of the session list. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The service state. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Critical section serializing access to the SUPR3HardenedVerify APIs. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Internal Functions *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic const char *supSvcGrantStateName(SUPSVCGRANTSTATE enmState);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Services a client session.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VINF_SUCCESS.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hThread The thread handle.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvSession Pointer to the session instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(int) supSvcGrantSessionThread(RTTHREAD hThread, void *pvSession)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PSUPSVCGRANTSESSION pThis = (PSUPSVCGRANTSESSION)pvSession;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Process client requests untill it quits or we're cancelled on termination.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** @todo */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Clean up the session.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PSUPSVCGRANT pParent = (PSUPSVCGRANT)ASMAtomicReadPtr((void * volatile *)&pThis->pParent);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantSessionThread(%p): No parent\n", pThis));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantSessionThread(%p): No session handle\n", pThis));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Cleans up a session.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This is called while inside the grant service critical section.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis The session to destroy.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pParent The parent.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic void supSvcGrantSessionDestroy(PSUPSVCGRANTSESSION pThis, PSUPSVCGRANT pParent)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Unlink it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Free the resources associated with it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Cleans up zombie sessions, locked.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis Pointer to the grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic void supSvcGrantCleanUpSessionsLocked(PSUPSVCGRANT pThis)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Iterate untill be make it all the way thru the list.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Only use the thread state as and indicator on whether we can destroy
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * the session or not.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Cleans up zombie sessions.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VINF_SUCCESS, VBox error code on internal error.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis Pointer to the grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param fOwnCritSect Whether we own the crit sect already. The state is preserved.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic int supSvcGrantCleanUpSessions(PSUPSVCGRANT pThis, bool fOwnCritSect)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCleanUpSessions: RTCritSectEnter returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Gets the state name.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The state name string (read only).
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param enmState The state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic const char *supSvcGrantStateName(SUPSVCGRANTSTATE enmState)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync case kSupSvcGrantState_Creating: return "Creating";
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync case kSupSvcGrantState_Resuming: return "Resuming";
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync case kSupSvcGrantState_Butchered: return "Butchered";
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync case kSupSvcGrantState_Terminating: return "Terminating";
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync case kSupSvcGrantState_Destroyed: return "Destroyed";
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync default: return "?Unknown?";
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Attempts to flip into the butchered state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns rc.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis The instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param fOwnCritSect Whether we own the crit sect already.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pszFailed What failed.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param rc What to return (lazy bird).
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic int supSvcGrantThreadButchered(PSUPSVCGRANT pThis, bool fOwnCritSect, const char *pszFailed, int rc)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantThread(%s): Butchered; %Rrc: %s",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(pThis->enmState), rc, pszFailed);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Creates a new session.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VINF_SUCCESS on success, VBox error code on internal error.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis Pointer to the grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hSession The client session handle.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic int supSvcGrantThreadCreateSession(PSUPSVCGRANT pThis, RTLOCALIPCSESSION hSession)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Allocate and initialize a new session instance before entering the critsect.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PSUPSVCGRANTSESSION pSession = (PSUPSVCGRANTSESSION)RTMemAlloc(sizeof(*pSession));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantThreadListen: failed to allocate session");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Enter the critsect, check the state, link it and fire off the session thread.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* check the state */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* link it */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* fire up the thread */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantThreadListen: starting session %p\n", pSession));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTThreadCreate(&pSession->hThread, supSvcGrantSessionThread, pSession, 0,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "SESSION");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTCritSectLeave", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Successfully handled the client.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* bail out */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantThreadListen: RTThreadCreate returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantThreadListen: dropping connection, state %s\n", supSvcGrantStateName(enmState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTCritSectEnter", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Listen for a client session and kicks off the service thread for it.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VINF_SUCCESS on normal state change, failure if something gets screwed up.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis Pointer to the grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic int supSvcGrantThreadListen(PSUPSVCGRANT pThis)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wait for a client to connect and create a new session.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = RTLocalIpcServerListen(pThis->hServer, &hClientSession);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* for testing */;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTLocalIpcServerListen", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadCreateSession(pThis, hClientSession);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Grant service thread.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This thread is the one listening for clients and kicks off
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * the session threads and stuff.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VINF_SUCCESS on normal exit, VBox error status on failure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param hThread The thread handle.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvThis Pointer to the grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(int) supSvcGrantThread(RTTHREAD hThread, void *pvThis)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * The state loop.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Switch on the current state (requires critsect).
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantThread - RTCritSectEnter returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogFlow(("supSvcGrantThread: switching %s\n", supSvcGrantStateName(enmState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "RTSemEventSignal", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* fall thru */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTThreadUserWait(hThread, 60*1000); /* wake up once in a while (paranoia) */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect*/, "RTThreadUserWait", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "RTSemEventSignal", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* fall thru */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantThread: supSvcGrantDoListening returns %Rrc, exiting\n", rc));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "Bad state", VERR_INTERNAL_ERROR);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Massage the session list between clients and states.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = supSvcGrantCleanUpSessions(pThis, false /* fOwnCritSect */);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "supSvcGrantCleanUpSessions", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Waits for the service thread to respond to a state change.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time, other error code on internal error.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pThis Pointer to the grant service instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param enmCurState The current state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param enmNewState The new state we're waiting for it to enter.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic int supSvcGrantWait(PSUPSVCGRANT pThis, SUPSVCGRANTSTATE enmCurState, SUPSVCGRANTSTATE enmNewState)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wait a short while for the response event to be set.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wait good while longer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTSemEventWait(pThis->hResponseEvent, 59*1000); /* 59 sec */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check the state whether we've succeeded.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantWait(,%s,%s) - the thread doesn't respond in a timely manner, failing.",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantWait(,%s,%s) - wrong state %s!", supSvcGrantStateName(enmCurState),
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmNewState), supSvcGrantStateName(enmState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertMsgFailed(("%s\n", supSvcGrantStateName(enmState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantWait(,%s,%s) - RTCritSectEnter returns %Rrc",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantWait(,%s,%s) - RTSemEventWait returns %Rrc",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantWait(,%s,%s) - wrong state %s!", supSvcGrantStateName(enmCurState),
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmNewState), supSvcGrantStateName(pThis->enmState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertMsgFailed(("%s\n", supSvcGrantStateName(pThis->enmState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantWait(,%s,%s) - RTCritSectEnter returns %Rrc",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState), rc));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @copydoc SUPSVCSERVICE::pfnCreate */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLCALLBACK(int) supSvcGrantCreate(void **ppvInstance)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Allocate and initialize the session data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PSUPSVCGRANT pThis = (PSUPSVCGRANT)RTMemAlloc(sizeof(*pThis));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync bool fFreeIt = true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Create the local IPC instance and then finally fire up the thread.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTLocalIpcServerCreate(&pThis->hServer, SUPSVC_GRANT_SERVICE_NAME, RTLOCALIPC_FLAGS_MULTI_SESSION);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTThreadCreate(&pThis->hThread, supSvcGrantThread, pThis, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "GRANT");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = supSvcGrantWait(pThis, kSupSvcGrantState_Creating, kSupSvcGrantState_Paused);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Successfully created the grant service!
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantCreate: returns VINF_SUCCESS (pThis=%p)\n", pThis));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * The thread FAILED to start in a timely manner!
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc2 = RTThreadWait(pThis->hThread, 20000, NULL);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* poke it a few more times before giving up. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync while (--cTries > 0)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RTThreadWait(pThis->hThread, 1000, NULL) != VERR_TIMEOUT)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCreate - RTThreadCreate returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCreate - RTLocalIpcServiceCreate returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCreate - RTSemEventCreate returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCreate - RTSemEventCreate returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCreate - RTCritSectInit returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantCreate - RTCritSectInit returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @copydoc SUPSVCSERVICE::pfnStart */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLCALLBACK(void) supSvcGrantStart(void *pvInstance)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Change the state and signal the thread.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wait for the bugger to respond (no need to bitch here).
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantWait(pThis, kSupSvcGrantState_Resuming, kSupSvcGrantState_Listen);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantStart - Incorrect state %s!", supSvcGrantStateName(enmState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantStart - RTCritSectEnter returns %Rrc!", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @copydoc SUPSVCSERVICE::pfnTryStop */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLCALLBACK(int) supSvcGrantTryStop(void *pvInstance)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Don't give up immediately.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * First check the state to make sure the thing is actually running.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * If the critsect is butchered, just pretend success.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - RTCritSectEnter returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - Not running, state: %s", supSvcGrantStateName(enmState));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * If there are no clients, usher the thread into the paused state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_SUCCESS(rc) && RT_SUCCESS(rc2) && RT_SUCCESS(rc3))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantWait(pThis, kSupSvcGrantState_Pausing, kSupSvcGrantState_Paused);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - RTThreadUserReset returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - RTLocalIpcServerCancel returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - RTCritSectLeave returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check the time limit, otherwise wait for a client event.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync uint64_t u64Elapsed = RTTimeMilliTS() - u64StartTS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned cSessions = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - %u active sessions after waiting %u ms", cSessions, (unsigned)u64Elapsed);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - RTCritSectLeave returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTSemEventWait(pThis->hSessionEvent, 60*1000 - u64Elapsed);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantTryStop - RTSemEventWait returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @copydoc SUPSVCSERVICE::pfnStopAndDestroy */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLCALLBACK(void) supSvcGrantStopAndDestroy(void *pvInstance, bool fRunning)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Attempt to stop the service, cancelling blocked server and client calls.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertMsg(fRunning == (pThis->enmState == kSupSvcGrantState_Listen),
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ("%RTbool %s\n", fRunning, supSvcGrantStateName(enmState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* try cancel local ipc operations that might be pending */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wait for the thread to respond (outside the crit sect).
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcGrantWait(pThis, kSupSvcGrantState_Pausing, kSupSvcGrantState_Paused);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wait for any lingering sessions to exit.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Destroy the sessions since cancelling didn't do the trick. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicXchgHandle(&pCur->hSession, NIL_RTLOCALIPCSESSION, &hSession);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantStopAndDestroy: RTLocalIpcSessionClose(%p) returns %Rrc",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Check the time. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync uint64_t u64Elapsed = RTTimeMilliTS() - u64StartTS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = RTSemEventWait(pThis->hSessionEvent, 60*1000 - u64Elapsed);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* cleanup and check again */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Tell the service thread to terminate and wait for it to do so.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicXchgHandle(&pThis->hServer, NIL_RTLOCALIPCSERVER, &hServer);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantStopAndDestroy - RTThreadWait(40 sec) returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantStopAndDestroy - RTThreadWait(20 sec) returns %Rrc", rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Kill the parent pointers of any lingering sessions.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned cSessions = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicWritePtr((void * volatile *)&pCur->pParent, NULL);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync supSvcLogError("supSvcGrantStopAndDestroy: %d session failed to terminate!", cSessions);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Free the resource.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("supSvcGrantStopAndDestroy: done (rc=%Rrc)\n", rc));