27168b438ba33d0fa2bc0717e40a35ed1ad90739
[akaros.git] / kern / src / resource.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  *
6  * Kernel resource management.
7  */
8
9 #ifdef __IVY__
10 #pragma nosharc
11 #endif
12
13 #include <resource.h>
14 #include <process.h>
15 #include <smp.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <schedule.h>
19 #include <hashtable.h>
20
21 /* This deals with a request for more cores.  The request is already stored in
22  * the proc's amt_wanted (it is compared to amt_granted). 
23  *
24  * It doesn't take the amount requested directly to avoid a race (or holding the
25  * proc_lock across the call), and allowing it to be called in other situations,
26  * such as if there was not a new request, but it's time to look at the
27  * difference between amt_wanted and amt_granted (maybe on a timer interrupt).
28  *
29  * Will return either the number actually granted or an error code.  This will
30  * not decrease the actual amount of cores (e.g. from 5 to 2), but it will
31  * transition a process from _M to _S (amt_wanted == 0).
32  *
33  * This needs a consumable/edible reference of p, in case it doesn't return.
34  */
35 bool core_request(struct proc *p)
36 {
37         uint32_t num_granted, amt_new, amt_wanted, amt_granted;
38         uint32_t corelist[MAX_NUM_CPUS]; /* TODO UGH, this could be huge! */
39
40         /* Currently, this is all locked, and there's a variety of races involved,
41          * esp with moving amt_wanted to procdata (TODO).  Will probably want to
42          * copy-in amt_wanted too. */
43         spin_lock(&p->proc_lock);
44         amt_wanted = p->procdata->res_req[RES_CORES].amt_wanted;
45         amt_granted = p->procinfo->res_grant[RES_CORES];
46
47         /* Help them out - if they ask for something impossible, give them 1 so they
48          * can make some progress. (these two are racy). */
49         if (amt_wanted > p->procinfo->max_vcores) {
50                 p->procdata->res_req[RES_CORES].amt_wanted = 1;
51         }
52         /* TODO: sort how this works with WAITING. */
53         if (!amt_wanted) {
54                 p->procdata->res_req[RES_CORES].amt_wanted = 1;
55         }
56         /* if they are satisfied, we're done.  There's a slight chance they have
57          * cores, but they aren't running (sched gave them cores while they were
58          * yielding, and now we see them on the run queue). */
59         if (amt_wanted <= amt_granted) {
60                 if (amt_granted) {
61                         spin_unlock(&p->proc_lock);
62                         return TRUE;
63                 } else {
64                         spin_unlock(&p->proc_lock);
65                         return FALSE;
66                 }
67         }
68         /* otherwise, see what they want.  Current models are simple - it's just a
69          * raw number of cores, and we just give out what we can. */
70         amt_new = amt_wanted - amt_granted;
71         /* TODO: Could also consider amt_min */
72
73         /* TODO: change this.  this function is really "find me amt_new cores", the
74          * nature of this info depends on how we express desires, and a lot of that
75          * info could be lost through this interface. */
76         num_granted = proc_wants_cores(p, corelist, amt_new);
77
78         /* Now, actually give them out */
79         if (num_granted) {
80                 /* give them the cores.  this will start up the extras if RUNNING_M. */
81                 __proc_give_cores(p, corelist, num_granted);
82                 /* at some point after giving cores, call proc_run_m() (harmless on
83                  * RUNNING_Ms).  You can give small groups of cores, then run them
84                  * (which is more efficient than interleaving runs with the gives for
85                  * bulk preempted processes). */
86                 __proc_run_m(p); /* harmless to call this on RUNNING_Ms */
87                 spin_unlock(&p->proc_lock);
88                 return TRUE;    /* proc can run (if it isn't already) */
89         }
90         spin_unlock(&p->proc_lock);
91         return FALSE;           /* Not giving them anything more */
92 }
93
94 error_t resource_req(struct proc *p, int type, size_t amt_wanted,
95                      size_t amt_wanted_min, uint32_t flags)
96 {
97         error_t retval;
98         printd("Received request for type: %d, amt_wanted: %d, amt_wanted_min: %d, "
99                "flag: %d\n", type, amt_wanted, amt_wanted_min, flags);
100         if (flags & REQ_ASYNC)
101                 // We have no sense of time yet, or of half-filling requests
102                 printk("[kernel] Async requests treated synchronously for now.\n");
103
104         switch (type) {
105                 case RES_CORES:
106                         return -EFAIL;
107                         break;
108                 case RES_MEMORY:
109                         // not clear if we should be in RUNNABLE_M or not
110                         printk("[kernel] Memory requests are not implemented.\n");
111                         return -EFAIL;
112                         break;
113                 case RES_APPLE_PIES:
114                         printk("You can have all the apple pies you want.\n");
115                         break;
116                 default:
117                         printk("[kernel] Unknown resource!  No oranges for you!\n");
118                         return -EINVAL;
119         }
120         return 0;
121 }
122
123 void print_resources(struct proc *p)
124 {
125         printk("--------------------\n");
126         printk("PID: %d\n", p->pid);
127         printk("--------------------\n");
128         for (int i = 0; i < MAX_NUM_RESOURCES; i++)
129                 printk("Res type: %02d, amt wanted: %08d, amt granted: %08d\n", i,
130                        p->procdata->res_req[i].amt_wanted, p->procinfo->res_grant[i]);
131 }
132
133 void print_all_resources(void)
134 {
135         /* Hash helper */
136         void __print_resources(void *item)
137         {
138                 print_resources((struct proc*)item);
139         }
140         spin_lock(&pid_hash_lock);
141         hash_for_each(pid_hash, __print_resources);
142         spin_unlock(&pid_hash_lock);
143 }