7487556d5157cfa1d4ec61e6e7ca69fa76e43749
[akaros.git] / kern / src / arsc.c
1 /* See COPYRIGHT for copyright information. */
2
3 #ifdef __SHARC__
4 #pragma nosharc
5 #endif
6
7
8 #include <ros/common.h>
9 #include <ros/ring_syscall.h>
10 #include <arch/types.h>
11 #include <arch/arch.h>
12 #include <arch/mmu.h>
13 #include <error.h>
14
15 #include <syscall.h>
16 #include <kmalloc.h>
17 #include <pmap.h>
18 #include <stdio.h>
19 #include <hashtable.h>
20 #include <smp.h>
21 #include <arsc_server.h>
22 #include <kref.h>
23
24
25
26 struct proc_list arsc_proc_list = TAILQ_HEAD_INITIALIZER(arsc_proc_list);
27 spinlock_t arsc_proc_lock = SPINLOCK_INITIALIZER;
28
29 intreg_t inline syscall_async(struct proc *p, syscall_req_t *call)
30 {
31         return syscall(p, call->num, call->args[0], call->args[1],
32                        call->args[2], call->args[3], call->args[4], call->args[5]);
33 }
34
35 intreg_t sys_init_arsc(struct proc *p)
36 {
37         kref_get(&p->kref, 1);          /* we're storing an external ref here */
38         spin_lock_irqsave(&arsc_proc_lock);
39         TAILQ_INSERT_TAIL(&arsc_proc_list, p, proc_arsc_link);
40         spin_unlock_irqsave(&arsc_proc_lock);
41         return ESUCCESS;
42 }
43
44 void arsc_server(struct trapframe *tf)
45 {
46         struct proc *p = NULL;
47         TAILQ_INIT(&arsc_proc_list);
48         while (1) {
49                 while (TAILQ_EMPTY(&arsc_proc_list))
50                         cpu_relax();
51
52                 TAILQ_FOREACH(p, &arsc_proc_list, proc_link) {
53                         /* Probably want to try to process a dying process's syscalls.  If
54                          * not, just move it to an else case */
55                         process_generic_syscalls (p, MAX_ASRC_BATCH); 
56                         if (p->state == PROC_DYING) {
57                                 TAILQ_REMOVE(&arsc_proc_list, p, proc_arsc_link);
58                                 kref_put(&p->kref);
59                                 /* Need to break out, so the TAILQ_FOREACH doesn't flip out.
60                                  * It's not fair, but we're not dealing with that yet anyway */
61                                 break;
62                         }
63                 }
64         }
65 }
66
67 static intreg_t process_generic_syscalls(struct proc *p, size_t max)
68 {
69         size_t count = 0;
70         syscall_back_ring_t* sysbr = &p->syscallbackring;
71         struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
72         // looking at a process not initialized to perform arsc. 
73         if (sysbr == NULL) 
74                 return count;
75
76         // max is the most we'll process.  max = 0 means do as many as possible
77         // TODO: check for initialization of the ring. 
78         while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max)) ) {
79                 if (!count) {
80                         // ASSUME: one queue per process
81                         // only switch cr3 for the very first request for this queue
82                         // need to switch to the right context, so we can handle the user pointer
83                         // that points to a data payload of the syscall
84                         lcr3(p->env_cr3);
85                 }
86                 count++;
87                 //printk("DEBUG PRE: sring->req_prod: %d, sring->rsp_prod: %d\n",
88                 //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
89                 // might want to think about 0-ing this out, if we aren't
90                 // going to explicitly fill in all fields
91                 syscall_rsp_t rsp;
92                 // this assumes we get our answer immediately for the syscall.
93                 syscall_req_t* req = RING_GET_REQUEST(sysbr, ++(sysbr->req_cons));
94                 // print req
95                 printd("req no %d, req arg %c\n", req->num, *((char*)req->args[0]));
96                 
97                 /* TODO: when the remote syscall stuff can handle the new async
98                  * syscalls, they need to use a real sysc.  This might at least stop it
99                  * from crashing. */
100                 struct syscall sysc = {0};
101                 coreinfo->cur_sysc = &sysc;
102                 
103                 rsp.retval = syscall_async(p, req);
104                 rsp.syserr = sysc.err;
105                 // write response into the slot it came from
106                 memcpy(req, &rsp, sizeof(syscall_rsp_t));
107                 // update our counter for what we've produced (assumes we went in order!)
108                 (sysbr->rsp_prod_pvt)++;
109                 RING_PUSH_RESPONSES(sysbr);
110                 //printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n",
111                 //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
112         }
113         // load sane page tables (and don't rely on decref to do it for you).
114         lcr3(boot_cr3);
115         return (intreg_t)count;
116 }
117