source: mainline/uspace/lib/c/generic/ipc.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 11.0 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 <stdlib.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 } msg;
62} async_call_t;
63
64/** Prologue for ipc_call_async_*() functions.
65 *
66 * @param private Argument for the answer/error callback.
67 * @param callback Answer/error callback.
68 *
69 * @return New, partially initialized async_call structure or NULL.
70 *
71 */
72static inline async_call_t *ipc_prepare_async(void *private,
73 ipc_async_callback_t callback)
74{
75 async_call_t *call =
76 (async_call_t *) malloc(sizeof(async_call_t));
77 if (!call) {
78 if (callback)
79 callback(private, ENOMEM, NULL);
80
81 return NULL;
82 }
83
84 call->callback = callback;
85 call->private = private;
86
87 return call;
88}
89
90/** Epilogue for ipc_call_async_*() functions.
91 *
92 * @param rc Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
93 * @param call Structure returned by ipc_prepare_async().
94 */
95static inline void ipc_finish_async(errno_t rc, async_call_t *call)
96{
97 if (!call) {
98 /* Nothing to do regardless if failed or not */
99 return;
100 }
101
102 if (rc != EOK) {
103 /* Call asynchronous handler with error code */
104 if (call->callback)
105 call->callback(call->private, ENOENT, NULL);
106
107 free(call);
108 return;
109 }
110}
111
112/** Fast asynchronous call.
113 *
114 * This function can only handle three arguments of payload. It is, however,
115 * faster than the more generic ipc_call_async_slow().
116 *
117 * Note that this function is a void function.
118 *
119 * During normal operation, answering this call will trigger the callback.
120 * In case of fatal error, the callback handler is called with the proper
121 * error code. If the call cannot be temporarily made, it is queued.
122 *
123 * @param phandle Phone handle for the call.
124 * @param imethod Requested interface and method.
125 * @param arg1 Service-defined payload argument.
126 * @param arg2 Service-defined payload argument.
127 * @param arg3 Service-defined payload argument.
128 * @param private Argument to be passed to the answer/error callback.
129 * @param callback Answer or error callback.
130 */
131void ipc_call_async_fast(cap_handle_t phandle, sysarg_t imethod, sysarg_t arg1,
132 sysarg_t arg2, sysarg_t arg3, void *private, ipc_async_callback_t callback)
133{
134 async_call_t *call = ipc_prepare_async(private, callback);
135 if (!call)
136 return;
137
138 errno_t rc = (errno_t) __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phandle, imethod, arg1,
139 arg2, arg3, (sysarg_t) call);
140
141 ipc_finish_async(rc, call);
142}
143
144/** Asynchronous call transmitting the entire payload.
145 *
146 * Note that this function is a void function.
147 *
148 * During normal operation, answering this call will trigger the callback.
149 * In case of fatal error, the callback handler is called with the proper
150 * error code. If the call cannot be temporarily made, it is queued.
151 *
152 * @param phandle Phone handle for the call.
153 * @param imethod Requested interface and method.
154 * @param arg1 Service-defined payload argument.
155 * @param arg2 Service-defined payload argument.
156 * @param arg3 Service-defined payload argument.
157 * @param arg4 Service-defined payload argument.
158 * @param arg5 Service-defined payload argument.
159 * @param private Argument to be passed to the answer/error callback.
160 * @param callback Answer or error callback.
161 */
162void ipc_call_async_slow(int phandle, sysarg_t imethod, sysarg_t arg1,
163 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
164 ipc_async_callback_t callback)
165{
166 async_call_t *call = ipc_prepare_async(private, callback);
167 if (!call)
168 return;
169
170 IPC_SET_IMETHOD(call->msg.data, imethod);
171 IPC_SET_ARG1(call->msg.data, arg1);
172 IPC_SET_ARG2(call->msg.data, arg2);
173 IPC_SET_ARG3(call->msg.data, arg3);
174 IPC_SET_ARG4(call->msg.data, arg4);
175 IPC_SET_ARG5(call->msg.data, arg5);
176
177 errno_t rc = (errno_t) __SYSCALL3(SYS_IPC_CALL_ASYNC_SLOW, phandle,
178 (sysarg_t) &call->msg.data, (sysarg_t) call);
179
180 ipc_finish_async(rc, call);
181}
182
183/** Answer received call (fast version).
184 *
185 * The fast answer makes use of passing retval and first four arguments in
186 * registers. If you need to return more, use the ipc_answer_slow() instead.
187 *
188 * @param chandle Handle of the call being answered.
189 * @param retval Return value.
190 * @param arg1 First return argument.
191 * @param arg2 Second return argument.
192 * @param arg3 Third return argument.
193 * @param arg4 Fourth return argument.
194 *
195 * @return Zero on success.
196 * @return Value from @ref errno.h on failure.
197 *
198 */
199errno_t ipc_answer_fast(cap_handle_t chandle, errno_t retval, sysarg_t arg1,
200 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
201{
202 return (errno_t) __SYSCALL6(SYS_IPC_ANSWER_FAST, chandle, (sysarg_t) retval, arg1, arg2,
203 arg3, arg4);
204}
205
206/** Answer received call (entire payload).
207 *
208 * @param chandle Handle of the call being answered.
209 * @param retval Return value.
210 * @param arg1 First return argument.
211 * @param arg2 Second return argument.
212 * @param arg3 Third return argument.
213 * @param arg4 Fourth return argument.
214 * @param arg5 Fifth return argument.
215 *
216 * @return Zero on success.
217 * @return Value from @ref errno.h on failure.
218 *
219 */
220errno_t ipc_answer_slow(cap_handle_t chandle, errno_t retval, sysarg_t arg1,
221 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
222{
223 ipc_call_t data;
224
225 IPC_SET_RETVAL(data, retval);
226 IPC_SET_ARG1(data, arg1);
227 IPC_SET_ARG2(data, arg2);
228 IPC_SET_ARG3(data, arg3);
229 IPC_SET_ARG4(data, arg4);
230 IPC_SET_ARG5(data, arg5);
231
232 return (errno_t) __SYSCALL2(SYS_IPC_ANSWER_SLOW, chandle, (sysarg_t) &data);
233}
234
235/** Handle received answer.
236 *
237 * @param data Call data of the answer.
238 */
239static void handle_answer(ipc_call_t *data)
240{
241 async_call_t *call = data->label;
242
243 if (!call)
244 return;
245
246 if (call->callback)
247 call->callback(call->private, IPC_GET_RETVAL(*data), data);
248 free(call);
249}
250
251/** Wait for first IPC call to come.
252 *
253 * @param call Incoming call storage.
254 * @param usec Timeout in microseconds
255 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
256 * @param[out] out_handle Call handle.
257 *
258 * @return Error code.
259 */
260errno_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec, unsigned int flags)
261{
262 errno_t rc = (errno_t) __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
263
264 /* Handle received answers */
265 if ((rc == EOK) && (call->cap_handle == CAP_NIL) &&
266 (call->flags & IPC_CALL_ANSWERED)) {
267 handle_answer(call);
268 }
269
270 return rc;
271}
272
273/** Interrupt one thread of this task from waiting for IPC.
274 *
275 */
276void ipc_poke(void)
277{
278 __SYSCALL0(SYS_IPC_POKE);
279}
280
281/** Wait for first IPC call to come.
282 *
283 * Only requests are returned, answers are processed internally.
284 *
285 * @param call Incoming call storage.
286 * @param usec Timeout in microseconds
287 *
288 * @return Error code.
289 *
290 */
291errno_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
292{
293 errno_t rc;
294
295 do {
296 rc = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
297 } while ((rc == EOK) && (call->cap_handle == CAP_NIL) && (call->flags & IPC_CALL_ANSWERED));
298
299 return rc;
300}
301
302/** Check if there is an IPC call waiting to be picked up.
303 *
304 * Only requests are returned, answers are processed internally.
305 *
306 * @param call Incoming call storage.
307 *
308 * @return Error code.
309 *
310 */
311errno_t ipc_trywait_for_call(ipc_call_t *call)
312{
313 errno_t rc;
314
315 do {
316 rc = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
317 SYNCH_FLAGS_NON_BLOCKING);
318 } while ((rc == EOK) && (call->cap_handle == CAP_NIL) && (call->flags & IPC_CALL_ANSWERED));
319
320 return rc;
321}
322
323/** Hang up a phone.
324 *
325 * @param phandle Handle of the phone to be hung up.
326 *
327 * @return Zero on success or an error code.
328 *
329 */
330errno_t ipc_hangup(cap_handle_t phandle)
331{
332 return (errno_t) __SYSCALL1(SYS_IPC_HANGUP, phandle);
333}
334
335/** Forward a received call to another destination.
336 *
337 * For non-system methods, the old method, arg1 and arg2 are rewritten by the
338 * new values. For system methods, the new method, arg1 and arg2 are written to
339 * the old arg1, arg2 and arg3, respectivelly. Calls with immutable methods are
340 * forwarded verbatim.
341 *
342 * @param chandle Handle of the call to forward.
343 * @param phandle Phone handle to use for forwarding.
344 * @param imethod New interface and method for the forwarded call.
345 * @param arg1 New value of the first argument for the forwarded call.
346 * @param arg2 New value of the second argument for the forwarded call.
347 * @param mode Flags specifying mode of the forward operation.
348 *
349 * @return Zero on success or an error code.
350 *
351 */
352errno_t ipc_forward_fast(cap_handle_t chandle, cap_handle_t phandle,
353 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
354{
355 return (errno_t) __SYSCALL6(SYS_IPC_FORWARD_FAST, chandle, phandle, imethod, arg1,
356 arg2, mode);
357}
358
359errno_t ipc_forward_slow(cap_handle_t chandle, cap_handle_t phandle,
360 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
361 sysarg_t arg4, sysarg_t arg5, unsigned int mode)
362{
363 ipc_call_t data;
364
365 IPC_SET_IMETHOD(data, imethod);
366 IPC_SET_ARG1(data, arg1);
367 IPC_SET_ARG2(data, arg2);
368 IPC_SET_ARG3(data, arg3);
369 IPC_SET_ARG4(data, arg4);
370 IPC_SET_ARG5(data, arg5);
371
372 return (errno_t) __SYSCALL4(SYS_IPC_FORWARD_SLOW, chandle, phandle,
373 (sysarg_t) &data, mode);
374}
375
376/** Connect to a task specified by id.
377 *
378 */
379errno_t ipc_connect_kbox(task_id_t id, cap_handle_t *phone)
380{
381 return (errno_t) __SYSCALL2(SYS_IPC_CONNECT_KBOX, (sysarg_t) &id, (sysarg_t) phone);
382}
383
384/** @}
385 */
Note: See TracBrowser for help on using the repository browser.