VirtualBox

Ignore:
Timestamp:
May 14, 2015 6:29:34 PM (10 years ago)
Author:
vboxsync
Message:

IPRT,SUPDrv,VMM: Revised the context switching hook interface. Do less work when enabling the hook (formerly 'registration'). Drop the reference counting (kept internally for solaris) as it complicates restrictions wrt destroying enabled hooks. Bumped support driver version.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c

    r54872 r55863  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Thread-Context Hook, Ring-0 Driver, Linux.
     3 * IPRT - Thread Context Switching Hook, Ring-0 Driver, Linux.
    44 */
    55
     
    4242#include "internal/thread.h"
    4343
     44
    4445/*
    45  * Linux kernel 2.6.23 introduced thread-context hooks but RedHat 2.6.18 kernels
     46 * Linux kernel 2.6.23 introduced preemption notifiers but RedHat 2.6.18 kernels
    4647 * got it backported.
    4748 */
     
    5253*******************************************************************************/
    5354/**
    54  * The internal thread-context object.
    55  */
    56 typedef struct RTTHREADCTXINT
    57 {
    58     /** Magic value (RTTHREADCTXINT_MAGIC). */
     55 * The internal hook object for linux.
     56 */
     57typedef struct RTTHREADCTXHOOKINT
     58{
     59    /** Magic value (RTTHREADCTXHOOKINT_MAGIC). */
    5960    uint32_t volatile           u32Magic;
    60     /** The thread handle (owner) for which the context-hooks are registered. */
     61    /** The thread handle (owner) for which the hook is registered. */
    6162    RTNATIVETHREAD              hOwner;
    6263    /** The preemption notifier object. */
    63     struct preempt_notifier     hPreemptNotifier;
    64     /** Whether this handle has any hooks registered or not. */
    65     bool                        fRegistered;
    66     /** Pointer to the registered thread-context hook. */
    67     PFNRTTHREADCTXHOOK          pfnThreadCtxHook;
    68     /** User argument passed to the thread-context hook. */
     64    struct preempt_notifier     LnxPreemptNotifier;
     65    /** Whether the hook is enabled or not.  If enabled, the LnxPreemptNotifier
     66     * is linked into the owning thread's list of preemption callouts. */
     67    bool                        fEnabled;
     68    /** Pointer to the user callback. */
     69    PFNRTTHREADCTXHOOK          pfnCallback;
     70    /** User argument passed to the callback. */
    6971    void                       *pvUser;
    70     /** The thread-context operations. */
    71     struct preempt_ops          hPreemptOps;
    72     /** The reference count for this object. */
    73     uint32_t volatile           cRefs;
     72    /** The linux callbacks. */
     73    struct preempt_ops          PreemptOps;
    7474#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 19) && defined(RT_ARCH_AMD64)
    7575    /** Starting with 3.1.19, the linux kernel doesn't restore kernel RFLAGS during
     
    7777    RTCCUINTREG                 fSavedRFlags;
    7878#endif
    79 } RTTHREADCTXINT, *PRTTHREADCTXINT;
     79} RTTHREADCTXHOOKINT;
     80typedef RTTHREADCTXHOOKINT *PRTTHREADCTXHOOKINT;
    8081
    8182
    8283/**
    83  * Hook function for the thread-preempting event.
     84 * Hook function for the thread schedule out event.
    8485 *
    8586 * @param   pPreemptNotifier    Pointer to the preempt_notifier struct.
    86  * @param   pNext               Pointer to the task that is preempting the
    87  *                              current thread.
     87 * @param   pNext               Pointer to the task that is being scheduled
     88 *                              instead of the current thread.
    8889 *
    8990 * @remarks Called with the rq (runqueue) lock held and with preemption and
     
    9293static void rtThreadCtxHooksLnxSchedOut(struct preempt_notifier *pPreemptNotifier, struct task_struct *pNext)
    9394{
    94     PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
     95    PRTTHREADCTXHOOKINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXHOOKINT, LnxPreemptNotifier);
    9596#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    9697    RTCCUINTREG fSavedEFlags = ASMGetFlags();
     
    99100
    100101    AssertPtr(pThis);
    101     AssertPtr(pThis->pfnThreadCtxHook);
    102     Assert(pThis->fRegistered);
     102    AssertPtr(pThis->pfnCallback);
     103    Assert(pThis->fEnabled);
    103104    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    104105
    105     pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
     106    pThis->pfnCallback(RTTHREADCTXEVENT_OUT, pThis->pvUser);
    106107
    107108#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
     
    115116
    116117/**
    117  * Hook function for the thread-resumed event.
     118 * Hook function for the thread schedule in event.
    118119 *
    119120 * @param   pPreemptNotifier    Pointer to the preempt_notifier struct.
    120  * @param   iCpu                The CPU this thread is scheduled on.
     121 * @param   iCpu                The CPU this thread is being scheduled on.
    121122 *
    122123 * @remarks Called without holding the rq (runqueue) lock and with preemption
    123124 *          enabled!
     125 * @todo    r=bird: Preemption is of course disabled when it is called.
    124126 */
    125127static void rtThreadCtxHooksLnxSchedIn(struct preempt_notifier *pPreemptNotifier, int iCpu)
    126128{
    127     PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
     129    PRTTHREADCTXHOOKINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXHOOKINT, LnxPreemptNotifier);
    128130#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    129131    RTCCUINTREG fSavedEFlags = ASMGetFlags();
     
    132134
    133135    AssertPtr(pThis);
    134     AssertPtr(pThis->pfnThreadCtxHook);
    135     Assert(pThis->fRegistered);
    136 
    137     pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
     136    AssertPtr(pThis->pfnCallback);
     137    Assert(pThis->fEnabled);
     138
     139    pThis->pfnCallback(RTTHREADCTXEVENT_IN, pThis->pvUser);
    138140
    139141#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
     
    152154 * @param   pThis   Pointer to the internal thread-context object.
    153155 */
    154 DECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis)
    155 {
    156     preempt_notifier_unregister(&pThis->hPreemptNotifier);
    157     pThis->hPreemptOps.sched_out = NULL;
    158     pThis->hPreemptOps.sched_in  = NULL;
    159     pThis->fRegistered           = false;
    160 }
    161 
    162 
    163 RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
    164 {
    165     PRTTHREADCTXINT pThis;
     156DECLINLINE(void) rtThreadCtxHookDisable(PRTTHREADCTXHOOKINT pThis)
     157{
     158    Assert(pThis->PreemptOps.sched_out == rtThreadCtxHooksLnxSchedOut);
     159    Assert(pThis->PreemptOps.sched_in  == rtThreadCtxHooksLnxSchedIn);
     160    preempt_disable();
     161    preempt_notifier_unregister(&pThis->LnxPreemptNotifier);
     162    pThis->fEnabled = false;
     163    preempt_enable();
     164}
     165
     166
     167RTDECL(int) RTThreadCtxHookCreate(PRTTHREADCTXHOOK phCtxHook, uint32_t fFlags, PFNRTTHREADCTXHOOK pfnCallback, void *pvUser)
     168{
     169    /*
     170     * Validate input.
     171     */
     172    PRTTHREADCTXHOOKINT pThis;
    166173    Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    167 
    168     pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
     174    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
     175    AssertReturn(fFlags == 0, VERR_INVALID_FLAGS);
     176
     177    /*
     178     * Allocate and initialize a new hook.  We don't register it yet, just
     179     * create it.
     180     */
     181    pThis = (PRTTHREADCTXHOOKINT)RTMemAllocZ(sizeof(*pThis));
    169182    if (RT_UNLIKELY(!pThis))
    170183        return VERR_NO_MEMORY;
    171     pThis->u32Magic    = RTTHREADCTXINT_MAGIC;
    172     pThis->hOwner      = RTThreadNativeSelf();
    173     pThis->fRegistered = false;
    174     preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
    175     pThis->cRefs       = 1;
    176 
    177     *phThreadCtx = pThis;
     184    pThis->u32Magic     = RTTHREADCTXHOOKINT_MAGIC;
     185    pThis->hOwner       = RTThreadNativeSelf();
     186    pThis->fEnabled     = false;
     187    pThis->pfnCallback  = pfnCallback;
     188    pThis->pvUser       = pvUser;
     189    preempt_notifier_init(&pThis->LnxPreemptNotifier, &pThis->PreemptOps);
     190    pThis->PreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut;
     191    pThis->PreemptOps.sched_in  = rtThreadCtxHooksLnxSchedIn;
     192
     193    *phCtxHook = pThis;
    178194    return VINF_SUCCESS;
    179195}
    180 RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
    181 
    182 
    183 RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
    184 {
    185     /*
    186      * Validate input.
    187      */
    188     uint32_t        cRefs;
    189     PRTTHREADCTXINT pThis = hThreadCtx;
    190     AssertPtr(pThis);
    191     AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    192                     UINT32_MAX);
    193 
    194     cRefs = ASMAtomicIncU32(&pThis->cRefs);
    195     Assert(cRefs < UINT32_MAX / 2);
    196     return cRefs;
    197 }
    198 RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
    199 
    200 
    201 
    202 RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
    203 {
    204     /*
    205      * Validate input.
    206      */
    207     uint32_t        cRefs;
    208     PRTTHREADCTXINT pThis = hThreadCtx;
    209     if (pThis == NIL_RTTHREADCTX)
    210         return 0;
    211 
    212     AssertPtr(pThis);
    213     AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    214                     UINT32_MAX);
     196RT_EXPORT_SYMBOL(RTThreadCtxHookCreate);
     197
     198
     199RTDECL(int ) RTThreadCtxHookDestroy(RTTHREADCTXHOOK hCtxHook)
     200{
     201    /*
     202     * Validate input.
     203     */
     204    PRTTHREADCTXHOOKINT pThis = hCtxHook;
     205    if (pThis == NIL_RTTHREADCTXHOOK)
     206        return VINF_SUCCESS;
     207    AssertPtr(pThis);
     208    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
     209                    VERR_INVALID_HANDLE);
    215210    Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    216 
    217     cRefs = ASMAtomicDecU32(&pThis->cRefs);
    218     if (!cRefs)
     211    Assert(pThis->fEnabled || pThis->hOwner == RTThreadNativeSelf());
     212
     213    /*
     214     * If there's still a registered thread-context hook, deregister it now before destroying the object.
     215     */
     216    if (pThis->fEnabled)
    219217    {
    220         /*
    221          * If there's still a registered thread-context hook, deregister it now before destroying the object.
    222          */
    223         if (pThis->fRegistered)
    224             rtThreadCtxHooksDeregister(pThis);
    225 
    226         /*
    227          * Paranoia... but since these are ring-0 threads we can't be too careful.
    228          */
    229         Assert(!pThis->fRegistered);
    230         Assert(!pThis->hPreemptOps.sched_out);
    231         Assert(!pThis->hPreemptOps.sched_in);
    232 
    233         ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
    234         RTMemFree(pThis);
     218        Assert(pThis->hOwner == RTThreadNativeSelf());
     219        rtThreadCtxHookDisable(pThis);
     220        Assert(!pThis->fEnabled); /* paranoia */
    235221    }
    236     else
    237         Assert(cRefs < UINT32_MAX / 2);
    238 
    239     return cRefs;
    240 }
    241 RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
    242 
    243 
    244 RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
    245 {
    246     /*
    247      * Validate input.
    248      */
    249     PRTTHREADCTXINT pThis = hThreadCtx;
    250     if (pThis == NIL_RTTHREADCTX)
    251         return VERR_INVALID_HANDLE;
    252     AssertPtr(pThis);
    253     AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
     222
     223    ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXHOOKINT_MAGIC);
     224    RTMemFree(pThis);
     225
     226    return VINF_SUCCESS;
     227}
     228RT_EXPORT_SYMBOL(RTThreadCtxHookDestroy);
     229
     230
     231RTDECL(int) RTThreadCtxHookEnable(RTTHREADCTXHOOK hCtxHook)
     232{
     233    /*
     234     * Validate input.
     235     */
     236    PRTTHREADCTXHOOKINT pThis = hCtxHook;
     237    AssertPtr(pThis);
     238    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    254239                    VERR_INVALID_HANDLE);
    255240    Assert(pThis->hOwner == RTThreadNativeSelf());
    256     Assert(!pThis->hPreemptOps.sched_out);
    257     Assert(!pThis->hPreemptOps.sched_in);
    258 
    259     /*
    260      * Register the callback.
    261      */
    262     pThis->hPreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut;
    263     pThis->hPreemptOps.sched_in  = rtThreadCtxHooksLnxSchedIn;
    264     pThis->pvUser                = pvUser;
    265     pThis->pfnThreadCtxHook      = pfnThreadCtxHook;
    266     pThis->fRegistered           = true;
    267     preempt_notifier_register(&pThis->hPreemptNotifier);
     241    Assert(!pThis->fEnabled);
     242    if (!pThis->fEnabled)
     243    {
     244        Assert(pThis->PreemptOps.sched_out == rtThreadCtxHooksLnxSchedOut);
     245        Assert(pThis->PreemptOps.sched_in == rtThreadCtxHooksLnxSchedIn);
     246
     247        /*
     248         * Register the callback.
     249         */
     250        preempt_disable();
     251        pThis->fEnabled = true;
     252        preempt_notifier_register(&pThis->LnxPreemptNotifier);
     253        preempt_enable();
     254    }
    268255
    269256    return VINF_SUCCESS;
    270257}
    271 RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
    272 
    273 
    274 RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
    275 {
    276     /*
    277      * Validate input.
    278      */
    279     PRTTHREADCTXINT pThis = hThreadCtx;
    280     if (pThis == NIL_RTTHREADCTX)
    281         return VERR_INVALID_HANDLE;
    282     AssertPtr(pThis);
    283     AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    284                     VERR_INVALID_HANDLE);
    285     Assert(pThis->hOwner == RTThreadNativeSelf());
    286     Assert(pThis->fRegistered);
    287 
    288     /*
    289      * Deregister the callback.
    290      */
    291     rtThreadCtxHooksDeregister(pThis);
     258RT_EXPORT_SYMBOL(RTThreadCtxHookEnable);
     259
     260
     261RTDECL(int) RTThreadCtxHookDisable(RTTHREADCTXHOOK hCtxHook)
     262{
     263    /*
     264     * Validate input.
     265     */
     266    PRTTHREADCTXHOOKINT pThis = hCtxHook;
     267    if (pThis != NIL_RTTHREADCTXHOOK)
     268    {
     269        AssertPtr(pThis);
     270        AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
     271                        VERR_INVALID_HANDLE);
     272        Assert(pThis->hOwner == RTThreadNativeSelf());
     273
     274        /*
     275         * Deregister the callback.
     276         */
     277        if (pThis->fEnabled)
     278            rtThreadCtxHookDisable(pThis);
     279    }
    292280    return VINF_SUCCESS;
    293281}
    294 RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
    295 
    296 
    297 RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
    298 {
    299     /*
    300      * Validate input.
    301      */
    302     PRTTHREADCTXINT pThis = hThreadCtx;
    303     if (pThis == NIL_RTTHREADCTX)
     282RT_EXPORT_SYMBOL(RTThreadCtxHookDisable);
     283
     284
     285RTDECL(bool) RTThreadCtxHookIsEnabled(RTTHREADCTXHOOK hCtxHook)
     286{
     287    /*
     288     * Validate input.
     289     */
     290    PRTTHREADCTXHOOKINT pThis = hCtxHook;
     291    if (pThis == NIL_RTTHREADCTXHOOK)
    304292        return false;
    305293    AssertPtr(pThis);
    306     AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
    307 
    308     return pThis->fRegistered;
     294    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
     295                    false);
     296
     297    return pThis->fEnabled;
    309298}
    310299
    311300#else    /* Not supported / Not needed */
    312 
    313 RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
    314 {
    315     NOREF(phThreadCtx);
    316     return VERR_NOT_SUPPORTED;
    317 }
    318 RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
    319 
    320 
    321 RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
    322 {
    323     NOREF(hThreadCtx);
    324     return UINT32_MAX;
    325 }
    326 RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
    327 
    328 
    329 RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
    330 {
    331     NOREF(hThreadCtx);
    332     return UINT32_MAX;
    333 }
    334 RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
    335 
    336 
    337 RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
    338 {
    339     NOREF(hThreadCtx);
    340     NOREF(pfnThreadCtxHook);
    341     NOREF(pvUser);
    342     return VERR_NOT_SUPPORTED;
    343 }
    344 RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
    345 
    346 
    347 RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
    348 {
    349     NOREF(hThreadCtx);
    350     return VERR_NOT_SUPPORTED;
    351 }
    352 RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
    353 
    354 
    355 RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
    356 {
    357     NOREF(hThreadCtx);
    358     return false;
    359 }
    360 RT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered);
    361 
     301# include "../generic/threadctxhooks-r0drv-generic.cpp"
    362302#endif   /* Not supported / Not needed */
    363303
Note: See TracChangeset for help on using the changeset viewer.

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