void JobManager::DoSchedule(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay) { Poco::ScopedLock<Poco::Mutex> managerLock(m_mutex); //job may have been canceled already int state = job->InternalGetState(); if (state != InternalJob::ABOUT_TO_SCHEDULE && state != Job::SLEEPING) return; //if it's a decoration job with no rule, don't run it right now if the system is busy if (job->GetPriority() == Job::DECORATE && job->GetRule() == 0) { Poco::Timestamp::TimeDiff tmp_minDelay = m_running.size() * 100; delay = std::max(delay, tmp_minDelay); } if (delay > 0) { job->SetStartTime(Poco::Timestamp() + delay * 100); InternalJob::Pointer sptr_job(job); ChangeState(sptr_job, Job::SLEEPING); } else { job->SetStartTime(Poco::Timestamp() + DelayFor(job->GetPriority()) * 100); job->SetWaitQueueStamp(m_waitQueueCounter++); InternalJob::Pointer sptr_job(job); ChangeState(sptr_job, Job::WAITING); } }
bool JobManager::Sleep(InternalJob::Pointer job) { { Poco::ScopedLock<Poco::Mutex> lockMe (m_mutex); InternalJob::Pointer sptr_job(job); switch (job->GetState()) { case Job::RUNNING : //cannot be paused if it is already running (as opposed to ABOUT_TO_RUN) if (job->InternalGetState() == Job::RUNNING) return false; //job hasn't started running yet (aboutToRun listener) break; case Job::SLEEPING : //update the job wake time job->SetStartTime(InternalJob::T_INFINITE); //change state again to re-shuffle the sleep queue ChangeState(sptr_job, Job::SLEEPING); return true; case Job::NONE : return true; case Job::WAITING : //put the job to sleep break; } job->SetStartTime(InternalJob::T_INFINITE); ChangeState(sptr_job, Job::SLEEPING); } m_JobListeners.Sleeping(job.Cast<Job>()); return true; }
void JobManager::Schedule(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay, bool reschedule) { if (!m_active) throw Poco::IllegalStateException("Job manager has been shut down."); poco_assert(job); // "Job is null" poco_assert(delay >= 0); // "Scheduling delay is negative" { Poco::ScopedLock<Poco::Mutex> managerLock (m_mutex); //if the job is already running, set it to be rescheduled when done if (job->GetState() == Job::RUNNING) { job->SetStartTime(delay); return; } //can't schedule a job that is waiting or sleeping if (job->InternalGetState() != Job::NONE) return; //remember that we are about to schedule the job //to prevent multiple schedule attempts from succeeding (bug 68452) InternalJob::Pointer sptr_job(job); ChangeState(sptr_job, InternalJob::ABOUT_TO_SCHEDULE); } //notify listeners outside sync block m_JobListeners.Scheduled(job.Cast<Job>(), delay, reschedule); //schedule the job DoSchedule(job, delay); //call the pool outside sync block to avoid deadlock m_Pool->JobQueued(); }
bool JobManager::Cancel(InternalJob::Pointer sptr_job) { IProgressMonitor::Pointer sptr_progressMonitor(nullptr); bool runCanceling = false; { Poco::ScopedLock<Poco::Mutex> mangerMutex (m_mutex); switch (sptr_job->GetState()) { case Job::NONE : return true; case Job::RUNNING : //cannot cancel a job that has already started (as opposed to ABOUT_TO_RUN) if (sptr_job->InternalGetState() == Job::RUNNING) { sptr_progressMonitor = sptr_job->GetProgressMonitor(); runCanceling = sptr_job->IsRunCanceled(); if(runCanceling) sptr_job->SetRunCanceled(true); break ; } //signal that the job should be canceled before it gets a chance to run sptr_job->SetAboutToRunCanceled(true); return false; default : ChangeState(sptr_job, Job::NONE); } } //call monitor outside sync block if (sptr_progressMonitor != 0) { if(runCanceling) { if (!sptr_progressMonitor->IsCanceled()) sptr_progressMonitor->SetCanceled(true); sptr_job->Canceling(); } return false; } //only notify listeners if the job was waiting or sleeping m_JobListeners.Done(sptr_job.Cast<Job>(), Status::CANCEL_STATUS(BERRY_STATUS_LOC), false); return true; }
Job::Pointer JobManager::StartJob() { Job::Pointer job(nullptr); while (true) { job = NextJob(); if (!job) return Job::Pointer(nullptr); //must perform this outside sync block because it is third party code bool shouldRun = job->ShouldRun(); //check for listener veto if (shouldRun) m_JobListeners.AboutToRun(job); //listeners may have canceled or put the job to sleep bool endJob = false; { Poco::ScopedLock<Poco::Mutex> lock(m_mutex); InternalJob::Pointer internal = job; if (internal->InternalGetState() == InternalJob::ABOUT_TO_RUN) { if (shouldRun && !internal->IsAboutToRunCanceled()) { internal->SetProgressMonitor(CreateMonitor(job)); //change from ABOUT_TO_RUN to RUNNING internal->InternalSetState(Job::RUNNING); break; } internal->SetAboutToRunCanceled(false); endJob = true; //fall through and end the job below } } if (endJob) { //job has been vetoed or canceled, so mark it as done EndJob(job,Status::CANCEL_STATUS(BERRY_STATUS_LOC), true); continue; } } m_JobListeners.Running(job); return job; }
void JobManager::ChangeState(InternalJob::Pointer sptr_job, int newState) { bool blockedJobs = false; { Poco::ScopedLock<Poco::Mutex> m_managerLock(m_mutex); int tmp_oldState = sptr_job->InternalGetState(); switch (tmp_oldState) { case Job::NONE: case InternalJob::ABOUT_TO_SCHEDULE: break; case InternalJob::BLOCKED: //remove this job from the linked list of blocked jobs sptr_job->Remove(); break; case Job::WAITING: m_JobQueueWaiting.Remove(sptr_job); // assert(false, "Tried to remove a job that wasn't in the queue"); break; case Job::SLEEPING: m_JobQueueSleeping.Remove(sptr_job); // assert(false, "Tried to remove a job that wasn't in the queue"); case Job::RUNNING: case InternalJob::ABOUT_TO_RUN: m_running.remove(sptr_job); //add any blocked jobs back to the wait queue InternalJob::Pointer sptr_blocked(sptr_job->Previous()); sptr_job->Remove(); blockedJobs = sptr_blocked != 0; while (sptr_blocked != 0) { InternalJob::Pointer previous = sptr_blocked->Previous(); ChangeState(sptr_blocked, Job::WAITING); sptr_blocked = previous; } break; // default : // Assert.isLegal(false, "Invalid job state: " + job + ", state: " + oldState); } sptr_job->InternalSetState(newState); switch (newState) { case Job::NONE: sptr_job->SetStartTime(InternalJob::T_NONE); sptr_job->SetWaitQueueStamp(InternalJob::T_NONE); case InternalJob::BLOCKED: break; case Job::WAITING: m_JobQueueWaiting.Enqueue(sptr_job); break; case Job::SLEEPING: //try { m_JobQueueSleeping.Enqueue(sptr_job); //} catch (RuntimeException e) { // throw new RuntimeException("Error changing from state: " + oldState); //} break; case Job::RUNNING: case InternalJob::ABOUT_TO_RUN: sptr_job->SetStartTime(InternalJob::T_NONE); sptr_job->SetWaitQueueStamp(InternalJob::T_NONE); m_running.insert(sptr_job); break; case InternalJob::ABOUT_TO_SCHEDULE: break; // default : // Assert.isLegal(false, "Invalid job state: " + job + ", state: " + newState); } } //notify queue outside sync block if (blockedJobs) m_Pool->JobQueued(); }