VirtualBox

Changeset 47199 in vbox


Ignore:
Timestamp:
Jul 16, 2013 3:45:42 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
87306
Message:

IPRT: Kernel thread-context hooks, linux implementation. Extended tstR0ThreadPreemption testcase to test the thread-context hooks.

Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/mangling.h

    r46639 r47199  
    15921592# define RTThreadCreateF                                RT_MANGLER(RTThreadCreateF)
    15931593# define RTThreadCreateV                                RT_MANGLER(RTThreadCreateV)
     1594# define RTThreadCtxHooksCreate                         RT_MANGLER(RTThreadCtxHooksCreate)         /* r0drv */
     1595# define RTThreadCtxHooksDeregister                     RT_MANGLER(RTThreadCtxHooksDeregister)     /* r0drv */
     1596# define RTThreadCtxHooksDestroy                        RT_MANGLER(RTThreadCtxHooksDestroy)        /* r0drv */
     1597# define RTThreadCtxHooksRegister                       RT_MANGLER(RTThreadCtxHooksRegister)       /* r0drv */
    15941598# define RTThreadFromNative                             RT_MANGLER(RTThreadFromNative)
    15951599# define RTThreadGetAffinity                            RT_MANGLER(RTThreadGetAffinity)
  • trunk/include/iprt/thread.h

    r43363 r47199  
    580580RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread);
    581581
     582
     583/**
     584 * Thread-context events.
     585 */
     586typedef enum RTTHREADCTXEVENT
     587{
     588    /** This thread is about to be preempted. */
     589    RTTHREADCTXEVENT_PREEMPTING = 0,
     590    /** This thread has just been resumed. */
     591    RTTHREADCTXEVENT_RESUMED,
     592    /** The usual 32-bit size hack. */
     593    RTTHREADCTXEVENT_32BIT_HACK = 0x7fffffff
     594} RTTHREADCTXEVENT;
     595
     596/**
     597 * Thread-context hook.
     598 *
     599 * @returns IPRT status code.
     600 * @param   enmEvent    The thread-context event.
     601 * @param   pvUser      User argument.
     602 *
     603 * @remarks This function may be called under different contexts, i.e. with
     604 *          different locks held, with/without preemption disabled depending on
     605 *          the event in @a enmEvent.
     606 */
     607typedef DECLCALLBACK(void) FNRTTHREADCTXHOOK(RTTHREADCTXEVENT enmEvent, void *pvUser);
     608/** Pointer to a thread-context hook. */
     609typedef FNRTTHREADCTXHOOK *PFNRTTHREADCTXHOOK;
     610
     611/**
     612 * Create a handle for a thread-context hook.
     613 *
     614 * This must be called once per-thread before using RTThreadCtxHooksRegister().
     615 *
     616 * @returns IPRT status code.
     617 * @param   phThreadCtx         Where to store the thread-context handle.
     618 */
     619RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx);
     620
     621/**
     622 * Destroy a thread-context hook handle for the current thread.
     623 *
     624 * This will deregister any thread-context hooks registered under this handle if
     625 * required.
     626 *
     627 * @param   phThreadCtx         Pointer to the thread-context handle.
     628 */
     629RTDECL(void) RTThreadCtxHooksDestroy(RTTHREADCTX hThreadCtx);
     630
     631/**
     632 * Registers a thread-context hook for the current thread to receive
     633 * notifications for all supported thread-context events.
     634 *
     635 * @returns IPRT status code.
     636 * @param   phThreadCtx         Poinner to the thread-context handle.
     637 * @param   pfnThreadHook       Pointer to a thread-context hook (a callback)
     638 *                              for all thread-context events.
     639 * @param   pvUser              User argument (optional, can be NULL).
     640 */
     641RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadHook, void *pvUser);
     642
     643/**
     644 * Deregisters a thread-context hook for the current thread.
     645 *
     646 * @returns IPRT status code.
     647 * @param   phThreadCtx         Pointer to the thread-context handle.
     648 */
     649RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx);
     650
    582651# endif /* IN_RING0 */
    583652
  • trunk/include/iprt/types.h

    r46688 r47199  
    18251825#define NIL_RTTHREAD                                0
    18261826
     1827/** Thread-context handle.*/
     1828typedef R0PTRTYPE(struct RTTHREADCTXINT *)          RTTHREADCTX;
     1829/** Pointer to thread handle. */
     1830typedef RTTHREADCTX                                *PRTTHREADCTX;
     1831/** Nil thread-context handle. */
     1832#define NIL_RTTHREADCTX                             0
     1833
    18271834/** A TLS index. */
    18281835typedef RTHCINTPTR                                  RTTLS;
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r46889 r47199  
    367367    { "RTStrPrintfV",                           (void *)RTStrPrintfV },
    368368    { "RTThreadCreate",                         (void *)RTThreadCreate },
     369    { "RTThreadCtxHooksCreate",                 (void *)RTThreadCtxHooksCreate },
     370    { "RTThreadCtxHooksDeregister",             (void *)RTThreadCtxHooksDeregister },
     371    { "RTThreadCtxHooksDestroy",                (void *)RTThreadCtxHooksDestroy },
     372    { "RTThreadCtxHooksRegister",               (void *)RTThreadCtxHooksRegister },
    369373    { "RTThreadGetName",                        (void *)RTThreadGetName },
    370374    { "RTThreadGetNative",                      (void *)RTThreadGetNative },
  • trunk/src/VBox/HostDrivers/Support/freebsd/files_vboxdrv

    r43389 r47199  
    194194    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c=>r0drv/generic/semspinmutex-r0drv-generic.c \
    195195    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp=>r0drv/generic/mpnotification-r0drv-generic.c \
     196    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp=>r0drv/generic/threadctxhooks-r0drv-generic.c \
    196197    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp=>r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.c \
    197198    ${PATH_ROOT}/src/VBox/Runtime/r0drv/memobj-r0drv.cpp=>r0drv/memobj-r0drv.c \
  • trunk/src/VBox/HostDrivers/Support/linux/Makefile

    r46646 r47199  
    9595        r0drv/linux/thread-r0drv-linux.o \
    9696        r0drv/linux/thread2-r0drv-linux.o \
     97        r0drv/linux/threadctxhooks-r0drv-linux.o \
    9798        r0drv/linux/time-r0drv-linux.o \
    9899        r0drv/linux/timer-r0drv-linux.o \
  • trunk/src/VBox/HostDrivers/Support/linux/files_vboxdrv

    r46646 r47199  
    186186    ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c=>r0drv/linux/thread-r0drv-linux.c \
    187187    ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c=>r0drv/linux/thread2-r0drv-linux.c \
     188    ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c=>r0drv/linux/threadctxhooks-r0drv-linux.c \
    188189    ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c=>r0drv/linux/time-r0drv-linux.c \
    189190    ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c=>r0drv/linux/timer-r0drv-linux.c \
  • trunk/src/VBox/Runtime/Makefile.kmk

    r47126 r47199  
    17371737        r0drv/linux/thread-r0drv-linux.c \
    17381738        r0drv/linux/thread2-r0drv-linux.c \
     1739        r0drv/linux/threadctxhooks-r0drv-linux.c \
    17391740        r0drv/linux/time-r0drv-linux.c \
    17401741        r0drv/linux/timer-r0drv-linux.c \
     
    17591760        generic/RTMpGetCoreCount-generic.cpp \
    17601761        nt/RTErrConvertFromNtStatus.cpp \
     1762        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    17611763        r0drv/memobj-r0drv.cpp \
    17621764        r0drv/mpnotification-r0drv.c \
     
    17981800        generic/timer-generic.cpp \
    17991801        r0drv/generic/mpnotification-r0drv-generic.cpp \
     1802        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    18001803        r0drv/darwin/alloc-r0drv-darwin.cpp \
    18011804        r0drv/darwin/assert-r0drv-darwin.cpp \
     
    18571860        r0drv/generic/RTMpOn-r0drv-generic.cpp \
    18581861        r0drv/generic/mpnotification-r0drv-generic.cpp \
     1862        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    18591863        r0drv/memobj-r0drv.cpp \
    18601864        r0drv/powernotification-r0drv.c \
     
    18941898        r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
    18951899        r0drv/generic/mpnotification-r0drv-generic.cpp \
     1900        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    18961901        r0drv/freebsd/alloc-r0drv-freebsd.c \
    18971902        r0drv/freebsd/assert-r0drv-freebsd.c \
     
    19241929        r0drv/mpnotification-r0drv.c \
    19251930        r0drv/powernotification-r0drv.c \
     1931        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    19261932        r0drv/solaris/RTLogWriteDebugger-r0drv-solaris.c \
    19271933        r0drv/solaris/RTMpPokeCpu-r0drv-solaris.c \
     
    19571963        r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
    19581964        r0drv/generic/mpnotification-r0drv-generic.cpp \
     1965        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    19591966        r0drv/haiku/alloc-r0drv-haiku.c \
    19601967        r0drv/haiku/assert-r0drv-haiku.c \
  • trunk/src/VBox/Runtime/include/internal/magics.h

    r46567 r47199  
    191191/** RTTESTINT::u32Magic value. (Daniel Kehlmann) */
    192192#define RTTESTINT_MAGIC                 UINT32_C(0x19750113)
     193/** RTTHREADCTXINT::u32Magic value. (Dennis MacAlistair Ritchie) */
     194#define RTTHREADCTXINT_MAGIC            UINT32_C(0x19410909)
    193195/** RTTHREADINT::u32Magic value. (Gilbert Keith Chesterton) */
    194196#define RTTHREADINT_MAGIC               UINT32_C(0x18740529)
  • trunk/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h

    r44867 r47199  
    125125#include <asm/div64.h>
    126126
     127/* For thread-context hooks. */
     128#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_PREEMPT_NOTIFIERS)
     129# include <linux/preempt.h>
     130#endif
     131
    127132/* for workqueue / task queues. */
    128133#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
  • trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp

    r45541 r47199  
    3232#include <iprt/asm-amd64-x86.h>
    3333#include <iprt/err.h>
     34#include <iprt/mem.h>
    3435#include <iprt/time.h>
    3536#include <iprt/string.h>
     
    3738#include "tstR0ThreadPreemption.h"
    3839
     40
     41#define TSTRTR0THREADCTXDATA_MAGIC      0xc01a50da
     42
     43/**
     44 * Thread-context hook data.
     45 */
     46typedef struct TSTRTR0THREADCTXDATA
     47{
     48    uint32_t volatile   u32Magic;
     49    RTCPUID             uSourceCpuId;
     50    RTTHREADCTX         hThreadCtx;
     51
     52    /* For RTTHREADCTXEVENT_PREEMPTING. */
     53    bool                fPreemptingSuccess;
     54    volatile bool       fPreemptingInvoked;
     55
     56    /* For RTTHREADCTXEVENT_RESUMED. */
     57    bool                fResumedSuccess;
     58    volatile bool       fResumedInvoked;
     59
     60    char                achResult[512];
     61} TSTRTR0THREADCTXDATA, *PTSTRTR0THREADCTXDATA;
     62
     63
     64/**
     65 * Thread-context hook function.
     66 *
     67 * @param   enmEvent    The thread-context event.
     68 * @param   pvUser      Pointer to the user argument.
     69 */
     70static void tstR0ThreadCtxHook(RTTHREADCTXEVENT enmEvent, void *pvUser)
     71{
     72    PTSTRTR0THREADCTXDATA pData = (PTSTRTR0THREADCTXDATA)pvUser;
     73    AssertPtrReturnVoid(pData);
     74
     75    if (pData->u32Magic != TSTRTR0THREADCTXDATA_MAGIC)
     76    {
     77        RTStrPrintf(pData->achResult, sizeof(pData->achResult), "!tstR0ThreadCtxHook: Invalid magic.");
     78        return;
     79    }
     80
     81    switch (enmEvent)
     82    {
     83        case RTTHREADCTXEVENT_PREEMPTING:
     84        {
     85            ASMAtomicWriteBool(&pData->fPreemptingInvoked, true);
     86
     87            /* We've already been called once, we now might very well be on another CPU. Nothing to do here. */
     88            if (pData->fPreemptingSuccess)
     89                return;
     90
     91            if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
     92            {
     93                RTStrPrintf(pData->achResult, sizeof(pData->achResult),
     94                            "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_PREEMPTING]: Called with preemption enabled");
     95                break;
     96            }
     97
     98            RTCPUID uCurrentCpuId = RTMpCpuId();
     99            if (pData->uSourceCpuId != uCurrentCpuId)
     100            {
     101                RTStrPrintf(pData->achResult, sizeof(pData->achResult),
     102                            "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_PREEMPTING]: migrated uSourceCpuId=%RU32 uCurrentCpuId=%RU32",
     103                            pData->uSourceCpuId, uCurrentCpuId);
     104                break;
     105            }
     106
     107            pData->fPreemptingSuccess = true;
     108            break;
     109        }
     110
     111        case RTTHREADCTXEVENT_RESUMED:
     112        {
     113            ASMAtomicWriteBool(&pData->fResumedInvoked, true);
     114
     115            /* We've already been called once successfully, nothing more to do. */
     116            if (ASMAtomicReadBool(&pData->fResumedSuccess))
     117                return;
     118
     119            if (!pData->fPreemptingSuccess)
     120            {
     121                RTStrPrintf(pData->achResult, sizeof(pData->achResult),
     122                            "!tstR0ThreadCtxHook[RTTHREADCTXEVENT_RESUMED]: Called before preempting callback was invoked.");
     123            }
     124
     125            ASMAtomicWriteBool(&pData->fResumedSuccess, true);
     126            break;
     127        }
     128
     129        default:
     130            AssertMsgFailed(("Invalid event %#x\n", enmEvent));
     131            break;
     132    }
     133}
    39134
    40135
     
    179274        }
    180275
     276        case TSTR0THREADPREEMPTION_CTXHOOKS:
     277        {
     278            if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
     279            {
     280                RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksCreate must be called with preemption enabled");
     281                break;
     282            }
     283
     284            RTTHREADCTX hThreadCtx;
     285            int rc = RTThreadCtxHooksCreate(&hThreadCtx);
     286            if (RT_FAILURE(rc))
     287            {
     288                if (rc == VERR_NOT_SUPPORTED)
     289                    RTStrPrintf(pszErr, cchErr, "RTThreadCtxHooksCreate returns VERR_NOT_SUPPORTED");
     290                else
     291                    RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksCreate returns %Rrc", rc);
     292                break;
     293            }
     294
     295            PTSTRTR0THREADCTXDATA pCtxData = (PTSTRTR0THREADCTXDATA)RTMemAlloc(sizeof(*pCtxData));
     296            AssertReturn(pCtxData, VERR_NO_MEMORY);
     297            pCtxData->u32Magic           = TSTRTR0THREADCTXDATA_MAGIC;
     298            pCtxData->hThreadCtx         = hThreadCtx;
     299            pCtxData->fPreemptingSuccess = false;
     300            pCtxData->fPreemptingInvoked = false;
     301            pCtxData->fResumedInvoked    = false;
     302            pCtxData->fResumedSuccess    = false;
     303            RT_ZERO(pCtxData->achResult);
     304
     305            RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
     306            RTThreadPreemptDisable(&PreemptState);
     307            Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
     308
     309            pCtxData->uSourceCpuId       = RTMpCpuId();
     310
     311            rc = RTThreadCtxHooksRegister(hThreadCtx, &tstR0ThreadCtxHook, pCtxData);
     312            if (RT_FAILURE(rc))
     313            {
     314                RTMemFree(pCtxData);
     315                RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksRegister returns %Rrc", rc);
     316                break;
     317            }
     318
     319            RTThreadPreemptRestore(&PreemptState);
     320
     321            /* Check if the preempting callback has/will been invoked. */
     322            const uint32_t  cMsTimeout           = 8000;
     323            const uint32_t  cMsSleepGranularity  = 50;
     324            uint32_t        cMsSlept             = 0;
     325            for (;;)
     326            {
     327                RTThreadPreemptDisable(&PreemptState);
     328                const RTCPUID uCurrentCpuId = RTMpCpuId();
     329                RTThreadPreemptRestore(&PreemptState);
     330
     331                if (   pCtxData->uSourceCpuId != uCurrentCpuId
     332                    || cMsSlept >= cMsTimeout)
     333                {
     334                    break;
     335                }
     336
     337                RTThreadSleep(cMsSleepGranularity);
     338                cMsSlept += cMsSleepGranularity;
     339            }
     340
     341            if (!ASMAtomicReadBool(&pCtxData->fPreemptingInvoked))
     342            {
     343                RTStrPrintf(pszErr, cchErr, "!tstR0ThreadCtxHooks[RTTHREADCTXEVENT_PREEMPTING] not invoked after ca. %u ms",
     344                            cMsSlept);
     345            }
     346            else if (!pCtxData->fPreemptingSuccess)
     347                RTStrCopy(pszErr, cchErr, pCtxData->achResult);
     348            else
     349            {
     350                /* Preempting callback succeeded, now check if the resumed callback has/will been invoked. */
     351                cMsSlept = 0;
     352                for (;;)
     353                {
     354                    if (   ASMAtomicReadBool(&pCtxData->fResumedInvoked)
     355                        || cMsSlept >= cMsTimeout)
     356                    {
     357                        break;
     358                    }
     359
     360                    RTThreadSleep(cMsSleepGranularity);
     361                    cMsSlept += cMsSleepGranularity;
     362                }
     363
     364                if (!ASMAtomicReadBool(&pCtxData->fResumedInvoked))
     365                {
     366                    RTStrPrintf(pszErr, cchErr, "!tstR0ThreadCtxHooks[RTTHREADCTXEVENT_RESUMED] not invoked after ca. %u ms",
     367                                cMsSlept);
     368                }
     369                else if (!pCtxData->fResumedSuccess)
     370                    RTStrCopy(pszErr, cchErr, pCtxData->achResult);
     371            }
     372
     373            RTThreadCtxHooksDeregister(hThreadCtx);
     374            RTThreadCtxHooksDestroy(hThreadCtx);
     375            RTMemFree(pCtxData);
     376            break;
     377        }
     378
    181379        default:
    182380            RTStrPrintf(pszErr, cchErr, "!Unknown test #%d", uOperation);
  • trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h

    r45538 r47199  
    3939    TSTR0THREADPREMEPTION_IS_TRUSTY,
    4040    TSTR0THREADPREMEPTION_IS_PENDING,
    41     TSTR0THREADPREMEPTION_NESTED
     41    TSTR0THREADPREMEPTION_NESTED,
     42    TSTR0THREADPREEMPTION_CTXHOOKS
    4243} TSTR0THREADPREMEPTION;
    4344
  • trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp

    r46326 r47199  
    245245        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
    246246
     247
     248    /*
     249     * Test thread-context hooks.
     250     */
     251    RTTestSub(hTest, "RTThreadCtxHooks");
     252    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
     253    Req.Hdr.cbReq = sizeof(Req);
     254    Req.szMsg[0] = '\0';
     255    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
     256                                             TSTR0THREADPREEMPTION_CTXHOOKS, 0, &Req.Hdr), VINF_SUCCESS);
     257    if (RT_FAILURE(rc))
     258        return RTTestSummaryAndDestroy(hTest);
     259    if (Req.szMsg[0] == '!')
     260        RTTestIFailed("%s", &Req.szMsg[1]);
     261    else if (Req.szMsg[0])
     262        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
     263
    247264    /*
    248265     * Done.
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette