source: mainline/libc/generic/async.c@ ce5bcb4

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

Fixed race condition in async framework on phone disconnect.

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