VirtualBox

Changeset 6084 in vbox


Ignore:
Timestamp:
Dec 15, 2007 2:56:01 PM (17 years ago)
Author:
vboxsync
Message:

Attempt at fixing (most of) the concurrency issues in tmTimerQueueScheduleOne.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r5999 r6084  
    11381138     * Processing.
    11391139     */
    1140     switch (pTimer->enmState)
    1141     {
    1142         /*
    1143          * Reschedule timer (in the active list).
    1144          */
    1145         case TMTIMERSTATE_PENDING_RESCHEDULE:
     1140    unsigned cRetries = 2;
     1141    do
     1142    {
     1143        TMTIMERSTATE enmState = pTimer->enmState;
     1144        switch (enmState)
    11461145        {
    1147             const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
    1148             const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
    1149             if (pPrev)
    1150                 TMTIMER_SET_NEXT(pPrev, pNext);
    1151             else
     1146            /*
     1147             * Reschedule timer (in the active list).
     1148             */
     1149            case TMTIMERSTATE_PENDING_RESCHEDULE:
    11521150            {
    1153                 TMTIMER_SET_HEAD(pQueue, pNext);
    1154                 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
     1151                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE)))
     1152                    break; /* retry */
     1153
     1154                const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
     1155                const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
     1156                if (pPrev)
     1157                    TMTIMER_SET_NEXT(pPrev, pNext);
     1158                else
     1159                {       
     1160                    TMTIMER_SET_HEAD(pQueue, pNext);
     1161                    pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
     1162                }
     1163                if (pNext)
     1164                    TMTIMER_SET_PREV(pNext, pPrev);
     1165                pTimer->offNext = 0;
     1166                pTimer->offPrev = 0;
     1167                /* fall thru */
    11551168            }
    1156             if (pNext)
    1157                 TMTIMER_SET_PREV(pNext, pPrev);
    1158             pTimer->offNext = 0;
    1159             pTimer->offPrev = 0;
    1160             /* fall thru */
     1169   
     1170            /*
     1171             * Schedule timer (insert into the active list).
     1172             */
     1173            case TMTIMERSTATE_PENDING_SCHEDULE:
     1174            {
     1175                Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
     1176                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, TMTIMERSTATE_PENDING_SCHEDULE)))
     1177                    break; /* retry */
     1178
     1179                PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);
     1180                if (pCur)
     1181                {
     1182                    const uint64_t u64Expire = pTimer->u64Expire;
     1183                    for (;; pCur = TMTIMER_GET_NEXT(pCur))
     1184                    {
     1185                        if (pCur->u64Expire > u64Expire)
     1186                        {
     1187                            const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);
     1188                            TMTIMER_SET_NEXT(pTimer, pCur);
     1189                            TMTIMER_SET_PREV(pTimer, pPrev);
     1190                            if (pPrev)
     1191                                TMTIMER_SET_NEXT(pPrev, pTimer);
     1192                            else
     1193                            {
     1194                                TMTIMER_SET_HEAD(pQueue, pTimer);
     1195                                pQueue->u64Expire = u64Expire;
     1196                            }
     1197                            TMTIMER_SET_PREV(pCur, pTimer);
     1198                            return;
     1199                        }
     1200                        if (!pCur->offNext)
     1201                        {
     1202                            TMTIMER_SET_NEXT(pCur, pTimer);
     1203                            TMTIMER_SET_PREV(pTimer, pCur);
     1204                            return;
     1205                        }
     1206                    }
     1207                }
     1208                else
     1209                {
     1210                    TMTIMER_SET_HEAD(pQueue, pTimer);
     1211                    pQueue->u64Expire = pTimer->u64Expire;
     1212                }
     1213                return;
     1214            }
     1215   
     1216            /*
     1217             * Stop the timer in active list.
     1218             */
     1219            case TMTIMERSTATE_PENDING_STOP:
     1220            {
     1221                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP)))
     1222                    break; /* retry */
     1223
     1224                const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
     1225                const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
     1226                if (pPrev)
     1227                    TMTIMER_SET_NEXT(pPrev, pNext);
     1228                else
     1229                {
     1230                    TMTIMER_SET_HEAD(pQueue, pNext);
     1231                    pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
     1232                }
     1233                if (pNext)
     1234                    TMTIMER_SET_PREV(pNext, pPrev);
     1235                pTimer->offNext = 0;
     1236                pTimer->offPrev = 0;
     1237                /* fall thru */
     1238            }
     1239   
     1240            /*
     1241             * Stop the timer (not on the active list).
     1242             */
     1243            case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     1244                Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
     1245                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_PENDING_STOP_SCHEDULE)))
     1246                    break;
     1247                return;
     1248   
     1249            /*
     1250             * Stop & destroy the timer.
     1251             */
     1252            case TMTIMERSTATE_PENDING_STOP_DESTROY:
     1253            {
     1254                const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
     1255                const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
     1256                if (pPrev)
     1257                    TMTIMER_SET_NEXT(pPrev, pNext);
     1258                else
     1259                {
     1260                    TMTIMER_SET_HEAD(pQueue, pNext);
     1261                    pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
     1262                }
     1263                if (pNext)
     1264                    TMTIMER_SET_PREV(pNext, pPrev);
     1265                pTimer->offNext = 0;
     1266                pTimer->offPrev = 0;
     1267                /* fall thru */
     1268            }
     1269   
     1270            /*
     1271             * Destroy the timer.
     1272             */
     1273            case TMTIMERSTATE_PENDING_DESTROY:
     1274            {
     1275                Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
     1276                PVM pVM = pTimer->CTXALLSUFF(pVM);
     1277                const PTMTIMER pBigPrev = (PTMTIMER)(pTimer->pBigPrev ? MMHyperR3ToCC(pVM, pTimer->pBigPrev) : NULL);
     1278                const PTMTIMER pBigNext = (PTMTIMER)(pTimer->pBigNext ? MMHyperR3ToCC(pVM, pTimer->pBigNext) : NULL);
     1279   
     1280                /* unlink from created list */
     1281                if (pBigPrev)
     1282                    pBigPrev->pBigNext = pTimer->pBigNext;
     1283                else
     1284                    pVM->tm.s.pCreated = pTimer->pBigNext;
     1285                if (pBigNext)
     1286                    pBigNext->pBigPrev = pTimer->pBigPrev;
     1287                pTimer->pBigNext = 0;
     1288                pTimer->pBigPrev = 0;
     1289   
     1290                /* free */
     1291                Log2(("TM: Inserting %p into the free list ahead of %p!\n", pTimer, pVM->tm.s.pFree));
     1292                pTimer->pBigNext = pVM->tm.s.pFree;
     1293                pVM->tm.s.pFree = (PTMTIMERR3)MMHyperCCToR3(pVM, pTimer);
     1294                TM_SET_STATE(pTimer, TMTIMERSTATE_FREE);
     1295                return;
     1296            }
     1297   
     1298            /*
     1299             * Postpone these until they get into the right state.
     1300             */
     1301            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     1302            case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     1303                tmTimerLink(pQueue, pTimer);
     1304                STAM_COUNTER_INC(&pTimer->CTXALLSUFF(pVM)->tm.s.CTXALLSUFF(StatPostponed));
     1305                return;
     1306   
     1307            /*
     1308             * None of these can be in the schedule.
     1309             */
     1310            case TMTIMERSTATE_FREE:
     1311            case TMTIMERSTATE_STOPPED:
     1312            case TMTIMERSTATE_ACTIVE:
     1313            case TMTIMERSTATE_EXPIRED:
     1314            default:
     1315                AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!",
     1316                                 pTimer, tmTimerState(pTimer->enmState), pTimer->enmState));
     1317                return;
    11611318        }
    1162 
    1163         /*
    1164          * Schedule timer (insert into the active list).
    1165          */
    1166         case TMTIMERSTATE_PENDING_SCHEDULE:
    1167         {
    1168             Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
    1169             TM_SET_STATE(pTimer, TMTIMERSTATE_ACTIVE);
    1170             PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);
    1171             if (pCur)
    1172             {
    1173                 const uint64_t u64Expire = pTimer->u64Expire;
    1174                 for (;; pCur = TMTIMER_GET_NEXT(pCur))
    1175                 {
    1176                     if (pCur->u64Expire > u64Expire)
    1177                     {
    1178                         const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);
    1179                         TMTIMER_SET_NEXT(pTimer, pCur);
    1180                         TMTIMER_SET_PREV(pTimer, pPrev);
    1181                         if (pPrev)
    1182                             TMTIMER_SET_NEXT(pPrev, pTimer);
    1183                         else
    1184                         {
    1185                             TMTIMER_SET_HEAD(pQueue, pTimer);
    1186                             pQueue->u64Expire = u64Expire;
    1187                         }
    1188                         TMTIMER_SET_PREV(pCur, pTimer);
    1189                         break;
    1190                     }
    1191                     else if (!pCur->offNext)
    1192                     {
    1193                         TMTIMER_SET_NEXT(pCur, pTimer);
    1194                         TMTIMER_SET_PREV(pTimer, pCur);
    1195                         break;
    1196                     }
    1197                 }
    1198             }
    1199             else
    1200             {
    1201                 TMTIMER_SET_HEAD(pQueue, pTimer);
    1202                 pQueue->u64Expire = pTimer->u64Expire;
    1203             }
    1204             break;
    1205         }
    1206 
    1207                 /*
    1208          * Stop the timer in active list.
    1209          */
    1210         case TMTIMERSTATE_PENDING_STOP:
    1211         {
    1212             const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
    1213             const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
    1214             if (pPrev)
    1215                 TMTIMER_SET_NEXT(pPrev, pNext);
    1216             else
    1217             {
    1218                 TMTIMER_SET_HEAD(pQueue, pNext);
    1219                 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
    1220             }
    1221             if (pNext)
    1222                 TMTIMER_SET_PREV(pNext, pPrev);
    1223             pTimer->offNext = 0;
    1224             pTimer->offPrev = 0;
    1225             /* fall thru */
    1226         }
    1227 
    1228         /*
    1229          * Stop the timer (not on the active list).
    1230          */
    1231         case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
    1232             Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
    1233             TM_SET_STATE(pTimer, TMTIMERSTATE_STOPPED);
    1234             break;
    1235 
    1236         /*
    1237          * Stop & destroy the timer.
    1238          */
    1239         case TMTIMERSTATE_PENDING_STOP_DESTROY:
    1240         {
    1241             const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
    1242             const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
    1243             if (pPrev)
    1244                 TMTIMER_SET_NEXT(pPrev, pNext);
    1245             else
    1246             {
    1247                 TMTIMER_SET_HEAD(pQueue, pNext);
    1248                 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
    1249             }
    1250             if (pNext)
    1251                 TMTIMER_SET_PREV(pNext, pPrev);
    1252             pTimer->offNext = 0;
    1253             pTimer->offPrev = 0;
    1254             /* fall thru */
    1255         }
    1256 
    1257         /*
    1258          * Destroy the timer.
    1259          */
    1260         case TMTIMERSTATE_PENDING_DESTROY:
    1261         {
    1262             Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
    1263             PVM pVM = pTimer->CTXALLSUFF(pVM);
    1264             const PTMTIMER pBigPrev = (PTMTIMER)(pTimer->pBigPrev ? MMHyperR3ToCC(pVM, pTimer->pBigPrev) : NULL);
    1265             const PTMTIMER pBigNext = (PTMTIMER)(pTimer->pBigNext ? MMHyperR3ToCC(pVM, pTimer->pBigNext) : NULL);
    1266 
    1267             /* unlink from created list */
    1268             if (pBigPrev)
    1269                 pBigPrev->pBigNext = pTimer->pBigNext;
    1270             else
    1271                 pVM->tm.s.pCreated = pTimer->pBigNext;
    1272             if (pBigNext)
    1273                 pBigNext->pBigPrev = pTimer->pBigPrev;
    1274             pTimer->pBigNext = 0;
    1275             pTimer->pBigPrev = 0;
    1276 
    1277             /* free */
    1278             Log2(("TM: Inserting %p into the free list ahead of %p!\n", pTimer, pVM->tm.s.pFree));
    1279             pTimer->pBigNext = pVM->tm.s.pFree;
    1280             pVM->tm.s.pFree = (PTMTIMERR3)MMHyperCCToR3(pVM, pTimer);
    1281             TM_SET_STATE(pTimer, TMTIMERSTATE_FREE);
    1282             break;
    1283         }
    1284 
    1285         /*
    1286          * Postpone these until they get into the right state.
    1287          */
    1288         case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
    1289         case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
    1290             tmTimerLink(pQueue, pTimer);
    1291             STAM_COUNTER_INC(&pTimer->CTXALLSUFF(pVM)->tm.s.CTXALLSUFF(StatPostponed));
    1292             break;
    1293 
    1294         /*
    1295          * None of these can be in the schedule.
    1296          */
    1297         case TMTIMERSTATE_FREE:
    1298         case TMTIMERSTATE_STOPPED:
    1299         case TMTIMERSTATE_ACTIVE:
    1300         case TMTIMERSTATE_EXPIRED:
    1301             AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!",
    1302                              pTimer, tmTimerState(pTimer->enmState), pTimer->enmState));
    1303             break;
    1304     }
     1319    } while (cRetries-- > 0);
    13051320}
    13061321
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