Rev 1443 | Rev 1489 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1443 | Rev 1463 | ||
---|---|---|---|
Line 33... | Line 33... | ||
33 | #include <libadt/list.h> |
33 | #include <libadt/list.h> |
34 | #include <stdio.h> |
34 | #include <stdio.h> |
35 | #include <unistd.h> |
35 | #include <unistd.h> |
36 | #include <futex.h> |
36 | #include <futex.h> |
37 | #include <kernel/synch/synch.h> |
37 | #include <kernel/synch/synch.h> |
- | 38 | #include <async.h> |
|
- | 39 | #include <psthread.h> |
|
38 | 40 | ||
39 | /** Structure used for keeping track of sent async msgs |
41 | /** Structure used for keeping track of sent async msgs |
40 | * and queing unsent msgs |
42 | * and queing unsent msgs |
41 | * |
43 | * |
42 | */ |
44 | */ |
Line 50... | Line 52... | ||
50 | struct { |
52 | struct { |
51 | ipc_call_t data; |
53 | ipc_call_t data; |
52 | int phoneid; |
54 | int phoneid; |
53 | } msg; |
55 | } msg; |
54 | }u; |
56 | }u; |
- | 57 | pstid_t ptid; /**< Thread waiting for sending this msg */ |
|
55 | } async_call_t; |
58 | } async_call_t; |
56 | 59 | ||
57 | LIST_INITIALIZE(dispatched_calls); |
60 | LIST_INITIALIZE(dispatched_calls); |
- | 61 | ||
- | 62 | /* queued_calls is protcted by async_futex, because if the |
|
- | 63 | * call cannot be sent into kernel, async framework is used |
|
- | 64 | * automatically |
|
- | 65 | */ |
|
58 | LIST_INITIALIZE(queued_calls); |
66 | LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted |
- | 67 | * by kernel */ |
|
59 | 68 | ||
60 | static atomic_t ipc_futex = FUTEX_INITIALIZER; |
69 | static atomic_t ipc_futex = FUTEX_INITIALIZER; |
61 | 70 | ||
62 | int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, |
71 | int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, |
63 | ipcarg_t *result) |
72 | ipcarg_t *result) |
Line 123... | Line 132... | ||
123 | if (callback) |
132 | if (callback) |
124 | callback(private, ENOMEM, NULL); |
133 | callback(private, ENOMEM, NULL); |
125 | return; |
134 | return; |
126 | } |
135 | } |
127 | 136 | ||
- | 137 | call->callback = callback; |
|
- | 138 | call->private = private; |
|
- | 139 | ||
- | 140 | /* We need to make sure that we get callid before |
|
- | 141 | * another thread accesses the queue again */ |
|
- | 142 | futex_down(&ipc_futex); |
|
128 | callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2); |
143 | callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2); |
129 | if (callid == IPC_CALLRET_FATAL) { |
144 | if (callid == IPC_CALLRET_FATAL) { |
- | 145 | futex_up(&ipc_futex); |
|
130 | /* Call asynchronous handler with error code */ |
146 | /* Call asynchronous handler with error code */ |
131 | if (callback) |
147 | if (callback) |
132 | callback(private, ENOENT, NULL); |
148 | callback(private, ENOENT, NULL); |
133 | free(call); |
149 | free(call); |
134 | return; |
150 | return; |
135 | } |
151 | } |
136 | 152 | ||
137 | call->callback = callback; |
- | |
138 | call->private = private; |
- | |
139 | - | ||
140 | if (callid == IPC_CALLRET_TEMPORARY) { |
153 | if (callid == IPC_CALLRET_TEMPORARY) { |
141 | /* Add asynchronous call to queue of non-dispatched async calls */ |
154 | futex_up(&ipc_futex); |
- | 155 | ||
142 | call->u.msg.phoneid = phoneid; |
156 | call->u.msg.phoneid = phoneid; |
143 | IPC_SET_METHOD(call->u.msg.data, method); |
157 | IPC_SET_METHOD(call->u.msg.data, method); |
144 | IPC_SET_ARG1(call->u.msg.data, arg1); |
158 | IPC_SET_ARG1(call->u.msg.data, arg1); |
145 | IPC_SET_ARG2(call->u.msg.data, arg2); |
159 | IPC_SET_ARG2(call->u.msg.data, arg2); |
146 | 160 | ||
- | 161 | call->ptid = psthread_get_id(); |
|
147 | futex_down(&ipc_futex); |
162 | futex_down(&async_futex); |
148 | list_append(&call->list, &queued_calls); |
163 | list_append(&call->list, &queued_calls); |
- | 164 | ||
149 | futex_up(&ipc_futex); |
165 | psthread_schedule_next_adv(PS_TO_MANAGER); |
- | 166 | /* Async futex unlocked by previous call */ |
|
150 | return; |
167 | return; |
151 | } |
168 | } |
152 | call->u.callid = callid; |
169 | call->u.callid = callid; |
153 | /* Add call to list of dispatched calls */ |
170 | /* Add call to list of dispatched calls */ |
154 | futex_down(&ipc_futex); |
- | |
155 | list_append(&call->list, &dispatched_calls); |
171 | list_append(&call->list, &dispatched_calls); |
156 | futex_up(&ipc_futex); |
172 | futex_up(&ipc_futex); |
157 | } |
173 | } |
158 | 174 | ||
159 | 175 | ||
Line 192... | Line 208... | ||
192 | static void try_dispatch_queued_calls(void) |
208 | static void try_dispatch_queued_calls(void) |
193 | { |
209 | { |
194 | async_call_t *call; |
210 | async_call_t *call; |
195 | ipc_callid_t callid; |
211 | ipc_callid_t callid; |
196 | 212 | ||
- | 213 | /* TODO: integrate intelligently ipc_futex, so that it |
|
- | 214 | * is locked during ipc_call_async, until it is added |
|
- | 215 | * to dispatched_calls |
|
- | 216 | */ |
|
197 | futex_down(&ipc_futex); |
217 | futex_down(&async_futex); |
198 | while (!list_empty(&queued_calls)) { |
218 | while (!list_empty(&queued_calls)) { |
199 | call = list_get_instance(queued_calls.next, async_call_t, |
219 | call = list_get_instance(queued_calls.next, async_call_t, |
200 | list); |
220 | list); |
201 | 221 | ||
202 | callid = _ipc_call_async(call->u.msg.phoneid, |
222 | callid = _ipc_call_async(call->u.msg.phoneid, |
203 | &call->u.msg.data); |
223 | &call->u.msg.data); |
204 | if (callid == IPC_CALLRET_TEMPORARY) |
224 | if (callid == IPC_CALLRET_TEMPORARY) { |
205 | break; |
225 | break; |
- | 226 | } |
|
206 | list_remove(&call->list); |
227 | list_remove(&call->list); |
207 | 228 | ||
- | 229 | futex_up(&async_futex); |
|
- | 230 | psthread_add_ready(call->ptid); |
|
- | 231 | ||
208 | if (callid == IPC_CALLRET_FATAL) { |
232 | if (callid == IPC_CALLRET_FATAL) { |
209 | futex_up(&ipc_futex); |
- | |
210 | if (call->callback) |
233 | if (call->callback) |
211 | call->callback(call->private, ENOENT, NULL); |
234 | call->callback(call->private, ENOENT, NULL); |
212 | free(call); |
235 | free(call); |
213 | futex_down(&ipc_futex); |
- | |
214 | } else { |
236 | } else { |
215 | call->u.callid = callid; |
237 | call->u.callid = callid; |
- | 238 | futex_down(&ipc_futex); |
|
216 | list_append(&call->list, &dispatched_calls); |
239 | list_append(&call->list, &dispatched_calls); |
- | 240 | futex_up(&ipc_futex); |
|
217 | } |
241 | } |
- | 242 | futex_down(&async_futex); |
|
218 | } |
243 | } |
219 | futex_up(&ipc_futex); |
244 | futex_up(&async_futex); |
220 | } |
245 | } |
221 | 246 | ||
222 | /** Handle received answer |
247 | /** Handle received answer |
223 | * |
248 | * |
224 | * TODO: Make it use hash table |
249 | * TODO: Make it use hash table |
Line 262... | Line 287... | ||
262 | */ |
287 | */ |
263 | ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags) |
288 | ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags) |
264 | { |
289 | { |
265 | ipc_callid_t callid; |
290 | ipc_callid_t callid; |
266 | 291 | ||
267 | try_dispatch_queued_calls(); |
- | |
268 | - | ||
269 | callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags); |
292 | callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags); |
270 | /* Handle received answers */ |
293 | /* Handle received answers */ |
271 | if (callid & IPC_CALLID_ANSWERED) |
294 | if (callid & IPC_CALLID_ANSWERED) { |
272 | handle_answer(callid, call); |
295 | handle_answer(callid, call); |
- | 296 | try_dispatch_queued_calls(); |
|
- | 297 | } |
|
273 | 298 | ||
274 | return callid; |
299 | return callid; |
275 | } |
300 | } |
276 | 301 | ||
277 | /** Wait some time for an IPC call. |
302 | /** Wait some time for an IPC call. |