EE445M RTOS
Taken at the University of Texas Spring 2015
Operating system routines

Operating system routines. More...

Data Structures

struct  hwcontext
 
struct  swcontext
 

Macros

#define PIDWORK_BUFFER_SIZE   32
 
#define OS_STACK_SIZE   100
 
#define OS_NUM_POOLS   2
 
#define OS_SYSTEM_POOL   0
 
#define OS_REAL_TIME_POOL   0
 
#define OS_INTERACTIVE_POOL   1
 
#define os_spawn_thread(_thread, _priority)   os_add_thread(_thread, priority)
 
#define os_kill_thread(_thread)   os_remove_thread(_thread)
 
#define os_surrender_context()   os_suspend()
 

Typedefs

typedef struct hwcontext hwcontext_t
 
typedef struct swcontext swcontext_t
 

Functions

void pidwork_increment ()
 
void pidwork_record ()
 
void os_threading_init (void)
 
void _os_reset_thread_stack (tcb_t *tcb, task_t task)
 
int8_t get_os_num_threads ()
 
tcb_tos_add_thread (task_t)
 
tcb_tos_remove_thread (task_t)
 
tcb_tos_tcb_of (task_t)
 
tcb_t_os_next_dead_thread ()
 
int32_t os_running_thread_id ()
 
void os_launch ()
 
void os_suspend ()
 

Variables

static volatile uint32_t PIDWORK
 
static volatile uint32_t HIGHEST_PIDWORK
 
static volatile uint32_t LOWEST_PIDWORK
 
static volatile uint32_t PIDWORK_IDX
 
static volatile uint32_t PIDWORK_BUFFER [32]
 
static tcb_tos_running_threads = NULL
 
static tcb_tos_dead_threads = NULL
 
static tcb_tOS_NEXT_THREAD
 
static tcb_t OS_THREADS [SCHEDULER_MAX_THREADS]
 
static tcb_tOS_THREAD_POOL [2]
 

Detailed Description

Operating system routines.

''

Author
Hershal Bhave
Eric Crosson
Version
0.1
Date
2015
Precondition
None

Macro Definition Documentation

#define OS_INTERACTIVE_POOL   1

Second highest priority thread pool alias

Definition at line 32 of file os.h.

Referenced by main().

#define os_kill_thread (   _thread)    os_remove_thread(_thread)

An alias to . Feels like home sweet home.

Definition at line 39 of file os.h.

#define OS_NUM_POOLS   2

Static number of thread pools of distinct priority in use

Definition at line 25 of file os.h.

Referenced by os_threading_init().

#define OS_REAL_TIME_POOL   0

Highest priority thread pool alias

Definition at line 30 of file os.h.

#define os_spawn_thread (   _thread,
  _priority 
)    os_add_thread(_thread, priority)

An alias to . Feels like home sweet home.

Definition at line 35 of file os.h.

#define OS_STACK_SIZE   100

Maximum number of 32-bit values allowed in each thread's stack

Definition at line 22 of file os.h.

Referenced by _os_reset_thread_stack().

#define os_surrender_context ( )    os_suspend()

A convenience alias to to circumnavigate the naming conventions chosen by the couse Administrators.

Definition at line 142 of file os.h.

Referenced by hw_daemon(), led_blink_blue(), led_blink_green(), led_blink_red(), and postpone_suicide().

#define OS_SYSTEM_POOL   0

Highest priority thread pool alias

Definition at line 28 of file os.h.

Referenced by main().

#define PIDWORK_BUFFER_SIZE   32

Definition at line 14 of file jitter.h.

Typedef Documentation

typedef struct hwcontext hwcontext_t

The contents of the stack immediately after a function call.

typedef struct swcontext swcontext_t

The contents of the stack during a context switch.

Function Documentation

tcb_t* _os_next_dead_thread ( )

Returns the next dead thread in the dead thread circle. If the length of the dead thread circle is greater than 1, then the current dead thread is removed and the circle is relinked with the next dead thread. If the circle contains only one dead thread, then that thread is removed and the current dead thread is set to null. If there is no thread in the dead thread circle, then it retuns null.

Returns
The first thread removed from the dead thread circle, or null if the dead thread circle is empty.
void _os_reset_thread_stack ( tcb_t tcb,
task_t  task 
)
inline

Resets the thread stack for a given tcb to run a given task.

Parameters
threadthe thread whose stack is to be reset
thetask for which the thread should run

Definition at line 197 of file os.c.

References tcb_t::id, swcontext::lr, OS_PROGRAM_STACKS, OS_STACK_SIZE, hwcontext::pc, hwcontext::psr, hwcontext::r0, hwcontext::r1, swcontext::r10, swcontext::r11, hwcontext::r2, hwcontext::r3, swcontext::r4, swcontext::r5, swcontext::r6, swcontext::r7, swcontext::r8, swcontext::r9, and tcb_t::sp.

Referenced by os_add_thread().

197  {
198 
200  (((uint32_t)OS_PROGRAM_STACKS[tcb->id]) +
201  sizeof(uint32_t)*OS_STACK_SIZE - sizeof(hwcontext_t));
202 
204  (((uint32_t)hwcontext) - sizeof(swcontext_t));
205 
206  hwcontext->pc = (uint32_t)(task);
207  hwcontext->psr = 0x01000000;
208 
209  swcontext->lr = 0xfffffff9;
210 
211  #ifdef OS_REGISTER_DEBUGGING_ENABLED
212  hwcontext->r0 = 0x00000000;
213  hwcontext->r1 = 0x01010101;
214  hwcontext->r2 = 0x02020202;
215  hwcontext->r3 = 0x03030303;
216 
217  swcontext->r4 = 0x04040404;
218  swcontext->r5 = 0x05050505;
219  swcontext->r6 = 0x06060606;
220  swcontext->r7 = 0x07070707;
221  swcontext->r8 = 0x08080808;
222  swcontext->r9 = 0x09090909;
223  swcontext->r10 = 0x10101010;
224  swcontext->r11 = 0x11111111;
225  #endif /* OS_REGISTER_DEBUGGING_ENABLED */
226 
227  tcb->sp = (uint32_t*)(((uint32_t)hwcontext) - sizeof(swcontext_t));
228  asm volatile ("PUSH {R9, R10, R11, R12}");
229  asm volatile ( "mrs r12, msp" );
230  asm volatile ( "mrs r11, msp" );
231  asm volatile ( "mrs r10, control" );
232 
233  asm volatile ("POP {R9, R10, R11, R12}");
234 }
uint32_t r11
Definition: os.h:71
immutable int32_t id
uint32_t r2
Definition: os.h:54
uint32_t r6
Definition: os.h:66
uint32_t r4
Definition: os.h:64
static int32_t OS_PROGRAM_STACKS[SCHEDULER_MAX_THREADS][100]
Definition: os.c:16
uint32_t r3
Definition: os.h:55
uint32_t pc
Definition: os.h:58
uint32_t r8
Definition: os.h:68
uint32_t r1
Definition: os.h:53
uint32_t r5
Definition: os.h:65
uint32_t psr
Definition: os.h:59
uint32_t lr
Definition: os.h:72
int32_t * sp
uint32_t r7
Definition: os.h:67
#define OS_STACK_SIZE
Definition: os.h:22
Definition: os.h:63
Definition: os.h:51
uint32_t r10
Definition: os.h:70
uint32_t r9
Definition: os.h:69
uint32_t r0
Definition: os.h:52

Here is the caller graph for this function:

int8_t get_os_num_threads ( )

Definition at line 68 of file os.c.

References OS_NUM_THREADS.

68  {
69  return OS_NUM_THREADS;
70 }
uint8_t OS_NUM_THREADS
Definition: os.c:32
tcb_t* os_add_thread ( task_t  )

Adds a new thread with the specified task.

Returns
the TCB of the newly added thread, null if the addition was not possible for some reason.

Definition at line 72 of file os.c.

References _os_reset_thread_stack(), atomic_end, atomic_start, CDL_DELETE, tcb_t::entry_point, and os_dead_threads.

Referenced by hw_init_daemon(), main(), and schedule().

72  {
73 
74  int32_t status;
75  tcb_t* thread_to_add;
76 
77  /* 1. Disable interrupts and save the priority mask */
78  atomic_start();
79 
80  /* 2. Pop the task from the dead_thread pile */
81  thread_to_add = os_dead_threads;
82  CDL_DELETE(os_dead_threads, thread_to_add);
83 
84  /* 3. Add the thread to the appropriate priority pool. */
85  /* CDL_APPEND(os_running_threads, thread_to_add); */
86  /* CDL_APPEND(OS_THREAD_POOL[priority], thread_to_add); */
87 
88  /* 4. Set the initial stack contents for the new thread. */
89  _os_reset_thread_stack(thread_to_add, task);
90 
91  /* 5. Set metadata for this thread's TCB. */
92 
93  /* TODO: Remove this from semaphore. The scheduler manages
94  * this. */
95  /* thread_to_add->status = THREAD_RUNNING; */
96  thread_to_add->entry_point = task;
97  /* thread_to_add->priority = priority; */
98  /* thread_to_add->sleep_timer = 0; */
99 
100  atomic_end();
101 
102  /* 5. Return. */
103  return thread_to_add;
104 }
#define atomic_start()
Definition: nexus.h:20
always void _os_reset_thread_stack(tcb_t *tcb, task_t task)
Definition: os.c:197
static tcb_t * os_dead_threads
Definition: os.h:48
#define CDL_DELETE(head, del)
Definition: utlist.h:705
task_t entry_point
#define atomic_end()
Definition: nexus.h:25

Here is the call graph for this function:

Here is the caller graph for this function:

void os_launch ( )

Launches the operating system.

Note
This function drastically changes the execution paradigm of the machine; do not expect to call it and be able to return to the previous context.

Definition at line 161 of file os.c.

References _os_choose_next_thread(), edf_init(), OS_NEXT_THREAD, and os_running_threads.

Referenced by main().

161  {
162 
163  edf_init();
166 
167  /* acquire the pointer to the stack pointer here */
168  asm volatile("LDR R0, =OS_NEXT_THREAD");
169 
170  /* acquire the current value of the stack pointer */
171  asm volatile("LDR R0, [R0]");
172  asm volatile("LDR R0, [R0]");
173 
174  /* set the process stack value */
175  asm volatile("MSR MSP, R0");
176 
177  /* change EXC_RETURN for return on MSP */
178  /* asm volatile("ORR LR, LR, #4"); */
179 
180  /* change the active stack to use msp */
181  /* asm volatile("MRS R0, CONTROL"); */
182  /* asm volatile("ORR R0, R0, #2"); */
183  /* asm volatile("MSR CONTROL, R0"); */
184 
185  asm volatile("POP {R4-R11}");
186 
187  asm volatile("POP {LR}");
188  asm volatile("POP {R0-R3}");
189 
190  asm volatile("pop {r12, lr}");
191  asm volatile("pop {pc}");
192 
193  asm volatile ("BX LR");
194 }
static tcb_t * os_running_threads
Definition: os.h:45
static tcb_t * OS_NEXT_THREAD
Definition: os.h:78
void _os_choose_next_thread()
Definition: os.c:544
void edf_init()
Definition: os.c:475

Here is the call graph for this function:

Here is the caller graph for this function:

tcb_t* os_remove_thread ( task_t  )

Remove a thread from the queue the schedule will choose from.

Parameters
Thetask to kill. This should be the task that was used to start the thread to remove via .
Returns
The newly released tcb

Definition at line 106 of file os.c.

References CDL_APPEND, CDL_DELETE, tcb_t::entry_point, tcb_t::next, NULL, os_dead_threads, OS_NUM_THREADS, os_tcb_of(), OS_THREAD_POOL, tcb_t::prev, and tcb_t::priority.

106  {
107 
108  int32_t status;
109  tcb_t* thread_to_remove;
110 
111  /* 1. Disable interrupts and save the priority mask */
112  /* TODO: clean this up, make uniform */
113  status = StartCritical();
114 
115  /* 2. Pop the task from the running_thread pile and add it to the
116  * list of dead threads. */
117  thread_to_remove = os_tcb_of(task);
118  CDL_DELETE(OS_THREAD_POOL[thread_to_remove->priority], thread_to_remove);
119  /* Append means low tcb_t memory reusability. Prepend means high */
120  CDL_APPEND(os_dead_threads, thread_to_remove);
121 
122  /* OPTIONAL TODO: do the check for overwritten stacks as long as
123  * we kill every thread in our testing we'll get valuable yet
124  * unobtrusive debugging data. also consider a check on the
125  * immutable fields, using the offset from the array base as
126  * verification. */
127 
128  /* 3. Reset metadata for this thread's TCB. */
129  /* thread_to_remove->status = THREAD_DEAD; */
130  thread_to_remove->entry_point = NULL;
131  thread_to_remove->next = NULL;
132  thread_to_remove->prev = NULL;
133 
134  /* 4. Return. */
135  /* TODO: clean this up, make uniform */
136  --OS_NUM_THREADS;
137 
138  EndCritical(status);
139  return thread_to_remove;
140 }
static tcb_t * OS_THREAD_POOL[2]
Definition: os.h:84
static tcb_t * os_dead_threads
Definition: os.h:48
#define CDL_DELETE(head, del)
Definition: utlist.h:705
struct tcb_t * prev
priority_t priority
task_t entry_point
tcb_t * os_tcb_of(const task_t task)
Definition: os.c:147
struct tcb_t * next
uint8_t OS_NUM_THREADS
Definition: os.c:32
#define NULL
Definition: defines.h:32
#define CDL_APPEND(head, add)
Definition: utlist.h:688

Here is the call graph for this function:

int32_t os_running_thread_id ( )

Definition at line 142 of file os.c.

References tcb_t::id, and os_running_threads.

142  {
143 
144  return os_running_threads->id;
145 }
immutable int32_t id
static tcb_t * os_running_threads
Definition: os.h:45
void os_suspend ( )

Put the invoking thread to sleep and let another thread take over. This s another way to say "set the interrupt bit of the \PendSV_Handler".

Definition at line 380 of file os.c.

References scheduler_reschedule().

380  {
381 
383 }
always void scheduler_reschedule(void)
Definition: os.c:237

Here is the call graph for this function:

tcb_t* os_tcb_of ( task_t  )

Return the tcb used to control the specified task_t.

Parameters
Thetask to lookup the tcb of
Returns
The tcb of the specified task_t

Definition at line 147 of file os.c.

References NULL, OS_THREADS, postpone_death, and SCHEDULER_MAX_THREADS.

Referenced by os_remove_thread().

147  {
148 
149  int32_t i;
150  for(i=0; i<SCHEDULER_MAX_THREADS; ++i) {
151  if (task == OS_THREADS[i].entry_point) {
152  return &OS_THREADS[i];
153  }
154  }
155 #ifndef DANGER_ZONE
156  postpone_death();
157 #endif
158  return NULL;
159 }
#define postpone_death()
Definition: nexus.h:40
#define SCHEDULER_MAX_THREADS
static tcb_t OS_THREADS[SCHEDULER_MAX_THREADS]
Definition: os.h:81
#define NULL
Definition: defines.h:32

Here is the caller graph for this function:

void os_threading_init ( void  )

Initialize the threading engine, setting all threads to dead. This initializes the dead thread circle appropriately and sets the running thread circle to null.

Definition at line 34 of file os.c.

References CDL_APPEND, tcb_t::entry_point, tcb_t::id, NULL, os_dead_threads, OS_NUM_POOLS, OS_PROGRAM_STACKS, os_running_threads, OS_THREAD_POOL, OS_THREADING_INITIALIZED, OS_THREADS, schedule_init(), SCHEDULER_MAX_THREADS, and tcb_t::sp.

Referenced by main().

34  {
35 
36  uint32_t i;
37 
38  /* This check exists so libraries may call os_threading_init
39  * without breaking everything. We dont' want to contribute to the
40  * black magic that is the specific initialization of TI
41  * libraries, do we? */
43  return;
44  }
45 
47 
48  /* Initialize thread metadata */
49  for (i=0; i<SCHEDULER_MAX_THREADS; ++i) {
52  OS_THREADS[i].id = i;
54  /* OS_THREADS[i].status = THREAD_DEAD; */
55  /* OS_THREADS[i].sleep_timer = 0; */
56  }
57 
58  /* Initialize thread pool metadata */
59  for (i=0; i<OS_NUM_POOLS; ++i) {
60  OS_THREAD_POOL[i] = (tcb_t*) NULL;
61  }
62 
64 
65  schedule_init();
66 }
#define OS_NUM_POOLS
Definition: os.h:25
immutable int32_t id
static int32_t OS_PROGRAM_STACKS[SCHEDULER_MAX_THREADS][100]
Definition: os.c:16
static tcb_t * OS_THREAD_POOL[2]
Definition: os.h:84
static tcb_t * os_running_threads
Definition: os.h:45
void schedule_init()
Definition: os.c:445
static tcb_t * os_dead_threads
Definition: os.h:48
bool OS_THREADING_INITIALIZED
Definition: os.c:31
int32_t * sp
#define SCHEDULER_MAX_THREADS
static tcb_t OS_THREADS[SCHEDULER_MAX_THREADS]
Definition: os.h:81
task_t entry_point
#define NULL
Definition: defines.h:32
#define CDL_APPEND(head, add)
Definition: utlist.h:688

Here is the call graph for this function:

Here is the caller graph for this function:

void pidwork_increment ( )

Definition at line 15 of file jitter.c.

References PIDWORK.

15  {
16 
17  while(1) {
18  asm volatile("CPSID I");
19  ++PIDWORK;
20  asm volatile("CPSIE I");
21  }
22 }
static volatile uint32_t PIDWORK
Definition: jitter.h:16
void pidwork_record ( )

A thread that continuously toggles GPIO pin 2 on GPIO_PORT_F.

Definition at line 25 of file jitter.c.

References HIGHEST_PIDWORK, LOWEST_PIDWORK, PIDWORK, PIDWORK_BUFFER, PIDWORK_BUFFER_SIZE, and PIDWORK_IDX.

25  {
26 
27  while(1) {
28  if (PIDWORK != 0) {
29  if (HIGHEST_PIDWORK < PIDWORK) {
31  }
32  if (LOWEST_PIDWORK > PIDWORK) {
34  }
37  }
38  PIDWORK = 0;
39  }
40 }
static volatile uint32_t PIDWORK_IDX
Definition: jitter.h:19
#define PIDWORK_BUFFER_SIZE
Definition: test-os.c:32
static volatile uint32_t PIDWORK
Definition: jitter.h:16
static volatile uint32_t LOWEST_PIDWORK
Definition: jitter.h:18
static volatile uint32_t PIDWORK_BUFFER[32]
Definition: jitter.h:20
static volatile uint32_t HIGHEST_PIDWORK
Definition: jitter.h:17

Variable Documentation

volatile uint32_t HIGHEST_PIDWORK
static

Definition at line 17 of file jitter.h.

Referenced by pidwork_init(), and pidwork_record().

volatile uint32_t LOWEST_PIDWORK
static

Definition at line 18 of file jitter.h.

Referenced by pidwork_init(), and pidwork_record().

tcb_t* os_dead_threads = NULL
static

A circular doubly linked list of currently dead threads.

Definition at line 48 of file os.h.

Referenced by os_add_thread(), os_remove_thread(), and os_threading_init().

tcb_t* OS_NEXT_THREAD
static

Communication mailbox from the SysTick_Handler to the PendSV_Handler; will contain the tcb_t* of the next thread to execute come PendSV_Handler execution time.

Definition at line 78 of file os.h.

Referenced by os_launch(), and scheduler_reschedule().

tcb_t* os_running_threads = NULL
static

A circular doubly linked list of currently running threads.

Note
The head of this list is 'os_current_running_thread'

Definition at line 45 of file os.h.

Referenced by os_launch(), os_running_thread_id(), os_threading_init(), and PendSV_Handler().

tcb_t* OS_THREAD_POOL[2]
static

An array of thread pools to place OS_THREADS into.

Definition at line 84 of file os.h.

Referenced by os_remove_thread(), and os_threading_init().

tcb_t OS_THREADS[SCHEDULER_MAX_THREADS]
static

An array of statically allocated threads.

Definition at line 81 of file os.h.

Referenced by os_tcb_of(), and os_threading_init().

volatile uint32_t PIDWORK
static

Definition at line 16 of file jitter.h.

Referenced by pidwork_increment(), pidwork_init(), and pidwork_record().

volatile uint32_t PIDWORK_BUFFER[32]
static

Definition at line 20 of file jitter.h.

Referenced by pidwork_record().

volatile uint32_t PIDWORK_IDX
static

Definition at line 19 of file jitter.h.

Referenced by pidwork_init(), and pidwork_record().