VirtualBox

Changeset 27883 in vbox


Ignore:
Timestamp:
Mar 31, 2010 12:07:15 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
59570
Message:

AsyncCompletion: Replace our own task cache with a RTMemCache. The old code had a race condition

Location:
trunk/src/VBox/VMM
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/PDMAsyncCompletion.cpp

    r27738 r27883  
    116116} PDMASYNCCOMPLETIONTEMPLATE;
    117117
    118 static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask, bool fLocal);
     118static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask);
    119119
    120120/**
     
    580580    }
    581581
    582     pdmR3AsyncCompletionPutTask(pTask->pEndpoint, pTask, true);
     582    pdmR3AsyncCompletionPutTask(pTask->pEndpoint, pTask);
    583583}
    584584
     
    620620            PCFGMNODE pCfgNodeClass = CFGMR3GetChild(pCfgHandle, pEpClassOps->pcszName);
    621621
    622             /* Query the common CFGM options */
    623             rc = CFGMR3QueryU32Def(pCfgNodeClass, "TaskCachePerEndpoint", &pEndpointClass->cEndpointCacheSize, 5);
    624             AssertRCReturn(rc, rc);
    625 
    626             rc = CFGMR3QueryU32Def(pCfgNodeClass, "TaskCachePerClass", &pEndpointClass->cEpClassCacheSize, 50);
    627             AssertRCReturn(rc, rc);
    628 
    629             /* Call the specific endpoint class initializer. */
    630             rc = pEpClassOps->pfnInitialize(pEndpointClass, pCfgNodeClass);
     622            /* Create task cache */
     623            rc = RTMemCacheCreate(&pEndpointClass->hMemCacheTasks, pEpClassOps->cbTask,
     624                                  0, UINT32_MAX, NULL, NULL, NULL, 0);
    631625            if (RT_SUCCESS(rc))
    632626            {
    633                 AssertMsg(!pVM->pdm.s.papAsyncCompletionEndpointClass[pEpClassOps->enmClassType],
    634                               ("Endpoint class was already initialized\n"));
    635 
    636                 pVM->pdm.s.papAsyncCompletionEndpointClass[pEpClassOps->enmClassType] = pEndpointClass;
    637                 LogFlowFunc((": Initialized endpoint class \"%s\" rc=%Rrc\n", pEpClassOps->pcszName, rc));
    638                 return VINF_SUCCESS;
     627                /* Call the specific endpoint class initializer. */
     628                rc = pEpClassOps->pfnInitialize(pEndpointClass, pCfgNodeClass);
     629                if (RT_SUCCESS(rc))
     630                {
     631                    AssertMsg(!pVM->pdm.s.papAsyncCompletionEndpointClass[pEpClassOps->enmClassType],
     632                                  ("Endpoint class was already initialized\n"));
     633
     634                    pVM->pdm.s.papAsyncCompletionEndpointClass[pEpClassOps->enmClassType] = pEndpointClass;
     635                    LogFlowFunc((": Initialized endpoint class \"%s\" rc=%Rrc\n", pEpClassOps->pcszName, rc));
     636                    return VINF_SUCCESS;
     637                }
     638                RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
    639639            }
    640640            RTCritSectDelete(&pEndpointClass->CritSect);
     
    665665        PDMR3AsyncCompletionEpClose(pEndpointClass->pEndpointsHead);
    666666
    667     /* Destroy all cached tasks. */
    668     for (unsigned i = 0; i < RT_ELEMENTS(pEndpointClass->apTaskCache); i++)
    669     {
    670         PPDMASYNCCOMPLETIONTASK pTask = pEndpointClass->apTaskCache[i];
    671 
    672         while (pTask)
    673         {
    674             PPDMASYNCCOMPLETIONTASK pTaskFree = pTask;
    675             pTask = pTask->pNext;
    676             MMR3HeapFree(pTaskFree);
    677         }
    678     }
    679 
    680667    /* Call the termination callback of the class. */
    681668    pEndpointClass->pEndpointOps->pfnTerminate(pEndpointClass);
    682669
     670    RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
    683671    RTCritSectDelete(&pEndpointClass->CritSect);
    684672
     
    754742static PPDMASYNCCOMPLETIONTASK pdmR3AsyncCompletionGetTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser)
    755743{
     744    PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
    756745    PPDMASYNCCOMPLETIONTASK pTask = NULL;
    757746
    758     /* Try the small per endpoint cache first. */
    759     uint32_t cTasksCached = ASMAtomicReadU32(&pEndpoint->cTasksCached);
    760     if (cTasksCached == 0)
    761     {
    762         /* Try the bigger per endpoint class cache. */
    763         PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
    764 
    765         /* We start with the assigned slot id to distribute the load when allocating new tasks. */
    766         unsigned iSlot = pEndpoint->iSlotStart;
    767         do
    768         {
    769             pTask = (PPDMASYNCCOMPLETIONTASK)ASMAtomicXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[iSlot], NULL);
    770             if (pTask)
    771                 break;
    772 
    773             iSlot = (iSlot + 1) % RT_ELEMENTS(pEndpointClass->apTaskCache);
    774         } while (iSlot != pEndpoint->iSlotStart);
    775 
    776         if (!pTask)
    777         {
    778             /*
    779              * Allocate completely new.
    780              * If this fails we return NULL.
    781              */
    782             int rc = MMR3HeapAllocZEx(pEndpointClass->pVM, MM_TAG_PDM_ASYNC_COMPLETION,
    783                                       pEndpointClass->pEndpointOps->cbTask,
    784                                       (void **)&pTask);
    785             if (RT_FAILURE(rc))
    786                 pTask = NULL;
    787         }
    788         else
    789         {
    790             /* Remove the first element and put the rest into the slot again. */
    791             PPDMASYNCCOMPLETIONTASK pTaskHeadNew = pTask->pNext;
    792 
    793             /* Put back into the list adding any new tasks. */
    794             while (true)
    795             {
    796                 bool fChanged = ASMAtomicCmpXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[iSlot], pTaskHeadNew, NULL);
    797 
    798                 if (fChanged)
    799                     break;
    800 
    801                 PPDMASYNCCOMPLETIONTASK pTaskHead = (PPDMASYNCCOMPLETIONTASK)ASMAtomicXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[iSlot], NULL);
    802 
    803                 /* The new task could be taken inbetween */
    804                 if (pTaskHead)
    805                 {
    806                     /* Go to the end of the probably much shorter new list. */
    807                     PPDMASYNCCOMPLETIONTASK pTaskTail = pTaskHead;
    808                     while (pTaskTail->pNext)
    809                         pTaskTail = pTaskTail->pNext;
    810 
    811                     /* Concatenate */
    812                     pTaskTail->pNext = pTaskHeadNew;
    813 
    814                     pTaskHeadNew = pTaskHead;
    815                 }
    816                 /* Another round trying to change the list. */
    817             }
    818             /* We got a task from the global cache so decrement the counter */
    819             ASMAtomicDecU32(&pEndpointClass->cTasksCached);
    820         }
    821     }
    822     else
    823     {
    824         /* Grab a free task from the head. */
    825         AssertMsg(pEndpoint->cTasksCached > 0, ("No tasks cached but list contain more than one element\n"));
    826 
    827         pTask = pEndpoint->pTasksFreeHead;
    828         pEndpoint->pTasksFreeHead = pTask->pNext;
    829         ASMAtomicDecU32(&pEndpoint->cTasksCached);
    830     }
     747    pTask = (PPDMASYNCCOMPLETIONTASK)RTMemCacheAlloc(pEndpointClass->hMemCacheTasks);
    831748
    832749    if (RT_LIKELY(pTask))
     
    856773 * @param   pEndpoint    The endpoint the task belongs to.
    857774 * @param   pTask        The task to cache.
    858  * @param   fLocal       Whether the per endpoint cache should be tried first.
    859  */
    860 static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask, bool fLocal)
     775 */
     776static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
    861777{
    862778    PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
     
    921837#endif
    922838
    923     /* Check whether we can use the per endpoint cache */
    924     if (   fLocal
    925         && (pEndpoint->cTasksCached < pEndpointClass->cEndpointCacheSize))
    926     {
    927         /* Add it to the list. */
    928         pTask->pPrev = NULL;
    929         pEndpoint->pTasksFreeTail->pNext = pTask;
    930         pEndpoint->pTasksFreeTail        = pTask;
    931         ASMAtomicIncU32(&pEndpoint->cTasksCached);
    932     }
    933     else if (ASMAtomicReadU32(&pEndpoint->cTasksCached) < pEndpointClass->cEpClassCacheSize)
    934     {
    935         /* Use the global cache. */
    936         ASMAtomicIncU32(&pEndpointClass->cTasksCached);
    937 
    938         PPDMASYNCCOMPLETIONTASK pNext;
    939         do
    940         {
    941             pNext = pEndpointClass->apTaskCache[pEndpoint->iSlotStart];
    942             pTask->pNext = pNext;
    943         } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[pEndpoint->iSlotStart], (void *)pTask, (void *)pNext));
    944     }
    945     else
    946     {
    947         /* Free it */
    948         MMR3HeapFree(pTask);
    949     }
     839    RTMemCacheFree(pEndpointClass->hMemCacheTasks, pTask);
    950840}
    951841
     
    1005895            pEndpoint->pPrev             = NULL;
    1006896            pEndpoint->pEpClass          = pEndpointClass;
    1007             pEndpoint->pTasksFreeHead    = NULL;
    1008             pEndpoint->pTasksFreeTail    = NULL;
    1009             pEndpoint->cTasksCached      = 0;
    1010897            pEndpoint->uTaskIdNext       = 0;
    1011898            pEndpoint->fTaskIdWraparound = false;
    1012899            pEndpoint->pTemplate         = pTemplate;
    1013             pEndpoint->iSlotStart        = pEndpointClass->cEndpoints % RT_ELEMENTS(pEndpointClass->apTaskCache);
    1014900            pEndpoint->pszUri            = RTStrDup(pszFilename);
    1015901            pEndpoint->cUsers            = 1;
     
    11241010                && RT_SUCCESS(rc))
    11251011            {
    1126                 /* Init the cache. */
    1127                 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
    1128                                       pEndpointClass->pEndpointOps->cbTask,
    1129                                       (void **)&pEndpoint->pTasksFreeHead);
     1012                /* Call the initializer for the endpoint. */
     1013                rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
    11301014                if (RT_SUCCESS(rc))
    11311015                {
    1132                     pEndpoint->pTasksFreeTail = pEndpoint->pTasksFreeHead;
    1133 
    1134                     /* Call the initializer for the endpoint. */
    1135                     rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
    1136                     if (RT_SUCCESS(rc))
    1137                     {
    1138                         /* Link it into the list of endpoints. */
    1139                         rc = RTCritSectEnter(&pEndpointClass->CritSect);
    1140                         AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
    1141 
    1142                         pEndpoint->pNext = pEndpointClass->pEndpointsHead;
    1143                         if (pEndpointClass->pEndpointsHead)
    1144                             pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
    1145 
    1146                         pEndpointClass->pEndpointsHead = pEndpoint;
    1147                         pEndpointClass->cEndpoints++;
    1148 
    1149                         rc = RTCritSectLeave(&pEndpointClass->CritSect);
    1150                         AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
    1151 
    1152                         /* Reference the template. */
    1153                         ASMAtomicIncU32(&pTemplate->cUsed);
    1154 
    1155                         *ppEndpoint = pEndpoint;
    1156 
    1157                         LogFlowFunc((": Created endpoint for %s: rc=%Rrc\n", pszFilename, rc));
    1158                         return VINF_SUCCESS;
    1159                     }
    1160                     MMR3HeapFree(pEndpoint->pTasksFreeHead);
    1161                     RTStrFree(pEndpoint->pszUri);
     1016                    /* Link it into the list of endpoints. */
     1017                    rc = RTCritSectEnter(&pEndpointClass->CritSect);
     1018                    AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
     1019
     1020                    pEndpoint->pNext = pEndpointClass->pEndpointsHead;
     1021                    if (pEndpointClass->pEndpointsHead)
     1022                        pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
     1023
     1024                    pEndpointClass->pEndpointsHead = pEndpoint;
     1025                    pEndpointClass->cEndpoints++;
     1026
     1027                    rc = RTCritSectLeave(&pEndpointClass->CritSect);
     1028                    AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
     1029
     1030                    /* Reference the template. */
     1031                    ASMAtomicIncU32(&pTemplate->cUsed);
     1032
     1033                    *ppEndpoint = pEndpoint;
     1034
     1035                    LogFlowFunc((": Created endpoint for %s: rc=%Rrc\n", pszFilename, rc));
     1036                    return VINF_SUCCESS;
    11621037                }
    1163                 else
    1164                     rc = VERR_NO_MEMORY;
     1038                RTStrFree(pEndpoint->pszUri);
    11651039            }
    11661040            MMR3HeapFree(pEndpoint);
     
    11951069        PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
    11961070        pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
    1197 
    1198         /* Free cached tasks. */
    1199         PPDMASYNCCOMPLETIONTASK pTask = pEndpoint->pTasksFreeHead;
    1200 
    1201         while (pTask)
    1202         {
    1203             PPDMASYNCCOMPLETIONTASK pTaskFree = pTask;
    1204             pTask = pTask->pNext;
    1205             MMR3HeapFree(pTaskFree);
    1206         }
    12071071
    12081072        /* Drop reference from the template. */
     
    12791143    }
    12801144    else
    1281         pdmR3AsyncCompletionPutTask(pEndpoint, pTask, false);
     1145        pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
    12821146
    12831147    return rc;
     
    13111175    }
    13121176    else
    1313         pdmR3AsyncCompletionPutTask(pEndpoint, pTask, false);
     1177        pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
    13141178
    13151179    return rc;
     
    13371201    }
    13381202    else
    1339         pdmR3AsyncCompletionPutTask(pEndpoint, pTask, false);
     1203        pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
    13401204
    13411205    return rc;
  • trunk/src/VBox/VMM/PDMAsyncCompletionInternal.h

    r27738 r27883  
    2525#include <iprt/cdefs.h>
    2626#include <iprt/critsect.h>
     27#include <iprt/memcache.h>
    2728#include <VBox/types.h>
    2829#include <VBox/cfgm.h>
     
    198199    /** Pointer to the callback table. */
    199200    R3PTRTYPE(PCPDMASYNCCOMPLETIONEPCLASSOPS)   pEndpointOps;
    200     /** Bigger cache for free task items used by all endpoints
    201      * of this class. */
    202     R3PTRTYPE(volatile PPDMASYNCCOMPLETIONTASK) apTaskCache[10];
    203     /** Number of tasks cached */
    204     volatile uint32_t                           cTasksCached;
     201    /** Task cache. */
     202    RTMEMCACHE                                  hMemCacheTasks;
    205203} PDMASYNCCOMPLETIONEPCLASS;
    206204/** Pointer to the PDM async completion endpoint class data. */
     
    219217    /** Pointer to the class this endpoint belongs to. */
    220218    R3PTRTYPE(PPDMASYNCCOMPLETIONEPCLASS)       pEpClass;
    221     /** Head of the small cache for allocated task structures for exclusive
    222      * use by this endpoint. */
    223     R3PTRTYPE(volatile PPDMASYNCCOMPLETIONTASK) pTasksFreeHead;
    224     /** Tail of the small cache for allocated task structures for exclusive
    225      * use by this endpoint. */
    226     R3PTRTYPE(volatile PPDMASYNCCOMPLETIONTASK) pTasksFreeTail;
    227     /** Number of elements in the cache. */
    228     volatile uint32_t                           cTasksCached;
    229     /** Start slot for the global task cache. */
    230     unsigned                                    iSlotStart;
    231219    /** ID of the next task to ensure consistency. */
    232220    volatile uint32_t                           uTaskIdNext;
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