~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to uspace/lib/libc/generic/ipc.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/** @addtogroup libc
 
30
 * @{
 
31
 * @}
 
32
 */
 
33
 
 
34
/** @addtogroup libcipc IPC
 
35
 * @brief HelenOS uspace IPC
 
36
 * @{
 
37
 * @ingroup libc
 
38
 */
 
39
/** @file
 
40
 */ 
 
41
 
 
42
#include <ipc/ipc.h>
 
43
#include <libc.h>
 
44
#include <malloc.h>
 
45
#include <errno.h>
 
46
#include <adt/list.h>
 
47
#include <stdio.h>
 
48
#include <unistd.h>
 
49
#include <futex.h>
 
50
#include <kernel/synch/synch.h>
 
51
#include <async.h>
 
52
#include <fibril.h>
 
53
#include <assert.h>
 
54
 
 
55
/**
 
56
 * Structures of this type are used for keeping track of sent asynchronous calls
 
57
 * and queing unsent calls.
 
58
 */
 
59
typedef struct {
 
60
        link_t list;
 
61
 
 
62
        ipc_async_callback_t callback;
 
63
        void *private;
 
64
        union {
 
65
                ipc_callid_t callid;
 
66
                struct {
 
67
                        ipc_call_t data;
 
68
                        int phoneid;
 
69
                } msg;
 
70
        } u;
 
71
        fid_t fid;      /**< Fibril waiting for sending this call. */
 
72
} async_call_t;
 
73
 
 
74
LIST_INITIALIZE(dispatched_calls);
 
75
 
 
76
/** List of asynchronous calls that were not accepted by kernel.
 
77
 *
 
78
 * It is protected by async_futex, because if the call cannot be sent into the
 
79
 * kernel, the async framework is used automatically.
 
80
 */
 
81
LIST_INITIALIZE(queued_calls);
 
82
 
 
83
static atomic_t ipc_futex = FUTEX_INITIALIZER;
 
84
 
 
85
/** Make a fast synchronous call.
 
86
 *
 
87
 * Only three payload arguments can be passed using this function. However, this
 
88
 * function is faster than the generic ipc_call_sync_slow() because the payload
 
89
 * is passed directly in registers.
 
90
 *
 
91
 * @param phoneid       Phone handle for the call.
 
92
 * @param method        Requested method.
 
93
 * @param arg1          Service-defined payload argument.
 
94
 * @param arg2          Service-defined payload argument.
 
95
 * @param arg3          Service-defined payload argument.
 
96
 * @param result1       If non-NULL, the return ARG1 will be stored there.
 
97
 * @param result2       If non-NULL, the return ARG2 will be stored there.
 
98
 * @param result3       If non-NULL, the return ARG3 will be stored there.
 
99
 * @param result4       If non-NULL, the return ARG4 will be stored there.
 
100
 * @param result5       If non-NULL, the return ARG5 will be stored there.
 
101
 *
 
102
 * @return              Negative values represent errors returned by IPC.
 
103
 *                      Otherwise the RETVAL of the answer is returned.
 
104
 */
 
105
int
 
106
ipc_call_sync_fast(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
 
107
    ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3,
 
108
    ipcarg_t *result4, ipcarg_t *result5)
 
109
{
 
110
        ipc_call_t resdata;
 
111
        int callres;
 
112
        
 
113
        callres = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
 
114
            arg2, arg3, (sysarg_t) &resdata);
 
115
        if (callres)
 
116
                return callres;
 
117
        if (result1)
 
118
                *result1 = IPC_GET_ARG1(resdata);
 
119
        if (result2)
 
120
                *result2 = IPC_GET_ARG2(resdata);
 
121
        if (result3)
 
122
                *result3 = IPC_GET_ARG3(resdata);
 
123
        if (result4)
 
124
                *result4 = IPC_GET_ARG4(resdata);
 
125
        if (result5)
 
126
                *result5 = IPC_GET_ARG5(resdata);
 
127
 
 
128
        return IPC_GET_RETVAL(resdata);
 
129
}
 
130
 
 
131
/** Make a synchronous call transmitting 5 arguments of payload.
 
132
 *
 
133
 * @param phoneid       Phone handle for the call.
 
134
 * @param method        Requested method.
 
135
 * @param arg1          Service-defined payload argument.
 
136
 * @param arg2          Service-defined payload argument.
 
137
 * @param arg3          Service-defined payload argument.
 
138
 * @param arg4          Service-defined payload argument.
 
139
 * @param arg5          Service-defined payload argument.
 
140
 * @param result1       If non-NULL, storage for the first return argument.
 
141
 * @param result2       If non-NULL, storage for the second return argument.
 
142
 * @param result3       If non-NULL, storage for the third return argument.
 
143
 * @param result4       If non-NULL, storage for the fourth return argument.
 
144
 * @param result5       If non-NULL, storage for the fifth return argument.
 
145
 *
 
146
 * @return              Negative value means IPC error.
 
147
 *                      Otherwise the RETVAL of the answer.
 
148
 */
 
149
int
 
150
ipc_call_sync_slow(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
 
151
    ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, ipcarg_t *result1,
 
152
    ipcarg_t *result2, ipcarg_t *result3, ipcarg_t *result4, ipcarg_t *result5)
 
153
{
 
154
        ipc_call_t data;
 
155
        int callres;
 
156
 
 
157
        IPC_SET_METHOD(data, method);
 
158
        IPC_SET_ARG1(data, arg1);
 
159
        IPC_SET_ARG2(data, arg2);
 
160
        IPC_SET_ARG3(data, arg3);
 
161
        IPC_SET_ARG4(data, arg4);
 
162
        IPC_SET_ARG5(data, arg5);
 
163
 
 
164
        callres = __SYSCALL3(SYS_IPC_CALL_SYNC_SLOW, phoneid, (sysarg_t) &data,
 
165
            (sysarg_t) &data);
 
166
        if (callres)
 
167
                return callres;
 
168
 
 
169
        if (result1)
 
170
                *result1 = IPC_GET_ARG1(data);
 
171
        if (result2)
 
172
                *result2 = IPC_GET_ARG2(data);
 
173
        if (result3)
 
174
                *result3 = IPC_GET_ARG3(data);
 
175
        if (result4)
 
176
                *result4 = IPC_GET_ARG4(data);
 
177
        if (result5)
 
178
                *result5 = IPC_GET_ARG5(data);
 
179
 
 
180
        return IPC_GET_RETVAL(data);
 
181
}
 
182
 
 
183
/** Syscall to send asynchronous message.
 
184
 *
 
185
 * @param phoneid       Phone handle for the call.
 
186
 * @param data          Call data with the request.
 
187
 *
 
188
 * @return              Hash of the call or an error code.
 
189
 */
 
190
static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
 
191
{
 
192
        return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
 
193
}
 
194
 
 
195
/** Prolog to ipc_call_async_*() functions.
 
196
 *
 
197
 * @param private       Argument for the answer/error callback.
 
198
 * @param callback      Answer/error callback.
 
199
 *
 
200
 * @return              New, partially initialized async_call structure or NULL.
 
201
 */
 
202
static inline async_call_t *ipc_prepare_async(void *private,
 
203
    ipc_async_callback_t callback)
 
204
{
 
205
        async_call_t *call;
 
206
 
 
207
        call = malloc(sizeof(*call));
 
208
        if (!call) {
 
209
                if (callback)
 
210
                        callback(private, ENOMEM, NULL);
 
211
                return NULL;
 
212
        }
 
213
        call->callback = callback;
 
214
        call->private = private;
 
215
 
 
216
        return call;
 
217
}
 
218
 
 
219
/** Epilogue of ipc_call_async_*() functions.
 
220
 *
 
221
 * @param callid        Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
 
222
 * @param phoneid       Phone handle through which the call was made.
 
223
 * @param call          async_call structure returned by ipc_prepare_async().
 
224
 * @param can_preempt   If non-zero, the current fibril can be preempted in this
 
225
 *                      call.
 
226
 */
 
227
static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
 
228
    async_call_t *call, int can_preempt)
 
229
{
 
230
        if (!call) { /* Nothing to do regardless if failed or not */
 
231
                futex_up(&ipc_futex);
 
232
                return;
 
233
        }
 
234
 
 
235
        if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
 
236
                futex_up(&ipc_futex);
 
237
                /* Call asynchronous handler with error code */
 
238
                if (call->callback)
 
239
                        call->callback(call->private, ENOENT, NULL);
 
240
                free(call);
 
241
                return;
 
242
        }
 
243
 
 
244
        if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
 
245
                futex_up(&ipc_futex);
 
246
 
 
247
                call->u.msg.phoneid = phoneid;
 
248
                
 
249
                futex_down(&async_futex);
 
250
                list_append(&call->list, &queued_calls);
 
251
 
 
252
                if (can_preempt) {
 
253
                        call->fid = fibril_get_id();
 
254
                        fibril_switch(FIBRIL_TO_MANAGER);
 
255
                        /* Async futex unlocked by previous call */
 
256
                } else {
 
257
                        call->fid = 0;
 
258
                        futex_up(&async_futex);
 
259
                }
 
260
                return;
 
261
        }
 
262
        call->u.callid = callid;
 
263
        /* Add call to the list of dispatched calls */
 
264
        list_append(&call->list, &dispatched_calls);
 
265
        futex_up(&ipc_futex);
 
266
        
 
267
}
 
268
 
 
269
/** Make a fast asynchronous call.
 
270
 *
 
271
 * This function can only handle four arguments of payload. It is, however,
 
272
 * faster than the more generic ipc_call_async_slow().
 
273
 *
 
274
 * Note that this function is a void function.
 
275
 * During normal opertation, answering this call will trigger the callback.
 
276
 * In case of fatal error, call the callback handler with the proper error code.
 
277
 * If the call cannot be temporarily made, queue it.
 
278
 *
 
279
 * @param phoneid       Phone handle for the call.
 
280
 * @param method        Requested method.
 
281
 * @param arg1          Service-defined payload argument.
 
282
 * @param arg2          Service-defined payload argument.
 
283
 * @param arg3          Service-defined payload argument.
 
284
 * @param arg4          Service-defined payload argument.
 
285
 * @param private       Argument to be passed to the answer/error callback.
 
286
 * @param callback      Answer or error callback.
 
287
 * @param can_preempt   If non-zero, the current fibril will be preempted in
 
288
 *                      case the kernel temporarily refuses to accept more
 
289
 *                      asynchronous calls.
 
290
 */
 
291
void ipc_call_async_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
 
292
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, void *private,
 
293
    ipc_async_callback_t callback, int can_preempt)
 
294
{
 
295
        async_call_t *call = NULL;
 
296
        ipc_callid_t callid;
 
297
 
 
298
        if (callback) {
 
299
                call = ipc_prepare_async(private, callback);
 
300
                if (!call)
 
301
                        return;
 
302
        }
 
303
 
 
304
        /*
 
305
         * We need to make sure that we get callid before another thread
 
306
         * accesses the queue again.
 
307
         */
 
308
        futex_down(&ipc_futex);
 
309
        callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1,
 
310
            arg2, arg3, arg4);
 
311
 
 
312
        if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
 
313
                if (!call) {
 
314
                        call = ipc_prepare_async(private, callback);
 
315
                        if (!call)
 
316
                                return;
 
317
                }
 
318
                IPC_SET_METHOD(call->u.msg.data, method);
 
319
                IPC_SET_ARG1(call->u.msg.data, arg1);
 
320
                IPC_SET_ARG2(call->u.msg.data, arg2);
 
321
                IPC_SET_ARG3(call->u.msg.data, arg3);
 
322
                IPC_SET_ARG4(call->u.msg.data, arg4);
 
323
                /*
 
324
                 * To achieve deterministic behavior, we always zero out the
 
325
                 * arguments that are beyond the limits of the fast version.
 
326
                 */
 
327
                IPC_SET_ARG5(call->u.msg.data, 0);
 
328
        }
 
329
        ipc_finish_async(callid, phoneid, call, can_preempt);
 
330
}
 
331
 
 
332
/** Make an asynchronous call transmitting the entire payload.
 
333
 *
 
334
 * Note that this function is a void function.
 
335
 * During normal opertation, answering this call will trigger the callback.
 
336
 * In case of fatal error, call the callback handler with the proper error code.
 
337
 * If the call cannot be temporarily made, queue it.
 
338
 *
 
339
 * @param phoneid       Phone handle for the call.
 
340
 * @param method        Requested method.
 
341
 * @param arg1          Service-defined payload argument.
 
342
 * @param arg2          Service-defined payload argument.
 
343
 * @param arg3          Service-defined payload argument.
 
344
 * @param arg4          Service-defined payload argument.
 
345
 * @param arg5          Service-defined payload argument.
 
346
 * @param private       Argument to be passed to the answer/error callback.
 
347
 * @param callback      Answer or error callback.
 
348
 * @param can_preempt   If non-zero, the current fibril will be preempted in
 
349
 *                      case the kernel temporarily refuses to accept more
 
350
 *                      asynchronous calls.
 
351
 *
 
352
 */
 
353
void ipc_call_async_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
 
354
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, void *private,
 
355
    ipc_async_callback_t callback, int can_preempt)
 
356
{
 
357
        async_call_t *call;
 
358
        ipc_callid_t callid;
 
359
 
 
360
        call = ipc_prepare_async(private, callback);
 
361
        if (!call)
 
362
                return;
 
363
 
 
364
        IPC_SET_METHOD(call->u.msg.data, method);
 
365
        IPC_SET_ARG1(call->u.msg.data, arg1);
 
366
        IPC_SET_ARG2(call->u.msg.data, arg2);
 
367
        IPC_SET_ARG3(call->u.msg.data, arg3);
 
368
        IPC_SET_ARG4(call->u.msg.data, arg4);
 
369
        IPC_SET_ARG5(call->u.msg.data, arg5);
 
370
        /*
 
371
         * We need to make sure that we get callid before another thread
 
372
         * accesses the queue again.
 
373
         */
 
374
        futex_down(&ipc_futex);
 
375
        callid = _ipc_call_async(phoneid, &call->u.msg.data);
 
376
 
 
377
        ipc_finish_async(callid, phoneid, call, can_preempt);
 
378
}
 
379
 
 
380
 
 
381
/** Answer a received call - fast version.
 
382
 *
 
383
 * The fast answer makes use of passing retval and first four arguments in
 
384
 * registers. If you need to return more, use the ipc_answer_slow() instead.
 
385
 *
 
386
 * @param callid        Hash of the call being answered.
 
387
 * @param retval        Return value.
 
388
 * @param arg1          First return argument.
 
389
 * @param arg2          Second return argument.
 
390
 * @param arg3          Third return argument.
 
391
 * @param arg4          Fourth return argument.
 
392
 *
 
393
 * @return              Zero on success or a value from @ref errno.h on failure.
 
394
 */
 
395
ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
 
396
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4)
 
397
{
 
398
        return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
 
399
            arg4);
 
400
}
 
401
 
 
402
/** Answer a received call - slow full version.
 
403
 *
 
404
 * @param callid        Hash of the call being answered.
 
405
 * @param retval        Return value.
 
406
 * @param arg1          First return argument.
 
407
 * @param arg2          Second return argument.
 
408
 * @param arg3          Third return argument.
 
409
 * @param arg4          Fourth return argument.
 
410
 * @param arg5          Fifth return argument.
 
411
 *
 
412
 * @return              Zero on success or a value from @ref errno.h on failure.
 
413
 */
 
414
ipcarg_t ipc_answer_slow(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
 
415
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5)
 
416
{
 
417
        ipc_call_t data;
 
418
 
 
419
        IPC_SET_RETVAL(data, retval);
 
420
        IPC_SET_ARG1(data, arg1);
 
421
        IPC_SET_ARG2(data, arg2);
 
422
        IPC_SET_ARG3(data, arg3);
 
423
        IPC_SET_ARG4(data, arg4);
 
424
        IPC_SET_ARG5(data, arg5);
 
425
 
 
426
        return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
 
427
}
 
428
 
 
429
 
 
430
/** Try to dispatch queued calls from the async queue. */
 
431
static void try_dispatch_queued_calls(void)
 
432
{
 
433
        async_call_t *call;
 
434
        ipc_callid_t callid;
 
435
 
 
436
        /** @todo
 
437
         * Integrate intelligently ipc_futex, so that it is locked during
 
438
         * ipc_call_async_*(), until it is added to dispatched_calls.
 
439
         */
 
440
        futex_down(&async_futex);
 
441
        while (!list_empty(&queued_calls)) {
 
442
                call = list_get_instance(queued_calls.next, async_call_t, list);
 
443
                callid = _ipc_call_async(call->u.msg.phoneid,
 
444
                    &call->u.msg.data);
 
445
                if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
 
446
                        break;
 
447
                }
 
448
                list_remove(&call->list);
 
449
 
 
450
                futex_up(&async_futex);
 
451
                if (call->fid)
 
452
                        fibril_add_ready(call->fid);
 
453
                
 
454
                if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
 
455
                        if (call->callback)
 
456
                                call->callback(call->private, ENOENT, NULL);
 
457
                        free(call);
 
458
                } else {
 
459
                        call->u.callid = callid;
 
460
                        futex_down(&ipc_futex);
 
461
                        list_append(&call->list, &dispatched_calls);
 
462
                        futex_up(&ipc_futex);
 
463
                }
 
464
                futex_down(&async_futex);
 
465
        }
 
466
        futex_up(&async_futex);
 
467
}
 
468
 
 
469
/** Handle a received answer.
 
470
 *
 
471
 * Find the hash of the answer and call the answer callback.
 
472
 *
 
473
 * @todo Make it use hash table.
 
474
 *
 
475
 * @param callid        Hash of the received answer.
 
476
 *                      The answer has the same hash as the request OR'ed with
 
477
 *                      the IPC_CALLID_ANSWERED bit.
 
478
 * @param data          Call data of the answer.
 
479
 */
 
480
static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
 
481
{
 
482
        link_t *item;
 
483
        async_call_t *call;
 
484
 
 
485
        callid &= ~IPC_CALLID_ANSWERED;
 
486
        
 
487
        futex_down(&ipc_futex);
 
488
        for (item = dispatched_calls.next; item != &dispatched_calls;
 
489
            item = item->next) {
 
490
                call = list_get_instance(item, async_call_t, list);
 
491
                if (call->u.callid == callid) {
 
492
                        list_remove(&call->list);
 
493
                        futex_up(&ipc_futex);
 
494
                        if (call->callback)
 
495
                                call->callback(call->private, 
 
496
                                    IPC_GET_RETVAL(*data), data);
 
497
                        free(call);
 
498
                        return;
 
499
                }
 
500
        }
 
501
        futex_up(&ipc_futex);
 
502
}
 
503
 
 
504
 
 
505
/** Wait for a first call to come.
 
506
 *
 
507
 * @param call          Storage where the incoming call data will be stored.
 
508
 * @param usec          Timeout in microseconds
 
509
 * @param flags         Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
 
510
 *
 
511
 * @return              Hash of the call. Note that certain bits have special
 
512
 *                      meaning. IPC_CALLID_ANSWERED will be set in an answer
 
513
 *                      and IPC_CALLID_NOTIFICATION is used for notifications.
 
514
 *                      
 
515
 */
 
516
ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
 
517
{
 
518
        ipc_callid_t callid;
 
519
 
 
520
        callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
 
521
        /* Handle received answers */
 
522
        if (callid & IPC_CALLID_ANSWERED) {
 
523
                handle_answer(callid, call);
 
524
                try_dispatch_queued_calls();
 
525
        }
 
526
 
 
527
        return callid;
 
528
}
 
529
 
 
530
/** Wait some time for an IPC call.
 
531
 *
 
532
 * The call will return after an answer is received.
 
533
 *
 
534
 * @param call          Storage where the incoming call data will be stored.
 
535
 * @param usec          Timeout in microseconds.
 
536
 *
 
537
 * @return              Hash of the answer.
 
538
 */
 
539
ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
 
540
{
 
541
        ipc_callid_t callid;
 
542
 
 
543
        do {
 
544
                callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
 
545
        } while (callid & IPC_CALLID_ANSWERED);
 
546
 
 
547
        return callid;
 
548
}
 
549
 
 
550
/** Check if there is an IPC call waiting to be picked up.
 
551
 *
 
552
 * @param call          Storage where the incoming call will be stored.
 
553
 * @return              Hash of the answer.
 
554
 */
 
555
ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
 
556
{
 
557
        ipc_callid_t callid;
 
558
 
 
559
        do {
 
560
                callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
 
561
                    SYNCH_FLAGS_NON_BLOCKING);
 
562
        } while (callid & IPC_CALLID_ANSWERED);
 
563
 
 
564
        return callid;
 
565
}
 
566
 
 
567
/** Ask destination to do a callback connection.
 
568
 *
 
569
 * @param phoneid       Phone handle used for contacting the other side.
 
570
 * @param arg1          Service-defined argument.
 
571
 * @param arg2          Service-defined argument.
 
572
 * @param arg3          Service-defined argument.
 
573
 * @param phonehash     Storage where the library will store an opaque
 
574
 *                      identifier of the phone that will be used for incoming
 
575
 *                      calls. This identifier can be used for connection
 
576
 *                      tracking.
 
577
 *
 
578
 * @return              Zero on success or a negative error code.
 
579
 */
 
580
int ipc_connect_to_me(int phoneid, int arg1, int arg2, int arg3, 
 
581
    ipcarg_t *phonehash)
 
582
{
 
583
        return ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2,
 
584
            arg3, NULL, NULL, NULL, NULL, phonehash);
 
585
}
 
586
 
 
587
/** Ask through phone for a new connection to some service.
 
588
 *
 
589
 * @param phoneid       Phone handle used for contacting the other side.
 
590
 * @param arg1          User defined argument.
 
591
 * @param arg2          User defined argument.
 
592
 * @param arg3          User defined argument.
 
593
 *
 
594
 * @return              New phone handle on success or a negative error code.
 
595
 */
 
596
int ipc_connect_me_to(int phoneid, int arg1, int arg2, int arg3)
 
597
{
 
598
        ipcarg_t newphid;
 
599
        int res;
 
600
 
 
601
        res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
 
602
            NULL, NULL, NULL, NULL, &newphid);
 
603
        if (res)
 
604
                return res;
 
605
        return newphid;
 
606
}
 
607
 
 
608
/** Ask through phone for a new connection to some service.
 
609
 *
 
610
 * If the connection is not available at the moment, the
 
611
 * call will block.
 
612
 *
 
613
 * @param phoneid       Phone handle used for contacting the other side.
 
614
 * @param arg1          User defined argument.
 
615
 * @param arg2          User defined argument.
 
616
 * @param arg3          User defined argument.
 
617
 *
 
618
 * @return              New phone handle on success or a negative error code.
 
619
 */
 
620
int ipc_connect_me_to_blocking(int phoneid, int arg1, int arg2, int arg3)
 
621
{
 
622
        ipcarg_t newphid;
 
623
        int res;
 
624
 
 
625
        res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
 
626
            IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
 
627
        if (res)
 
628
                return res;
 
629
        return newphid;
 
630
}
 
631
 
 
632
/** Hang up a phone.
 
633
 *
 
634
 * @param phoneid       Handle of the phone to be hung up.
 
635
 *
 
636
 * @return              Zero on success or a negative error code.
 
637
 */
 
638
int ipc_hangup(int phoneid)
 
639
{
 
640
        return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
 
641
}
 
642
 
 
643
/** Register IRQ notification.
 
644
 *
 
645
 * @param inr           IRQ number.
 
646
 * @param devno         Device number of the device generating inr.
 
647
 * @param method        Use this method for notifying me.
 
648
 * @param ucode         Top-half pseudocode handler.
 
649
 *
 
650
 * @return              Value returned by the kernel.
 
651
 */
 
652
int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode)
 
653
{
 
654
        return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method,
 
655
            (sysarg_t) ucode);
 
656
}
 
657
 
 
658
/** Unregister IRQ notification.
 
659
 *
 
660
 * @param inr           IRQ number.
 
661
 * @param devno         Device number of the device generating inr.
 
662
 *
 
663
 * @return              Value returned by the kernel.
 
664
 */
 
665
int ipc_unregister_irq(int inr, int devno)
 
666
{
 
667
        return __SYSCALL2(SYS_IPC_UNREGISTER_IRQ, inr, devno);
 
668
}
 
669
 
 
670
/** Forward a received call to another destination.
 
671
 *
 
672
 * @param callid        Hash of the call to forward.
 
673
 * @param phoneid       Phone handle to use for forwarding.
 
674
 * @param method        New method for the forwarded call.
 
675
 * @param arg1          New value of the first argument for the forwarded call.
 
676
 * @param arg2          New value of the second argument for the forwarded call.
 
677
 * @param mode          Flags specifying mode of the forward operation.
 
678
 *
 
679
 * @return              Zero on success or an error code.
 
680
 *
 
681
 * For non-system methods, the old method, arg1 and arg2 are rewritten by the
 
682
 * new values. For system methods, the new method, arg1 and arg2 are written 
 
683
 * to the old arg1, arg2 and arg3, respectivelly. Calls with immutable 
 
684
 * methods are forwarded verbatim.
 
685
 */
 
686
int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method,
 
687
    ipcarg_t arg1, ipcarg_t arg2, int mode)
 
688
{
 
689
        return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1, 
 
690
            arg2, mode);
 
691
}
 
692
 
 
693
 
 
694
int ipc_forward_slow(ipc_callid_t callid, int phoneid, int method,
 
695
    ipcarg_t arg1, ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5,
 
696
    int mode)
 
697
{
 
698
        ipc_call_t data;
 
699
 
 
700
        IPC_SET_METHOD(data, method);
 
701
        IPC_SET_ARG1(data, arg1);
 
702
        IPC_SET_ARG2(data, arg2);
 
703
        IPC_SET_ARG3(data, arg3);
 
704
        IPC_SET_ARG4(data, arg4);
 
705
        IPC_SET_ARG5(data, arg5);
 
706
 
 
707
        return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data, mode);
 
708
}
 
709
 
 
710
/** Wrapper for making IPC_M_SHARE_IN calls.
 
711
 *
 
712
 * @param phoneid       Phone that will be used to contact the receiving side.
 
713
 * @param dst           Destination address space area base.
 
714
 * @param size          Size of the destination address space area.
 
715
 * @param arg           User defined argument.
 
716
 * @param flags         Storage where the received flags will be stored. Can be
 
717
 *                      NULL.
 
718
 *
 
719
 * @return              Zero on success or a negative error code from errno.h.
 
720
 */
 
721
int ipc_share_in_start(int phoneid, void *dst, size_t size, ipcarg_t arg,
 
722
    int *flags)
 
723
{
 
724
        int res;
 
725
        sysarg_t tmp_flags;
 
726
        res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst,
 
727
            (ipcarg_t) size, arg, NULL, &tmp_flags);
 
728
        if (flags)
 
729
                *flags = tmp_flags;
 
730
        return res;
 
731
}
 
732
 
 
733
/** Wrapper for receiving the IPC_M_SHARE_IN calls.
 
734
 *
 
735
 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN calls
 
736
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
737
 *
 
738
 * So far, this wrapper is to be used from within a connection fibril.
 
739
 *
 
740
 * @param callid        Storage where the hash of the IPC_M_SHARE_IN call will
 
741
 *                      be stored.
 
742
 * @param size          Destination address space area size.    
 
743
 *
 
744
 * @return              Non-zero on success, zero on failure.
 
745
 */
 
746
int ipc_share_in_receive(ipc_callid_t *callid, size_t *size)
 
747
{
 
748
        ipc_call_t data;
 
749
        
 
750
        assert(callid);
 
751
        assert(size);
 
752
 
 
753
        *callid = async_get_call(&data);
 
754
        if (IPC_GET_METHOD(data) != IPC_M_SHARE_IN)
 
755
                return 0;
 
756
        *size = (size_t) IPC_GET_ARG2(data);
 
757
        return 1;
 
758
}
 
759
 
 
760
/** Wrapper for answering the IPC_M_SHARE_IN calls.
 
761
 *
 
762
 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
 
763
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
764
 *
 
765
 * @param callid        Hash of the IPC_M_DATA_READ call to answer.
 
766
 * @param src           Source address space base.
 
767
 * @param flags         Flags to be used for sharing. Bits can be only cleared.
 
768
 *
 
769
 * @return              Zero on success or a value from @ref errno.h on failure.
 
770
 */
 
771
int ipc_share_in_finalize(ipc_callid_t callid, void *src, int flags)
 
772
{
 
773
        return ipc_answer_2(callid, EOK, (ipcarg_t) src, (ipcarg_t) flags);
 
774
}
 
775
 
 
776
/** Wrapper for making IPC_M_SHARE_OUT calls.
 
777
 *
 
778
 * @param phoneid       Phone that will be used to contact the receiving side.
 
779
 * @param src           Source address space area base address.
 
780
 * @param flags         Flags to be used for sharing. Bits can be only cleared.
 
781
 *
 
782
 * @return              Zero on success or a negative error code from errno.h.
 
783
 */
 
784
int ipc_share_out_start(int phoneid, void *src, int flags)
 
785
{
 
786
        return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0,
 
787
            (ipcarg_t) flags);
 
788
}
 
789
 
 
790
/** Wrapper for receiving the IPC_M_SHARE_OUT calls.
 
791
 *
 
792
 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT calls
 
793
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
794
 *
 
795
 * So far, this wrapper is to be used from within a connection fibril.
 
796
 *
 
797
 * @param callid        Storage where the hash of the IPC_M_SHARE_OUT call will
 
798
 *                      be stored.
 
799
 * @param size          Storage where the source address space area size will be
 
800
 *                      stored.
 
801
 * @param flags         Storage where the sharing flags will be stored.
 
802
 *
 
803
 * @return              Non-zero on success, zero on failure.
 
804
 */
 
805
int ipc_share_out_receive(ipc_callid_t *callid, size_t *size, int *flags)
 
806
{
 
807
        ipc_call_t data;
 
808
        
 
809
        assert(callid);
 
810
        assert(size);
 
811
        assert(flags);
 
812
 
 
813
        *callid = async_get_call(&data);
 
814
        if (IPC_GET_METHOD(data) != IPC_M_SHARE_OUT)
 
815
                return 0;
 
816
        *size = (size_t) IPC_GET_ARG2(data);
 
817
        *flags = (int) IPC_GET_ARG3(data);
 
818
        return 1;
 
819
}
 
820
 
 
821
/** Wrapper for answering the IPC_M_SHARE_OUT calls.
 
822
 *
 
823
 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT calls
 
824
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
825
 *
 
826
 * @param callid        Hash of the IPC_M_DATA_WRITE call to answer.
 
827
 * @param dst           Destination address space area base address.    
 
828
 *
 
829
 * @return              Zero on success or a value from @ref errno.h on failure.
 
830
 */
 
831
int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
 
832
{
 
833
        return ipc_answer_1(callid, EOK, (ipcarg_t) dst);
 
834
}
 
835
 
 
836
 
 
837
/** Wrapper for making IPC_M_DATA_READ calls.
 
838
 *
 
839
 * @param phoneid       Phone that will be used to contact the receiving side.
 
840
 * @param dst           Address of the beginning of the destination buffer.
 
841
 * @param size          Size of the destination buffer.
 
842
 *
 
843
 * @return              Zero on success or a negative error code from errno.h.
 
844
 */
 
845
int ipc_data_read_start(int phoneid, void *dst, size_t size)
 
846
{
 
847
        return async_req_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst,
 
848
            (ipcarg_t) size);
 
849
}
 
850
 
 
851
/** Wrapper for receiving the IPC_M_DATA_READ calls.
 
852
 *
 
853
 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls
 
854
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
855
 *
 
856
 * So far, this wrapper is to be used from within a connection fibril.
 
857
 *
 
858
 * @param callid        Storage where the hash of the IPC_M_DATA_READ call will
 
859
 *                      be stored.
 
860
 * @param size          Storage where the maximum size will be stored. Can be
 
861
 *                      NULL.
 
862
 *
 
863
 * @return              Non-zero on success, zero on failure.
 
864
 */
 
865
int ipc_data_read_receive(ipc_callid_t *callid, size_t *size)
 
866
{
 
867
        ipc_call_t data;
 
868
        
 
869
        assert(callid);
 
870
 
 
871
        *callid = async_get_call(&data);
 
872
        if (IPC_GET_METHOD(data) != IPC_M_DATA_READ)
 
873
                return 0;
 
874
        if (size)
 
875
                *size = (size_t) IPC_GET_ARG2(data);
 
876
        return 1;
 
877
}
 
878
 
 
879
/** Wrapper for answering the IPC_M_DATA_READ calls.
 
880
 *
 
881
 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
 
882
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
883
 *
 
884
 * @param callid        Hash of the IPC_M_DATA_READ call to answer.
 
885
 * @param src           Source address for the IPC_M_DATA_READ call.
 
886
 * @param size          Size for the IPC_M_DATA_READ call. Can be smaller than
 
887
 *                      the maximum size announced by the sender.
 
888
 *
 
889
 * @return              Zero on success or a value from @ref errno.h on failure.
 
890
 */
 
891
int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
 
892
{
 
893
        return ipc_answer_2(callid, EOK, (ipcarg_t) src, (ipcarg_t) size);
 
894
}
 
895
 
 
896
/** Wrapper for making IPC_M_DATA_WRITE calls.
 
897
 *
 
898
 * @param phoneid       Phone that will be used to contact the receiving side.
 
899
 * @param src           Address of the beginning of the source buffer.
 
900
 * @param size          Size of the source buffer.
 
901
 *
 
902
 * @return              Zero on success or a negative error code from errno.h.
 
903
 */
 
904
int ipc_data_write_start(int phoneid, const void *src, size_t size)
 
905
{
 
906
        return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src,
 
907
            (ipcarg_t) size);
 
908
}
 
909
 
 
910
/** Wrapper for receiving the IPC_M_DATA_WRITE calls.
 
911
 *
 
912
 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE calls
 
913
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
914
 *
 
915
 * So far, this wrapper is to be used from within a connection fibril.
 
916
 *
 
917
 * @param callid        Storage where the hash of the IPC_M_DATA_WRITE call will
 
918
 *                      be stored.
 
919
 * @param size          Storage where the suggested size will be stored. May be
 
920
 *                      NULL
 
921
 *
 
922
 * @return              Non-zero on success, zero on failure.
 
923
 */
 
924
int ipc_data_write_receive(ipc_callid_t *callid, size_t *size)
 
925
{
 
926
        ipc_call_t data;
 
927
        
 
928
        assert(callid);
 
929
 
 
930
        *callid = async_get_call(&data);
 
931
        if (IPC_GET_METHOD(data) != IPC_M_DATA_WRITE)
 
932
                return 0;
 
933
        if (size)
 
934
                *size = (size_t) IPC_GET_ARG2(data);
 
935
        return 1;
 
936
}
 
937
 
 
938
/** Wrapper for answering the IPC_M_DATA_WRITE calls.
 
939
 *
 
940
 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE calls
 
941
 * so that the user doesn't have to remember the meaning of each IPC argument.
 
942
 *
 
943
 * @param callid        Hash of the IPC_M_DATA_WRITE call to answer.
 
944
 * @param dst           Final destination address for the IPC_M_DATA_WRITE call.
 
945
 * @param size          Final size for the IPC_M_DATA_WRITE call.
 
946
 *
 
947
 * @return              Zero on success or a value from @ref errno.h on failure.
 
948
 */
 
949
int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
 
950
{
 
951
        return ipc_answer_2(callid, EOK, (ipcarg_t) dst, (ipcarg_t) size);
 
952
}
 
953
 
 
954
#include <kernel/syscall/sysarg64.h>
 
955
/** Connect to a task specified by id.
 
956
 */
 
957
int ipc_connect_kbox(task_id_t id)
 
958
{
 
959
        sysarg64_t arg;
 
960
 
 
961
        arg.value = (unsigned long long) id;
 
962
 
 
963
        return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
 
964
}
 
965
 
 
966
/** @}
 
967
 */