Exemplo n.º 1
0
FAR void *up_stack_frame(FAR struct tcb_s *tcb, size_t frame_size)
{
  uintptr_t topaddr;

  /* Align the frame_size */

  frame_size = STACK_ALIGN_UP(frame_size);

  /* Is there already a stack allocated? Is it big enough? */

  if (!tcb->stack_alloc_ptr || tcb->adj_stack_size <= frame_size)
    {
      return NULL;
    }

  /* Save the adjusted stack values in the struct tcb_s */

  topaddr              = (uintptr_t)tcb->adj_stack_ptr - frame_size;
  tcb->adj_stack_ptr   = (FAR void *)topaddr;
  tcb->adj_stack_size -= frame_size;

  /* Reset the initial state */

  up_initial_state(tcb);

  /* And return a pointer to the allocated memory */

  return (FAR void *)(topaddr + sizeof(uint32_t));
}
Exemplo n.º 2
0
static int thread_schedsetup(FAR struct tcb_s *tcb, int priority,
                             start_t start, CODE void *entry, uint8_t ttype)
{
  int ret;

  /* Assign a unique task ID to the task. */

  ret = task_assignpid(tcb);
  if (ret == OK)
    {
      /* Save task priority and entry point in the TCB */

      tcb->sched_priority = (uint8_t)priority;
#ifdef CONFIG_PRIORITY_INHERITANCE
      tcb->base_priority  = (uint8_t)priority;
#endif
      tcb->start          = start;
      tcb->entry.main     = (main_t)entry;

      /* Save the thread type.  This setting will be needed in
       * up_initial_state() is called.
       */

      ttype              &= TCB_FLAG_TTYPE_MASK;
      tcb->flags         &= ~TCB_FLAG_TTYPE_MASK;
      tcb->flags         |= ttype;

      /* Save the task ID of the parent task in the TCB and allocate
       * a child status structure.
       */

      task_saveparent(tcb, ttype);

      /* exec(), pthread_create(), task_create(), and vfork() all
       * inherit the signal mask of the parent thread.
       */

#ifndef CONFIG_DISABLE_SIGNALS
      (void)sigprocmask(SIG_SETMASK, NULL, &tcb->sigprocmask);
#endif

      /* Initialize the task state.  It does not get a valid state
       * until it is activated.
       */

      tcb->task_state = TSTATE_TASK_INVALID;

      /* Clone the parent tasks D-Space (if it was running PIC).  This
       * must be done before calling up_initial_state() so that the
       * state setup will take the PIC address base into account.
       */

      task_dupdspace(tcb);

      /* Initialize the processor-specific portion of the TCB */

      up_initial_state(tcb);

      /* Add the task to the inactive task list */

      sched_lock();
      dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks);
      tcb->task_state = TSTATE_TASK_INACTIVE;
      sched_unlock();
    }

  return ret;
}
Exemplo n.º 3
0
int task_restart(pid_t pid)
{
  FAR struct tcb_s *rtcb;
  FAR struct task_tcb_s *tcb;
  FAR dq_queue_t *tasklist;
  irqstate_t state;
  int status;

  /* Make sure this task does not become ready-to-run while
   * we are futzing with its TCB
   */

  sched_lock();

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

  rtcb = this_task();
  if ((pid == 0) || (pid == rtcb->pid))
    {
      /* Not implemented */

      set_errno(ENOSYS);
      return ERROR;
    }

#ifdef CONFIG_SMP
  /* There is currently no capability to restart a task that is actively
   * running on another CPU either.  This is not the calling cast so if it
   * is running, then it could only be running a a different CPU.
   *
   * Also, will need some interlocks to assure that no tasks are rescheduled
   * on any other CPU while we do this.
   */

#warning Missing SMP logic
  if (rtcb->task_state == TSTATE_TASK_RUNNING)
    {
      /* Not implemented */

      set_errno(ENOSYS);
      return ERROR;
    }
#endif

  /* We are restarting some other task than ourselves */
  /* Find for the TCB associated with matching pid  */

  tcb = (FAR struct task_tcb_s *)sched_gettcb(pid);
#ifndef CONFIG_DISABLE_PTHREAD
  if (!tcb || (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
#else
  if (!tcb)
#endif
    {
      /* There is no TCB with this pid or, if there is, it is not a task. */

      set_errno(ESRCH);
      return ERROR;
    }

  /* Try to recover from any bad states */

  task_recover((FAR struct tcb_s *)tcb);

  /* Kill any children of this thread */

#ifdef HAVE_GROUP_MEMBERS
  (void)group_killchildren(tcb);
#endif

  /* Remove the TCB from whatever list it is in.  After this point, the TCB
   * should no longer be accessible to the system
   */

#ifdef CONFIG_SMP
  tasklist = TLIST_HEAD(tcb->cmn.task_state, tcb->cmn.cpu);
#else
  tasklist = TLIST_HEAD(tcb->cmn.task_state);
#endif

  state = irqsave();
  dq_rem((FAR dq_entry_t *)tcb, tasklist);
  tcb->cmn.task_state = TSTATE_TASK_INVALID;
  irqrestore(state);

  /* Deallocate anything left in the TCB's queues */

  sig_cleanup((FAR struct tcb_s *)tcb); /* Deallocate Signal lists */

  /* Reset the current task priority  */

  tcb->cmn.sched_priority = tcb->init_priority;

  /* Reset the base task priority and the number of pending reprioritizations */

#ifdef CONFIG_PRIORITY_INHERITANCE
  tcb->cmn.base_priority = tcb->init_priority;
#  if CONFIG_SEM_NNESTPRIO > 0
  tcb->cmn.npend_reprio = 0;
#  endif
#endif

  /* Re-initialize the processor-specific portion of the TCB.  This will
   * reset the entry point and the start-up parameters
   */

  up_initial_state((FAR struct tcb_s *)tcb);

  /* Add the task to the inactive task list */

  dq_addfirst((FAR dq_entry_t *)tcb, (FAR dq_queue_t *)&g_inactivetasks);
  tcb->cmn.task_state = TSTATE_TASK_INACTIVE;

  /* Activate the task */

  status = task_activate((FAR struct tcb_s *)tcb);
  if (status != OK)
    {
      (void)task_delete(pid);
      set_errno(-status);
      return ERROR;
    }

  sched_unlock();
  return OK;
}
Exemplo n.º 4
0
int task_restart(pid_t pid)
{
  FAR _TCB  *rtcb;
  FAR _TCB  *tcb;
  int        status;
  irqstate_t state;

  /* Make sure this task does not become ready-to-run while
   * we are futzing with its TCB
   */

  sched_lock();

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

  rtcb = (FAR _TCB*)g_readytorun.head;
  if ((pid == 0) || (pid == rtcb->pid))
    {
      /* Not implemented */

      return ERROR;
    }

  /* We are restarting some other task than ourselves */

  else
    {
      /* Find for the TCB associated with matching pid  */

      tcb = sched_gettcb(pid);
      if (!tcb)
        {
          /* There is no TCB with this pid */

          return ERROR;
        }

      /* Remove the TCB from whatever list it is in.  At this point, the
       * TCB should no longer be accessible to the system 
       */

      state = irqsave();
      dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)g_tasklisttable[tcb->task_state].list);
      tcb->task_state = TSTATE_TASK_INVALID;
      irqrestore(state);

      /* Deallocate anything left in the TCB's queues */

      sig_cleanup(tcb); /* Deallocate Signal lists */

      /* Reset the current task priority  */

      tcb->sched_priority = tcb->init_priority;

      /* Reset the base task priority and the number of pending reprioritizations */

#ifdef CONFIG_PRIORITY_INHERITANCE
      tcb->base_priority  = tcb->init_priority;
#  if CONFIG_SEM_NNESTPRIO > 0
      tcb->npend_reprio   = 0;
#  endif
#endif

      /* Re-initialize the processor-specific portion of the TCB
       * This will reset the entry point and the start-up parameters
       */

      up_initial_state(tcb);

      /* Add the task to the inactive task list */

      dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks);
      tcb->task_state = TSTATE_TASK_INACTIVE;

      /* Activate the task */

      status = task_activate(tcb);
      if (status != OK)
        {
          dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks);
          sched_releasetcb(tcb);
          return ERROR;
        }
    }

  sched_unlock();
  return OK;
}
Exemplo n.º 5
0
int task_restart(pid_t pid)
{
  FAR struct tcb_s *rtcb;
  FAR struct task_tcb_s *tcb;
  FAR dq_queue_t *tasklist;
  irqstate_t flags;
  int errcode;
#ifdef CONFIG_SMP
  int cpu;
#endif
  int ret;

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

  rtcb = this_task();
  if ((pid == 0) || (pid == rtcb->pid))
    {
      /* Not implemented */

      errcode = ENOSYS;
      goto errout;
    }

  /* We are restarting some other task than ourselves.  Make sure that the
   * task does not change its state while we are executing.  In the single
   * CPU state this could be done by disabling pre-emption.  But we will
   * a little stronger medicine on the SMP case:  The task make be running
   * on another CPU.
   */

  flags = enter_critical_section();

  /* Find for the TCB associated with matching pid  */

  tcb = (FAR struct task_tcb_s *)sched_gettcb(pid);
#ifndef CONFIG_DISABLE_PTHREAD
  if (!tcb || (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
#else
  if (!tcb)
#endif
    {
      /* There is no TCB with this pid or, if there is, it is not a task. */

      errcode = ESRCH;
      goto errout_with_lock;
    }

#ifdef CONFIG_SMP
  /* If the task is running on another CPU, then pause that CPU.  We can
   * then manipulate the TCB of the restarted task and when we resume the
   * that CPU, the restart take effect.
   */

  cpu = sched_cpu_pause(&tcb->cmn);
#endif /* CONFIG_SMP */

  /* Try to recover from any bad states */

  task_recover((FAR struct tcb_s *)tcb);

  /* Kill any children of this thread */

#ifdef HAVE_GROUP_MEMBERS
  (void)group_killchildren(tcb);
#endif

  /* Remove the TCB from whatever list it is in.  After this point, the TCB
   * should no longer be accessible to the system
   */

#ifdef CONFIG_SMP
  tasklist = TLIST_HEAD(tcb->cmn.task_state, tcb->cmn.cpu);
#else
  tasklist = TLIST_HEAD(tcb->cmn.task_state);
#endif

  dq_rem((FAR dq_entry_t *)tcb, tasklist);
  tcb->cmn.task_state = TSTATE_TASK_INVALID;

  /* Deallocate anything left in the TCB's queues */

  sig_cleanup((FAR struct tcb_s *)tcb); /* Deallocate Signal lists */

  /* Reset the current task priority  */

  tcb->cmn.sched_priority = tcb->cmn.init_priority;

  /* The task should restart with pre-emption disabled and not in a critical
   * secton.
   */

  tcb->cmn.lockcount = 0;
#ifdef CONFIG_SMP
  tcb->cmn.irqcount  = 0;
#endif

  /* Reset the base task priority and the number of pending reprioritizations */

#ifdef CONFIG_PRIORITY_INHERITANCE
  tcb->cmn.base_priority = tcb->cmn.init_priority;
#  if CONFIG_SEM_NNESTPRIO > 0
  tcb->cmn.npend_reprio = 0;
#  endif
#endif

  /* Re-initialize the processor-specific portion of the TCB.  This will
   * reset the entry point and the start-up parameters
   */

  up_initial_state((FAR struct tcb_s *)tcb);

  /* Add the task to the inactive task list */

  dq_addfirst((FAR dq_entry_t *)tcb, (FAR dq_queue_t *)&g_inactivetasks);
  tcb->cmn.task_state = TSTATE_TASK_INACTIVE;

#ifdef CONFIG_SMP
  /* Resume the paused CPU (if any) */

  if (cpu >= 0)
    {
      ret = up_cpu_resume(cpu);
      if (ret < 0)
        {
          errcode = -ret;
          goto errout_with_lock;
        }
    }
#endif /* CONFIG_SMP */

  leave_critical_section(flags);

  /* Activate the task. */

  ret = task_activate((FAR struct tcb_s *)tcb);
  if (ret != OK)
    {
      (void)task_terminate(pid, true);
      errcode = -ret;
      goto errout_with_lock;
    }

  return OK;

errout_with_lock:
  leave_critical_section(flags);
errout:
  set_errno(errcode);
  return ERROR;
}
Exemplo n.º 6
0
int exec_module(FAR const struct binary_s *binp)
{
  FAR _TCB     *tcb;
#ifndef CONFIG_CUSTOM_STACK
  FAR uint32_t *stack;
#endif
  pid_t         pid;
  int           err;
  int           ret;

  /* Sanity checking */

#ifdef CONFIG_DEBUG
  if (!binp || !binp->entrypt || binp->stacksize <= 0)
    {
      err = EINVAL;
      goto errout;
    }
#endif

  bdbg("Executing %s\n", binp->filename);

  /* Allocate a TCB for the new task. */

  tcb = (FAR _TCB*)kzalloc(sizeof(_TCB));
  if (!tcb)
    {
      err = ENOMEM;
      goto errout;
    }

  /* Allocate the stack for the new task */

#ifndef CONFIG_CUSTOM_STACK
  stack = (FAR uint32_t*)kmalloc(binp->stacksize);
  if (!tcb)
    {
      err = ENOMEM;
      goto errout_with_tcb;
    }

  /* Initialize the task */

  ret = task_init(tcb, binp->filename, binp->priority, stack,
                  binp->stacksize, binp->entrypt, binp->argv);
#else
  /* Initialize the task */

  ret = task_init(tcb, binp->filename, binp->priority, stack,
                  binp->entrypt, binp->argv);
#endif
  if (ret < 0)
    {
      err = errno;
      bdbg("task_init() failed: %d\n", err);
      goto errout_with_stack;
    }

  /* Note that tcb->flags are not modified.  0=normal task */
  /* tcb->flags |= TCB_FLAG_TTYPE_TASK; */

  /* Add the D-Space address as the PIC base address.  By convention, this
   * must be the first allocated address space.
   */

#ifdef CONFIG_PIC
  tcb->dspace = binp->alloc[0];

  /* Re-initialize the task's initial state to account for the new PIC base */

  up_initial_state(tcb);
#endif

  /* Assign the address environment to the task */

#ifdef CONFIG_ADDRENV
  ret = up_addrenv_assign(binp->addrenv, tcb);
  if (ret < 0)
    {
      err = -ret;
      bdbg("up_addrenv_assign() failed: %d\n", ret);
      goto errout_with_stack;
    }
#endif

  /* Get the assigned pid before we start the task */

  pid = tcb->pid;

  /* Execute all of the C++ static constructors */

#ifdef CONFIG_BINFMT_CONSTRUCTORS
  ret = exec_ctors(binp);
  if (ret < 0)
    {
      err = -ret;
      bdbg("exec_ctors() failed: %d\n", ret);
      goto errout_with_stack;
    }
#endif

  /* Then activate the task at the provided priority */

  ret = task_activate(tcb);
  if (ret < 0)
    {
      err = errno;
      bdbg("task_activate() failed: %d\n", err);
      goto errout_with_stack;
    }

  return (int)pid;

errout_with_stack:
#ifndef CONFIG_CUSTOM_STACK
  tcb->stack_alloc_ptr = NULL;
  sched_releasetcb(tcb);
  kfree(stack);
#else
  sched_releasetcb(tcb);
#endif
  goto errout;

errout_with_tcb:
  kfree(tcb);
errout:
  errno = err;
  bdbg("returning errno: %d\n", err);
  return ERROR;
}
Exemplo n.º 7
0
void os_start(void)
{
  int i;

  slldbg("Entry\n");

  /* Initialize all task lists */

  dq_init(&g_readytorun);
  dq_init(&g_pendingtasks);
  dq_init(&g_waitingforsemaphore);
#ifndef CONFIG_DISABLE_SIGNALS
  dq_init(&g_waitingforsignal);
#endif
#ifndef CONFIG_DISABLE_MQUEUE
  dq_init(&g_waitingformqnotfull);
  dq_init(&g_waitingformqnotempty);
#endif
#ifdef CONFIG_PAGING
  dq_init(&g_waitingforfill);
#endif
  dq_init(&g_inactivetasks);
  sq_init(&g_delayeddeallocations);

  /* Initialize the logic that determine unique process IDs. */

  g_lastpid = 0;
  for (i = 0; i < CONFIG_MAX_TASKS; i++)
    {
      g_pidhash[i].tcb = NULL;
      g_pidhash[i].pid = INVALID_PROCESS_ID;
    }

  /* Assign the process ID of ZERO to the idle task */

  g_pidhash[ PIDHASH(0)].tcb = &g_idletcb;
  g_pidhash[ PIDHASH(0)].pid = 0;

  /* Initialize a TCB for this thread of execution.  NOTE:  The default
   * value for most components of the g_idletcb are zero.  The entire
   * structure is set to zero.  Then only the (potentially) non-zero
   * elements are initialized. NOTE:  The idle task is the only task in
   * that has pid == 0 and sched_priority == 0.
   */

  bzero((void*)&g_idletcb, sizeof(_TCB));
  g_idletcb.task_state = TSTATE_TASK_RUNNING;
  g_idletcb.entry.main = (main_t)os_start;

#if CONFIG_TASK_NAME_SIZE > 0
  strncpy(g_idletcb.name, g_idlename, CONFIG_TASK_NAME_SIZE-1);
  g_idletcb.argv[0] = g_idletcb.name;
#else
  g_idletcb.argv[0] = (char*)g_idlename;
#endif /* CONFIG_TASK_NAME_SIZE */

  /* Then add the idle task's TCB to the head of the ready to run list */

  dq_addfirst((FAR dq_entry_t*)&g_idletcb, (FAR dq_queue_t*)&g_readytorun);

  /* Initialize the processor-specific portion of the TCB */

  g_idletcb.flags = TCB_FLAG_TTYPE_KERNEL;
  up_initial_state(&g_idletcb);

  /* Initialize the semaphore facility(if in link).  This has to be done
   * very early because many subsystems depend upon fully functional
   * semaphores.
   */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sem_initialize != NULL)
#endif
    {
      sem_initialize();
    }

  /* Initialize the memory manager */

#ifndef CONFIG_HEAP_BASE
  {
    FAR void *heap_start;
    size_t heap_size;
    up_allocate_heap(&heap_start, &heap_size);
    kmm_initialize(heap_start, heap_size);
  }
#else
  kmm_initialize((void*)CONFIG_HEAP_BASE, CONFIG_HEAP_SIZE);
#endif

  /* Initialize the interrupt handling subsystem (if included) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (irq_initialize != NULL)
#endif
    {
      irq_initialize();
    }

  /* Initialize the watchdog facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (wd_initialize != NULL)
#endif
    {
      wd_initialize();
    }

  /* Initialize the POSIX timer facility (if included in the link) */

#ifndef CONFIG_DISABLE_CLOCK
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (clock_initialize != NULL)
#endif
    {
      clock_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_POSIX_TIMERS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (timer_initialize != NULL)
#endif
    {
      timer_initialize();
    }
#endif

  /* Initialize the signal facility (if in link) */

#ifndef CONFIG_DISABLE_SIGNALS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sig_initialize != NULL)
#endif
    {
      sig_initialize();
    }
#endif

  /* Initialize the named message queue facility (if in link) */

#ifndef CONFIG_DISABLE_MQUEUE
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (mq_initialize != NULL)
#endif
    {
      mq_initialize();
    }
#endif

  /* Initialize the thread-specific data facility (if in link) */

#ifndef CONFIG_DISABLE_PTHREAD
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (pthread_initialize != NULL)
#endif
    {
      pthread_initialize();
    }
#endif

  /* Initialize the file system (needed to support device drivers) */

#if CONFIG_NFILE_DESCRIPTORS > 0
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (fs_initialize != NULL)
#endif
    {
      fs_initialize();
    }
#endif

  /* Initialize the network system */

#ifdef CONFIG_NET
#if 0
  if (net_initialize != NULL)
#endif
    {
      net_initialize();
    }
#endif

  /* The processor specific details of running the operating system
   * will be handled here.  Such things as setting up interrupt
   * service routines and starting the clock are some of the things
   * that are different for each  processor and hardware platform.
   */

  up_initialize();

  /* Initialize the C libraries (if included in the link).  This
   * is done last because the libraries may depend on the above.
   */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (lib_initialize != NULL)
#endif
    {
      lib_initialize();
    }

  /* Create stdout, stderr, stdin on the IDLE task.  These will be
   * inherited by all of the threads created by the IDLE task.
   */

  (void)sched_setupidlefiles(&g_idletcb);

  /* Create initial tasks and bring-up the system */

  (void)os_bringup();

  /* When control is return to this point, the system is idle. */

  sdbg("Beginning Idle Loop\n");
  for (;;)
    {
      /* Perform garbage collection (if it is not being done by the worker
       * thread).  This cleans-up memory de-allocations that were queued
       * because they could not be freed in that execution context (for
       * example, if the memory was freed from an interrupt handler).
       */

#ifndef CONFIG_SCHED_WORKQUEUE
      /* We must have exclusive access to the memory manager to do this
       * BUT the idle task cannot wait on a semaphore.  So we only do
       * the cleanup now if we can get the semaphore -- this should be
       * possible because if the IDLE thread is running, no other task is!
       */

      if (kmm_trysemaphore() == 0)
        {
          sched_garbagecollection();
          kmm_givesemaphore();
        }
#endif

      /* Perform any processor-specific idle state operations */

      up_idle();
    }
}
Exemplo n.º 8
0
void os_start(void)
{
  int i;

  slldbg("Entry\n");

  /* Initialize RTOS Data ***************************************************/
  /* Initialize all task lists */

  dq_init(&g_readytorun);
  dq_init(&g_pendingtasks);
  dq_init(&g_waitingforsemaphore);
#ifndef CONFIG_DISABLE_SIGNALS
  dq_init(&g_waitingforsignal);
#endif
#ifndef CONFIG_DISABLE_MQUEUE
  dq_init(&g_waitingformqnotfull);
  dq_init(&g_waitingformqnotempty);
#endif
#ifdef CONFIG_PAGING
  dq_init(&g_waitingforfill);
#endif
  dq_init(&g_inactivetasks);
  sq_init(&g_delayed_kufree);
#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \
     defined(CONFIG_MM_KERNEL_HEAP)
  sq_init(&g_delayed_kfree);
#endif

  /* Initialize the logic that determine unique process IDs. */

  g_lastpid = 0;
  for (i = 0; i < CONFIG_MAX_TASKS; i++)
    {
      g_pidhash[i].tcb = NULL;
      g_pidhash[i].pid = INVALID_PROCESS_ID;
    }

  /* Assign the process ID of ZERO to the idle task */

  g_pidhash[PIDHASH(0)].tcb = &g_idletcb.cmn;
  g_pidhash[PIDHASH(0)].pid = 0;

  /* Initialize the IDLE task TCB *******************************************/
  /* Initialize a TCB for this thread of execution.  NOTE:  The default
   * value for most components of the g_idletcb are zero.  The entire
   * structure is set to zero.  Then only the (potentially) non-zero
   * elements are initialized. NOTE:  The idle task is the only task in
   * that has pid == 0 and sched_priority == 0.
   */

  bzero((void*)&g_idletcb, sizeof(struct task_tcb_s));
  g_idletcb.cmn.task_state = TSTATE_TASK_RUNNING;
  g_idletcb.cmn.entry.main = (main_t)os_start;
  g_idletcb.cmn.flags      = TCB_FLAG_TTYPE_KERNEL;

  /* Set the IDLE task name */

#if CONFIG_TASK_NAME_SIZE > 0
  strncpy(g_idletcb.cmn.name, g_idlename, CONFIG_TASK_NAME_SIZE);
  g_idletcb.cmn.name[CONFIG_TASK_NAME_SIZE] = '\0';
#endif /* CONFIG_TASK_NAME_SIZE */

  /* Configure the task name in the argument list.  The IDLE task does
   * not really have an argument list, but this name is still useful
   * for things like the NSH PS command.
   *
   * In the kernel mode build, the arguments are saved on the task's stack
   * and there is no support that yet.
   */

#if CONFIG_TASK_NAME_SIZE > 0
  g_idleargv[0]  = g_idletcb.cmn.name;
#else
  g_idleargv[0]  = (FAR char *)g_idlename;
#endif /* CONFIG_TASK_NAME_SIZE */
  g_idleargv[1]  = NULL;
  g_idletcb.argv = g_idleargv;

  /* Then add the idle task's TCB to the head of the ready to run list */

  dq_addfirst((FAR dq_entry_t*)&g_idletcb, (FAR dq_queue_t*)&g_readytorun);

  /* Initialize the processor-specific portion of the TCB */

  up_initial_state(&g_idletcb.cmn);

  /* Initialize RTOS facilities *********************************************/
  /* Initialize the semaphore facility.  This has to be done very early
   * because many subsystems depend upon fully functional semaphores.
   */

  sem_initialize();

#if defined(MM_KERNEL_USRHEAP_INIT) || defined(CONFIG_MM_KERNEL_HEAP) || defined(CONFIG_MM_PGALLOC)
  /* Initialize the memory manager */

  {
    FAR void *heap_start;
    size_t heap_size;

#ifdef MM_KERNEL_USRHEAP_INIT
    /* Get the user-mode heap from the platform specific code and configure
     * the user-mode memory allocator.
     */

    up_allocate_heap(&heap_start, &heap_size);
    kumm_initialize(heap_start, heap_size);
#endif

#ifdef CONFIG_MM_KERNEL_HEAP
    /* Get the kernel-mode heap from the platform specific code and configure
     * the kernel-mode memory allocator.
     */

    up_allocate_kheap(&heap_start, &heap_size);
    kmm_initialize(heap_start, heap_size);
#endif

#ifdef CONFIG_MM_PGALLOC
    /* If there is a page allocator in the configuration, then get the page
     * heap information from the platform-specific code and configure the
     * page allocator.
     */

    up_allocate_pgheap(&heap_start, &heap_size);
    mm_pginitialize(heap_start, heap_size);
#endif
  }
#endif

#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
  /* Initialize tasking data structures */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (task_initialize != NULL)
#endif
    {
      task_initialize();
    }
#endif

  /* Initialize the interrupt handling subsystem (if included) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (irq_initialize != NULL)
#endif
    {
      irq_initialize();
    }

  /* Initialize the watchdog facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (wd_initialize != NULL)
#endif
    {
      wd_initialize();
    }

  /* Initialize the POSIX timer facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (clock_initialize != NULL)
#endif
    {
      clock_initialize();
    }

#ifndef CONFIG_DISABLE_POSIX_TIMERS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (timer_initialize != NULL)
#endif
    {
      timer_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_SIGNALS
  /* Initialize the signal facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sig_initialize != NULL)
#endif
    {
      sig_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_MQUEUE
  /* Initialize the named message queue facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (mq_initialize != NULL)
#endif
    {
      mq_initialize();
    }
#endif

#ifndef CONFIG_DISABLE_PTHREAD
  /* Initialize the thread-specific data facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (pthread_initialize != NULL)
#endif
    {
      pthread_initialize();
    }
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0
  /* Initialize the file system (needed to support device drivers) */

  fs_initialize();
#endif

#ifdef CONFIG_NET
  /* Initialize the networking system.  Network initialization is
   * performed in two steps:  (1) net_setup() initializes static
   * configuration of the network support.  This must be done prior
   * to registering network drivers by up_initialize().  This step
   * cannot require upon any hardware-depending features such as
   * timers or interrupts.
   */

  net_setup();
#endif

  /* The processor specific details of running the operating system
   * will be handled here.  Such things as setting up interrupt
   * service routines and starting the clock are some of the things
   * that are different for each  processor and hardware platform.
   */

  up_initialize();

#ifdef CONFIG_NET
  /* Complete initialization the networking system now that interrupts
   * and timers have been configured by up_initialize().
   */

  net_initialize();
#endif

#ifdef CONFIG_MM_SHM
  /* Initialize shared memory support */

  shm_initialize();
#endif

  /* Initialize the C libraries.  This is done last because the libraries
   * may depend on the above.
   */

  lib_initialize();

  /* IDLE Group Initialization **********************************************/
#ifdef HAVE_TASK_GROUP
  /* Allocate the IDLE group */

  DEBUGVERIFY(group_allocate(&g_idletcb, g_idletcb.cmn.flags));
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
  /* Create stdout, stderr, stdin on the IDLE task.  These will be
   * inherited by all of the threads created by the IDLE task.
   */

  DEBUGVERIFY(group_setupidlefiles(&g_idletcb));
#endif

#ifdef HAVE_TASK_GROUP
  /* Complete initialization of the IDLE group.  Suppress retention
   * of child status in the IDLE group.
   */

  DEBUGVERIFY(group_initialize(&g_idletcb));
  g_idletcb.cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT;
#endif

  /* Bring Up the System ****************************************************/
  /* Create initial tasks and bring-up the system */

  DEBUGVERIFY(os_bringup());

  /* The IDLE Loop **********************************************************/
  /* When control is return to this point, the system is idle. */

  sdbg("Beginning Idle Loop\n");
  for (;;)
    {
      /* Perform garbage collection (if it is not being done by the worker
       * thread).  This cleans-up memory de-allocations that were queued
       * because they could not be freed in that execution context (for
       * example, if the memory was freed from an interrupt handler).
       */

#ifndef CONFIG_SCHED_WORKQUEUE
      /* We must have exclusive access to the memory manager to do this
       * BUT the idle task cannot wait on a semaphore.  So we only do
       * the cleanup now if we can get the semaphore -- this should be
       * possible because if the IDLE thread is running, no other task is!
       *
       * WARNING: This logic could have undesirable side-effects if priority
       * inheritance is enabled.  Imaginee the possible issues if the
       * priority of the IDLE thread were to get boosted!  Moral: If you
       * use priority inheritance, then you should also enable the work
       * queue so that is done in a safer context.
       */

      if (kmm_trysemaphore() == 0)
        {
          sched_garbagecollection();
          kmm_givesemaphore();
        }
#endif

      /* Perform any processor-specific idle state operations */

      up_idle();
    }
}
Exemplo n.º 9
0
int task_restart(pid_t pid)
{
  FAR struct tcb_s *rtcb;
  FAR struct task_tcb_s *tcb;
  irqstate_t state;
  int status;

  /* Make sure this task does not become ready-to-run while
   * we are futzing with its TCB
   */

  sched_lock();

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

  rtcb = (FAR struct tcb_s *)g_readytorun.head;
  if ((pid == 0) || (pid == rtcb->pid))
    {
      /* Not implemented */

      set_errno(ENOSYS);
      return ERROR;
    }

  /* We are restarting some other task than ourselves */

  else
    {
      /* Find for the TCB associated with matching pid  */

      tcb = (FAR struct task_tcb_s *)sched_gettcb(pid);
#ifndef CONFIG_DISABLE_PTHREAD
      if (!tcb || (tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
#else
      if (!tcb)
#endif
        {
          /* There is no TCB with this pid or, if there is, it is not a
           * task.
           */

          set_errno(ESRCH);
          return ERROR;
        }

      /* Try to recover from any bad states */

      task_recover((FAR struct tcb_s *)tcb);

      /* Kill any children of this thread */

#if HAVE_GROUP_MEMBERS
      (void)group_killchildren(tcb);
#endif

      /* Remove the TCB from whatever list it is in.  At this point, the
       * TCB should no longer be accessible to the system
       */

      state = irqsave();
      dq_rem((FAR dq_entry_t*)tcb,
             (dq_queue_t*)g_tasklisttable[tcb->cmn.task_state].list);
      tcb->cmn.task_state = TSTATE_TASK_INVALID;
      irqrestore(state);

      /* Deallocate anything left in the TCB's queues */

      sig_cleanup((FAR struct tcb_s *)tcb); /* Deallocate Signal lists */

      /* Reset the current task priority  */

      tcb->cmn.sched_priority = tcb->init_priority;

      /* Reset the base task priority and the number of pending reprioritizations */

#ifdef CONFIG_PRIORITY_INHERITANCE
      tcb->cmn.base_priority = tcb->init_priority;
#  if CONFIG_SEM_NNESTPRIO > 0
      tcb->cmn.npend_reprio = 0;
#  endif
#endif

      /* Re-initialize the processor-specific portion of the TCB
       * This will reset the entry point and the start-up parameters
       */

      up_initial_state((FAR struct tcb_s *)tcb);

      /* Add the task to the inactive task list */

      dq_addfirst((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks);
      tcb->cmn.task_state = TSTATE_TASK_INACTIVE;

      /* Activate the task */

      status = task_activate((FAR struct tcb_s *)tcb);
      if (status != OK)
        {
          (void)task_delete(pid);
          set_errno(-status);
          return ERROR;
        }
    }

  sched_unlock();
  return OK;
}