Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

...

Wiki Markup
The CPU {{n}} scheduling logic would execute whenever the currently running task is removed from the head of {{g_assignedtasks\[n]}}.  The algorithm might be something like:

Code Block

  /* Is the assigned task list for the CPU empty? */
    
  if (g_assignedtasks[cpu].head == NULL)
    {
      /* No.. Is the task at the head of the assigned list for the CPU lower

  • in priority that the current (unassigned) task at the head of the
  • ready-to-run list?
  • /

...

Wiki Markup
Of course, that would not work with the proposed changes.  We would need to then get the TCB of the currently executing task/thread for CPU {{n}} from the head of {{g_assignedtasks\[n]}}.  I would propose a replacing the above assignment with a macro like {{current_task()}} where that macro might expand to:

Code Block

    #ifdef CONFIG_SMP
    #  define current_task(cpu)  ((FAR struct tcb_s *)g_assignedtasks[cpu].head)
    #  define this_cpu()         up_cpu_index()
    #else
    #  define current_task(cpu)  ((FAR struct tcb_s *)g_readytorun.head)
    #  define this_cpu()         (0)
    #endif
    #define this_task()          (current_task(this_cpu))

where up_cpu_index() is some new MCU specific interface that will return an index associated with the currently active CPU.

...

  • Special aligned stack allocation,
  • Wiki Markup
    Logic to write the CPU index into the stack when each thread is \[re-]started.

This would also place an upper limit on the size of the stack: If we are going to find the far end of the stack by simply ANDing out the lower bits, then size of that mask would also determine the maximum size of the stack.

...

  • Keep the task data structures stable while they are being analyzed.
  • Find the lowest priority running task which could be on any CPU.
  • Wiki Markup
    If that priority is lower than the priority task, then replace it with the new task at the head of the {{g_assignedtasks\[]}} list.

  • If not, find the task with the next lowest priority and compare that one.
  • Continue until until the new task is assigned to a CPU or until it is determined that all of the currently running tasks are higher priority than the new task. In that base, the new task should be added to the g_readytorun list.

...

  • There is a global lock count g_cpu_lockset that includes a bit for each CPU: If the bit is '1', then the corresponding CPU has the scheduler locked; if '0', then the CPU does not have the scheduler locked.
  • Wiki Markup
    Scheduling logic would set the bit associated with the {{cpu}} in {{g_cpu_lockset}} when the TCB at the head of the {{g_assignedtasks\[cpu]}} list transitions has {{lockount > 0}}.  This might happen when {{sched_lock()}} is called, or after a context switch that changes the TCB at the head of the {{g_assignedtasks\[cpu]}} list.

  • Wiki Markup
    Similarly, the {{cpu}} bit in the global {{g_cpu_lockset}} would be cleared when the TCB at the head of the {{g_assignedtasks\[cpu]}} list has {{lockount == 0}}.  This might happen when {{sched_unlock()}} is called, or after a context switch that changes the TCB at the head of the {{g_assignedtasks\[cpu]}} list.

  • Modification of the global g_cpu_lockset must be protected by a simplified spinlock, g_cpu_schedlock. That spinlock would be taken when sched_lock() is called, and released when sched_unlock() is called. This assures that the scheduler does enforce the critical section. NOTE: Because of this spinlock, there should never be more than one bit set in g_cpu_lockset; attempts to set additional bits should be cause the CPU to block on the spinlock. However, additional bits could get set in 'g_cpu_lockset' due to the context switches on the various CPUs.
  • Wiki Markup
    Each the time the head of a {{g_assignedtasks\[}}] list changes and the scheduler modifies {{g_cpu_lockset}}, it must also set {{g_cpu_schedlock}} depending on the new state of {{g_cpu_lockset}}.

  • Logic that currently uses the currently running tasks lockcount should instead use the global g_cpu_schedlock. A value of SP_UNLOCKED would mean that no CPU has pre-emption disabled; SP_LOCKED would mean that at least one CPU has pre-emption disabled.

...