Moves retvals, start_routine, and args to the 2LSs
[akaros.git] / user / parlib / asynccall.c
1 #include <stdlib.h>
2
3 #include <ros/common.h>
4 #include <ros/syscall.h>
5 #include <ros/ring_syscall.h>
6 #include <ros/sysevent.h>
7 #include <arc.h>
8 #include <errno.h>
9 #include <arch/arch.h>
10 #include <sys/param.h>
11
12 syscall_front_ring_t syscallfrontring;
13 sysevent_back_ring_t syseventbackring;
14 syscall_desc_pool_t syscall_desc_pool;
15 async_desc_pool_t async_desc_pool;
16 async_desc_t* current_async_desc;
17
18 // use globals for now
19 void init_arc()
20 {
21         // Set up the front ring for the general syscall ring
22         // and the back ring for the general sysevent ring
23         // TODO: Reorganize these global variables
24         FRONT_RING_INIT(&syscallfrontring, &(__procdata.syscallring), SYSCALLRINGSIZE);
25         BACK_RING_INIT(&syseventbackring, &(__procdata.syseventring), SYSEVENTRINGSIZE);
26         POOL_INIT(&syscall_desc_pool, MAX_SYSCALLS);
27         POOL_INIT(&async_desc_pool, MAX_ASYNCCALLS);
28         sys_init_arsc();
29
30
31 }
32 // Wait on all syscalls within this async call.  TODO - timeout or something?
33 int waiton_async_call(async_desc_t* desc, async_rsp_t* rsp)
34 {
35         syscall_rsp_t syscall_rsp;
36         syscall_desc_t* d;
37         int err = 0;
38         if (!desc) {
39                 errno = EINVAL;
40                 return -1;
41         }
42
43         while (!(TAILQ_EMPTY(&desc->syslist))) {
44                 d = TAILQ_FIRST(&desc->syslist);
45                 err = waiton_syscall(d, &syscall_rsp);
46                 // TODO: processing the retval out of rsp here.  might be specific to
47                 // the async call.  do we want to accumulate?  return any negative
48                 // values?  depends what we want from the return value, so we might
49                 // have to pass in a function that is used to do the processing and
50                 // pass the answer back out in rsp.
51                 //rsp->retval += syscall_rsp.retval; // For example
52                 rsp->retval = MIN(rsp->retval, syscall_rsp.retval);
53                 // remove from the list and free the syscall desc
54                 TAILQ_REMOVE(&desc->syslist, d, next);
55                 POOL_PUT(&syscall_desc_pool, d);
56         }
57         // run a cleanup function for this desc, if available
58         if (desc->cleanup)
59                 desc->cleanup(desc->data);
60         // free the asynccall desc
61         POOL_PUT(&async_desc_pool, desc);
62         return err;
63 }
64
65 // Finds a free async_desc_t, on which you can wait for a series of syscalls
66 async_desc_t* get_async_desc(void)
67 {
68         async_desc_t* desc = POOL_GET(&async_desc_pool);
69         if (desc) {
70                 // Clear out any data that was in the old desc
71                 memset(desc, 0, sizeof(*desc));
72                 TAILQ_INIT(&desc->syslist);
73         }
74         return desc;
75 }
76
77 // Finds a free sys_desc_t, on which you can wait for a specific syscall, and
78 // binds it to the group desc.
79 syscall_desc_t* get_sys_desc(async_desc_t* desc)
80 {
81         syscall_desc_t* d = POOL_GET(&syscall_desc_pool);
82         if (d) {
83                 // Clear out any data that was in the old desc
84                 memset(d, 0, sizeof(*d));
85         TAILQ_INSERT_TAIL(&desc->syslist, d, next);
86         }
87         return d;
88 }
89
90 // Gets an async and a sys desc, with the sys bound to async.  Also sets
91 // current_async_desc.  This is meant as an easy wrapper when there is only one
92 // syscall for an async call.
93 int get_all_desc(async_desc_t** a_desc, syscall_desc_t** s_desc)
94 {
95         assert(a_desc && s_desc);
96         if ((current_async_desc = get_async_desc()) == NULL){
97                 errno = EBUSY;
98                 return -1;
99         }
100         *a_desc = current_async_desc;
101         if ((*s_desc = get_sys_desc(current_async_desc)))
102                 return 0;
103         // in case we could get an async, but not a syscall desc, then clean up.
104         POOL_PUT(&async_desc_pool, current_async_desc);
105         current_async_desc = NULL;
106         errno = EBUSY;
107         return -1;
108 }
109
110 // This runs one syscall instead of a group. 
111 int async_syscall(syscall_req_t* req, syscall_desc_t* desc)
112 {
113         // Note that this assumes one global frontring (TODO)
114         // abort if there is no room for our request.  ring size is currently 64.
115         // we could spin til it's free, but that could deadlock if this same thread
116         // is supposed to consume the requests it is waiting on later.
117         if (RING_FULL(&syscallfrontring)) {
118                 errno = EBUSY;
119                 return -1;
120         }
121         // req_prod_pvt comes in as the previously produced item.  need to
122         // increment to the next available spot, which is the one we'll work on.
123         // at some point, we need to listen for the responses.
124         desc->idx = ++(syscallfrontring.req_prod_pvt);
125         desc->sysfr = &syscallfrontring;
126         syscall_req_t* r = RING_GET_REQUEST(&syscallfrontring, desc->idx);
127         memcpy(r, req, sizeof(syscall_req_t));
128         // push our updates to syscallfrontring.req_prod_pvt
129         RING_PUSH_REQUESTS(&syscallfrontring);
130         //cprintf("DEBUG: sring->req_prod: %d, sring->rsp_prod: %d\n", 
131         //   syscallfrontring.sring->req_prod, syscallfrontring.sring->rsp_prod);
132         return 0;
133 }
134
135 // consider a timeout too
136 int waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
137 {
138         // Make sure we were given a desc with a non-NULL frontring.  This could
139         // happen if someone forgot to check the error code on the paired syscall.
140         if (!desc->sysfr){
141                 errno = EFAIL;
142                 return -1;
143         }
144         // this forces us to call wait in the order in which the syscalls are made.
145         if (desc->idx != desc->sysfr->rsp_cons + 1){
146                 errno = EDEADLOCK;
147                 return -1;
148         }
149         while (!(RING_HAS_UNCONSUMED_RESPONSES(desc->sysfr)))
150                 cpu_relax();
151         memcpy(rsp, RING_GET_RESPONSE(desc->sysfr, desc->idx), sizeof(*rsp));
152         desc->sysfr->rsp_cons++;
153     // run a cleanup function for this desc, if available
154     if (desc->cleanup)
155         desc->cleanup(desc->data);
156         if (rsp->syserr){
157                 errno = rsp->syserr;
158                 return -1;
159         } else 
160                 return 0;
161 }
162
163