summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2013-07-20 08:41:41 +0200
committerVegard Storheil Eriksen <zyp@jvnv.net>2013-07-20 08:43:10 +0200
commite14b2f0d2406311a6fcdaea313584995ec8adefd (patch)
treef2cffca4fe334aeb873cce8a77bd5b6f98cc0096
parent657d427aa41e6e05c8c4d4b1179b42d3363e8018 (diff)
Add support for sleeping threads.scheduler_improvements
-rw-r--r--interrupt/fault.cpp6
-rw-r--r--os/thread.cpp1
-rw-r--r--os/thread.h55
-rw-r--r--os/time.h9
4 files changed, 57 insertions, 14 deletions
diff --git a/interrupt/fault.cpp b/interrupt/fault.cpp
index 9af0eb8..8a577bf 100644
--- a/interrupt/fault.cpp
+++ b/interrupt/fault.cpp
@@ -13,9 +13,11 @@ inline void __attribute__((naked)) switch_context() {
// Update running thread.
if(!Thread::reschedule()) {
- // TODO: Set SLEEPONEXIT
+ // No threads are ready - set SLEEPONEXIT.
+ SCB.SCR = 1 << 1;
} else {
- // TODO: Clear SLEEPONEXIT
+ // Clear SLEEPONEXIT.
+ SCB.SCR = 0 << 1;
}
// Fetch stack pointer for new thread.
diff --git a/os/thread.cpp b/os/thread.cpp
index 0f2437d..432727a 100644
--- a/os/thread.cpp
+++ b/os/thread.cpp
@@ -1,5 +1,6 @@
#include "thread.h"
List<Thread> Thread::ready_queue __attribute__ ((init_priority (1000)));
+List<Thread> Thread::sleep_queue;
Thread Thread::main_thread __attribute__ ((init_priority (1001)));
Thread* Thread::active_thread = &Thread::main_thread;
diff --git a/os/thread.h b/os/thread.h
index 72ee275..9270727 100644
--- a/os/thread.h
+++ b/os/thread.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <util/intrusive_list.h>
+#include "time.h"
+
class Thread {
friend void switch_context();
@@ -33,20 +35,42 @@ class Thread {
int_frame_t* sp;
+ enum State {
+ Running,
+ Sleeping,
+ };
+
+ State state;
+ uint32_t sleep_deadline;
+
ListHandle<Thread> queue_handle;
static List<Thread> ready_queue;
+ static List<Thread> sleep_queue;
static Thread* active_thread;
static Thread main_thread;
static bool reschedule() {
- //active_thread = active_thread->next;
+ uint32_t now = Time::time();
- // TODO: Check whether active thread still is ready.
+ // Go through sleep queue.
+ for(auto h : sleep_queue) {
+ // Move to ready queue if deadline has expired.
+ if(h->p->sleep_deadline <= now) {
+ h->p->state = Running;
+ ready_queue.append(*h);
+
+ // Moving one element makes the iterator unusable, so break here.
+ break;
+ }
+ }
- // Move thread to end of ready queue.
- ready_queue.append(active_thread->queue_handle);
+ // Check whether active thread still is ready.
+ if(active_thread->state == Running) {
+ // Move thread to end of ready queue.
+ ready_queue.append(active_thread->queue_handle);
+ }
// Check whether any threads are ready to run.
if(ready_queue.empty()) {
@@ -78,6 +102,29 @@ class Thread {
ready_queue.append(queue_handle);
}
+ void set_sleeping(uint32_t until) {
+ sleep_deadline = until;
+ state = Sleeping;
+
+ // Search for thread with later deadline.
+ for(auto h : sleep_queue) {
+ // Insert before if found.
+ if(h->p->sleep_deadline > sleep_deadline) {
+ queue_handle.insert_before(*h);
+ return;
+ }
+ }
+
+ // Otherwise append to end of queue.
+ sleep_queue.append(queue_handle);
+ }
+
+ static void sleep(uint32_t delay) {
+ active_thread->set_sleeping(Time::time() + delay);
+
+ yield();
+ }
+
static inline void yield() {
asm volatile("svc 0" ::: "memory");
}
diff --git a/os/time.h b/os/time.h
index f4e3ce6..6287834 100644
--- a/os/time.h
+++ b/os/time.h
@@ -1,7 +1,7 @@
#ifndef TIME_H
#define TIME_H
-#include "thread.h"
+#include <stdint.h>
struct STK_t {
volatile uint32_t CTRL;
@@ -24,13 +24,6 @@ class Time {
inline static uint32_t time() {
return systime;
}
-
- inline static void sleep(uint32_t ms) {
- ms += systime;
- while(systime < ms) {
- Thread::yield();
- }
- }
};
#endif