proc_run() now returns
[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->resources[RES_CORES].amt_wanted;
45         amt_granted = p->resources[RES_CORES].amt_granted;      /* aka, num_vcores */
46
47         /* Help them out - if they ask for something impossible, give them 1 so they
48          * can make some progress. */
49         if (amt_wanted > p->procinfo->max_vcores) {
50                 p->resources[RES_CORES].amt_wanted = 1;
51         }
52         /* TODO: sort how this works with WAITING. */
53         if (!amt_wanted) {
54                 p->resources[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                 spin_unlock(&p->proc_lock);
83                 return TRUE;    /* proc can run (if it isn't already) */
84         }
85         spin_unlock(&p->proc_lock);
86         return FALSE;           /* Not giving them anything more */
87 }
88
89 error_t resource_req(struct proc *p, int type, size_t amt_wanted,
90                      size_t amt_wanted_min, uint32_t flags)
91 {
92         error_t retval;
93         printd("Received request for type: %d, amt_wanted: %d, amt_wanted_min: %d, "
94                "flag: %d\n", type, amt_wanted, amt_wanted_min, flags);
95         if (flags & REQ_ASYNC)
96                 // We have no sense of time yet, or of half-filling requests
97                 printk("[kernel] Async requests treated synchronously for now.\n");
98
99         /* set the desired resource amount in the process's resource list. */
100         spin_lock(&p->proc_lock);
101         size_t old_amount = p->resources[type].amt_wanted;
102         p->resources[type].amt_wanted = amt_wanted;
103         p->resources[type].amt_wanted_min = MIN(amt_wanted_min, amt_wanted);
104         p->resources[type].flags = flags;
105         spin_unlock(&p->proc_lock);
106
107         switch (type) {
108                 case RES_CORES:
109                         spin_lock(&p->proc_lock);
110                         if (p->state == PROC_RUNNING_S) {
111                                 __proc_switch_to_m(p);  /* will later be a separate syscall */
112                                 schedule_proc(p);
113                                 spin_unlock(&p->proc_lock);
114                         } else {
115                                 /* _M */
116                                 spin_unlock(&p->proc_lock);
117                                 poke_ksched(p, RES_CORES); /* will be a separate syscall */
118                         }
119                         return 0;
120                         break;
121                 case RES_MEMORY:
122                         // not clear if we should be in RUNNABLE_M or not
123                         printk("[kernel] Memory requests are not implemented.\n");
124                         return -EFAIL;
125                         break;
126                 case RES_APPLE_PIES:
127                         printk("You can have all the apple pies you want.\n");
128                         break;
129                 default:
130                         printk("[kernel] Unknown resource!  No oranges for you!\n");
131                         return -EINVAL;
132         }
133         return 0;
134 }
135
136 void print_resources(struct proc *p)
137 {
138         printk("--------------------\n");
139         printk("PID: %d\n", p->pid);
140         printk("--------------------\n");
141         for (int i = 0; i < MAX_NUM_RESOURCES; i++)
142                 printk("Res type: %02d, amt wanted: %08d, amt granted: %08d\n", i,
143                        p->resources[i].amt_wanted, p->resources[i].amt_granted);
144 }
145
146 void print_all_resources(void)
147 {
148         /* Hash helper */
149         void __print_resources(void *item)
150         {
151                 print_resources((struct proc*)item);
152         }
153         spin_lock(&pid_hash_lock);
154         hash_for_each(pid_hash, __print_resources);
155         spin_unlock(&pid_hash_lock);
156 }