VirtualBox

Changeset 47352 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jul 23, 2013 4:19:20 PM (11 years ago)
Author:
vboxsync
Message:

Runtime/r0drv: Reference counting for kernel thread-context hooks.

Location:
trunk/src/VBox
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r47199 r47352  
    369369    { "RTThreadCtxHooksCreate",                 (void *)RTThreadCtxHooksCreate },
    370370    { "RTThreadCtxHooksDeregister",             (void *)RTThreadCtxHooksDeregister },
    371     { "RTThreadCtxHooksDestroy",                (void *)RTThreadCtxHooksDestroy },
    372371    { "RTThreadCtxHooksRegister",               (void *)RTThreadCtxHooksRegister },
     372    { "RTThreadCtxHooksRelease",                (void *)RTThreadCtxHooksRelease },
     373    { "RTThreadCtxHooksRetain",                 (void *)RTThreadCtxHooksRetain },
    373374    { "RTThreadGetName",                        (void *)RTThreadGetName },
    374375    { "RTThreadGetNative",                      (void *)RTThreadGetNative },
  • trunk/src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp

    r47201 r47352  
    4242
    4343
    44 RTDECL(void) RTThreadCtxHooksDestroy(RTTHREADCTX hThreadCtx)
     44RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
    4545{
    4646    NOREF(hThreadCtx);
     47    return UINT32_MAX;
    4748}
    48 RT_EXPORT_SYMBOL(RTThreadCtxHooksDestroy);
     49RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
     50
     51
     52RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
     53{
     54    NOREF(hThreadCtx);
     55    return UINT32_MAX;
     56}
     57RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
    4958
    5059
  • trunk/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c

    r47229 r47352  
    5252    uint32_t volatile           u32Magic;
    5353    /** The thread handle (owner) for which the context-hooks are registered. */
    54     RTTHREAD                    hOwner;
     54    RTNATIVETHREAD              hOwner;
    5555    /** The preemption notifier object. */
    5656    struct preempt_notifier     hPreemptNotifier;
     
    6363    /** The thread-context operations. */
    6464    struct preempt_ops          hPreemptOps;
     65    /** The reference count for this object. */
     66    uint32_t volatile           cRefs;
    6567} RTTHREADCTXINT, *PRTTHREADCTXINT;
    6668
     
    109111
    110112/**
    111  * Worker function for RTThreadCtxHooks(Deregister|Destroy)().
     113 * Worker function for RTThreadCtxHooks(Deregister|Release)().
    112114 *
    113115 * @param   pThis   Pointer to the internal thread-context object.
     
    131133        return VERR_NO_MEMORY;
    132134    pThis->u32Magic    = RTTHREADCTXINT_MAGIC;
    133     pThis->hOwner      = RTThreadSelf();
     135    pThis->hOwner      = RTThreadNativeSelf();
    134136    pThis->fRegistered = false;
    135137    preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
     138    pThis->cRefs       = 1;
    136139
    137140    *phThreadCtx = pThis;
     
    141144
    142145
    143 RTDECL(void) RTThreadCtxHooksDestroy(RTTHREADCTX hThreadCtx)
     146RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
    144147{
    145148    /*
    146149     * Validate input.
    147150     */
     151    uint32_t        cRefs;
     152    PRTTHREADCTXINT pThis = hThreadCtx;
     153    AssertPtr(pThis);
     154    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
     155                    UINT32_MAX);
     156
     157    cRefs = ASMAtomicIncU32(&pThis->cRefs);
     158    Assert(cRefs < UINT32_MAX / 2);
     159    return cRefs;
     160}
     161RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
     162
     163
     164
     165RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
     166{
     167    /*
     168     * Validate input.
     169     */
     170    uint32_t        cRefs;
    148171    PRTTHREADCTXINT pThis = hThreadCtx;
    149172    if (pThis == NIL_RTTHREADCTX)
    150         return;
    151     AssertPtr(pThis);
    152     AssertMsgReturnVoid(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
    153     Assert(pThis->hOwner == RTThreadSelf());
     173        return 0;
     174    AssertPtr(pThis);
     175    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
     176                    UINT32_MAX);
    154177    Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    155178
    156     /*
    157      * If there's still a registered thread-context hook, deregister it now before destroying the object.
    158      */
    159     if (pThis->fRegistered)
    160         rtThreadCtxHooksDeregister(pThis);
    161 
    162     /*
    163      * Paranoia... but since these are ring-0 threads we can't be too careful.
    164      */
    165     Assert(!pThis->fRegistered);
    166     Assert(!pThis->hPreemptOps.sched_out);
    167     Assert(!pThis->hPreemptOps.sched_in);
    168 
    169     /*
    170      * Destroy the object.
    171      */
    172     ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
    173     RTMemFree(pThis);
    174 }
    175 RT_EXPORT_SYMBOL(RTThreadCtxHooksDestroy);
     179    cRefs = ASMAtomicDecU32(&pThis->cRefs);
     180    if (!cRefs)
     181    {
     182        /*
     183         * If there's still a registered thread-context hook, deregister it now before destroying the object.
     184         */
     185        if (pThis->fRegistered)
     186            rtThreadCtxHooksDeregister(pThis);
     187
     188        /*
     189         * Paranoia... but since these are ring-0 threads we can't be too careful.
     190         */
     191        Assert(!pThis->fRegistered);
     192        Assert(!pThis->hPreemptOps.sched_out);
     193        Assert(!pThis->hPreemptOps.sched_in);
     194
     195        ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
     196        RTMemFree(pThis);
     197        printk("freed pThis=%p\n", pThis);
     198    }
     199    else
     200        Assert(cRefs < UINT32_MAX / 2);
     201
     202    return cRefs;
     203}
     204RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
    176205
    177206
     
    187216    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    188217                    VERR_INVALID_HANDLE);
    189     Assert(pThis->hOwner == RTThreadSelf());
     218    Assert(pThis->hOwner == RTThreadNativeSelf());
    190219    Assert(!pThis->hPreemptOps.sched_out);
    191220    Assert(!pThis->hPreemptOps.sched_in);
     
    217246    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    218247                    VERR_INVALID_HANDLE);
    219     Assert(pThis->hOwner == RTThreadSelf());
     248    Assert(pThis->hOwner == RTThreadNativeSelf());
    220249    Assert(pThis->fRegistered);
    221250
     
    238267
    239268
    240 RTDECL(void) RTThreadCtxHooksDestroy(RTTHREADCTX hThreadCtx)
     269RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
    241270{
    242271    NOREF(hThreadCtx);
    243 }
    244 RT_EXPORT_SYMBOL(RTThreadCtxHooksDestroy);
     272    return UINT32_MAX;
     273}
     274RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
     275
     276
     277RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
     278{
     279    NOREF(hThreadCtx);
     280    return UINT32_MAX;
     281}
     282RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
    245283
    246284
  • trunk/src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c

    r47302 r47352  
    5151    uint32_t volatile           u32Magic;
    5252    /** The thread handle (owner) for which the context-hooks are registered. */
    53     RTTHREAD                    hOwner;
     53    RTNATIVETHREAD              hOwner;
    5454    /** Pointer to the registered thread-context hook. */
    5555    PFNRTTHREADCTXHOOK          pfnThreadCtxHook;
     
    5858    /** Whether this handle has any hooks registered or not. */
    5959    bool                        fRegistered;
     60    /** Number of references to this object. */
     61    uint32_t volatile           cRefs;
    6062} RTTHREADCTXINT, *PRTTHREADCTXINT;
    6163
     64
     65/*******************************************************************************
     66*   Defined Constants And Macros                                               *
     67*******************************************************************************/
     68/** Validates a thread-context hook handle and returns rc if not valid. */
     69#define RTTHREADCTX_VALID_RETURN_RC(pThis, rc) \
     70    do { \
     71        AssertPtrReturn((pThis), (rc)); \
     72        AssertMsgReturn((pThis)->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", (pThis)->u32Magic,  \
     73                        (pThis)), (rc));  \
     74        AssertMsgReturn((pThis)->cRefs > 0, ("cRefs is 0! pThis=%p\n", (pThis)), (rc)); \
     75    } while (0)
    6276
    6377
     
    100114        Assert(pThis->pfnThreadCtxHook);
    101115        pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
     116    }
     117}
     118
     119
     120/**
     121 * Hook function for the thread-free event.
     122 *
     123 * @param   pvThreadCtxInt      Opaque pointer to the internal thread-context
     124 *                              object.
     125 * @param   fIsExec             Whether this event is triggered due to exec().
     126 */
     127static void rtThreadCtxHooksSolFree(void *pvThreadCtxInt, int fIsExec)
     128{
     129    PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
     130    AssertPtrReturnVoid(pThis);
     131    AssertMsgReturnVoid(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
     132
     133    uint32_t cRefs = ASMAtomicReadU32(&pThis->cRefs);
     134    if (RT_UNLIKELY(!cRefs))
     135    {
     136        /* Should never happen. */
     137        AssertMsgFailed(("rtThreadCtxHooksSolFree with cRefs=0 pThis=%p\n", pThis));
     138        return;
     139    }
     140
     141    if (!ASMAtomicDecU32(&pThis->cRefs))
     142    {
     143        Assert(!pThis->fRegistered);
     144        ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
     145        RTMemFree(pThis);
    102146    }
    103147}
     
    113157        return VERR_NO_MEMORY;
    114158    pThis->u32Magic    = RTTHREADCTXINT_MAGIC;
    115     pThis->hOwner      = RTThreadSelf();
     159    pThis->hOwner      = RTThreadNativeSelf();
    116160    pThis->fRegistered = false;
     161    pThis->cRefs       = 2;               /* One reference for the thread, one for the hook object. */
    117162
    118163    /*
     
    129174                                                       NULL,                          /* fork */
    130175                                                       NULL,                          /* lwp_create */
    131                                                        NULL);                         /* free */
     176                                                       rtThreadCtxHooksSolFree);
    132177    }
    133178    else
     
    140185                                                   NULL,                              /* lwp_create */
    141186                                                   NULL,                              /* exit */
    142                                                    NULL);                             /* free */
     187                                                   rtThreadCtxHooksSolFree);
    143188    }
    144189
     
    148193
    149194
    150 RTDECL(void) RTThreadCtxHooksDestroy(RTTHREADCTX hThreadCtx)
    151 {
    152     /*
    153      * Validate input.
    154      */
     195RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
     196{
     197    PRTTHREADCTXINT pThis = hThreadCtx;
     198    RTTHREADCTX_VALID_RETURN_RC(hThreadCtx, UINT32_MAX);
     199
     200    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     201    Assert(cRefs < UINT32_MAX / 2);
     202    return cRefs;
     203}
     204
     205
     206RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
     207{
    155208    PRTTHREADCTXINT pThis = hThreadCtx;
    156209    if (pThis == NIL_RTTHREADCTX)
    157         return;
    158     AssertPtr(pThis);
    159     AssertMsgReturnVoid(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
    160     Assert(pThis->hOwner == RTThreadSelf());
     210        return 0;
     211
     212    RTTHREADCTX_VALID_RETURN_RC(hThreadCtx, UINT32_MAX);
    161213    Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    162214
    163     /*
    164      * Deregister the hook.
    165      */
    166     int rc;
    167     if (g_frtSolOldThreadCtx)
    168     {
    169         rc = g_rtSolThreadCtx.Remove.pfnSol_removectx_old(curthread,
     215    pThis->fRegistered = false;
     216    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     217
     218    if (   pThis->hOwner == RTThreadNativeSelf()
     219        && cRefs == 1)
     220    {
     221        /*
     222         * removectx() will invoke rtThreadCtxHooksSolFree() and there is no way to bypass it and still use
     223         * rtThreadCtxHooksSolFree() at the same time.  Hence the convulated reference counting.
     224         *
     225         * When this function is called from the owner thread and is the last reference, we call removectx() which
     226         * will invoke rtThreadCtxHooksSolFree() with cRefs = 1 and that will then free the hook object.
     227         *
     228         * When the function is called from a different thread, we simply decrement the reference. Whenever the
     229         * ring-0 thread dies, Solaris will call rtThreadCtxHooksSolFree() which will free the hook object.
     230         */
     231        int rc;
     232        if (g_frtSolOldThreadCtx)
     233        {
     234            rc = g_rtSolThreadCtx.Remove.pfnSol_removectx_old(curthread,
     235                                                              pThis,
     236                                                              rtThreadCtxHooksSolPreempting,
     237                                                              rtThreadCtxHooksSolResumed,
     238                                                              NULL,                          /* fork */
     239                                                              NULL,                          /* lwp_create */
     240                                                              rtThreadCtxHooksSolFree);
     241        }
     242        else
     243        {
     244            rc = g_rtSolThreadCtx.Remove.pfnSol_removectx(curthread,
    170245                                                          pThis,
    171246                                                          rtThreadCtxHooksSolPreempting,
    172247                                                          rtThreadCtxHooksSolResumed,
    173                                                           NULL,                          /* fork */
    174                                                           NULL,                          /* lwp_create */
    175                                                           NULL);                         /* free */
    176     }
    177     else
    178     {
    179         rc = g_rtSolThreadCtx.Remove.pfnSol_removectx(curthread,
    180                                                       pThis,
    181                                                       rtThreadCtxHooksSolPreempting,
    182                                                       rtThreadCtxHooksSolResumed,
    183                                                       NULL,                              /* fork */
    184                                                       NULL,                              /* lwp_create */
    185                                                       NULL,                              /* exit */
    186                                                       NULL);                             /* free */
    187     }
    188     AssertMsg(rc, ("removectx failed. rc=%d\n", rc));
    189     NOREF(rc);
    190 
    191     /*
    192      * Destroy the object.
    193      */
    194     ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
    195     RTMemFree(pThis);
     248                                                          NULL,                              /* fork */
     249                                                          NULL,                              /* lwp_create */
     250                                                          NULL,                              /* exit */
     251                                                          rtThreadCtxHooksSolFree);
     252        }
     253        AssertMsg(rc, ("removectx failed. rc=%d\n", rc));
     254        NOREF(rc);
     255
     256#ifdef VBOX_STRICT
     257        cRefs = ASMAtomicReadU32(&pThis->cRefs);
     258        Assert(!cRefs);
     259#endif
     260        cRefs = 0;
     261    }
     262
     263    return cRefs;
    196264}
    197265
     
    208276    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    209277                    VERR_INVALID_HANDLE);
    210     Assert(pThis->hOwner == RTThreadSelf());
     278    Assert(pThis->hOwner == RTThreadNativeSelf());
    211279
    212280    /*
     
    232300    AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
    233301                    VERR_INVALID_HANDLE);
    234     Assert(pThis->hOwner == RTThreadSelf());
     302    Assert(pThis->hOwner == RTThreadNativeSelf());
    235303    Assert(pThis->fRegistered);
    236304
  • trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp

    r47302 r47352  
    374374
    375375            Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    376             RTThreadCtxHooksDestroy(hThreadCtx);
     376            uint32_t cRefs = RTThreadCtxHooksRelease(hThreadCtx);
     377            if (cRefs == UINT32_MAX)
     378                RTStrPrintf(pszErr, cchErr, "!RTThreadCtxHooksRelease returns invalid cRefs!");
    377379
    378380            RTMemFree(pCtxData);
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