VirtualBox

Ignore:
Timestamp:
Oct 17, 2011 2:12:14 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
74405
Message:

timer-r0drv-linux.c, ++: Don't use del_timer_sync when calling from a handler since we're in an atomic context and trigger the WARN_ON in del_timer_sync().

Location:
trunk/src/VBox/Runtime/r0drv/linux
Files:
3 edited

Legend:

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

    r36555 r39004  
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3737
    3838/*******************************************************************************
     39*   Global Variables                                                           *
     40*******************************************************************************/
     41/** The IPRT work queue. */
     42#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
     43static struct workqueue_struct *g_prtR0LnxWorkQueue;
     44#else
     45static DECLARE_TASK_QUEUE(g_rtR0LnxWorkQueue);
     46#endif
     47
     48
     49/*******************************************************************************
    3950*   Internal Functions                                                         *
    4051*******************************************************************************/
     
    4556
    4657
     58/**
     59 * Pushes an item onto the IPRT work queue.
     60 *
     61 * @param   pWork               The work item.
     62 * @param   pfnWorker           The callback function.  It will be called back
     63 *                              with @a pWork as argument.
     64 */
     65DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWorker)(RTR0LNXWORKQUEUEITEM *))
     66{
     67#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
     68    INIT_WORK(pWork, pfnWorker);
     69    queue_work(g_prtR0LnxWorkQueue, pWork);
     70#else
     71    INIT_TQUEUE(pWork, pfnWorker, pWork);
     72    queue_task(pWork, &g_rtR0LnxWorkQueue);
     73#endif
     74}
     75
     76
     77/**
     78 * Flushes all items in the IPRT work queue.
     79 *
     80 * @remarks This is mostly for 2.4.x compatability.  Must not be called from
     81 *          atomic contexts or with unncessary locks held.
     82 */
     83DECLHIDDEN(void) rtR0LnxWorkqueueFlush(void)
     84{
     85#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
     86    flush_workqueue(g_prtR0LnxWorkQueue);
     87#else
     88    run_task_queue(&g_rtR0LnxWorkQueue);
     89#endif
     90}
     91
     92
    4793DECLHIDDEN(int) rtR0InitNative(void)
    4894{
     95    g_prtR0LnxWorkQueue = create_workqueue("iprt");
     96    if (!g_prtR0LnxWorkQueue)
     97        return VERR_NO_MEMORY;
     98
    4999    return VINF_SUCCESS;
    50100}
     
    53103DECLHIDDEN(void) rtR0TermNative(void)
    54104{
     105    rtR0LnxWorkqueueFlush();
     106#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
     107    destroy_workqueue(g_prtR0LnxWorkQueue);
     108    g_prtR0LnxWorkQueue = NULL;
     109#endif
     110
    55111#ifdef RT_ARCH_AMD64
    56112    rtR0MemExecCleanup();
  • trunk/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h

    r36233 r39004  
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    119119#include <asm/div64.h>
    120120
     121/* for workqueue / task queues. */
     122#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
     123# include <linux/workqueue.h>
     124#else
     125# include <linux/tqueue.h>
     126#endif
     127
    121128#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
    122129# include <linux/kthread.h>
     
    368375#endif
    369376
    370 #endif
     377/*
     378 * Workqueue stuff, see initterm-r0drv-linux.c.
     379 */
     380#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
     381typedef struct work_struct  RTR0LNXWORKQUEUEITEM;
     382#else
     383typedef struct tq_struct    RTR0LNXWORKQUEUEITEM;
     384#endif
     385DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWorker)(RTR0LNXWORKQUEUEITEM *));
     386DECLHIDDEN(void) rtR0LnxWorkqueueFlush(void);
     387
     388
     389#endif
  • trunk/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c

    r33603 r39004  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    175175    /** The change interval spinlock for standard timers only. */
    176176    spinlock_t              ChgIntLock;
     177    /** Workqueue item for delayed destruction. */
     178    RTR0LNXWORKQUEUEITEM    DtorWorkqueueItem;
    177179    /** Sub-timers.
    178180     * Normally there is just one, but for RTTIMER_FLAGS_CPU_ALL this will contain
     
    386388#ifdef RTTIMER_LINUX_WITH_HRTIMER
    387389    if (fHighRes)
    388         hrtimer_cancel(&pSubTimer->u.Hr.LnxTimer);
     390    {
     391        /* There is no equivalent to del_timer in the hrtimer API,
     392           hrtimer_cancel() == del_timer_sync().  Just like the WARN_ON in
     393           del_timer_sync() asserts, waiting for a timer callback to complete
     394           is deadlock prone, so don't do it.  */
     395        int rc = hrtimer_try_to_cancel(&pSubTimer->u.Hr.LnxTimer);
     396        if (rc < 0)
     397        {
     398            hrtimer_start(&pSubTimer->u.Hr.LnxTimer, ktime_set(KTIME_SEC_MAX, 0), HRTIMER_MODE_ABS);
     399            hrtimer_try_to_cancel(&pSubTimer->u.Hr.LnxTimer);
     400        }
     401    }
    389402    else
    390403#endif
    391     {
    392         if (timer_pending(&pSubTimer->u.Std.LnxTimer))
    393             del_timer_sync(&pSubTimer->u.Std.LnxTimer);
    394     }
     404        del_timer(&pSubTimer->u.Std.LnxTimer);
    395405
    396406    rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED);
     
    405415static void rtTimerLnxDestroyIt(PRTTIMER pTimer)
    406416{
    407     RTSPINLOCK hSpinlock = pTimer->hSpinlock;
     417    RTSPINLOCK  hSpinlock = pTimer->hSpinlock;
     418    RTCPUID     iCpu;
    408419    Assert(pTimer->fSuspended);
    409420    RTTIMERLNX_LOG(("destroyit %p\n", pTimer));
     
    423434
    424435    /*
    425      * Uninitialize the structure and free the associated resources.
    426      * The spinlock goes last.
     436     * Invalidate the handle.
    427437     */
    428438    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
     439
     440    /*
     441     * Make sure all timers have stopped executing since we're stopping them in
     442     * an asynchronous manner up in rtTimerLnxStopSubTimer.
     443     */
     444    iCpu = pTimer->cCpus;
     445    while (iCpu-- > 0)
     446    {
     447#ifdef RTTIMER_LINUX_WITH_HRTIMER
     448        if (pTimer->fHighRes)
     449            hrtimer_cancel(&pTimer->aSubTimers[iCpu].u.Hr.LnxTimer);
     450        else
     451#endif
     452            del_timer_sync(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
     453    }
     454
     455    /*
     456     * Finally, free the resources.
     457     */
    429458    RTMemFreeEx(pTimer, RT_OFFSETOF(RTTIMER, aSubTimers[pTimer->cCpus]));
    430459    if (hSpinlock != NIL_RTSPINLOCK)
    431460        RTSpinlockDestroy(hSpinlock);
     461}
     462
     463
     464/**
     465 * Workqueue callback (no DECLCALLBACK!) for deferred destruction.
     466 *
     467 * @param   pWork        Pointer to the DtorWorkqueueItem member of our timer
     468 *                       structure.
     469 */
     470static void rtTimerLnxDestroyDeferred(RTR0LNXWORKQUEUEITEM *pWork)
     471{
     472    PRTTIMER pTimer = RT_FROM_MEMBER(pWork, RTTIMER, DtorWorkqueueItem);
     473    rtTimerLnxDestroyIt(pTimer);
    432474}
    433475
     
    464506    }
    465507
    466     rtTimerLnxDestroyIt(pTimer);
     508    /*
     509     * Destroying a timer from the callback is unsafe since the callout code
     510     * might be touching the timer structure upon return (hrtimer does!).  So,
     511     * we have to defer the actual destruction to the IRPT workqueue.
     512     */
     513    rtR0LnxWorkqueuePush(&pTimer->DtorWorkqueueItem, rtTimerLnxDestroyDeferred);
    467514}
    468515
     
    933980    RTSPINLOCKTMP   Tmp = RTSPINLOCKTMP_INITIALIZER;
    934981    RTCPUID         iCpu;
     982    RTTIMERLNXSTATE enmState;
    935983
    936984
     
    944992    for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
    945993    {
    946         RTTIMERLNXSTATE enmState;
    947994        for (;;)
    948995        {
     
    9781025    /*
    9791026     * Do the actual stopping. Fortunately, this doesn't require any IPIs.
    980      * Unfortunately it cannot be done synchronously from within the spinlock,
    981      * because we might end up in an active waiting for a handler to complete.
     1027     * Unfortunately it cannot be done synchronously.
    9821028     */
    9831029    for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
     
    14191465    int         rc;
    14201466
     1467    rtR0LnxWorkqueueFlush();                /* for 2.4 */
    14211468    *ppTimer = NULL;
    14221469
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