]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/include/kern/sched.h
5592063c1fd39fdd7c3d01e3f078490cdd30b056
[polintos/scott/priv.git] / kernel / include / kern / sched.h
1 #ifndef _KERN_SCHED_H
2 #define _KERN_SCHED_H
3
4 #include <kern/types.h>
5 #include <kern/time.h>
6 #include <kern/spinlock.h>
7
8 #include <arch/thread.h>
9
10 #include <util/list.h>
11
12 extern "C" void schedule();
13 extern "C" void sched_new_thread();
14
15 // FIXME: per-CPU
16 extern int need_resched;
17
18 namespace Threads {
19         class Thread;
20         class WaitQueue;
21
22         // This is a reasonably simple O(1) scheduler that provides both
23         // real-time and timeshared scheduling, with (non-rt) priority boosts
24         // for interactive tasks.
25         //
26         // At some point, it'd be nice to extend/replace this with something
27         // that gives more options to how to schedule tasks.  Priority
28         // inheritance would be nice, as would the ability to schedule groups
29         // of threads as one prior to scheduling within the group.  The latter
30         // would help avoid giving more CPU time to certain apps simply
31         // because they divided their work among more threads (or to certain
32         // users simply because they're running more programs).
33         //
34         // At some sooner point, SMP support will need to be added.
35
36         class Sched {
37         public:
38                 enum {
39                         // The default timeslice of 10 ms applies to priority 8 
40                         // timeshared tasks.
41                         
42                         default_timeslice = 10000000,
43                         rt_prios = 256,
44                         ts_static_prios = 16,
45                         
46                         // This must not exceed 32 without increasing the size
47                         // of ts_bitmap.
48                         
49                         ts_prios = 32
50                 };
51         
52         private:
53                 ulong bitmap[rt_prios / sizeof(ulong)];
54                 Util::List rt_runqueue[rt_prios];
55                 
56                 u32 ts_bitmap, ts_depleted_bitmap;
57                 int last_replenish;
58
59                 Util::List ts_runqueue[ts_prios];
60                 Util::List ts_depleted[ts_prios];
61                 
62                 Lock::SpinLock runqueue_lock;
63         
64                 void schedule_nolock();
65                 Thread *best_rt(int prio);
66                 Thread *best_ts();
67                 
68                 void replenish_prio(int prio);
69                 void replenish_all();
70                 
71                 static u32 prio_to_slice(int prio);
72                 static int slice_to_prio(u32 slice);
73                 
74                 Time::KTimerEntry resched_timer;
75
76         public:
77                 Util::List threadlist;
78                 
79                 // FIXME: use sleeping lock once implemented
80                 Lock::SpinLock threadlist_lock;
81         
82                 typedef void (*thread_func)(void *arg);
83         
84                 Thread *new_thread(thread_func func, void *arg, char *name = NULL);
85                 void schedule();
86                 void sched_new_thread();
87                 
88                 void init();
89
90                 friend class Thread;
91                 friend class WaitQueue;
92         };
93         
94         extern Sched sched;
95         
96         struct Blocker {
97                 Util::List list_node;
98                 bool blocked;
99                 
100                 // Besides the obvious use by ThreadBlocker, this is used in
101                 // CascadeBlocker by WaitQueue both for prioritization of wakeups
102                 // and for calling wake_nolock().
103                 
104                 Thread *thread;
105                 
106                 Blocker()
107                 {
108                         blocked = true;
109                 }
110         
111                 virtual ~Blocker()
112                 {
113                 }
114         
115                 virtual void wake() = 0;
116                 
117                 // Like wake, but doesn't wake the thread -- used by WaitQueue
118                 // which calls thread->wake_nolock itself.
119
120                 virtual void unblock() = 0;
121         };
122
123         // This is a basic one-thread blocker; all blocked threads must
124         // use one of these.
125         
126         struct ThreadBlocker : public Blocker {
127                 ThreadBlocker()
128                 {
129                 }
130                 
131                 ThreadBlocker(Thread *THREAD)
132                 {
133                         thread = THREAD;
134                 }
135         
136                 void wake();
137                 void unblock();
138         };
139         
140         // A thread that needs to block on more than one blocker can create
141         // multiple CascadeBlockers all pointing to the same ThreadBlocker.
142         // The thread wakes when any of the cascades has been woken.
143         
144         struct CascadeBlocker : public Blocker {
145                 CascadeBlocker()
146                 {
147                 }
148                 
149                 CascadeBlocker(Blocker *BLOCKER)
150                 {
151                         blocker = BLOCKER;
152                         thread = blocker->thread;
153                 }
154         
155                 Blocker *blocker;
156                 void wake();
157                 void unblock();
158         };
159         
160         // Waitqueues are queues of Blockers that can be woken up either one
161         // at a time in priority order or all at once, at the waker's option. 
162         // Unlike Blockers, waitqueues do not have a blocked field; blocking
163         // threads must check for completion after adding themselves to the
164         // wait queue.  When a blocker is woken, it is removed from the waitqueue.
165         
166         class WaitQueue {
167                 Util::List blockers;
168                 Lock::SpinLock lock;
169                 
170                 Blocker *unblock_one_nolock();
171         
172         public:
173                 void block(Blocker *blocker);
174                 void unblock(Blocker *blocker);
175                 
176                 bool empty();
177                 
178                 // Returns true if a task was successfully woken
179                 bool wake_one();
180                 
181                 // Returns the number of tasks successfully woken
182                 int wake_all();
183
184                 // Like wake_one, but return the thread instead of waking it.
185                 Blocker *unblock_one();
186         };
187 }
188
189 #endif