| 66 | } |
| 67 | |
| 68 | void CJobPool::RunLoop() |
| 69 | { |
| 70 | while(true) |
| 71 | { |
| 72 | // wait for job to become available |
| 73 | sphore_wait(&m_Semaphore); |
| 74 | |
| 75 | // fetch job from queue |
| 76 | std::shared_ptr<IJob> pJob = nullptr; |
| 77 | { |
| 78 | const CLockScope LockScope(m_Lock); |
| 79 | if(m_pFirstJob) |
| 80 | { |
| 81 | pJob = m_pFirstJob; |
| 82 | m_pFirstJob = m_pFirstJob->m_pNext; |
| 83 | // allow remaining objects in list to destruct, even when current object stays alive |
| 84 | pJob->m_pNext = nullptr; |
| 85 | if(!m_pFirstJob) |
| 86 | m_pLastJob = nullptr; |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | if(pJob) |
| 91 | { |
| 92 | IJob::EJobState OldStateQueued = IJob::STATE_QUEUED; |
| 93 | if(!pJob->m_State.compare_exchange_strong(OldStateQueued, IJob::STATE_RUNNING)) |
| 94 | { |
| 95 | if(OldStateQueued == IJob::STATE_ABORTED) |
| 96 | { |
| 97 | // job was aborted before it was started |
| 98 | pJob->m_State = IJob::STATE_ABORTED; |
| 99 | continue; |
| 100 | } |
| 101 | dbg_assert_failed("Job state invalid. Job was reused or uninitialized."); |
| 102 | } |
| 103 | |
| 104 | // remember running jobs so we can abort them |
| 105 | { |
| 106 | const CLockScope LockScope(m_LockRunning); |
| 107 | m_RunningJobs.push_back(pJob); |
| 108 | } |
| 109 | pJob->Run(); |
| 110 | { |
| 111 | const CLockScope LockScope(m_LockRunning); |
| 112 | m_RunningJobs.erase(std::find(m_RunningJobs.begin(), m_RunningJobs.end(), pJob)); |
| 113 | } |
| 114 | |
| 115 | // do not change state to done if job was not completed successfully |
| 116 | IJob::EJobState OldStateRunning = IJob::STATE_RUNNING; |
| 117 | if(!pJob->m_State.compare_exchange_strong(OldStateRunning, IJob::STATE_DONE)) |
| 118 | { |
| 119 | if(OldStateRunning != IJob::STATE_ABORTED) |
| 120 | { |
| 121 | dbg_assert_failed("Job state invalid, must be either running or aborted"); |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | else if(m_Shutdown) |
no test coverage detected