/trunk/uspace/lib/libc/generic/psthread.c |
---|
File deleted |
/trunk/uspace/lib/libc/generic/thread.c |
---|
37,7 → 37,7 |
#include <stdlib.h> |
#include <libarch/faddr.h> |
#include <kernel/proc/uarg.h> |
#include <psthread.h> |
#include <fibril.h> |
#include <string.h> |
#include <async.h> |
100,10 → 100,10 |
*/ |
void __thread_main(uspace_arg_t *uarg) |
{ |
psthread_data_t *pt; |
fibril_t *f; |
pt = psthread_setup(); |
__tcb_set(pt->tcb); |
f = fibril_setup(); |
__tcb_set(f->tcb); |
uarg->uspace_thread_function(uarg->uspace_thread_arg); |
/* XXX: we cannot free the userspace stack while running on it */ |
112,7 → 112,7 |
/* If there is a manager, destroy it */ |
async_destroy_manager(); |
psthread_teardown(pt); |
fibril_teardown(f); |
thread_exit(0); |
} |
/trunk/uspace/lib/libc/generic/fibril.c |
---|
0,0 → 1,374 |
/* |
* Copyright (c) 2006 Ondrej Palkovsky |
* Copyright (c) 2007 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libc |
* @{ |
*/ |
/** @file |
*/ |
#include <libadt/list.h> |
#include <fibril.h> |
#include <malloc.h> |
#include <unistd.h> |
#include <thread.h> |
#include <stdio.h> |
#include <libarch/faddr.h> |
#include <futex.h> |
#include <assert.h> |
#include <async.h> |
#ifndef FIBRIL_INITIAL_STACK_PAGES_NO |
#define FIBRIL_INITIAL_STACK_PAGES_NO 1 |
#endif |
static LIST_INITIALIZE(ready_list); |
static LIST_INITIALIZE(serialized_list); |
static LIST_INITIALIZE(manager_list); |
static void fibril_main(void); |
static atomic_t fibril_futex = FUTEX_INITIALIZER; |
/** Number of threads that are in async_serialized mode */ |
static int serialized_threads; /* Protected by async_futex */ |
/** Thread-local count of serialization. If >0, we must not preempt */ |
static __thread int serialization_count; |
/** Counter for fibrils residing in async_manager */ |
static int fibrils_in_manager; |
/** Setup fibril information into TCB structure */ |
fibril_t *fibril_setup(void) |
{ |
fibril_t *f; |
tcb_t *tcb; |
tcb = __make_tls(); |
if (!tcb) |
return NULL; |
f = malloc(sizeof(*f)); |
if (!f) { |
__free_tls(tcb); |
return NULL; |
} |
tcb->fibril_data = f; |
f->tcb = tcb; |
return f; |
} |
void fibril_teardown(fibril_t *f) |
{ |
__free_tls(f->tcb); |
free(f); |
} |
/** Function that spans the whole life-cycle of a fibril. |
* |
* Each fibril begins execution in this function. Then the function |
* implementing the fibril logic is called. After its return, the return value |
* is saved for a potentional joiner. If the joiner exists, it is woken up. The |
* fibril then switches to another fibril, which cleans up after it. |
*/ |
void fibril_main(void) |
{ |
fibril_t *f = __tcb_get()->fibril_data; |
f->retval = f->func(f->arg); |
/* |
* If there is a joiner, wake it up and save our return value. |
*/ |
if (f->joiner) { |
list_append(&f->joiner->link, &ready_list); |
f->joiner->joinee_retval = f->retval; |
} |
fibril_schedule_next_adv(FIBRIL_FROM_DEAD); |
/* not reached */ |
} |
/** Schedule next fibril. |
* |
* If calling with FIBRIL_TO_MANAGER parameter, the async_futex should be |
* held. |
* |
* @param stype One of FIBRIL_SLEEP, FIBRIL_PREEMPT, FIBRIL_TO_MANAGER, |
* FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter |
* describes the circumstances of the switch. |
* @return Return 0 if there is no ready fibril, |
* return 1 otherwise. |
*/ |
int fibril_schedule_next_adv(fibril_switch_type_t stype) |
{ |
fibril_t *srcf, *dstf; |
int retval = 0; |
futex_down(&fibril_futex); |
if (stype == FIBRIL_PREEMPT && list_empty(&ready_list)) |
goto ret_0; |
if (stype == FIBRIL_SLEEP) { |
if (list_empty(&ready_list) && list_empty(&serialized_list)) |
goto ret_0; |
} |
if (stype == FIBRIL_FROM_MANAGER) { |
if (list_empty(&ready_list) && list_empty(&serialized_list)) |
goto ret_0; |
/* |
* Do not preempt if there is not sufficient count of thread |
* managers. |
*/ |
if (list_empty(&serialized_list) && fibrils_in_manager <= |
serialized_threads) { |
goto ret_0; |
} |
} |
/* If we are going to manager and none exists, create it */ |
if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) { |
while (list_empty(&manager_list)) { |
futex_up(&fibril_futex); |
async_create_manager(); |
futex_down(&fibril_futex); |
} |
} |
srcf = __tcb_get()->fibril_data; |
if (stype != FIBRIL_FROM_DEAD) { |
/* Save current state */ |
if (!context_save(&srcf->ctx)) { |
if (serialization_count) |
srcf->flags &= ~FIBRIL_SERIALIZED; |
if (srcf->clean_after_me) { |
/* |
* Cleanup after the dead fibril from which we |
* restored context here. |
*/ |
free(srcf->clean_after_me->stack); |
fibril_teardown(srcf->clean_after_me); |
srcf->clean_after_me = NULL; |
} |
return 1; /* futex_up already done here */ |
} |
/* Save myself to the correct run list */ |
if (stype == FIBRIL_PREEMPT) |
list_append(&srcf->link, &ready_list); |
else if (stype == FIBRIL_FROM_MANAGER) { |
list_append(&srcf->link, &manager_list); |
fibrils_in_manager--; |
} else { |
/* |
* If stype == FIBRIL_TO_MANAGER, don't put ourselves to |
* any list, we should already be somewhere, or we will |
* be lost. |
* |
* The stype == FIBRIL_SLEEP case is similar. The fibril |
* has an external refernce which can be used to wake it |
* up once that time has come. |
*/ |
} |
} |
/* Choose a new fibril to run */ |
if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) { |
dstf = list_get_instance(manager_list.next, fibril_t, link); |
if (serialization_count && stype == FIBRIL_TO_MANAGER) { |
serialized_threads++; |
srcf->flags |= FIBRIL_SERIALIZED; |
} |
fibrils_in_manager++; |
if (stype == FIBRIL_FROM_DEAD) |
dstf->clean_after_me = srcf; |
} else { |
if (!list_empty(&serialized_list)) { |
dstf = list_get_instance(serialized_list.next, fibril_t, |
link); |
serialized_threads--; |
} else { |
dstf = list_get_instance(ready_list.next, fibril_t, |
link); |
} |
} |
list_remove(&dstf->link); |
futex_up(&fibril_futex); |
context_restore(&dstf->ctx); |
/* not reached */ |
ret_0: |
futex_up(&fibril_futex); |
return retval; |
} |
/** Wait for fibril to finish. |
* |
* Each fibril can be only joined by one other fibril. Moreover, the joiner must |
* be from the same thread as the joinee. |
* |
* @param fid Fibril to join. |
* |
* @return Value returned by the completed fibril. |
*/ |
int fibril_join(fid_t fid) |
{ |
fibril_t *f; |
fibril_t *cur; |
/* Handle fid = Kernel address -> it is wait for call */ |
f = (fibril_t *) fid; |
/* |
* The joiner is running so the joinee isn't. |
*/ |
cur = __tcb_get()->fibril_data; |
f->joiner = cur; |
fibril_schedule_next_adv(FIBRIL_SLEEP); |
/* |
* The joinee fills in the return value. |
*/ |
return cur->joinee_retval; |
} |
/** Create a new fibril. |
* |
* @param func Implementing function of the new fibril. |
* @param arg Argument to pass to func. |
* |
* @return Return 0 on failure or TLS of the new fibril. |
*/ |
fid_t fibril_create(int (*func)(void *), void *arg) |
{ |
fibril_t *f; |
f = fibril_setup(); |
if (!f) |
return 0; |
f->stack = (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * |
getpagesize()); |
if (!f->stack) { |
fibril_teardown(f); |
return 0; |
} |
f->arg = arg; |
f->func = func; |
f->clean_after_me = NULL; |
f->joiner = NULL; |
f->joinee_retval = 0; |
f->retval = 0; |
f->flags = 0; |
context_save(&f->ctx); |
context_set(&f->ctx, FADDR(fibril_main), f->stack, |
FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), f->tcb); |
return (fid_t) f; |
} |
/** Add a fibril to the ready list. |
* |
* @param fid Pinter to the fibril structure of the fibril to be added. |
*/ |
void fibril_add_ready(fid_t fid) |
{ |
fibril_t *f; |
f = (fibril_t *) fid; |
futex_down(&fibril_futex); |
if ((f->flags & FIBRIL_SERIALIZED)) |
list_append(&f->link, &serialized_list); |
else |
list_append(&f->link, &ready_list); |
futex_up(&fibril_futex); |
} |
/** Add a fibril to the manager list. |
* |
* @param fid Pinter to the fibril structure of the fibril to be added. |
*/ |
void fibril_add_manager(fid_t fid) |
{ |
fibril_t *f; |
f = (fibril_t *) fid; |
futex_down(&fibril_futex); |
list_append(&f->link, &manager_list); |
futex_up(&fibril_futex); |
} |
/** Remove one manager from the manager list. */ |
void fibril_remove_manager(void) |
{ |
futex_down(&fibril_futex); |
if (list_empty(&manager_list)) { |
futex_up(&fibril_futex); |
return; |
} |
list_remove(manager_list.next); |
futex_up(&fibril_futex); |
} |
/** Return fibril id of the currently running fibril. |
* |
* @return Fibril ID of the currently running pseudo thread. |
*/ |
fid_t fibril_get_id(void) |
{ |
return (fid_t) __tcb_get()->fibril_data; |
} |
/** Disable preemption |
* |
* If the fibril wants to send several message in a row and does not want to be |
* preempted, it should start async_serialize_start() in the beginning of |
* communication and async_serialize_end() in the end. If it is a true |
* multithreaded application, it should protect the communication channel by a |
* futex as well. Interrupt messages can still be preempted. |
*/ |
void fibril_inc_sercount(void) |
{ |
serialization_count++; |
} |
/** Restore the preemption counter to the previous state. */ |
void fibril_dec_sercount(void) |
{ |
serialization_count--; |
} |
/** @} |
*/ |
/trunk/uspace/lib/libc/generic/libc.c |
---|
42,7 → 42,7 |
#include <unistd.h> |
#include <thread.h> |
#include <malloc.h> |
#include <psthread.h> |
#include <fibril.h> |
#include <io/stream.h> |
#include <ipc/ipc.h> |
#include <async.h> |
57,12 → 57,12 |
void __main(void) |
{ |
psthread_data_t *pt; |
fibril_t *f; |
(void) as_area_create(&_heap, 1, AS_AREA_WRITE | AS_AREA_READ); |
_async_init(); |
pt = psthread_setup(); |
__tcb_set(pt->tcb); |
f = fibril_setup(); |
__tcb_set(f->tcb); |
} |
void __io_init(void) |
74,7 → 74,7 |
void __exit(void) |
{ |
psthread_teardown(__tcb_get()->pst_data); |
fibril_teardown(__tcb_get()->fibril_data); |
_exit(0); |
} |
/trunk/uspace/lib/libc/generic/ipc.c |
---|
49,7 → 49,7 |
#include <futex.h> |
#include <kernel/synch/synch.h> |
#include <async.h> |
#include <psthread.h> |
#include <fibril.h> |
/** Structure used for keeping track of sent asynchronous calls and queing |
* unsent calls. |
66,7 → 66,7 |
int phoneid; |
} msg; |
} u; |
pstid_t ptid; /**< Pseudothread waiting for sending this call. */ |
fid_t fid; /**< Fibril waiting for sending this call. */ |
} async_call_t; |
LIST_INITIALIZE(dispatched_calls); |
216,11 → 216,11 |
list_append(&call->list, &queued_calls); |
if (can_preempt) { |
call->ptid = psthread_get_id(); |
psthread_schedule_next_adv(PS_TO_MANAGER); |
call->fid = fibril_get_id(); |
fibril_schedule_next_adv(FIBRIL_TO_MANAGER); |
/* Async futex unlocked by previous call */ |
} else { |
call->ptid = 0; |
call->fid = 0; |
futex_up(&async_futex); |
} |
return; |
383,8 → 383,8 |
list_remove(&call->list); |
futex_up(&async_futex); |
if (call->ptid) |
psthread_add_ready(call->ptid); |
if (call->fid) |
fibril_add_ready(call->fid); |
if (callid == IPC_CALLRET_FATAL) { |
if (call->callback) |
/trunk/uspace/lib/libc/generic/async.c |
---|
85,11 → 85,10 |
* .... |
* } |
* |
* TODO: Detaching/joining dead psthreads? |
*/ |
#include <futex.h> |
#include <async.h> |
#include <psthread.h> |
#include <fibril.h> |
#include <stdio.h> |
#include <libadt/hash_table.h> |
#include <libadt/list.h> |
104,13 → 103,18 |
static LIST_INITIALIZE(timeout_list); |
typedef struct { |
struct timeval expires; /**< Expiration time for waiting thread */ |
int inlist; /**< If true, this struct is in timeout list */ |
/** Expiration time for waiting fibril. */ |
struct timeval expires; |
/** If true, this struct is in the timeout list. */ |
int inlist; |
link_t link; |
pstid_t ptid; /**< Thread waiting for this message */ |
int active; /**< If this thread is currently active */ |
int timedout; /**< If true, we timed out */ |
/** Fibril waiting for this message. */ |
fid_t fid; |
/** If this fibril is currently active. */ |
int active; |
/** If true, we timed out. */ |
int timedout; |
} awaiter_t; |
typedef struct { |
118,7 → 122,7 |
int done; /**< If reply was received */ |
ipc_call_t *dataptr; /**< Pointer where the answer data |
* is stored */ |
* is stored */ |
ipcarg_t retval; |
} amsg_t; |
131,18 → 135,19 |
typedef struct { |
awaiter_t wdata; |
link_t link; /**< Hash table link */ |
link_t link; /**< Hash table link. */ |
ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
link_t msg_queue; /**< Messages that should be delivered to this thread */ |
link_t msg_queue; /**< Messages that should be delivered |
* to this fibril. */ |
/* Structures for connection opening packet */ |
ipc_callid_t callid; |
ipc_call_t call; |
ipc_callid_t close_callid; /* Identification of closing packet */ |
void (*cthread)(ipc_callid_t,ipc_call_t *); |
ipc_callid_t close_callid; /* Identification of closing packet. */ |
void (*cfibril)(ipc_callid_t, ipc_call_t *); |
} connection_t; |
/** Identifier of incoming connection handled by current thread */ |
__thread connection_t *PS_connection; |
/** Identifier of the incoming connection handled by the current fibril. */ |
__thread connection_t *FIBRIL_connection; |
/** If true, it is forbidden to use async_req functions and |
* all preemption is disabled */ |
__thread int in_interrupt_handler; |
285,7 → 290,7 |
list_remove(&conn->wdata.link); |
} |
conn->wdata.active = 1; |
psthread_add_ready(conn->wdata.ptid); |
fibril_add_ready(conn->wdata.fid); |
} |
futex_up(&async_futex); |
300,13 → 305,13 |
ipc_callid_t callid; |
connection_t *conn; |
assert(PS_connection); |
/* GCC 4.1.0 coughs on PS_connection-> dereference, |
assert(FIBRIL_connection); |
/* GCC 4.1.0 coughs on FIBRIL_connection-> dereference, |
* GCC 4.1.1 happilly puts the rdhwr instruction in delay slot. |
* I would never expect to find so many errors in |
* compiler *($&$(*&$ |
*/ |
conn = PS_connection; |
conn = FIBRIL_connection; |
futex_down(&async_futex); |
322,11 → 327,11 |
insert_timeout(&conn->wdata); |
conn->wdata.active = 0; |
psthread_schedule_next_adv(PS_TO_MANAGER); |
fibril_schedule_next_adv(FIBRIL_TO_MANAGER); |
/* Futex is up after getting back from async_manager |
* get it again */ |
futex_down(&async_futex); |
if (usecs && conn->wdata.timedout && \ |
if (usecs && conn->wdata.timedout && |
list_empty(&conn->msg_queue)) { |
/* If we timed out-> exit */ |
futex_up(&async_futex); |
364,7 → 369,7 |
* |
* @param arg Connection structure pointer |
*/ |
static int connection_thread(void *arg) |
static int connection_fibril(void *arg) |
{ |
unsigned long key; |
msg_t *msg; |
371,26 → 376,28 |
int close_answered = 0; |
/* Setup thread local connection pointer */ |
PS_connection = (connection_t *)arg; |
PS_connection->cthread(PS_connection->callid, &PS_connection->call); |
FIBRIL_connection = (connection_t *) arg; |
FIBRIL_connection->cfibril(FIBRIL_connection->callid, |
&FIBRIL_connection->call); |
/* Remove myself from connection hash table */ |
futex_down(&async_futex); |
key = PS_connection->in_phone_hash; |
key = FIBRIL_connection->in_phone_hash; |
hash_table_remove(&conn_hash_table, &key, 1); |
futex_up(&async_futex); |
/* Answer all remaining messages with ehangup */ |
while (!list_empty(&PS_connection->msg_queue)) { |
msg = list_get_instance(PS_connection->msg_queue.next, msg_t, link); |
while (!list_empty(&FIBRIL_connection->msg_queue)) { |
msg = list_get_instance(FIBRIL_connection->msg_queue.next, |
msg_t, link); |
list_remove(&msg->link); |
if (msg->callid == PS_connection->close_callid) |
if (msg->callid == FIBRIL_connection->close_callid) |
close_answered = 1; |
ipc_answer_fast(msg->callid, EHANGUP, 0, 0); |
free(msg); |
} |
if (PS_connection->close_callid) |
ipc_answer_fast(PS_connection->close_callid, 0, 0, 0); |
if (FIBRIL_connection->close_callid) |
ipc_answer_fast(FIBRIL_connection->close_callid, 0, 0, 0); |
return 0; |
} |
405,11 → 412,12 |
* @param in_phone_hash Identification of the incoming connection |
* @param callid Callid of the IPC_M_CONNECT_ME_TO packet |
* @param call Call data of the opening packet |
* @param cthread Thread function that should be called upon |
* @param cfibril Fibril function that should be called upon |
* opening the connection |
* @return New thread id |
* @return New fibril id. |
*/ |
pstid_t async_new_connection(ipcarg_t in_phone_hash,ipc_callid_t callid, ipc_call_t *call, void (*cthread)(ipc_callid_t, ipc_call_t *)) |
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid, |
ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *)) |
{ |
connection_t *conn; |
unsigned long key; |
426,10 → 434,10 |
if (call) |
conn->call = *call; |
conn->wdata.active = 1; /* We will activate it asap */ |
conn->cthread = cthread; |
conn->cfibril = cfibril; |
conn->wdata.ptid = psthread_create(connection_thread, conn); |
if (!conn->wdata.ptid) { |
conn->wdata.fid = fibril_create(connection_fibril, conn); |
if (!conn->wdata.fid) { |
free(conn); |
ipc_answer_fast(callid, ENOMEM, 0, 0); |
return NULL; |
440,9 → 448,9 |
hash_table_insert(&conn_hash_table, &key, &conn->link); |
futex_up(&async_futex); |
psthread_add_ready(conn->wdata.ptid); |
fibril_add_ready(conn->wdata.fid); |
return conn->wdata.ptid; |
return conn->wdata.fid; |
} |
/** Handle call that was received */ |
459,7 → 467,8 |
switch (IPC_GET_METHOD(*call)) { |
case IPC_M_CONNECT_ME_TO: |
/* Open new connection with thread etc. */ |
async_new_connection(IPC_GET_ARG3(*call), callid, call, client_connection); |
async_new_connection(IPC_GET_ARG3(*call), callid, call, |
client_connection); |
return; |
} |
485,7 → 494,7 |
cur = timeout_list.next; |
while (cur != &timeout_list) { |
waiter = list_get_instance(cur,awaiter_t,link); |
waiter = list_get_instance(cur, awaiter_t, link); |
if (tv_gt(&waiter->expires, &tv)) |
break; |
cur = cur->next; |
497,7 → 506,7 |
*/ |
if (!waiter->active) { |
waiter->active = 1; |
psthread_add_ready(waiter->ptid); |
fibril_add_ready(waiter->fid); |
} |
} |
514,7 → 523,7 |
struct timeval tv; |
while (1) { |
if (psthread_schedule_next_adv(PS_FROM_MANAGER)) { |
if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) { |
futex_up(&async_futex); |
/* async_futex is always held |
* when entering manager thread |
523,8 → 532,9 |
} |
futex_down(&async_futex); |
if (!list_empty(&timeout_list)) { |
waiter = list_get_instance(timeout_list.next,awaiter_t,link); |
gettimeofday(&tv,NULL); |
waiter = list_get_instance(timeout_list.next, awaiter_t, |
link); |
gettimeofday(&tv, NULL); |
if (tv_gteq(&tv, &waiter->expires)) { |
futex_up(&async_futex); |
handle_expired_timeouts(); |
572,22 → 582,23 |
/** Add one manager to manager list */ |
void async_create_manager(void) |
{ |
pstid_t ptid; |
fid_t fid; |
ptid = psthread_create(async_manager_thread, NULL); |
psthread_add_manager(ptid); |
fid = fibril_create(async_manager_thread, NULL); |
fibril_add_manager(fid); |
} |
/** Remove one manager from manager list */ |
void async_destroy_manager(void) |
{ |
psthread_remove_manager(); |
fibril_remove_manager(); |
} |
/** Initialize internal structures needed for async manager */ |
int _async_init(void) |
{ |
if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1, &conn_hash_table_ops)) { |
if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1, |
&conn_hash_table_ops)) { |
printf("%s: cannot create hash table\n", "async"); |
return ENOMEM; |
} |
597,7 → 608,7 |
/** IPC handler for messages in async framework |
* |
* Notify thread that is waiting for this message, that it arrived |
* Notify the fibril which is waiting for this message, that it arrived |
*/ |
static void reply_received(void *private, int retval, |
ipc_call_t *data) |
620,7 → 631,7 |
msg->done = 1; |
if (! msg->wdata.active) { |
msg->wdata.active = 1; |
psthread_add_ready(msg->wdata.ptid); |
fibril_add_ready(msg->wdata.fid); |
} |
futex_up(&async_futex); |
} |
636,7 → 647,8 |
amsg_t *msg; |
if (in_interrupt_handler) { |
printf("Cannot send asynchronous request in interrupt handler.\n"); |
printf("Cannot send asynchronous request in interrupt " |
"handler.\n"); |
_exit(1); |
} |
646,7 → 658,7 |
msg->wdata.active = 1; /* We may sleep in next method, but it |
* will use it's own mechanism */ |
ipc_call_async_2(phoneid,method,arg1,arg2,msg,reply_received,1); |
ipc_call_async_2(phoneid, method, arg1, arg2, msg, reply_received, 1); |
return (aid_t) msg; |
} |
672,7 → 684,8 |
msg->wdata.active = 1; /* We may sleep in next method, but it |
* will use it's own mechanism */ |
ipc_call_async_3(phoneid,method,arg1,arg2,arg3, msg,reply_received,1); |
ipc_call_async_3(phoneid, method, arg1, arg2, arg3, msg, reply_received, |
1); |
return (aid_t) msg; |
} |
694,12 → 707,12 |
goto done; |
} |
msg->wdata.ptid = psthread_get_id(); |
msg->wdata.fid = fibril_get_id(); |
msg->wdata.active = 0; |
msg->wdata.inlist = 0; |
/* Leave locked async_futex when entering this function */ |
psthread_schedule_next_adv(PS_TO_MANAGER); |
/* futex is up automatically after psthread_schedule_next...*/ |
fibril_schedule_next_adv(FIBRIL_TO_MANAGER); |
/* futex is up automatically after fibril_schedule_next...*/ |
done: |
if (retval) |
*retval = msg->retval; |
732,13 → 745,13 |
gettimeofday(&msg->wdata.expires, NULL); |
tv_add(&msg->wdata.expires, timeout); |
msg->wdata.ptid = psthread_get_id(); |
msg->wdata.fid = fibril_get_id(); |
msg->wdata.active = 0; |
insert_timeout(&msg->wdata); |
/* Leave locked async_futex when entering this function */ |
psthread_schedule_next_adv(PS_TO_MANAGER); |
/* futex is up automatically after psthread_schedule_next...*/ |
fibril_schedule_next_adv(FIBRIL_TO_MANAGER); |
/* futex is up automatically after fibril_schedule_next...*/ |
if (!msg->done) |
return ETIMEOUT; |
768,7 → 781,7 |
if (!msg) |
return; |
msg->wdata.ptid = psthread_get_id(); |
msg->wdata.fid = fibril_get_id(); |
msg->wdata.active = 0; |
gettimeofday(&msg->wdata.expires, NULL); |
777,8 → 790,8 |
futex_down(&async_futex); |
insert_timeout(&msg->wdata); |
/* Leave locked async_futex when entering this function */ |
psthread_schedule_next_adv(PS_TO_MANAGER); |
/* futex is up automatically after psthread_schedule_next...*/ |
fibril_schedule_next_adv(FIBRIL_TO_MANAGER); |
/* futex is up automatically after fibril_schedule_next...*/ |
free(msg); |
} |
799,12 → 812,14 |
void async_msg_3(int phoneid, ipcarg_t method, ipcarg_t arg1, |
ipcarg_t arg2, ipcarg_t arg3) |
{ |
ipc_call_async_3(phoneid, method, arg1, arg2, arg3, NULL, NULL, !in_interrupt_handler); |
ipc_call_async_3(phoneid, method, arg1, arg2, arg3, NULL, NULL, |
!in_interrupt_handler); |
} |
void async_msg_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2) |
{ |
ipc_call_async_2(phoneid, method, arg1, arg2, NULL, NULL, !in_interrupt_handler); |
ipc_call_async_2(phoneid, method, arg1, arg2, NULL, NULL, |
!in_interrupt_handler); |
} |
/** @} |