Beispiel #1
0
int sched_setscheduler(pid_t pid, int policy,
                       const struct sched_param *param)
{
  FAR struct tcb_s *tcb;
#if CONFIG_RR_INTERVAL > 0
  irqstate_t saved_state;
#endif
  int ret;

  /* Check for supported scheduling policy */

#if CONFIG_RR_INTERVAL > 0
  if (policy != SCHED_FIFO && policy != SCHED_RR)
#else
  if (policy != SCHED_FIFO)
#endif
    {
      errno = EINVAL;
      return ERROR;
    }

  /* Check if the task to modify the calling task */

  if (pid == 0 )
    {
      pid = getpid();
    }

  /* Verify that the pid corresponds to a real task */

  tcb = sched_gettcb(pid);
  if (!tcb)
    {
      errno = ESRCH;
      return ERROR;
    }

  /* Prohibit any context switches while we muck with priority and scheduler
   * settings.
   */

  sched_lock();

#if CONFIG_RR_INTERVAL > 0
  /* Further, disable timer interrupts while we set up scheduling policy. */

  saved_state = irqsave();
  if (policy == SCHED_RR)
    {
      /* Set round robin scheduling */

      tcb->flags    |= TCB_FLAG_ROUND_ROBIN;
      tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK;
    }
  else
    {
      /* Set FIFO scheduling */

      tcb->flags    &= ~TCB_FLAG_ROUND_ROBIN;
      tcb->timeslice = 0;
    }

  irqrestore(saved_state);
#endif

  /* Set the new priority */

  ret = sched_reprioritize(tcb, param->sched_priority);
  sched_unlock();

  if (ret != OK)
    {
      return ERROR;
    }
  else
    {
      return OK;
    }
}
Beispiel #2
0
static int sem_restoreholderprio(FAR struct semholder_s *pholder, FAR sem_t *sem, FAR void *arg)
{
  FAR struct tcb_s *htcb = (FAR struct tcb_s *)pholder->htcb;
#if CONFIG_SEM_NNESTPRIO > 0
  FAR struct tcb_s *stcb = (FAR struct tcb_s *)arg;
  int rpriority;
  int i;
  int j;
#endif

  /* Make sure that the hdoler thread is still active.  If it exited without
   * releasing its counts, then that would be a bad thing.  But we can take no
   * real action because we don't know know that the program is doing.  Perhaps
   * its plan is to kill a thread, then destroy the semaphore.
   */

  if (!sched_verifytcb(htcb))
   {
      sdbg("TCB 0x%08x is a stale handle, counts lost\n", htcb);
      sem_freeholder(sem, pholder);
   }

  /* Was the priority of the holder thread boosted? If so, then drop its
   * priority back to the correct level.  What is the correct level?
   */

  else if (htcb->sched_priority != htcb->base_priority)
    {
#if CONFIG_SEM_NNESTPRIO > 0
      /* Are there other, pending priority levels to revert to? */

      if (htcb->npend_reprio < 1)
        {
          /* No... the holder thread has only been boosted once.
           * npend_reprio should be 0 and the boosted priority should be the
           * priority of the task that just got the semaphore
           * (stcb->sched_priority)
           *
           * That latter assumption may not be true if the stcb's priority
           * was also boosted so that it no longer matches the htcb's
           * sched_priority.  Or if CONFIG_SEM_NNESTPRIO is too small (so
           * that we do not have a proper record of the reprioritizations).
           */

          DEBUGASSERT(/* htcb->sched_priority == stcb->sched_priority && */
                      htcb->npend_reprio == 0);

          /* Reset the holder's priority back to the base priority. */

          sched_reprioritize(htcb, htcb->base_priority);
        }

      /* There are multiple pending priority levels. The holder thread's "boosted"
       * priority could greater than or equal to "stcb->sched_priority" (it could be
       * greater if its priority we boosted becuase it also holds another semaphore).
       */

      else if (htcb->sched_priority <= stcb->sched_priority)
        {
          /* The holder thread has been boosted to the same priority as the waiter
           * thread that just received the count.  We will simply reprioritize
           * to the next highest priority that we have in rpriority.
           */

          /* Find the highest pending priority and remove it from the list */

          for (i = 1, j = 0; i < htcb->npend_reprio; i++)
            {
              if (htcb->pend_reprios[i] > htcb->pend_reprios[j])
                {
                  j = i;
                }
            }

          /* Remove the highest priority pending priority from the list */

          rpriority = htcb->pend_reprios[j];
          i = htcb->npend_reprio - 1;
          if (i > 0)
            {
              htcb->pend_reprios[j] = htcb->pend_reprios[i];
            }

          htcb->npend_reprio = i;

          /* And apply that priority to the thread (while retaining the base_priority) */

          sched_setpriority(htcb, rpriority);
        }
      else
        {
          /* The holder thread has been boosted to a higher priority than the
           * waiter task.  The pending priority should be in the list (unless it
           * was lost because of of list overflow or because the holder was
           * reprioritize again unbeknownst to the priority inheritance logic).
           *
           * Search the list for the matching priority.
           */

          for (i = 0; i < htcb->npend_reprio; i++)
            {
              /* Does this pending priority match the priority of the thread
               * that just received the count?
               */

              if (htcb->pend_reprios[i] == stcb->sched_priority)
                {
                  /* Yes, remove it from the list */

                  j = htcb->npend_reprio - 1;
                  if (j > 0)
                    {
                      htcb->pend_reprios[i] = htcb->pend_reprios[j];
                    }

                   htcb->npend_reprio = j;
                   break;
                }
            }
        }
#else
      /* There is no alternative restore priorities, drop the priority
       * of the holder thread all the way back to the threads "base"
       * priority.
       */

      sched_reprioritize(htcb, htcb->base_priority);
#endif
    }

  return 0;
}
Beispiel #3
0
int sched_setparam(pid_t pid, FAR const struct sched_param *param)
{
    FAR struct tcb_s *rtcb;
    FAR struct tcb_s *tcb;
    int errcode;
    int ret;

    /* Verify that the requested priority is in the valid range */

    if (!param)
    {
        errcode = EINVAL;
        goto errout_with_errcode;
    }

    /* Prohibit modifications to the head of the ready-to-run task
     * list while adjusting the priority
     */

    sched_lock();

    /* Check if the task to reprioritize is the calling task */

    rtcb = this_task();
    if (pid == 0 || pid == rtcb->pid)
    {
        tcb = rtcb;
    }

    /* The PID is not the calling task, we will have to search for it */

    else
    {
        tcb = sched_gettcb(pid);
        if (!tcb)
        {
            /* No task with this PID was found */

            errcode = ESRCH;
            goto errout_with_lock;
        }
    }

#ifdef CONFIG_SCHED_SPORADIC
    /* Update parameters associated with SCHED_SPORADIC */

    if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
    {
        FAR struct sporadic_s *sporadic;
        irqstate_t flags;
        int repl_ticks;
        int budget_ticks;

        if (param->sched_ss_max_repl < 1 ||
                param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL)
        {
            errcode = EINVAL;
            goto errout_with_lock;
        }

        /* Convert timespec values to system clock ticks */

        (void)clock_time2ticks(&param->sched_ss_repl_period, &repl_ticks);
        (void)clock_time2ticks(&param->sched_ss_init_budget, &budget_ticks);

        /* Avoid zero/negative times */

        if (repl_ticks < 1)
        {
            repl_ticks = 1;
        }

        if (budget_ticks < 1)
        {
            budget_ticks = 1;
        }

        /* The replenishment period must be greater than or equal to the
         * budget period.
         */
#if 1
        /* REVISIT: In the current implementation, the budget cannot exceed
         * half the duty.
         */

        if (repl_ticks < (2 * budget_ticks))
#else
        if (repl_ticks < budget_ticks)
#endif
        {
            errcode = EINVAL;
            goto errout_with_lock;
        }

        /* Stop/reset current sporadic scheduling */

        flags = enter_critical_section();
        ret = sched_sporadic_reset(tcb);
        if (ret >= 0)
        {
            /* Save the sporadic scheduling parameters and reset to the
             * beginning to the replenishment interval.
             */

            tcb->timeslice         = budget_ticks;

            sporadic = rtcb->sporadic;
            DEBUGASSERT(sporadic != NULL);

            sporadic->hi_priority  = param->sched_priority;
            sporadic->low_priority = param->sched_ss_low_priority;
            sporadic->max_repl     = param->sched_ss_max_repl;
            sporadic->repl_period  = repl_ticks;
            sporadic->budget       = budget_ticks;

            /* And restart at the next replenishment interval */

            ret = sched_sporadic_start(tcb);
        }

        /* Restore interrupts and handler errors */

        leave_critical_section(flags);
        if (ret < 0)
        {
            errcode = -ret;
            goto errout_with_lock;
        }
    }
#endif

    /* Then perform the reprioritization */

    ret = sched_reprioritize(tcb, param->sched_priority);
    sched_unlock();
    return ret;

errout_with_lock:
    set_errno(errcode);
    sched_unlock();
    return ERROR;

errout_with_errcode:
    set_errno(errcode);
    return ERROR;
}