source: mainline/uspace/lib/c/generic/ipc.c@ 98cb5e0d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 98cb5e0d was 503ffce, checked in by Jakub Jermar <jakub@…>, 8 years ago

Return IPC_CALLID_* in call data instead of callid

Callid will be replaced by capability handles soon so the API needs
to be cleanup up and any flags passed together with callid must be
passed using some other way.

  • Property mode set to 100644
File size: 11.1 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * Copyright (c) 2017 Jakub Jermar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 * @}
33 */
34
35/** @addtogroup libcipc IPC
36 * @brief HelenOS uspace IPC
37 * @{
38 * @ingroup libc
39 */
40/** @file
41 */
42
43#include <ipc/ipc.h>
44#include <libc.h>
45#include <malloc.h>
46#include <errno.h>
47#include <adt/list.h>
48#include <futex.h>
49#include <fibril.h>
50#include <macros.h>
51
52/**
53 * Structures of this type are used for keeping track of sent asynchronous calls.
54 */
55typedef struct async_call {
56 ipc_async_callback_t callback;
57 void *private;
58
59 struct {
60 ipc_call_t data;
61 int phoneid;
62 } msg;
63} async_call_t;
64
65/** Prologue for ipc_call_async_*() functions.
66 *
67 * @param private Argument for the answer/error callback.
68 * @param callback Answer/error callback.
69 *
70 * @return New, partially initialized async_call structure or NULL.
71 *
72 */
73static inline async_call_t *ipc_prepare_async(void *private,
74 ipc_async_callback_t callback)
75{
76 async_call_t *call =
77 (async_call_t *) malloc(sizeof(async_call_t));
78 if (!call) {
79 if (callback)
80 callback(private, ENOMEM, NULL);
81
82 return NULL;
83 }
84
85 call->callback = callback;
86 call->private = private;
87
88 return call;
89}
90
91/** Epilogue for ipc_call_async_*() functions.
92 *
93 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
94 * @param phoneid Phone handle through which the call was made.
95 * @param call Structure returned by ipc_prepare_async().
96 */
97static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
98 async_call_t *call)
99{
100 if (!call) {
101 /* Nothing to do regardless if failed or not */
102 return;
103 }
104
105 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
106 /* Call asynchronous handler with error code */
107 if (call->callback)
108 call->callback(call->private, ENOENT, NULL);
109
110 free(call);
111 return;
112 }
113}
114
115/** Fast asynchronous call.
116 *
117 * This function can only handle three arguments of payload. It is, however,
118 * faster than the more generic ipc_call_async_slow().
119 *
120 * Note that this function is a void function.
121 *
122 * During normal operation, answering this call will trigger the callback.
123 * In case of fatal error, the callback handler is called with the proper
124 * error code. If the call cannot be temporarily made, it is queued.
125 *
126 * @param phoneid Phone handle for the call.
127 * @param imethod Requested interface and method.
128 * @param arg1 Service-defined payload argument.
129 * @param arg2 Service-defined payload argument.
130 * @param arg3 Service-defined payload argument.
131 * @param private Argument to be passed to the answer/error callback.
132 * @param callback Answer or error callback.
133 */
134void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
135 sysarg_t arg2, sysarg_t arg3, void *private, ipc_async_callback_t callback)
136{
137 async_call_t *call = ipc_prepare_async(private, callback);
138 if (!call)
139 return;
140
141 ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
142 imethod, arg1, arg2, arg3, (sysarg_t) call);
143
144 ipc_finish_async(callid, phoneid, call);
145}
146
147/** Asynchronous call transmitting the entire payload.
148 *
149 * Note that this function is a void function.
150 *
151 * During normal operation, answering this call will trigger the callback.
152 * In case of fatal error, the callback handler is called with the proper
153 * error code. If the call cannot be temporarily made, it is queued.
154 *
155 * @param phoneid Phone handle for the call.
156 * @param imethod Requested interface and method.
157 * @param arg1 Service-defined payload argument.
158 * @param arg2 Service-defined payload argument.
159 * @param arg3 Service-defined payload argument.
160 * @param arg4 Service-defined payload argument.
161 * @param arg5 Service-defined payload argument.
162 * @param private Argument to be passed to the answer/error callback.
163 * @param callback Answer or error callback.
164 */
165void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
166 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
167 ipc_async_callback_t callback)
168{
169 async_call_t *call = ipc_prepare_async(private, callback);
170 if (!call)
171 return;
172
173 IPC_SET_IMETHOD(call->msg.data, imethod);
174 IPC_SET_ARG1(call->msg.data, arg1);
175 IPC_SET_ARG2(call->msg.data, arg2);
176 IPC_SET_ARG3(call->msg.data, arg3);
177 IPC_SET_ARG4(call->msg.data, arg4);
178 IPC_SET_ARG5(call->msg.data, arg5);
179
180 ipc_callid_t callid = __SYSCALL3(SYS_IPC_CALL_ASYNC_SLOW, phoneid,
181 (sysarg_t) &call->msg.data, (sysarg_t) call);
182
183 ipc_finish_async(callid, phoneid, call);
184}
185
186/** Answer received call (fast version).
187 *
188 * The fast answer makes use of passing retval and first four arguments in
189 * registers. If you need to return more, use the ipc_answer_slow() instead.
190 *
191 * @param callid Hash of the call being answered.
192 * @param retval Return value.
193 * @param arg1 First return argument.
194 * @param arg2 Second return argument.
195 * @param arg3 Third return argument.
196 * @param arg4 Fourth return argument.
197 *
198 * @return Zero on success.
199 * @return Value from @ref errno.h on failure.
200 *
201 */
202sysarg_t ipc_answer_fast(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
203 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
204{
205 return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
206 arg4);
207}
208
209/** Answer received call (entire payload).
210 *
211 * @param callid Hash of the call being answered.
212 * @param retval Return value.
213 * @param arg1 First return argument.
214 * @param arg2 Second return argument.
215 * @param arg3 Third return argument.
216 * @param arg4 Fourth return argument.
217 * @param arg5 Fifth return argument.
218 *
219 * @return Zero on success.
220 * @return Value from @ref errno.h on failure.
221 *
222 */
223sysarg_t ipc_answer_slow(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
224 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
225{
226 ipc_call_t data;
227
228 IPC_SET_RETVAL(data, retval);
229 IPC_SET_ARG1(data, arg1);
230 IPC_SET_ARG2(data, arg2);
231 IPC_SET_ARG3(data, arg3);
232 IPC_SET_ARG4(data, arg4);
233 IPC_SET_ARG5(data, arg5);
234
235 return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
236}
237
238/** Handle received answer.
239 *
240 * @param callid Hash of the received answer.
241 * @param data Call data of the answer.
242 */
243static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
244{
245 async_call_t *call = data->label;
246
247 if (!call)
248 return;
249
250 if (call->callback)
251 call->callback(call->private, IPC_GET_RETVAL(*data), data);
252 free(call);
253}
254
255/** Wait for first IPC call to come.
256 *
257 * @param call Incoming call storage.
258 * @param usec Timeout in microseconds
259 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
260 *
261 * @return Hash of the call.
262 */
263ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec,
264 unsigned int flags)
265{
266 ipc_callid_t callid =
267 __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
268
269 /* Handle received answers */
270 if (callid && (call->flags & IPC_CALLID_ANSWERED))
271 handle_answer(callid, call);
272
273 return callid;
274}
275
276/** Interrupt one thread of this task from waiting for IPC.
277 *
278 */
279void ipc_poke(void)
280{
281 __SYSCALL0(SYS_IPC_POKE);
282}
283
284/** Wait for first IPC call to come.
285 *
286 * Only requests are returned, answers are processed internally.
287 *
288 * @param call Incoming call storage.
289 * @param usec Timeout in microseconds
290 *
291 * @return Hash of the call.
292 *
293 */
294ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
295{
296 ipc_callid_t callid;
297
298 do {
299 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
300 } while (callid && (call->flags & IPC_CALLID_ANSWERED));
301
302 return callid;
303}
304
305/** Check if there is an IPC call waiting to be picked up.
306 *
307 * Only requests are returned, answers are processed internally.
308 *
309 * @param call Incoming call storage.
310 *
311 * @return Hash of the call.
312 *
313 */
314ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
315{
316 ipc_callid_t callid;
317
318 do {
319 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
320 SYNCH_FLAGS_NON_BLOCKING);
321 } while (callid && (call->flags & IPC_CALLID_ANSWERED));
322
323 return callid;
324}
325
326/** Hang up a phone.
327 *
328 * @param phoneid Handle of the phone to be hung up.
329 *
330 * @return Zero on success or a negative error code.
331 *
332 */
333int ipc_hangup(int phoneid)
334{
335 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
336}
337
338/** Forward a received call to another destination.
339 *
340 * For non-system methods, the old method, arg1 and arg2 are rewritten
341 * by the new values. For system methods, the new method, arg1 and arg2
342 * are written to the old arg1, arg2 and arg3, respectivelly. Calls with
343 * immutable methods are forwarded verbatim.
344 *
345 * @param callid Hash of the call to forward.
346 * @param phoneid Phone handle to use for forwarding.
347 * @param imethod New interface and method for the forwarded call.
348 * @param arg1 New value of the first argument for the forwarded call.
349 * @param arg2 New value of the second argument for the forwarded call.
350 * @param mode Flags specifying mode of the forward operation.
351 *
352 * @return Zero on success or an error code.
353 *
354 */
355int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
356 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
357{
358 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1,
359 arg2, mode);
360}
361
362int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
363 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
364 unsigned int mode)
365{
366 ipc_call_t data;
367
368 IPC_SET_IMETHOD(data, imethod);
369 IPC_SET_ARG1(data, arg1);
370 IPC_SET_ARG2(data, arg2);
371 IPC_SET_ARG3(data, arg3);
372 IPC_SET_ARG4(data, arg4);
373 IPC_SET_ARG5(data, arg5);
374
375 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data,
376 mode);
377}
378
379/** Connect to a task specified by id.
380 *
381 */
382int ipc_connect_kbox(task_id_t id)
383{
384#ifdef __32_BITS__
385 sysarg64_t arg = (sysarg64_t) id;
386 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
387#endif
388
389#ifdef __64_BITS__
390 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id);
391#endif
392}
393
394/** @}
395 */
Note: See TracBrowser for help on using the repository browser.