source: mainline/uspace/lib/libc/generic/async.c@ f2f0392

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

More fibril/psthread cleanup.

  • Property mode set to 100644
File size: 20.1 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/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35/**
36 * Asynchronous library
37 *
38 * The aim of this library is facilitating writing programs utilizing the
39 * asynchronous nature of HelenOS IPC, yet using a normal way of programming.
40 *
41 * You should be able to write very simple multithreaded programs, the async
42 * framework will automatically take care of most synchronization problems.
43 *
44 * Default semantics:
45 * - async_send_*(): send asynchronously. If the kernel refuses to send
46 * more messages, [ try to get responses from kernel, if
47 * nothing found, might try synchronous ]
48 *
49 * Example of use (pseudo C):
50 *
51 * 1) Multithreaded client application
52 *
53 * fibril_create(fibril1, ...);
54 * fibril_create(fibril2, ...);
55 * ...
56 *
57 * int fibril1(void *arg)
58 * {
59 * conn = ipc_connect_me_to();
60 * c1 = async_send(conn);
61 * c2 = async_send(conn);
62 * async_wait_for(c1);
63 * async_wait_for(c2);
64 * ...
65 * }
66 *
67 *
68 * 2) Multithreaded server application
69 * main()
70 * {
71 * async_manager();
72 * }
73 *
74 *
75 * client_connection(icallid, *icall)
76 * {
77 * if (want_refuse) {
78 * ipc_answer_fast(icallid, ELIMIT, 0, 0);
79 * return;
80 * }
81 * ipc_answer_fast(icallid, EOK, 0, 0);
82 *
83 * callid = async_get_call(&call);
84 * handle_call(callid, call);
85 * ipc_answer_fast(callid, 1, 2, 3);
86 *
87 * callid = async_get_call(&call);
88 * ....
89 * }
90 *
91 */
92
93#include <futex.h>
94#include <async.h>
95#include <fibril.h>
96#include <stdio.h>
97#include <libadt/hash_table.h>
98#include <libadt/list.h>
99#include <ipc/ipc.h>
100#include <assert.h>
101#include <errno.h>
102#include <time.h>
103#include <arch/barrier.h>
104
105atomic_t async_futex = FUTEX_INITIALIZER;
106static hash_table_t conn_hash_table;
107static LIST_INITIALIZE(timeout_list);
108
109typedef struct {
110 /** Expiration time for waiting fibril. */
111 struct timeval expires;
112 /** If true, this struct is in the timeout list. */
113 int inlist;
114 link_t link;
115
116 /** Fibril waiting for this message. */
117 fid_t fid;
118 /** If this fibril is currently active. */
119 int active;
120 /** If true, we timed out. */
121 int timedout;
122} awaiter_t;
123
124typedef struct {
125 awaiter_t wdata;
126
127 int done; /**< If reply was received */
128 ipc_call_t *dataptr; /**< Pointer where the answer data
129 * is stored */
130 ipcarg_t retval;
131} amsg_t;
132
133typedef struct {
134 link_t link;
135 ipc_callid_t callid;
136 ipc_call_t call;
137} msg_t;
138
139typedef struct {
140 awaiter_t wdata;
141
142 link_t link; /**< Hash table link. */
143 ipcarg_t in_phone_hash; /**< Incoming phone hash. */
144 link_t msg_queue; /**< Messages that should be delivered
145 * to this fibril. */
146 /* Structures for connection opening packet */
147 ipc_callid_t callid;
148 ipc_call_t call;
149 ipc_callid_t close_callid; /* Identification of closing packet. */
150 void (*cfibril)(ipc_callid_t, ipc_call_t *);
151} connection_t;
152
153/** Identifier of the incoming connection handled by the current fibril. */
154__thread connection_t *FIBRIL_connection;
155/** If true, it is forbidden to use async_req functions and
156 * all preemption is disabled */
157__thread int in_interrupt_handler;
158
159static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
160static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
161static async_client_conn_t client_connection = default_client_connection;
162static async_client_conn_t interrupt_received = default_interrupt_received;
163
164/** Add microseconds to give timeval */
165static void tv_add(struct timeval *tv, suseconds_t usecs)
166{
167 tv->tv_sec += usecs / 1000000;
168 tv->tv_usec += usecs % 1000000;
169 if (tv->tv_usec > 1000000) {
170 tv->tv_sec++;
171 tv->tv_usec -= 1000000;
172 }
173}
174
175/** Subtract 2 timevals, return microseconds difference */
176static suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
177{
178 suseconds_t result;
179
180 result = tv1->tv_usec - tv2->tv_usec;
181 result += (tv1->tv_sec - tv2->tv_sec) * 1000000;
182
183 return result;
184}
185
186/** Compare timeval
187 *
188 * @return 1 if tv1 > tv2, otherwise 0
189 */
190static int tv_gt(struct timeval *tv1, struct timeval *tv2)
191{
192 if (tv1->tv_sec > tv2->tv_sec)
193 return 1;
194 if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec > tv2->tv_usec)
195 return 1;
196 return 0;
197}
198static int tv_gteq(struct timeval *tv1, struct timeval *tv2)
199{
200 if (tv1->tv_sec > tv2->tv_sec)
201 return 1;
202 if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec >= tv2->tv_usec)
203 return 1;
204 return 0;
205}
206
207/* Hash table functions */
208#define CONN_HASH_TABLE_CHAINS 32
209
210static hash_index_t conn_hash(unsigned long *key)
211{
212 assert(key);
213 return ((*key) >> 4) % CONN_HASH_TABLE_CHAINS;
214}
215
216static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
217{
218 connection_t *hs;
219
220 hs = hash_table_get_instance(item, connection_t, link);
221
222 return key[0] == hs->in_phone_hash;
223}
224
225static void conn_remove(link_t *item)
226{
227 free(hash_table_get_instance(item, connection_t, link));
228}
229
230
231/** Operations for NS hash table. */
232static hash_table_operations_t conn_hash_table_ops = {
233 .hash = conn_hash,
234 .compare = conn_compare,
235 .remove_callback = conn_remove
236};
237
238/** Insert sort timeout msg into timeouts list
239 *
240 */
241static void insert_timeout(awaiter_t *wd)
242{
243 link_t *tmp;
244 awaiter_t *cur;
245
246 wd->timedout = 0;
247 wd->inlist = 1;
248
249 tmp = timeout_list.next;
250 while (tmp != &timeout_list) {
251 cur = list_get_instance(tmp, awaiter_t, link);
252 if (tv_gteq(&cur->expires, &wd->expires))
253 break;
254 tmp = tmp->next;
255 }
256 list_append(&wd->link, tmp);
257}
258
259/** Try to route a call to an appropriate connection fibril
260 *
261 */
262static int route_call(ipc_callid_t callid, ipc_call_t *call)
263{
264 connection_t *conn;
265 msg_t *msg;
266 link_t *hlp;
267 unsigned long key;
268
269 futex_down(&async_futex);
270
271 key = call->in_phone_hash;
272 hlp = hash_table_find(&conn_hash_table, &key);
273 if (!hlp) {
274 futex_up(&async_futex);
275 return 0;
276 }
277 conn = hash_table_get_instance(hlp, connection_t, link);
278
279 msg = malloc(sizeof(*msg));
280 msg->callid = callid;
281 msg->call = *call;
282 list_append(&msg->link, &conn->msg_queue);
283
284 if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
285 conn->close_callid = callid;
286
287 /* If the call is waiting for event, run it */
288 if (!conn->wdata.active) {
289 /* If in timeout list, remove it */
290 if (conn->wdata.inlist) {
291 conn->wdata.inlist = 0;
292 list_remove(&conn->wdata.link);
293 }
294 conn->wdata.active = 1;
295 fibril_add_ready(conn->wdata.fid);
296 }
297
298 futex_up(&async_futex);
299
300 return 1;
301}
302
303/** Return new incoming message for the current (fibril-local) connection */
304ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
305{
306 msg_t *msg;
307 ipc_callid_t callid;
308 connection_t *conn;
309
310 assert(FIBRIL_connection);
311 /* GCC 4.1.0 coughs on FIBRIL_connection-> dereference,
312 * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
313 * I would never expect to find so many errors in
314 * compiler *($&$(*&$
315 */
316 conn = FIBRIL_connection;
317
318 futex_down(&async_futex);
319
320 if (usecs) {
321 gettimeofday(&conn->wdata.expires, NULL);
322 tv_add(&conn->wdata.expires, usecs);
323 } else {
324 conn->wdata.inlist = 0;
325 }
326 /* If nothing in queue, wait until something appears */
327 while (list_empty(&conn->msg_queue)) {
328 if (usecs)
329 insert_timeout(&conn->wdata);
330
331 conn->wdata.active = 0;
332 fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
333 /* Futex is up after getting back from async_manager
334 * get it again */
335 futex_down(&async_futex);
336 if (usecs && conn->wdata.timedout &&
337 list_empty(&conn->msg_queue)) {
338 /* If we timed out-> exit */
339 futex_up(&async_futex);
340 return 0;
341 }
342 }
343
344 msg = list_get_instance(conn->msg_queue.next, msg_t, link);
345 list_remove(&msg->link);
346 callid = msg->callid;
347 *call = msg->call;
348 free(msg);
349
350 futex_up(&async_futex);
351 return callid;
352}
353
354/** Fibril function that gets created on new connection
355 *
356 * This function is defined as a weak symbol - to be redefined in
357 * user code.
358 */
359static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
360{
361 ipc_answer_fast(callid, ENOENT, 0, 0);
362}
363static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
364{
365}
366
367/** Wrapper for client connection fibril.
368 *
369 * When new connection arrives, a fibril with this implementing function is
370 * created. It calls client_connection() and does the final cleanup.
371 *
372 * @param arg Connection structure pointer
373 *
374 * @return Always zero.
375 */
376static int connection_fibril(void *arg)
377{
378 unsigned long key;
379 msg_t *msg;
380 int close_answered = 0;
381
382 /* Setup fibril-local connection pointer */
383 FIBRIL_connection = (connection_t *) arg;
384 FIBRIL_connection->cfibril(FIBRIL_connection->callid,
385 &FIBRIL_connection->call);
386
387 /* Remove myself from connection hash table */
388 futex_down(&async_futex);
389 key = FIBRIL_connection->in_phone_hash;
390 hash_table_remove(&conn_hash_table, &key, 1);
391 futex_up(&async_futex);
392
393 /* Answer all remaining messages with ehangup */
394 while (!list_empty(&FIBRIL_connection->msg_queue)) {
395 msg = list_get_instance(FIBRIL_connection->msg_queue.next,
396 msg_t, link);
397 list_remove(&msg->link);
398 if (msg->callid == FIBRIL_connection->close_callid)
399 close_answered = 1;
400 ipc_answer_fast(msg->callid, EHANGUP, 0, 0);
401 free(msg);
402 }
403 if (FIBRIL_connection->close_callid)
404 ipc_answer_fast(FIBRIL_connection->close_callid, 0, 0, 0);
405
406 return 0;
407}
408
409/** Create a new fibril for a new connection.
410 *
411 * Creates new fibril for connection, fills in connection structures and inserts
412 * it into the hash table, so that later we can easily do routing of messages to
413 * particular fibrils.
414 *
415 * @param in_phone_hash Identification of the incoming connection
416 * @param callid Callid of the IPC_M_CONNECT_ME_TO packet
417 * @param call Call data of the opening packet
418 * @param cfibril Fibril function that should be called upon
419 * opening the connection
420 * @return New fibril id.
421 */
422fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
423 ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
424{
425 connection_t *conn;
426 unsigned long key;
427
428 conn = malloc(sizeof(*conn));
429 if (!conn) {
430 ipc_answer_fast(callid, ENOMEM, 0, 0);
431 return NULL;
432 }
433 conn->in_phone_hash = in_phone_hash;
434 list_initialize(&conn->msg_queue);
435 conn->callid = callid;
436 conn->close_callid = 0;
437 if (call)
438 conn->call = *call;
439 conn->wdata.active = 1; /* We will activate it asap */
440 conn->cfibril = cfibril;
441
442 conn->wdata.fid = fibril_create(connection_fibril, conn);
443 if (!conn->wdata.fid) {
444 free(conn);
445 ipc_answer_fast(callid, ENOMEM, 0, 0);
446 return NULL;
447 }
448 /* Add connection to hash table */
449 key = conn->in_phone_hash;
450 futex_down(&async_futex);
451 hash_table_insert(&conn_hash_table, &key, &conn->link);
452 futex_up(&async_futex);
453
454 fibril_add_ready(conn->wdata.fid);
455
456 return conn->wdata.fid;
457}
458
459/** Handle a call that was received. */
460static void handle_call(ipc_callid_t callid, ipc_call_t *call)
461{
462 /* Unrouted call - do some default behaviour */
463 if ((callid & IPC_CALLID_NOTIFICATION)) {
464 in_interrupt_handler = 1;
465 (*interrupt_received)(callid,call);
466 in_interrupt_handler = 0;
467 return;
468 }
469
470 switch (IPC_GET_METHOD(*call)) {
471 case IPC_M_CONNECT_ME_TO:
472 /* Open new connection with fibril etc. */
473 async_new_connection(IPC_GET_ARG3(*call), callid, call,
474 client_connection);
475 return;
476 }
477
478 /* Try to route call through connection tables */
479 if (route_call(callid, call))
480 return;
481
482 /* Unknown call from unknown phone - hang it up */
483 ipc_answer_fast(callid, EHANGUP, 0, 0);
484}
485
486/** Fire all timeouts that expired. */
487static void handle_expired_timeouts(void)
488{
489 struct timeval tv;
490 awaiter_t *waiter;
491 link_t *cur;
492
493 gettimeofday(&tv,NULL);
494 futex_down(&async_futex);
495
496 cur = timeout_list.next;
497 while (cur != &timeout_list) {
498 waiter = list_get_instance(cur, awaiter_t, link);
499 if (tv_gt(&waiter->expires, &tv))
500 break;
501 cur = cur->next;
502 list_remove(&waiter->link);
503 waiter->inlist = 0;
504 waiter->timedout = 1;
505 /* Redundant condition? The fibril should not
506 * be active when it gets here.
507 */
508 if (!waiter->active) {
509 waiter->active = 1;
510 fibril_add_ready(waiter->fid);
511 }
512 }
513
514 futex_up(&async_futex);
515}
516
517/** Endless loop dispatching incoming calls and answers */
518static int async_manager_worker(void)
519{
520 ipc_call_t call;
521 ipc_callid_t callid;
522 int timeout;
523 awaiter_t *waiter;
524 struct timeval tv;
525
526 while (1) {
527 if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) {
528 futex_up(&async_futex);
529 /* async_futex is always held
530 * when entering manager fibril
531 */
532 continue;
533 }
534 futex_down(&async_futex);
535 if (!list_empty(&timeout_list)) {
536 waiter = list_get_instance(timeout_list.next, awaiter_t,
537 link);
538 gettimeofday(&tv, NULL);
539 if (tv_gteq(&tv, &waiter->expires)) {
540 futex_up(&async_futex);
541 handle_expired_timeouts();
542 continue;
543 } else
544 timeout = tv_sub(&waiter->expires, &tv);
545 } else
546 timeout = SYNCH_NO_TIMEOUT;
547 futex_up(&async_futex);
548
549 callid = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
550
551 if (!callid) {
552 handle_expired_timeouts();
553 continue;
554 }
555
556 if (callid & IPC_CALLID_ANSWERED) {
557 continue;
558 }
559
560 handle_call(callid, &call);
561 }
562
563 return 0;
564}
565
566/** Function to start async_manager as a standalone fibril.
567 *
568 * When more kernel threads are used, one async manager should
569 * exist per thread.
570 */
571static int async_manager_fibril(void *arg)
572{
573 futex_up(&async_futex);
574 /* async_futex is always locked when entering
575 * manager */
576 async_manager_worker();
577
578 return 0;
579}
580
581/** Add one manager to manager list */
582void async_create_manager(void)
583{
584 fid_t fid;
585
586 fid = fibril_create(async_manager_fibril, NULL);
587 fibril_add_manager(fid);
588}
589
590/** Remove one manager from manager list */
591void async_destroy_manager(void)
592{
593 fibril_remove_manager();
594}
595
596/** Initialize internal structures needed for async manager */
597int _async_init(void)
598{
599 if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
600 &conn_hash_table_ops)) {
601 printf("%s: cannot create hash table\n", "async");
602 return ENOMEM;
603 }
604
605 return 0;
606}
607
608/** IPC handler for messages in async framework
609 *
610 * Notify the fibril which is waiting for this message, that it arrived
611 */
612static void reply_received(void *private, int retval, ipc_call_t *data)
613{
614 amsg_t *msg = (amsg_t *) private;
615
616 msg->retval = retval;
617
618 futex_down(&async_futex);
619 /* Copy data after futex_down, just in case the
620 * call was detached
621 */
622 if (msg->dataptr)
623 *msg->dataptr = *data;
624
625 write_barrier();
626 /* Remove message from timeout list */
627 if (msg->wdata.inlist)
628 list_remove(&msg->wdata.link);
629 msg->done = 1;
630 if (! msg->wdata.active) {
631 msg->wdata.active = 1;
632 fibril_add_ready(msg->wdata.fid);
633 }
634 futex_up(&async_futex);
635}
636
637/** Send message and return id of the sent message
638 *
639 * The return value can be used as input for async_wait() to wait
640 * for completion.
641 */
642aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
643 ipc_call_t *dataptr)
644{
645 amsg_t *msg;
646
647 if (in_interrupt_handler) {
648 printf("Cannot send asynchronous request in interrupt "
649 "handler.\n");
650 _exit(1);
651 }
652
653 msg = malloc(sizeof(*msg));
654 msg->done = 0;
655 msg->dataptr = dataptr;
656
657 msg->wdata.active = 1; /* We may sleep in next method, but it
658 * will use it's own mechanism */
659 ipc_call_async_2(phoneid, method, arg1, arg2, msg, reply_received, 1);
660
661 return (aid_t) msg;
662}
663
664/** Send message and return id of the sent message
665 *
666 * The return value can be used as input for async_wait() to wait
667 * for completion.
668 */
669aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
670 ipcarg_t arg3, ipc_call_t *dataptr)
671{
672 amsg_t *msg;
673
674 if (in_interrupt_handler) {
675 printf("Cannot send asynchronous request in interrupt handler.\n");
676 _exit(1);
677 }
678
679 msg = malloc(sizeof(*msg));
680 msg->done = 0;
681 msg->dataptr = dataptr;
682
683 msg->wdata.active = 1; /* We may sleep in next method, but it
684 * will use it's own mechanism */
685 ipc_call_async_3(phoneid, method, arg1, arg2, arg3, msg, reply_received,
686 1);
687
688 return (aid_t) msg;
689}
690
691/** Wait for a message sent by async framework
692 *
693 * @param amsgid Message ID to wait for
694 * @param retval Pointer to variable where will be stored retval of the
695 * answered message. If NULL, it is ignored.
696 */
697void async_wait_for(aid_t amsgid, ipcarg_t *retval)
698{
699 amsg_t *msg = (amsg_t *) amsgid;
700
701 futex_down(&async_futex);
702 if (msg->done) {
703 futex_up(&async_futex);
704 goto done;
705 }
706
707 msg->wdata.fid = fibril_get_id();
708 msg->wdata.active = 0;
709 msg->wdata.inlist = 0;
710 /* Leave locked async_futex when entering this function */
711 fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
712 /* futex is up automatically after fibril_schedule_next...*/
713done:
714 if (retval)
715 *retval = msg->retval;
716 free(msg);
717}
718
719/** Wait for a message sent by async framework with timeout
720 *
721 * @param amsgid Message ID to wait for
722 * @param retval Pointer to variable where will be stored retval
723 * of the answered message. If NULL, it is ignored.
724 * @param timeout Timeout in usecs
725 * @return 0 on success, ETIMEOUT if timeout expired
726 *
727 */
728int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
729{
730 amsg_t *msg = (amsg_t *) amsgid;
731
732 /* TODO: Let it go through the event read at least once */
733 if (timeout < 0)
734 return ETIMEOUT;
735
736 futex_down(&async_futex);
737 if (msg->done) {
738 futex_up(&async_futex);
739 goto done;
740 }
741
742 gettimeofday(&msg->wdata.expires, NULL);
743 tv_add(&msg->wdata.expires, timeout);
744
745 msg->wdata.fid = fibril_get_id();
746 msg->wdata.active = 0;
747 insert_timeout(&msg->wdata);
748
749 /* Leave locked async_futex when entering this function */
750 fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
751 /* futex is up automatically after fibril_schedule_next...*/
752
753 if (!msg->done)
754 return ETIMEOUT;
755
756done:
757 if (retval)
758 *retval = msg->retval;
759 free(msg);
760
761 return 0;
762}
763
764/** Wait specified time, but in the meantime handle incoming events
765 *
766 * @param timeout Time in microseconds to wait
767 */
768void async_usleep(suseconds_t timeout)
769{
770 amsg_t *msg;
771
772 if (in_interrupt_handler) {
773 printf("Cannot call async_usleep in interrupt handler.\n");
774 _exit(1);
775 }
776
777 msg = malloc(sizeof(*msg));
778 if (!msg)
779 return;
780
781 msg->wdata.fid = fibril_get_id();
782 msg->wdata.active = 0;
783
784 gettimeofday(&msg->wdata.expires, NULL);
785 tv_add(&msg->wdata.expires, timeout);
786
787 futex_down(&async_futex);
788 insert_timeout(&msg->wdata);
789 /* Leave locked the async_futex when entering this function */
790 fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
791 /* futex is up automatically after fibril_schedule_next_adv()...*/
792 free(msg);
793}
794
795/** Set function that is called when IPC_M_CONNECT_ME_TO is received.
796 *
797 * @param conn Function that will form a new fibril.
798 */
799void async_set_client_connection(async_client_conn_t conn)
800{
801 client_connection = conn;
802}
803void async_set_interrupt_received(async_client_conn_t conn)
804{
805 interrupt_received = conn;
806}
807
808/* Primitive functions for simple communication */
809void async_msg_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
810 ipcarg_t arg2, ipcarg_t arg3)
811{
812 ipc_call_async_3(phoneid, method, arg1, arg2, arg3, NULL, NULL,
813 !in_interrupt_handler);
814}
815
816void async_msg_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2)
817{
818 ipc_call_async_2(phoneid, method, arg1, arg2, NULL, NULL,
819 !in_interrupt_handler);
820}
821
822/** @}
823 */
Note: See TracBrowser for help on using the repository browser.