예제 #1
0
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();
}
예제 #2
0
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;
}
예제 #3
0
bool JobManager::IsBlocking(InternalJob::Pointer sptr_runningJob)
{
  {
    Poco::ScopedLock<Poco::Mutex> lockMe (m_mutex);
    // if this job isn't running, it can't be blocking anyone
    if (sptr_runningJob->GetState() != Job::RUNNING)
    return false;
    // if any job is queued behind this one, it is blocked by it
    InternalJob::Pointer ptr_previous = sptr_runningJob->Previous();
    while (ptr_previous != 0)
    {
      // ignore jobs of lower priority (higher priority value means lower priority)
      if (ptr_previous->GetPriority() < sptr_runningJob->GetPriority())
      {
        if (!ptr_previous->IsSystem())
        return true;
        // TODO Implicit Jobs
        // implicit jobs should interrupt unless they act on behalf of system jobs
        // if (previous instanceof ThreadJob && ((ThreadJob) previous).shouldInterrupt())
        // return true;
      }
      ptr_previous = ptr_previous->previous;
    }
    // none found
    return false;
  }
}
예제 #4
0
bool JobManager::RunNow(InternalJob::Pointer sptr_job)
{
  {
    Poco::ScopedLock<Poco::Mutex> lockMe (m_mutex);

    //cannot start if there is a conflicting job
    if (FindBlockingJob(sptr_job) != 0)
    return false;
    ChangeState(sptr_job, Job::RUNNING);
    sptr_job->SetProgressMonitor(IProgressMonitor::Pointer(new NullProgressMonitor()));
    sptr_job->Run(IProgressMonitor::Pointer(nullptr));
  }
  return true;
}
예제 #5
0
InternalJob::Pointer JobManager::FindBlockingJob(InternalJob::Pointer waitingJob)
{
  if (waitingJob->GetRule() == 0)
  return InternalJob::Pointer(nullptr);

  {
    Poco::ScopedLock<Poco::Mutex> managerLock (m_mutex);

    if (m_running.empty() )
    {
      InternalJob::Pointer dummy;
      return (dummy);
    }
    //check the running jobs
    bool hasBlockedJobs = false;
    QSet<InternalJob::Pointer>::Iterator it;
    for ( it = m_running.begin(); it != m_running.end(); it ++ )
    {
      InternalJob::Pointer sptr_job = *it ++;
      if (waitingJob->IsConflicting(sptr_job))
      return sptr_job;
      if (!hasBlockedJobs)
      hasBlockedJobs = sptr_job->Previous() != 0;
    }
    //  there are no blocked jobs, so we are done
    if (!hasBlockedJobs)
    {
      InternalJob::Pointer dummy;
      return (dummy);
    }
    //check all jobs blocked by running jobs
    QSet<InternalJob::Pointer>::Iterator it_blocked;
    for( it_blocked = m_running.begin(); it_blocked != m_running.end(); it_blocked ++ )
    {
      InternalJob::Pointer sptr_job = *it_blocked ++;
      while (true)
      {
        sptr_job = sptr_job->Previous();
        if (sptr_job == 0)
        break;
        if (waitingJob->IsConflicting(sptr_job))
        return sptr_job;
      }
    }
  }

  InternalJob::Pointer sptr_null;
  return (sptr_null);
}
예제 #6
0
IProgressMonitor::Pointer JobManager::CreateMonitor(InternalJob::Pointer sptr_job, IProgressMonitor::Pointer group, int ticks)
{
 {
     Poco::ScopedLock<Poco::Mutex> managerLock(m_mutex);

    //group must be set before the job is scheduled
    //this includes the ABOUT_TO_SCHEDULE state, during which it is still
    //valid to set the progress monitor
    if (sptr_job->GetState() != Job::NONE)
    {
      IProgressMonitor::Pointer dummy(nullptr);
      return dummy;
    }
    IProgressMonitor::Pointer sptr_monitor(nullptr);
    if (m_sptr_progressProvider != 0)
      sptr_monitor = m_sptr_progressProvider->CreateMonitor(sptr_job.Cast<Job>() , group, ticks);
    if (sptr_monitor == 0)
    {
      // return a default NullprogressMonitor
      NullProgressMonitor::Pointer sptr_defaultMonitor(new NullProgressMonitor() );
      return sptr_defaultMonitor;
    }

    return sptr_monitor;
  }
}
예제 #7
0
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);
  }

}
예제 #8
0
void JobManager::SetPriority(InternalJob::Pointer job, int newPriority)
{
  {
    Poco::ScopedLock<Poco::Mutex> lockMe (m_mutex);
    InternalJob::Pointer sptr_job(job);
    int oldPriority = job->GetPriority();
    if (oldPriority == newPriority)
    return;
    job->InternalSetPriority(newPriority);
    //if the job is waiting to run, re-shuffle the queue
    if (sptr_job->GetState() == Job::WAITING)
    {
      Poco::Timestamp oldStart = job->GetStartTime();
      job->SetStartTime(oldStart += (DelayFor(newPriority) - DelayFor(oldPriority)));
      m_JobQueueWaiting.Resort(job);
    }
  }
}
예제 #9
0
void JobManager::ReportBlocked(IProgressMonitor::Pointer sptr_monitor, InternalJob::Pointer sptr_blockingJob) const {

  if ( sptr_monitor.Cast<IProgressMonitorWithBlocking>() == 0 )
      return ;
  
  if (sptr_blockingJob == 0 || sptr_blockingJob->IsSystem()) 
    {
   Status::Pointer sptr_reason( new Status(IStatus::INFO_TYPE, JobManager::PI_JOBS(), 1, "the user operation is waiting for  background work to complete" ) );

    } 
  else 
    {
   std::stringstream msg ;
   msg << "the user operation is waiting for : " << sptr_blockingJob->GetName() << " to complete. " ;    
   JobStatus::Pointer sptr_reason(new JobStatus(IStatus::INFO_TYPE, sptr_blockingJob.Cast<Job>(), msg.str() ));
    }
    //  ((IProgressmonitorWithBlocking) sptr_monitor)->SetBlocked(sptr_reason);
  }
예제 #10
0
bool InternalJob::IsConflicting(InternalJob::Pointer otherJob) const
{
  ISchedulingRule::Pointer otherRule = otherJob->GetRule();
  if (sptr_schedulingRule.GetPointer() == 0 || otherRule.GetPointer() == 0)
    return false;
  // TODO MultiRule: extend the IsConflicting (...) method with MultiRule
  // if one of the rules is a compound rule, it must be asked the question.
  //if (schedulingRule.GetClass() == MultiRule.class)
  //  return schedulingRule.IsConflicting(otherRule);
  return otherRule->IsConflicting(sptr_schedulingRule);
}
예제 #11
0
bool JobQueue::CanOvertake(InternalJob::Pointer newEntry,
    InternalJob::Pointer queueEntry)
{
  //can never go past the end of the queue

  if (queueEntry == dummy.GetPointer())
    return false;
  //if the new entry was already in the wait queue, ensure it is re-inserted in correct position (bug 211799)
  if (newEntry->GetWaitQueueStamp() > 0 && newEntry->GetWaitQueueStamp()
      < queueEntry->GetWaitQueueStamp())
    return true;
  //if the new entry has lower priority, there is no need to overtake the existing entry
  if ((queueEntry == newEntry))
    return false;

  // the new entry has higher priority, but only overtake the existing entry if the queue allows it
  InternalJob::Pointer sptr_queueEntry(queueEntry);
  return m_allowConflictOvertaking || !newEntry->IsConflicting(sptr_queueEntry);

}
예제 #12
0
void JobManager::SetRule(InternalJob::Pointer job,
    ISchedulingRule::Pointer sptr_rule)
{
  Poco::ScopedLock<Poco::Mutex> m_managerLock(m_mutex);
  //cannot change the rule of a job that is already running ( GetRule is set to protected which should be
  // changed if this assert is needed
  // assert(job->GetState() == Job.NONE);
  ValidateRule(sptr_rule);
  job->InternalSetRule(sptr_rule);

}
예제 #13
0
void JobQueue::Enqueue(InternalJob::Pointer newEntry)
{
  InternalJob::Pointer tail = dummy->Next();
  //overtake lower priority jobs. Only overtake conflicting jobs if allowed to
  while (CanOvertake(newEntry, tail))
    tail = tail->Next();
  InternalJob::Pointer tailPrevious = tail->Previous();
  newEntry->SetNext(tail);
  newEntry->SetPrevious(tailPrevious);
  tailPrevious->SetNext(newEntry);
  tail->SetPrevious(newEntry);

}
예제 #14
0
void InternalJob::AddLast(InternalJob::Pointer entry)
{
  InternalJob::Pointer last;
  last = this;
  //find the end of the queue
  while (last->previous)
    last = last->previous;
  //add the new entry to the end of the queue
  last->previous = entry.GetPointer();
  entry->next = last;
  entry->previous = 0;
}
예제 #15
0
void JobManager::EndJob(InternalJob::Pointer ptr_job, IStatus::Pointer result, bool notify)
{
  Poco::Timestamp::TimeDiff rescheduleDelay(InternalJob::T_NONE);
  {
    Poco::ScopedLock<Poco::Mutex> lock ( m_mutex);

    //  if the job is finishing asynchronously, there is nothing more to do for now
    if (result == Job::ASYNC_FINISH)
      return;

    //if job is not known then it cannot be done
    if (ptr_job->GetState() == Job::NONE)
       return;
    ptr_job->SetResult(result);
    ptr_job->SetProgressMonitor(IProgressMonitor::Pointer(nullptr));
    ptr_job->SetThread(nullptr);
    rescheduleDelay = ptr_job->GetStartTime().epochMicroseconds();
    InternalJob::Pointer sptr_job(ptr_job);
    ChangeState(sptr_job, Job::NONE);
  }

  //notify listeners outside sync block
  bool reschedule = m_active && rescheduleDelay > InternalJob::T_NONE && ptr_job->ShouldSchedule();
  if (notify)
    m_JobListeners.Done(ptr_job.Cast<Job>(), result, reschedule);
  //reschedule the job if requested and we are still active
  if (reschedule)
    Schedule(ptr_job, rescheduleDelay, reschedule);
}
예제 #16
0
void JobManager::WakeUp(InternalJob::Pointer job, Poco::Timestamp::TimeDiff delay)
{
  poco_assert(delay >= 0); // "Scheduling delay is negative"

  {
    Poco::ScopedLock<Poco::Mutex> m_managerLock (m_mutex);
    //cannot wake up if it is not sleeping
    if (job->GetState() != Job::SLEEPING)
    return;
    DoSchedule(job, delay);
  }
  //call the pool outside sync block to avoid deadlock
  m_Pool->JobQueued();

  /// IListenerExtension only notify of wake up if immediate
  if (delay == 0)
  m_JobListeners.Awake(job.Cast<Job>());
}
예제 #17
0
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;
}
예제 #18
0
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;
}
예제 #19
0
void JobQueue::Remove(InternalJob::Pointer jobToRemove)
{
  jobToRemove->Remove();
}
예제 #20
0
void InternalJob::SetPrevious(InternalJob::Pointer entry)
{
  this->previous = entry.GetPointer();
}
예제 #21
0
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();
}