ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

coroutines.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/coroutines.h"
00024 #include "common/algorithm.h"
00025 #include "common/debug.h"
00026 #include "common/hashmap.h"
00027 #include "common/hash-str.h"
00028 #include "common/system.h"
00029 #include "common/textconsole.h"
00030 
00031 namespace Common {
00032 
00034 CoroContext nullContext = nullptr;
00035 
00036 DECLARE_SINGLETON(CoroutineScheduler);
00037 
00038 #ifdef COROUTINE_DEBUG
00039 namespace {
00041 static int s_coroCount = 0;
00042 
00043 typedef Common::HashMap<Common::String, int> CoroHashMap;
00044 static CoroHashMap *s_coroFuncs = 0;
00045 
00049 static void changeCoroStats(const char *func, int change) {
00050     if (!s_coroFuncs)
00051         s_coroFuncs = new CoroHashMap();
00052 
00053     (*s_coroFuncs)[func] += change;
00054 }
00055 
00059 static void displayCoroStats() {
00060     debug("%d active coros", s_coroCount);
00061 
00062     // Loop over s_coroFuncs and print info about active coros
00063     if (!s_coroFuncs)
00064         return;
00065     for (CoroHashMap::const_iterator it = s_coroFuncs->begin();
00066             it != s_coroFuncs->end(); ++it) {
00067         if (it->_value != 0)
00068             debug("  %3d x %s", it->_value, it->_key.c_str());
00069     }
00070 }
00071 
00072 } // End of anonymous namespace
00073 #endif
00074 
00075 CoroBaseContext::CoroBaseContext(const char *func)
00076     : _line(0), _sleep(0), _subctx(nullptr) {
00077 #ifdef COROUTINE_DEBUG
00078     _funcName = func;
00079     changeCoroStats(_funcName, +1);
00080     s_coroCount++;
00081 #endif
00082 }
00083 
00084 CoroBaseContext::~CoroBaseContext() {
00085 #ifdef COROUTINE_DEBUG
00086     s_coroCount--;
00087     changeCoroStats(_funcName, -1);
00088     debug("Deleting coro in %s at %p (subctx %p)",
00089           _funcName, (void *)this, (void *)_subctx);
00090     displayCoroStats();
00091 #endif
00092     delete _subctx;
00093 }
00094 
00095 //--------------------- Scheduler Class ------------------------
00096 
00097 CoroutineScheduler::CoroutineScheduler() {
00098     processList = nullptr;
00099     pFreeProcesses = nullptr;
00100     pCurrent = nullptr;
00101 
00102 #ifdef DEBUG
00103     // diagnostic process counters
00104     numProcs = 0;
00105     maxProcs = 0;
00106 #endif
00107 
00108     pRCfunction = nullptr;
00109     pidCounter = 0;
00110 
00111     active = new PROCESS;
00112     active->pPrevious = nullptr;
00113     active->pNext = nullptr;
00114 
00115     reset();
00116 }
00117 
00118 CoroutineScheduler::~CoroutineScheduler() {
00119     // Kill all running processes (i.e. free memory allocated for their state).
00120     PROCESS *pProc = active->pNext;
00121     while (pProc != nullptr) {
00122         delete pProc->state;
00123         pProc->state = nullptr;
00124         pProc = pProc->pNext;
00125     }
00126 
00127     free(processList);
00128     processList = nullptr;
00129 
00130     delete active;
00131     active = nullptr;
00132 
00133     // Clear the event list
00134     Common::List<EVENT *>::iterator i;
00135     for (i = _events.begin(); i != _events.end(); ++i)
00136         delete *i;
00137 }
00138 
00139 void CoroutineScheduler::reset() {
00140 #ifdef DEBUG
00141     // clear number of process in use
00142     numProcs = 0;
00143 #endif
00144 
00145     if (processList == nullptr) {
00146         // first time - allocate memory for process list
00147         processList = (PROCESS *)calloc(CORO_MAX_PROCESSES, sizeof(PROCESS));
00148 
00149         // make sure memory allocated
00150         if (processList == nullptr) {
00151             error("Cannot allocate memory for process data");
00152         }
00153 
00154         // fill with garbage
00155         memset(processList, 'S', CORO_MAX_PROCESSES * sizeof(PROCESS));
00156     }
00157 
00158     // Kill all running processes (i.e. free memory allocated for their state).
00159     PROCESS *pProc = active->pNext;
00160     while (pProc != nullptr) {
00161         delete pProc->state;
00162         pProc->state = nullptr;
00163         Common::fill(&pProc->pidWaiting[0], &pProc->pidWaiting[CORO_MAX_PID_WAITING], 0);
00164         pProc = pProc->pNext;
00165     }
00166 
00167     // no active processes
00168     pCurrent = active->pNext = nullptr;
00169 
00170     // place first process on free list
00171     pFreeProcesses = processList;
00172 
00173     // link all other processes after first
00174     for (int i = 1; i <= CORO_NUM_PROCESS; i++) {
00175         processList[i - 1].pNext = (i == CORO_NUM_PROCESS) ? nullptr : processList + i;
00176         processList[i - 1].pPrevious = (i == 1) ? active : processList + (i - 2);
00177     }
00178 }
00179 
00180 
00181 #ifdef DEBUG
00182 void CoroutineScheduler::printStats() {
00183     debug("%i process of %i used", maxProcs, CORO_NUM_PROCESS);
00184 }
00185 #endif
00186 
00187 #ifdef DEBUG
00188 void CoroutineScheduler::checkStack() {
00189     Common::List<PROCESS *> pList;
00190 
00191     // Check both the active and free process lists
00192     for (int i = 0; i < 2; ++i) {
00193         PROCESS *p = (i == 0) ? active : pFreeProcesses;
00194 
00195         if (p != NULL) {
00196             // Make sure the linkages are correct
00197             while (p->pNext != NULL) {
00198                 assert(p->pNext->pPrevious == p);
00199                 pList.push_back(p);
00200                 p = p->pNext;
00201             }
00202             pList.push_back(p);
00203         }
00204     }
00205 
00206     // Make sure all processes are accounted for
00207     for (int idx = 0; idx < CORO_NUM_PROCESS; idx++) {
00208         bool found = false;
00209         for (Common::List<PROCESS *>::iterator i = pList.begin(); i != pList.end(); ++i) {
00210             PROCESS *pTemp = *i;
00211             if (*i == &processList[idx]) {
00212                 found = true;
00213                 break;
00214             }
00215         }
00216 
00217         assert(found);
00218     }
00219 }
00220 #endif
00221 
00222 void CoroutineScheduler::schedule() {
00223     // start dispatching active process list
00224     PROCESS *pNext;
00225     PROCESS *pProc = active->pNext;
00226     while (pProc != nullptr) {
00227         pNext = pProc->pNext;
00228 
00229         if (--pProc->sleepTime <= 0) {
00230             // process is ready for dispatch, activate it
00231             pCurrent = pProc;
00232             pProc->coroAddr(pProc->state, pProc->param);
00233 
00234             if (!pProc->state || pProc->state->_sleep <= 0) {
00235                 // Coroutine finished
00236                 pCurrent = pCurrent->pPrevious;
00237                 killProcess(pProc);
00238             } else {
00239                 pProc->sleepTime = pProc->state->_sleep;
00240             }
00241 
00242             // pCurrent may have been changed
00243             pNext = pCurrent->pNext;
00244             pCurrent = nullptr;
00245         }
00246 
00247         pProc = pNext;
00248     }
00249 
00250     // Disable any events that were pulsed
00251     Common::List<EVENT *>::iterator i;
00252     for (i = _events.begin(); i != _events.end(); ++i) {
00253         EVENT *evt = *i;
00254         if (evt->pulsing) {
00255             evt->pulsing = evt->signalled = false;
00256         }
00257     }
00258 }
00259 
00260 void CoroutineScheduler::rescheduleAll() {
00261     assert(pCurrent);
00262 
00263     // Unlink current process
00264     pCurrent->pPrevious->pNext = pCurrent->pNext;
00265     if (pCurrent->pNext)
00266         pCurrent->pNext->pPrevious = pCurrent->pPrevious;
00267 
00268     // Add process to the start of the active list
00269     pCurrent->pNext = active->pNext;
00270     active->pNext->pPrevious = pCurrent;
00271     active->pNext = pCurrent;
00272     pCurrent->pPrevious = active;
00273 }
00274 
00275 void CoroutineScheduler::reschedule(PPROCESS pReSchedProc) {
00276     // If not currently processing the schedule list, then no action is needed
00277     if (!pCurrent)
00278         return;
00279 
00280     if (!pReSchedProc)
00281         pReSchedProc = pCurrent;
00282 
00283     PPROCESS pEnd;
00284 
00285     // Find the last process in the list.
00286     // But if the target process is down the list from here, do nothing
00287     for (pEnd = pCurrent; pEnd->pNext != nullptr; pEnd = pEnd->pNext) {
00288         if (pEnd->pNext == pReSchedProc)
00289             return;
00290     }
00291 
00292     assert(pEnd->pNext == nullptr);
00293 
00294     // Could be in the middle of a KillProc()!
00295     // Dying process was last and this process was penultimate
00296     if (pReSchedProc->pNext == nullptr)
00297         return;
00298 
00299     // If we're moving the current process, move it back by one, so that the next
00300     // schedule() iteration moves to the now next one
00301     if (pCurrent == pReSchedProc)
00302         pCurrent = pCurrent->pPrevious;
00303 
00304     // Unlink the process, and add it at the end
00305     pReSchedProc->pPrevious->pNext = pReSchedProc->pNext;
00306     pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious;
00307     pEnd->pNext = pReSchedProc;
00308     pReSchedProc->pPrevious = pEnd;
00309     pReSchedProc->pNext = nullptr;
00310 }
00311 
00312 void CoroutineScheduler::giveWay(PPROCESS pReSchedProc) {
00313     // If not currently processing the schedule list, then no action is needed
00314     if (!pCurrent)
00315         return;
00316 
00317     if (!pReSchedProc)
00318         pReSchedProc = pCurrent;
00319 
00320     // If the process is already at the end of the queue, nothing has to be done
00321     if (!pReSchedProc->pNext)
00322         return;
00323 
00324     PPROCESS pEnd;
00325 
00326     // Find the last process in the list.
00327     for (pEnd = pCurrent; pEnd->pNext != nullptr; pEnd = pEnd->pNext)
00328         ;
00329     assert(pEnd->pNext == nullptr);
00330 
00331 
00332     // If we're moving the current process, move it back by one, so that the next
00333     // schedule() iteration moves to the now next one
00334     if (pCurrent == pReSchedProc)
00335         pCurrent = pCurrent->pPrevious;
00336 
00337     // Unlink the process, and add it at the end
00338     pReSchedProc->pPrevious->pNext = pReSchedProc->pNext;
00339     pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious;
00340     pEnd->pNext = pReSchedProc;
00341     pReSchedProc->pPrevious = pEnd;
00342     pReSchedProc->pNext = nullptr;
00343 }
00344 
00345 void CoroutineScheduler::waitForSingleObject(CORO_PARAM, int pid, uint32 duration, bool *expired) {
00346     if (!pCurrent)
00347         error("Called CoroutineScheduler::waitForSingleObject from the main process");
00348 
00349     CORO_BEGIN_CONTEXT;
00350         uint32 endTime;
00351         PROCESS *pProcess;
00352         EVENT *pEvent;
00353     CORO_END_CONTEXT(_ctx);
00354 
00355     CORO_BEGIN_CODE(_ctx);
00356 
00357     // Signal the process Id this process is now waiting for
00358     pCurrent->pidWaiting[0] = pid;
00359 
00360     _ctx->endTime = (duration == CORO_INFINITE) ? CORO_INFINITE : g_system->getMillis() + duration;
00361     if (expired)
00362         // Presume it will expire
00363         *expired = true;
00364 
00365     // Outer loop for doing checks until expiry
00366     while (g_system->getMillis() <= _ctx->endTime) {
00367         // Check to see if a process or event with the given Id exists
00368         _ctx->pProcess = getProcess(pid);
00369         _ctx->pEvent = !_ctx->pProcess ? getEvent(pid) : nullptr;
00370 
00371         // If there's no active process or event, presume it's a process that's finished,
00372         // so the waiting can immediately exit
00373         if ((_ctx->pProcess == nullptr) && (_ctx->pEvent == nullptr)) {
00374             if (expired)
00375                 *expired = false;
00376             break;
00377         }
00378 
00379         // If a process was found, don't go into the if statement, and keep waiting.
00380         // Likewise if it's an event that's not yet signalled
00381         if ((_ctx->pEvent != nullptr) && _ctx->pEvent->signalled) {
00382             // Unless the event is flagged for manual reset, reset it now
00383             if (!_ctx->pEvent->manualReset)
00384                 _ctx->pEvent->signalled = false;
00385 
00386             if (expired)
00387                 *expired = false;
00388             break;
00389         }
00390 
00391         // Sleep until the next cycle
00392         CORO_SLEEP(1);
00393     }
00394 
00395     // Signal waiting is done
00396     Common::fill(&pCurrent->pidWaiting[0], &pCurrent->pidWaiting[CORO_MAX_PID_WAITING], 0);
00397 
00398     CORO_END_CODE;
00399 }
00400 
00401 void CoroutineScheduler::waitForMultipleObjects(CORO_PARAM, int nCount, uint32 *pidList, bool bWaitAll,
00402                                                 uint32 duration, bool *expired) {
00403     if (!pCurrent)
00404         error("Called CoroutineScheduler::waitForMultipleObjects from the main process");
00405 
00406     CORO_BEGIN_CONTEXT;
00407         uint32 endTime;
00408         bool signalled;
00409         bool pidSignalled;
00410         int i;
00411         PROCESS *pProcess;
00412         EVENT *pEvent;
00413     CORO_END_CONTEXT(_ctx);
00414 
00415     CORO_BEGIN_CODE(_ctx);
00416 
00417     // Signal the waiting events
00418     assert(nCount < CORO_MAX_PID_WAITING);
00419     Common::copy(pidList, pidList + nCount, pCurrent->pidWaiting);
00420 
00421     _ctx->endTime = (duration == CORO_INFINITE) ? CORO_INFINITE : g_system->getMillis() + duration;
00422     if (expired)
00423         // Presume that delay will expire
00424         *expired = true;
00425 
00426     // Outer loop for doing checks until expiry
00427     while (g_system->getMillis() <= _ctx->endTime) {
00428         _ctx->signalled = bWaitAll;
00429 
00430         for (_ctx->i = 0; _ctx->i < nCount; ++_ctx->i) {
00431             _ctx->pProcess = getProcess(pidList[_ctx->i]);
00432             _ctx->pEvent = !_ctx->pProcess ? getEvent(pidList[_ctx->i]) : nullptr;
00433 
00434             // Determine the signalled state
00435             _ctx->pidSignalled = (_ctx->pProcess) || !_ctx->pEvent ? false : _ctx->pEvent->signalled;
00436 
00437             if (bWaitAll && !_ctx->pidSignalled)
00438                 _ctx->signalled = false;
00439             else if (!bWaitAll && _ctx->pidSignalled)
00440                 _ctx->signalled = true;
00441         }
00442 
00443         // At this point, if the signalled variable is set, waiting is finished
00444         if (_ctx->signalled) {
00445             // Automatically reset any events not flagged for manual reset
00446             for (_ctx->i = 0; _ctx->i < nCount; ++_ctx->i) {
00447                 _ctx->pEvent = getEvent(pidList[_ctx->i]);
00448 
00449                 if (!_ctx->pEvent->manualReset)
00450                     _ctx->pEvent->signalled = false;
00451             }
00452 
00453             if (expired)
00454                 *expired = false;
00455             break;
00456         }
00457 
00458         // Sleep until the next cycle
00459         CORO_SLEEP(1);
00460     }
00461 
00462     // Signal waiting is done
00463     Common::fill(&pCurrent->pidWaiting[0], &pCurrent->pidWaiting[CORO_MAX_PID_WAITING], 0);
00464 
00465     CORO_END_CODE;
00466 }
00467 
00468 void CoroutineScheduler::sleep(CORO_PARAM, uint32 duration) {
00469     if (!pCurrent)
00470         error("Called CoroutineScheduler::sleep from the main process");
00471 
00472     CORO_BEGIN_CONTEXT;
00473         uint32 endTime;
00474         PROCESS *pProcess;
00475         EVENT *pEvent;
00476     CORO_END_CONTEXT(_ctx);
00477 
00478     CORO_BEGIN_CODE(_ctx);
00479 
00480     _ctx->endTime = g_system->getMillis() + duration;
00481 
00482     // Outer loop for doing checks until expiry
00483     while (g_system->getMillis() < _ctx->endTime) {
00484         // Sleep until the next cycle
00485         CORO_SLEEP(1);
00486     }
00487 
00488     CORO_END_CODE;
00489 }
00490 
00491 PROCESS *CoroutineScheduler::createProcess(uint32 pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) {
00492     PROCESS *pProc;
00493 
00494     // get a free process
00495     pProc = pFreeProcesses;
00496 
00497     // trap no free process
00498     assert(pProc != nullptr); // Out of processes
00499 
00500 #ifdef DEBUG
00501     // one more process in use
00502     if (++numProcs > maxProcs)
00503         maxProcs = numProcs;
00504 #endif
00505 
00506     // get link to next free process
00507     pFreeProcesses = pProc->pNext;
00508     if (pFreeProcesses)
00509         pFreeProcesses->pPrevious = nullptr;
00510 
00511     if (pCurrent != nullptr) {
00512         // place new process before the next active process
00513         pProc->pNext = pCurrent->pNext;
00514         if (pProc->pNext)
00515             pProc->pNext->pPrevious = pProc;
00516 
00517         // make this new process the next active process
00518         pCurrent->pNext = pProc;
00519         pProc->pPrevious = pCurrent;
00520 
00521     } else { // no active processes, place process at head of list
00522         pProc->pNext = active->pNext;
00523         pProc->pPrevious = active;
00524 
00525         if (pProc->pNext)
00526             pProc->pNext->pPrevious = pProc;
00527         active->pNext = pProc;
00528 
00529     }
00530 
00531     // set coroutine entry point
00532     pProc->coroAddr = coroAddr;
00533 
00534     // clear coroutine state
00535     pProc->state = nullptr;
00536 
00537     // wake process up as soon as possible
00538     pProc->sleepTime = 1;
00539 
00540     // set new process id
00541     pProc->pid = pid;
00542 
00543     // set new process specific info
00544     if (sizeParam) {
00545         assert(sizeParam > 0 && sizeParam <= CORO_PARAM_SIZE);
00546 
00547         // set new process specific info
00548         memcpy(pProc->param, pParam, sizeParam);
00549     }
00550 
00551     // return created process
00552     return pProc;
00553 }
00554 
00555 uint32 CoroutineScheduler::createProcess(CORO_ADDR coroAddr, const void *pParam, int sizeParam) {
00556     PROCESS *pProc = createProcess(++pidCounter, coroAddr, pParam, sizeParam);
00557     return pProc->pid;
00558 }
00559 
00560 uint32 CoroutineScheduler::createProcess(CORO_ADDR coroAddr, const void *pParam) {
00561     return createProcess(coroAddr, &pParam, sizeof(void *));
00562 }
00563 
00564 void CoroutineScheduler::killProcess(PROCESS *pKillProc) {
00565     // make sure a valid process pointer
00566     assert(pKillProc >= processList && pKillProc <= processList + CORO_NUM_PROCESS - 1);
00567 
00568     // can not kill the current process using killProcess !
00569     assert(pCurrent != pKillProc);
00570 
00571 #ifdef DEBUG
00572     // one less process in use
00573     --numProcs;
00574     assert(numProcs >= 0);
00575 #endif
00576 
00577     // Free process' resources
00578     if (pRCfunction != nullptr)
00579         (pRCfunction)(pKillProc);
00580 
00581     delete pKillProc->state;
00582     pKillProc->state = nullptr;
00583 
00584     // Take the process out of the active chain list
00585     pKillProc->pPrevious->pNext = pKillProc->pNext;
00586     if (pKillProc->pNext)
00587         pKillProc->pNext->pPrevious = pKillProc->pPrevious;
00588 
00589     // link first free process after pProc
00590     pKillProc->pNext = pFreeProcesses;
00591     if (pFreeProcesses)
00592         pKillProc->pNext->pPrevious = pKillProc;
00593     pKillProc->pPrevious = nullptr;
00594 
00595     // make pKillProc the first free process
00596     pFreeProcesses = pKillProc;
00597 }
00598 
00599 PROCESS *CoroutineScheduler::getCurrentProcess() {
00600     return pCurrent;
00601 }
00602 
00603 int CoroutineScheduler::getCurrentPID() const {
00604     PROCESS *pProc = pCurrent;
00605 
00606     // make sure a valid process pointer
00607     assert(pProc >= processList && pProc <= processList + CORO_NUM_PROCESS - 1);
00608 
00609     // return processes PID
00610     return pProc->pid;
00611 }
00612 
00613 int CoroutineScheduler::killMatchingProcess(uint32 pidKill, int pidMask) {
00614     int numKilled = 0;
00615     PROCESS *pProc, *pPrev; // process list pointers
00616 
00617     for (pProc = active->pNext, pPrev = active; pProc != nullptr; pPrev = pProc, pProc = pProc->pNext) {
00618         if ((pProc->pid & (uint32)pidMask) == pidKill) {
00619             // found a matching process
00620 
00621             // dont kill the current process
00622             if (pProc != pCurrent) {
00623                 // kill this process
00624                 numKilled++;
00625 
00626                 // Free the process' resources
00627                 if (pRCfunction != nullptr)
00628                     (pRCfunction)(pProc);
00629 
00630                 delete pProc->state;
00631                 pProc->state = nullptr;
00632 
00633                 // make prev point to next to unlink pProc
00634                 pPrev->pNext = pProc->pNext;
00635                 if (pProc->pNext)
00636                     pPrev->pNext->pPrevious = pPrev;
00637 
00638                 // link first free process after pProc
00639                 pProc->pNext = pFreeProcesses;
00640                 pProc->pPrevious = nullptr;
00641                 pFreeProcesses->pPrevious = pProc;
00642 
00643                 // make pProc the first free process
00644                 pFreeProcesses = pProc;
00645 
00646                 // set to a process on the active list
00647                 pProc = pPrev;
00648             }
00649         }
00650     }
00651 
00652 #ifdef DEBUG
00653     // adjust process in use
00654     numProcs -= numKilled;
00655     assert(numProcs >= 0);
00656 #endif
00657 
00658     // return number of processes killed
00659     return numKilled;
00660 }
00661 
00662 void CoroutineScheduler::setResourceCallback(VFPTRPP pFunc) {
00663     pRCfunction = pFunc;
00664 }
00665 
00666 PROCESS *CoroutineScheduler::getProcess(uint32 pid) {
00667     PROCESS *pProc = active->pNext;
00668     while ((pProc != nullptr) && (pProc->pid != pid))
00669         pProc = pProc->pNext;
00670 
00671     return pProc;
00672 }
00673 
00674 EVENT *CoroutineScheduler::getEvent(uint32 pid) {
00675     Common::List<EVENT *>::iterator i;
00676     for (i = _events.begin(); i != _events.end(); ++i) {
00677         EVENT *evt = *i;
00678         if (evt->pid == pid)
00679             return evt;
00680     }
00681 
00682     return nullptr;
00683 }
00684 
00685 
00686 uint32 CoroutineScheduler::createEvent(bool bManualReset, bool bInitialState) {
00687     EVENT *evt = new EVENT();
00688     evt->pid = ++pidCounter;
00689     evt->manualReset = bManualReset;
00690     evt->signalled = bInitialState;
00691     evt->pulsing = false;
00692 
00693     _events.push_back(evt);
00694     return evt->pid;
00695 }
00696 
00697 void CoroutineScheduler::closeEvent(uint32 pidEvent) {
00698     EVENT *evt = getEvent(pidEvent);
00699     if (evt) {
00700         _events.remove(evt);
00701         delete evt;
00702     }
00703 }
00704 
00705 void CoroutineScheduler::setEvent(uint32 pidEvent) {
00706     EVENT *evt = getEvent(pidEvent);
00707     if (evt)
00708         evt->signalled = true;
00709 }
00710 
00711 void CoroutineScheduler::resetEvent(uint32 pidEvent) {
00712     EVENT *evt = getEvent(pidEvent);
00713     if (evt)
00714         evt->signalled = false;
00715 }
00716 
00717 void CoroutineScheduler::pulseEvent(uint32 pidEvent) {
00718     EVENT *evt = getEvent(pidEvent);
00719     if (!evt)
00720         return;
00721 
00722     // Set the event as signalled and pulsing
00723     evt->signalled = true;
00724     evt->pulsing = true;
00725 
00726     // If there's an active process, and it's not the first in the queue, then reschedule all
00727     // the other prcoesses in the queue to run again this frame
00728     if (pCurrent && pCurrent != active->pNext)
00729         rescheduleAll();
00730 }
00731 
00732 } // end of namespace Common


Generated on Sat Feb 16 2019 05:00:48 for ResidualVM by doxygen 1.7.1
curved edge   curved edge