Breaks up sys_resource_req (XCC)
[akaros.git] / kern / src / schedule.c
1 /* Copyright (c) 2009, 2012 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Scheduling and dispatching. */
6
7 #ifdef __SHARC__
8 #pragma nosharc
9 #endif
10
11 #include <schedule.h>
12 #include <process.h>
13 #include <monitor.h>
14 #include <stdio.h>
15 #include <assert.h>
16 #include <atomic.h>
17 #include <resource.h>
18 #include <smp.h>
19 #include <sys/queue.h>
20
21 /* Process Lists */
22 struct proc_list runnable_scps = TAILQ_HEAD_INITIALIZER(runnable_scps);
23 struct proc_list all_mcps = TAILQ_HEAD_INITIALIZER(all_mcps);
24 spinlock_t sched_lock = SPINLOCK_INITIALIZER;
25
26 // This could be useful for making scheduling decisions.  
27 /* Physical coremap: each index is a physical core id, with a proc ptr for
28  * whoever *should be or is* running.  Very similar to current, which is what
29  * process is *really* running there. */
30 struct proc *pcoremap[MAX_NUM_CPUS];
31
32 /* Tracks which cores are idle, similar to the vcoremap.  Each value is the
33  * physical coreid of an unallocated core. */
34 spinlock_t idle_lock = SPINLOCK_INITIALIZER;
35 uint32_t idlecoremap[MAX_NUM_CPUS];
36 uint32_t num_idlecores = 0;
37 uint32_t num_mgmtcores = 1;
38
39 void schedule_init(void)
40 {
41         TAILQ_INIT(&runnable_scps);
42         TAILQ_INIT(&all_mcps);
43
44         /* Ghetto old idle core init */
45         /* Init idle cores. Core 0 is the management core. */
46         spin_lock(&idle_lock);
47 #ifdef __CONFIG_DISABLE_SMT__
48         /* assumes core0 is the only management core (NIC and monitor functionality
49          * are run there too.  it just adds the odd cores to the idlecoremap */
50         assert(!(num_cpus % 2));
51         // TODO: consider checking x86 for machines that actually hyperthread
52         num_idlecores = num_cpus >> 1;
53  #ifdef __CONFIG_ARSC_SERVER__
54         // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
55         num_mgmtcores++;
56         assert(num_cpus >= num_mgmtcores);
57         send_kernel_message(2, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
58  #endif
59         for (int i = 0; i < num_idlecores; i++)
60                 idlecoremap[i] = (i * 2) + 1;
61 #else
62         // __CONFIG_DISABLE_SMT__
63         #ifdef __CONFIG_NETWORKING__
64         num_mgmtcores++; // Next core is dedicated to the NIC
65         assert(num_cpus >= num_mgmtcores);
66         #endif
67         #ifdef __CONFIG_APPSERVER__
68         #ifdef __CONFIG_DEDICATED_MONITOR__
69         num_mgmtcores++; // Next core dedicated to running the kernel monitor
70         assert(num_cpus >= num_mgmtcores);
71         // Need to subtract 1 from the num_mgmtcores # to get the cores index
72         send_kernel_message(num_mgmtcores-1, (amr_t)monitor, 0,0,0, KMSG_ROUTINE);
73         #endif
74         #endif
75  #ifdef __CONFIG_ARSC_SERVER__
76         // Dedicate one core (core 2) to sysserver, might be able to share with NIC
77         num_mgmtcores++;
78         assert(num_cpus >= num_mgmtcores);
79         send_kernel_message(num_mgmtcores-1, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
80  #endif
81         num_idlecores = num_cpus - num_mgmtcores;
82         for (int i = 0; i < num_idlecores; i++)
83                 idlecoremap[i] = i + num_mgmtcores;
84 #endif /* __CONFIG_DISABLE_SMT__ */
85         spin_unlock(&idle_lock);
86         return;
87 }
88
89 /* _S procs are scheduled like in traditional systems */
90 void schedule_scp(struct proc *p)
91 {
92         /* up the refcnt since we are storing the reference */
93         proc_incref(p, 1);
94         spin_lock(&sched_lock);
95         printd("Scheduling PID: %d\n", p->pid);
96         TAILQ_INSERT_TAIL(&runnable_scps, p, proc_link);
97         spin_unlock(&sched_lock);
98 }
99
100 /* important to only call this on RUNNING_S, for now */
101 void register_mcp(struct proc *p)
102 {
103         proc_incref(p, 1);
104         spin_lock(&sched_lock);
105         TAILQ_INSERT_TAIL(&all_mcps, p, proc_link);
106         spin_unlock(&sched_lock);
107         //poke_ksched(p, RES_CORES);
108 }
109
110 /* Something has changed, and for whatever reason the scheduler should
111  * reevaluate things. 
112  *
113  * Don't call this from interrupt context (grabs proclocks). */
114 void schedule(void)
115 {
116         struct proc *p, *temp;
117         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
118         spin_lock(&sched_lock);
119         /* trivially try to handle the needs of all our MCPS.  smarter schedulers
120          * would do something other than FCFS */
121         TAILQ_FOREACH_SAFE(p, &all_mcps, proc_link, temp) {
122                 printd("Ksched has MCP %08p (%d)\n", p, p->pid);
123                 /* If they are dying, abort.  There's a bit of a race here.  If they
124                  * start dying right after the check, core_request/give_cores would
125                  * start dealing with a DYING proc.  The code can handle it, but this
126                  * will probably change. */
127                 if (p->state == PROC_DYING) {
128                         TAILQ_REMOVE(&all_mcps, p, proc_link);
129                         proc_decref(p);
130                         continue;
131                 }
132                 if (!num_idlecores)
133                         break;
134                 /* TODO: might use amt_wanted as a proxy.  right now, they have
135                  * amt_wanted == 1, even though they are waiting.
136                  * TODO: this is RACY too - just like with DYING. */
137                 if (p->state == PROC_WAITING)
138                         continue;
139                 core_request(p);
140         }
141         /* prune any dying SCPs at the head of the queue and maybe sched our core */
142         while ((p = TAILQ_FIRST(&runnable_scps))) {
143                 if (p->state == PROC_DYING) {
144                         TAILQ_REMOVE(&runnable_scps, p, proc_link);
145                         proc_decref(p);
146                 } else {
147                         /* check our core to see if we can give it out to an SCP */
148                         if (!pcpui->owning_proc) {
149                                 TAILQ_REMOVE(&runnable_scps, p, proc_link);
150                                 printd("PID of the SCP i'm running: %d\n", p->pid);
151                                 proc_run_s(p);  /* gives it core we're running on */
152                                 proc_decref(p);
153                         }
154                         break;
155                 }
156         }
157         spin_unlock(&sched_lock);
158 }
159
160 /* A process is asking the ksched to look at its resource desires.  The
161  * scheduler is free to ignore this, for its own reasons, so long as it
162  * eventually gets around to looking at resource desires. */
163 void poke_ksched(struct proc *p, int res_type)
164 {
165         /* TODO: probably want something to trigger all res_types */
166         /* Consider races with core_req called from other pokes or schedule */
167         switch (res_type) {
168                 case RES_CORES:
169                         /* ignore core requests from non-mcps (note we have races if we ever
170                          * allow procs to switch back). */
171                         if (!__proc_is_mcp(p))
172                                 break;
173                         /* TODO: issues with whether or not they are RUNNING.  Need to
174                          * change core_request / give_cores. */
175                         core_request(p);
176                         break;
177                 default:
178                         break;
179         }
180 }
181
182 /* Helper function to return a core to the idlemap.  It causes some more lock
183  * acquisitions (like in a for loop), but it's a little easier.  Plus, one day
184  * we might be able to do this without locks (for the putting). */
185 void put_idle_core(uint32_t coreid)
186 {
187         spin_lock(&idle_lock);
188         idlecoremap[num_idlecores++] = coreid;
189         spin_unlock(&idle_lock);
190 }
191
192 /* Normally it'll be the max number of CG cores ever */
193 uint32_t max_vcores(struct proc *p)
194 {
195 #ifdef __CONFIG_DISABLE_SMT__
196         return num_cpus >> 1;
197 #else
198         return MAX(1, num_cpus - num_mgmtcores);
199 #endif /* __CONFIG_DISABLE_SMT__ */
200 }
201
202 /* Ghetto old interface, hacked out of resource.c.  It doesn't even care about
203  * the proc yet, but in general the whole core_request bit needs reworked. */
204 uint32_t proc_wants_cores(struct proc *p, uint32_t *pc_arr, uint32_t amt_new)
205 {
206         uint32_t num_granted;
207         /* You should do something smarter than just giving the stuff out.  Like
208          * take in to account priorities, node locations, etc */
209         spin_lock(&idle_lock);
210         if (num_idlecores >= amt_new) {
211                 for (int i = 0; i < amt_new; i++) {
212                         // grab the last one on the list
213                         pc_arr[i] = idlecoremap[num_idlecores - 1];
214                         num_idlecores--;
215                 }
216                 num_granted = amt_new;
217         } else {
218                 /* In this case, you might want to preempt or do other fun things... */
219                 num_granted = 0;
220         }
221         spin_unlock(&idle_lock);
222         return num_granted;
223 }
224
225 /************** Debugging **************/
226 void sched_diag(void)
227 {
228         struct proc *p;
229         TAILQ_FOREACH(p, &runnable_scps, proc_link)
230                 printk("_S PID: %d\n", p->pid);
231         TAILQ_FOREACH(p, &all_mcps, proc_link)
232                 printk("MCP PID: %d\n", p->pid);
233         return;
234 }
235
236 void print_idlecoremap(void)
237 {
238         spin_lock(&idle_lock);
239         printk("There are %d idle cores.\n", num_idlecores);
240         for (int i = 0; i < num_idlecores; i++)
241                 printk("idlecoremap[%d] = %d\n", i, idlecoremap[i]);
242         spin_unlock(&idle_lock);
243 }