source: mainline/libc/generic/ipc.c@ aa0609b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since aa0609b was 7ee6aff, checked in by Ondrej Palkovsky <ondrap@…>, 19 years ago

Fixed not compiling uspace after libipc merge.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Copyright (C) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <ipc/ipc.h>
30#include <libc.h>
31#include <malloc.h>
32#include <errno.h>
33#include <libadt/list.h>
34#include <stdio.h>
35#include <unistd.h>
36#include <futex.h>
37
38/** Structure used for keeping track of sent async msgs
39 * and queing unsent msgs
40 *
41 */
42typedef struct {
43 link_t list;
44
45 ipc_async_callback_t callback;
46 void *private;
47 union {
48 ipc_callid_t callid;
49 struct {
50 ipc_call_t data;
51 int phoneid;
52 } msg;
53 }u;
54} async_call_t;
55
56LIST_INITIALIZE(dispatched_calls);
57LIST_INITIALIZE(queued_calls);
58
59static atomic_t ipc_futex;
60
61void _ipc_init(void)
62{
63 futex_initialize(&ipc_futex, 1);
64}
65
66int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
67 ipcarg_t *result)
68{
69 ipc_call_t resdata;
70 int callres;
71
72 callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
73 (sysarg_t)&resdata);
74 if (callres)
75 return callres;
76 if (result)
77 *result = IPC_GET_ARG1(resdata);
78 return IPC_GET_RETVAL(resdata);
79}
80
81int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
82 ipcarg_t arg2, ipcarg_t arg3,
83 ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
84{
85 ipc_call_t data;
86 int callres;
87
88 IPC_SET_METHOD(data, method);
89 IPC_SET_ARG1(data, arg1);
90 IPC_SET_ARG2(data, arg2);
91 IPC_SET_ARG3(data, arg3);
92
93 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t)&data,
94 (sysarg_t)&data);
95 if (callres)
96 return callres;
97
98 if (result1)
99 *result1 = IPC_GET_ARG1(data);
100 if (result2)
101 *result2 = IPC_GET_ARG2(data);
102 if (result3)
103 *result3 = IPC_GET_ARG3(data);
104 return IPC_GET_RETVAL(data);
105}
106
107/** Syscall to send asynchronous message */
108static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
109{
110 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t)data);
111}
112
113/** Send asynchronous message
114 *
115 * - if fatal error, call callback handler with proper error code
116 * - if message cannot be temporarily sent, add to queue
117 */
118void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
119 ipcarg_t arg2, void *private,
120 ipc_async_callback_t callback)
121{
122 async_call_t *call;
123 ipc_callid_t callid;
124
125 call = malloc(sizeof(*call));
126 if (!call) {
127 callback(private, ENOMEM, NULL);
128 return;
129 }
130
131 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2);
132 if (callid == IPC_CALLRET_FATAL) {
133 /* Call asynchronous handler with error code */
134 callback(private, ENOENT, NULL);
135 free(call);
136 return;
137 }
138
139 call->callback = callback;
140 call->private = private;
141
142 if (callid == IPC_CALLRET_TEMPORARY) {
143 /* Add asynchronous call to queue of non-dispatched async calls */
144 call->u.msg.phoneid = phoneid;
145 IPC_SET_METHOD(call->u.msg.data, method);
146 IPC_SET_ARG1(call->u.msg.data, arg1);
147 IPC_SET_ARG2(call->u.msg.data, arg2);
148
149 futex_down(&ipc_futex);
150 list_append(&call->list, &queued_calls);
151 futex_up(&ipc_futex);
152 return;
153 }
154 call->u.callid = callid;
155 /* Add call to list of dispatched calls */
156 futex_down(&ipc_futex);
157 list_append(&call->list, &dispatched_calls);
158 futex_up(&ipc_futex);
159}
160
161
162/** Send a fast answer to a received call.
163 *
164 * The fast answer makes use of passing retval and first two arguments in registers.
165 * If you need to return more, use the ipc_answer() instead.
166 *
167 * @param callid ID of the call being answered.
168 * @param retval Return value.
169 * @param arg1 First return argument.
170 * @param arg2 Second return argument.
171 *
172 * @return Zero on success or a value from @ref errno.h on failure.
173 */
174ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
175 ipcarg_t arg2)
176{
177 return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2);
178}
179
180/** Send a full answer to a received call.
181 *
182 * @param callid ID of the call being answered.
183 * @param call Call data. Must be already initialized by the responder.
184 *
185 * @return Zero on success or a value from @ref errno.h on failure.
186 */
187ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call)
188{
189 return __SYSCALL2(SYS_IPC_ANSWER, callid, (sysarg_t) call);
190}
191
192
193/** Try to dispatch queed calls from async queue */
194static void try_dispatch_queued_calls(void)
195{
196 async_call_t *call;
197 ipc_callid_t callid;
198
199 futex_down(&ipc_futex);
200 while (!list_empty(&queued_calls)) {
201 call = list_get_instance(queued_calls.next, async_call_t,
202 list);
203
204 callid = _ipc_call_async(call->u.msg.phoneid,
205 &call->u.msg.data);
206 if (callid == IPC_CALLRET_TEMPORARY)
207 break;
208 list_remove(&call->list);
209
210 if (callid == IPC_CALLRET_FATAL) {
211 futex_up(&ipc_futex);
212 call->callback(call->private, ENOENT, NULL);
213 free(call);
214 futex_down(&ipc_futex);
215 } else {
216 call->u.callid = callid;
217 list_append(&call->list, &dispatched_calls);
218 }
219 }
220 futex_up(&ipc_futex);
221}
222
223/** Handle received answer
224 *
225 * TODO: Make it use hash table
226 *
227 * @param callid Callid (with first bit set) of the answered call
228 */
229static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
230{
231 link_t *item;
232 async_call_t *call;
233
234 callid &= ~IPC_CALLID_ANSWERED;
235
236 futex_down(&ipc_futex);
237 for (item = dispatched_calls.next; item != &dispatched_calls;
238 item = item->next) {
239 call = list_get_instance(item, async_call_t, list);
240 if (call->u.callid == callid) {
241 list_remove(&call->list);
242 futex_up(&ipc_futex);
243 call->callback(call->private,
244 IPC_GET_RETVAL(*data),
245 data);
246 return;
247 }
248 }
249 futex_up(&ipc_futex);
250 printf("Received unidentified answer: %P!!!\n", callid);
251}
252
253
254/** Wait for IPC call and return
255 *
256 * - dispatch ASYNC reoutines in the background
257 * @param data Space where the message is stored
258 * @return Callid or 0 if nothing available and started with
259 * IPC_WAIT_NONBLOCKING
260 */
261ipc_callid_t ipc_wait_for_call(ipc_call_t *call, int flags)
262{
263 ipc_callid_t callid;
264
265 do {
266 try_dispatch_queued_calls();
267
268 callid = __SYSCALL2(SYS_IPC_WAIT, (sysarg_t)call, flags);
269 /* Handle received answers */
270 if (callid & IPC_CALLID_ANSWERED)
271 handle_answer(callid, call);
272 } while (callid & IPC_CALLID_ANSWERED);
273
274 return callid;
275}
276
277/** Ask destination to do a callback connection
278 *
279 * @return 0 - OK, error code
280 */
281int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone)
282{
283 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1,
284 arg2, 0, 0, 0, phone);
285}
286
287/** Ask through phone for a new connection to some service
288 *
289 * @return new phoneid - OK, error code
290 */
291int ipc_connect_me_to(int phoneid, int arg1, int arg2)
292{
293 ipcarg_t newphid;
294 int res;
295
296 res = ipc_call_sync_3(phoneid, IPC_M_CONNECT_ME_TO, arg1,
297 arg2, 0, 0, 0, &newphid);
298 if (res)
299 return res;
300 return newphid;
301}
302
303/* Hang up specified phone */
304int ipc_hangup(int phoneid)
305{
306 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
307}
308
309int ipc_register_irq(int irq, irq_code_t *ucode)
310{
311 return __SYSCALL2(SYS_IPC_REGISTER_IRQ, irq, (sysarg_t) ucode);
312}
313
314int ipc_unregister_irq(int irq)
315{
316 return __SYSCALL1(SYS_IPC_UNREGISTER_IRQ, irq);
317}
318
319int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
320{
321 return __SYSCALL4(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1);
322}
323
324
325/** Open shared memory connection over specified phoneid
326 *
327 *
328 * Allocates AS_area, notify the other side about our intention
329 * to open the connection
330 *
331 * @return Connection id identifying this connection
332 */
333//int ipc_dgr_open(int pohoneid, size_t bufsize)
334//{
335 /* Find new file descriptor in local descriptor table */
336 /* Create AS_area, initialize structures */
337 /* Send AS to other side, handle error states */
338
339//}
340/*
341void ipc_dgr_close(int cid)
342{
343}
344
345void * ipc_dgr_alloc(int cid, size_t size)
346{
347}
348
349void ipc_dgr_free(int cid, void *area)
350{
351
352}
353
354int ipc_dgr_send(int cid, void *area)
355{
356}
357
358
359int ipc_dgr_send_data(int cid, void *data, size_t size)
360{
361}
362
363*/
Note: See TracBrowser for help on using the repository browser.