Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1367 → Rev 1392

/uspace/trunk/libc/generic/libadt/hash_table.c
0,0 → 1,170
/*
* Copyright (C) 2006 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.
*/
 
/*
* This is an implementation of generic chained hash table.
*/
 
#include <libadt/hash_table.h>
#include <libadt/list.h>
#include <unistd.h>
#include <malloc.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
 
/** Create chained hash table.
*
* @param h Hash table structure. Will be initialized by this call.
* @param m Number of slots in the hash table.
* @param max_keys Maximal number of keys needed to identify an item.
* @param op Hash table operations structure.
* @return true on success
*/
int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, hash_table_operations_t *op)
{
hash_count_t i;
 
assert(h);
assert(op && op->hash && op->compare);
assert(max_keys > 0);
h->entry = malloc(m * sizeof(link_t));
if (!h->entry) {
printf("cannot allocate memory for hash table\n");
return false;
}
memset((void *) h->entry, 0, m * sizeof(link_t));
for (i = 0; i < m; i++)
list_initialize(&h->entry[i]);
h->entries = m;
h->max_keys = max_keys;
h->op = op;
return true;
}
 
/** Insert item into hash table.
*
* @param h Hash table.
* @param hey Array of all keys necessary to compute hash index.
* @param item Item to be inserted into the hash table.
*/
void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item)
{
hash_index_t chain;
 
assert(item);
assert(h && h->op && h->op->hash && h->op->compare);
 
chain = h->op->hash(key);
assert(chain < h->entries);
list_append(item, &h->entry[chain]);
}
 
/** Search hash table for an item matching keys.
*
* @param h Hash table.
* @param key Array of all keys needed to compute hash index.
*
* @return Matching item on success, NULL if there is no such item.
*/
link_t *hash_table_find(hash_table_t *h, unsigned long key[])
{
link_t *cur;
hash_index_t chain;
 
assert(h && h->op && h->op->hash && h->op->compare);
 
chain = h->op->hash(key);
assert(chain < h->entries);
for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
if (h->op->compare(key, h->max_keys, cur)) {
/*
* The entry is there.
*/
return cur;
}
}
return NULL;
}
 
/** Remove all matching items from hash table.
*
* For each removed item, h->remove_callback() is called.
*
* @param h Hash table.
* @param key Array of keys that will be compared against items of the hash table.
* @param keys Number of keys in the 'key' array.
*/
void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys)
{
hash_index_t chain;
link_t *cur;
 
assert(h && h->op && h->op->hash && h->op->compare && h->op->remove_callback);
assert(keys <= h->max_keys);
if (keys == h->max_keys) {
 
/*
* All keys are known, hash_table_find() can be used to find the entry.
*/
cur = hash_table_find(h, key);
if (cur) {
list_remove(cur);
h->op->remove_callback(cur);
}
return;
}
/*
* Fewer keys were passed.
* Any partially matching entries are to be removed.
*/
for (chain = 0; chain < h->entries; chain++) {
for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
if (h->op->compare(key, keys, cur)) {
link_t *hlp;
hlp = cur;
cur = cur->prev;
list_remove(hlp);
h->op->remove_callback(hlp);
continue;
}
}
}
}
/uspace/trunk/libc/generic/libadt/list.c
0,0 → 1,80
/*
* Copyright (C) 2004 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.
*/
 
#include <libadt/list.h>
 
 
/** Check for membership
*
* Check whether link is contained in the list head.
* The membership is defined as pointer equivalence.
*
* @param link Item to look for.
* @param head List to look in.
*
* @return true if link is contained in head, false otherwise.
*
*/
int list_member(const link_t *link, const link_t *head)
{
int found = false;
link_t *hlp = head->next;
while (hlp != head) {
if (hlp == link) {
found = true;
break;
}
hlp = hlp->next;
}
return found;
}
 
 
/** Concatenate two lists
*
* Concatenate lists head1 and head2, producing a single
* list head1 containing items from both (in head1, head2
* order) and empty list head2.
*
* @param head1 First list and concatenated output
* @param head2 Second list and empty output.
*
*/
void list_concat(link_t *head1, link_t *head2)
{
if (list_empty(head2))
return;
 
head2->next->prev = head1->prev;
head2->prev->next = head1;
head1->prev->next = head2->next;
head1->prev = head2->prev;
list_initialize(head2);
}
/uspace/trunk/libc/generic/thread.c
33,6 → 33,7
#include <kernel/proc/uarg.h>
#include <psthread.h>
#include <string.h>
#include <async.h>
 
#include <stdio.h>
 
80,21 → 81,24
* directly.
*
* @param uarg Pointer to userspace argument structure.
*
* TODO: Thread stack pages memory leak
*/
void __thread_main(uspace_arg_t *uarg)
{
tcb_t *tcb;
/* This should initialize the area according to TLS specicification */
tcb = __make_tls();
__tcb_set(tcb);
psthread_setup(tcb);
psthread_data_t *pt;
 
pt = psthread_setup();
__tcb_set(pt->tcb);
async_create_manager();
 
uarg->uspace_thread_function(uarg->uspace_thread_arg);
free(uarg->uspace_stack);
free(uarg);
 
psthread_teardown(tcb->pst_data);
__free_tls(tcb);
async_destroy_manager();
psthread_teardown(pt);
 
thread_exit(0);
}
/uspace/trunk/libc/generic/libc.c
33,6 → 33,7
#include <psthread.h>
#include <io/stream.h>
#include <ipc/ipc.h>
#include <async.h>
 
void _exit(int status) {
thread_exit(status);
39,12 → 40,11
}
 
void __main(void) {
tcb_t *tcb;
tcb = __make_tls();
__tcb_set(tcb);
psthread_setup(tcb);
_ipc_init();
psthread_data_t *pt;
 
_async_init();
pt = psthread_setup();
__tcb_set(pt->tcb);
}
 
void __io_init(void) {
54,10 → 54,6
}
 
void __exit(void) {
tcb_t *tcb;
 
tcb = __tcb_get();
psthread_teardown(tcb->pst_data);
__free_tls(tcb);
psthread_teardown(__tcb_get()->pst_data);
_exit(0);
}
/uspace/trunk/libc/generic/psthread.c
33,24 → 33,34
#include <thread.h>
#include <stdio.h>
#include <kernel/arch/faddr.h>
#include <futex.h>
#include <assert.h>
 
 
#ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
#define PSTHREAD_INITIAL_STACK_PAGES_NO 1
#endif
 
static LIST_INITIALIZE(ready_list);
static LIST_INITIALIZE(manager_list);
 
static void psthread_exit(void) __attribute__ ((noinline));
static void psthread_main(void);
 
static atomic_t psthread_futex = FUTEX_INITIALIZER;
 
/** Setup PSthread information into TCB structure */
psthread_data_t * psthread_setup(tcb_t *tcb)
psthread_data_t * psthread_setup()
{
psthread_data_t *pt;
tcb_t *tcb;
 
tcb = __make_tls();
if (!tcb)
return NULL;
 
pt = malloc(sizeof(*pt));
if (!pt) {
__free_tls(tcb);
return NULL;
}
 
62,6 → 72,7
 
void psthread_teardown(psthread_data_t *pt)
{
__free_tls(pt->tcb);
free(pt);
}
 
72,14 → 83,21
{
psthread_data_t *pt;
 
if (list_empty(&ready_list)) {
/* Wait on IPC queue etc... */
printf("Cannot exit!!!\n");
futex_down(&psthread_futex);
 
if (!list_empty(&ready_list))
pt = list_get_instance(ready_list.next, psthread_data_t, link);
else if (!list_empty(&manager_list))
pt = list_get_instance(manager_list.next, psthread_data_t, link);
else {
printf("Cannot find suitable psthread to run.\n");
_exit(0);
}
pt = list_get_instance(ready_list.next, psthread_data_t, link);
list_remove(&pt->link);
futex_up(&psthread_futex);
 
context_restore(&pt->ctx);
/* Never reached */
}
 
/** Function that is called on entry to new uspace thread */
98,24 → 116,47
 
/** Schedule next userspace pseudo thread.
*
* @param tomanager If true, we are switching to next ready manager thread
* (if none is found, thread is exited)
* @param frommanager If true, we are switching from manager thread
* @return 0 if there is no ready pseudo thread, 1 otherwise.
*/
int psthread_schedule_next(void)
int psthread_schedule_next_adv(pschange_type ctype)
{
psthread_data_t *pt;
int retval = 0;
futex_down(&psthread_futex);
 
if (list_empty(&ready_list))
return 0;
if (ctype == PS_PREEMPT && list_empty(&ready_list))
goto ret_0;
 
if (ctype == PS_FROM_MANAGER && list_empty(&ready_list)) {
goto ret_0;
}
assert(!(ctype == PS_TO_MANAGER && list_empty(&manager_list)));
 
pt = __tcb_get()->pst_data;
if (!context_save(&pt->ctx))
return 1;
if (!context_save(&pt->ctx))
return 1; // futex_up already done here
 
if (ctype == PS_PREEMPT)
list_append(&pt->link, &ready_list);
else if (ctype == PS_FROM_MANAGER)
list_append(&pt->link, &manager_list);
list_append(&pt->link, &ready_list);
pt = list_get_instance(ready_list.next, psthread_data_t, link);
if (ctype == PS_TO_MANAGER)
pt = list_get_instance(manager_list.next,psthread_data_t, link);
else
pt = list_get_instance(ready_list.next, psthread_data_t, link);
list_remove(&pt->link);
 
futex_up(&psthread_futex);
context_restore(&pt->ctx);
 
ret_0:
futex_up(&psthread_futex);
return retval;
}
 
/** Wait for uspace pseudo thread to finish.
142,7 → 183,6
retval = pt->retval;
 
free(pt->stack);
__free_tls(pt->tcb);
psthread_teardown((void *)pt);
 
return retval;
149,7 → 189,7
}
 
/**
* Create a userspace thread and append it to ready list.
* Create a userspace thread
*
* @param func Pseudo thread function.
* @param arg Argument to pass to func.
159,21 → 199,13
pstid_t psthread_create(int (*func)(void *), void *arg)
{
psthread_data_t *pt;
tcb_t *tcb;
 
tcb = __make_tls();
if (!tcb)
pt = psthread_setup();
if (!pt)
return 0;
 
pt = psthread_setup(tcb);
if (!pt) {
__free_tls(tcb);
return 0;
}
pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
 
if (!pt->stack) {
__free_tls(tcb);
psthread_teardown(pt);
return 0;
}
185,9 → 217,43
 
context_save(&pt->ctx);
context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(),
tcb);
pt->tcb);
 
return (pstid_t )pt;
}
 
/** Add a thread to ready list */
void psthread_add_ready(pstid_t psthrid)
{
psthread_data_t *pt;
 
pt = (psthread_data_t *) psthrid;
futex_down(&psthread_futex);
list_append(&pt->link, &ready_list);
futex_up(&psthread_futex);
}
 
return (pstid_t )pt;
/** Add a thread to manager list */
void psthread_add_manager(pstid_t psthrid)
{
psthread_data_t *pt;
 
pt = (psthread_data_t *) psthrid;
 
futex_down(&psthread_futex);
list_append(&pt->link, &manager_list);
futex_up(&psthread_futex);
}
 
/** Remove one manager from manager list */
void psthread_remove_manager()
{
futex_down(&psthread_futex);
if (list_empty(&manager_list)) {
printf("No manager found!.\n");
futex_up(&psthread_futex);
return;
}
list_remove(manager_list.next);
futex_up(&psthread_futex);
}
/uspace/trunk/libc/generic/ipc.c
57,13 → 57,8
LIST_INITIALIZE(dispatched_calls);
LIST_INITIALIZE(queued_calls);
 
static atomic_t ipc_futex;
static atomic_t ipc_futex = FUTEX_INITIALIZER;
 
void _ipc_init(void)
{
futex_initialize(&ipc_futex, 1);
}
 
int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t *result)
{
252,25 → 247,25
}
 
 
/** Unconditionally wait for an IPC call.
/** One cycle of ipc wait for call call
*
* - dispatch ASYNC reoutines in the background
* @param call Space where the message is stored
* @param usec Timeout in microseconds
* @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking)
* @return Callid of the answer.
*/
ipc_callid_t ipc_wait_for_call(ipc_call_t *call)
ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
{
ipc_callid_t callid;
 
do {
try_dispatch_queued_calls();
try_dispatch_queued_calls();
callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
/* Handle received answers */
if (callid & IPC_CALLID_ANSWERED)
handle_answer(callid, call);
 
callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, SYNCH_NO_TIMEOUT, SYNCH_BLOCKING);
/* Handle received answers */
if (callid & IPC_CALLID_ANSWERED)
handle_answer(callid, call);
} while (callid & IPC_CALLID_ANSWERED);
 
return callid;
}
 
286,12 → 281,7
ipc_callid_t callid;
 
do {
try_dispatch_queued_calls();
 
callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, SYNCH_BLOCKING);
/* Handle received answers */
if (callid & IPC_CALLID_ANSWERED)
handle_answer(callid, call);
callid = ipc_wait_cycle(call, usec, SYNCH_BLOCKING);
} while (callid & IPC_CALLID_ANSWERED);
 
return callid;
308,12 → 298,7
ipc_callid_t callid;
 
do {
try_dispatch_queued_calls();
 
callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t)call, SYNCH_NO_TIMEOUT, SYNCH_NON_BLOCKING);
/* Handle received answers */
if (callid & IPC_CALLID_ANSWERED)
handle_answer(callid, call);
callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_NON_BLOCKING);
} while (callid & IPC_CALLID_ANSWERED);
 
return callid;
/uspace/trunk/libc/generic/async.c
26,52 → 26,305
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
ipc_wait_t call_func(args)
/**
* Asynchronous library
*
* The aim of this library is facilitating writing programs utilizing
* the asynchronous nature of Helenos IPC, yet using a normal way
* of programming.
*
* You should be able to write very simple multithreaded programs,
* the async framework will automatically take care of most synchronization
* problems.
*
* Default semantics:
* - send() - send asynchronously. If the kernel refuses to send more
* messages, [ try to get responses from kernel, if nothing
* found, might try synchronous ]
*
* Example of use:
*
* 1) Multithreaded client application
* create_thread(thread1);
* create_thread(thread2);
* ...
*
* thread1() {
* conn = ipc_connect_me_to();
* c1 = send(conn);
* c2 = send(conn);
* wait_for(c1);
* wait_for(c2);
* }
*
*
* 2) Multithreaded server application
* main() {
* wait_for_connection(new_connection);
* }
*
*
* new_connection(int connection) {
* accept(connection);
* msg = get_msg();
* handle(msg);
* answer(msg);
*
* msg = get_msg();
* ....
* }
*/
#include <futex.h>
#include <async.h>
#include <psthread.h>
#include <stdio.h>
#include <libadt/hash_table.h>
#include <libadt/list.h>
#include <ipc/ipc.h>
#include <assert.h>
#include <errno.h>
 
static atomic_t conn_futex = FUTEX_INITIALIZER;
static hash_table_t conn_hash_table;
 
typedef struct {
link_t link;
ipc_callid_t callid;
ipc_call_t call;
} msg_t;
 
typedef struct {
link_t link;
ipcarg_t in_phone_hash; /**< Incoming phone hash. */
link_t msg_queue; /**< Messages that should be delivered to this thread */
pstid_t ptid; /**< Thread associated with this connection */
int active; /**< If this thread is currently active */
int opened; /* If the connection was accepted */
/* Structures for connection opening packet */
ipc_callid_t callid;
ipc_call_t call;
} connection_t;
 
__thread connection_t *PS_connection;
 
/* Hash table functions */
 
#define ASYNC_HASH_TABLE_CHAINS 32
 
static hash_index_t conn_hash(unsigned long *key)
{
assert(key);
return ((*key) >> 4) % ASYNC_HASH_TABLE_CHAINS;
}
 
ipc_wait_t fire_function(args)
static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
{
stack = malloc(stacksize);
setup(stack);
add_to_list_of_ready_funcs(stack);
if (threads_waiting_for_message)
send_message_to_self_to_one_up();
connection_t *hs;
 
hs = hash_table_get_instance(item, connection_t, link);
return key[0] == hs->in_phone_hash;
}
 
void discard_result(ipc_wait_t funcid)
static void conn_remove(link_t *item)
{
free(hash_table_get_instance(item, connection_t, link));
}
 
int wait_result(ipc_wait_t funcid);
 
/** Operations for NS hash table. */
static hash_table_operations_t conn_hash_table_ops = {
.hash = conn_hash,
.compare = conn_compare,
.remove_callback = conn_remove
};
 
/** Try to route a call to an appropriate connection thread
*
*/
static int route_call(ipc_callid_t callid, ipc_call_t *call)
{
save_context(self);
restart:
if result_available() {
if in_list_of_ready(self):
tear_off_list(self);
return retval;
connection_t *conn;
msg_t *msg;
link_t *hlp;
unsigned long key;
 
futex_down(&conn_futex);
 
key = call->in_phone_hash;
hlp = hash_table_find(&conn_hash_table, &key);
if (!hlp) {
futex_up(&conn_futex);
return 0;
}
add_to_waitlist_of(funcid);
conn = hash_table_get_instance(hlp, connection_t, link);
 
take_something_from_list_of_ready();
if something {
restore_context(something);
} else { /* nothing */
wait_for_call();
if (answer) {
mark_result_ready();
put_waiting_thread_to_waitlist();
msg = malloc(sizeof(*msg));
msg->callid = callid;
msg->call = *call;
list_append(&msg->link, &conn->msg_queue);
if (!conn->active) {
conn->active = 1;
psthread_add_ready(conn->ptid);
}
 
goto restart;
}
futex_up(&conn_futex);
 
return 1;
}
 
ipc_callid_t async_get_call(ipc_call_t *call)
{
msg_t *msg;
ipc_callid_t callid;
connection_t *conn;
futex_down(&conn_futex);
 
conn = PS_connection;
/* If nothing in queue, wait until something appears */
if (list_empty(&conn->msg_queue)) {
conn->active = 0;
psthread_schedule_next_adv(PS_TO_MANAGER);
}
msg = list_get_instance(conn->msg_queue.next, msg_t, link);
list_remove(&msg->link);
callid = msg->callid;
*call = msg->call;
free(msg);
futex_up(&conn_futex);
return callid;
}
 
void client_connection(ipc_callid_t callid, ipc_call_t *call)
{
printf("Got connection - no handler.\n");
_exit(1);
}
 
int ipc_call_sync(args)
static int connection_thread(void *arg)
{
return ipc_wait(call_func(args));
/* Setup thread local connection pointer */
PS_connection = (connection_t *)arg;
client_connection(PS_connection->callid, &PS_connection->call);
 
futex_down(&conn_futex);
/* TODO: remove myself from connection hash table */
futex_up(&conn_futex);
/* TODO: answer all unanswered messages in queue with
* EHANGUP */
}
 
/** Create new thread for a new connection
*
* Creates new thread for connection, fills in connection
* structures and inserts it into the hash table, so that
* later we can easily do routing of messages to particular
* threads.
*/
static void new_connection(ipc_callid_t callid, ipc_call_t *call)
{
pstid_t ptid;
connection_t *conn;
unsigned long key;
 
conn = malloc(sizeof(*conn));
if (!conn) {
ipc_answer_fast(callid, ENOMEM, 0, 0);
return;
}
conn->in_phone_hash = IPC_GET_ARG3(*call);
list_initialize(&conn->msg_queue);
conn->opened = 0;
conn->ptid = psthread_create(connection_thread, conn);
conn->callid = callid;
conn->call = *call;
conn->active = 1; /* We will activate it asap */
list_initialize(&conn->link);
if (!conn->ptid) {
free(conn);
ipc_answer_fast(callid, ENOMEM, 0, 0);
return;
}
key = conn->in_phone_hash;
futex_down(&conn_futex);
/* Add connection to hash table */
hash_table_insert(&conn_hash_table, &key, &conn->link);
futex_up(&conn_futex);
 
psthread_add_ready(conn->ptid);
}
 
/** Handle call to a task */
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
{
if (route_call(callid, call))
return;
 
switch (IPC_GET_METHOD(*call)) {
case IPC_M_INTERRUPT:
break;
case IPC_M_CONNECT_ME_TO:
/* Open new connection with thread etc. */
new_connection(callid, call);
break;
default:
ipc_answer_fast(callid, EHANGUP, 0, 0);
}
}
 
/** Endless loop dispatching incoming calls and answers */
int async_manager()
{
ipc_call_t call;
ipc_callid_t callid;
 
while (1) {
if (psthread_schedule_next_adv(PS_FROM_MANAGER)) {
futex_up(&conn_futex); /* conn_futex is always held
* when entering manager thread
*/
continue;
}
callid = ipc_wait_cycle(&call,SYNCH_NO_TIMEOUT,SYNCH_BLOCKING);
 
if (callid & IPC_CALLID_ANSWERED)
continue;
handle_call(callid, &call);
}
}
 
static int async_manager_thread(void *arg)
{
futex_up(&conn_futex); /* conn_futex is always locked when entering
* manager */
async_manager();
}
 
/** Add one manager to manager list */
void async_create_manager(void)
{
pstid_t ptid;
 
ptid = psthread_create(async_manager_thread, NULL);
psthread_add_manager(ptid);
}
 
/** Remove one manager from manager list */
void async_destroy_manager(void)
{
psthread_remove_manager();
}
 
/** Initialize internal structures needed for async manager */
int _async_init(void)
{
if (!hash_table_create(&conn_hash_table, ASYNC_HASH_TABLE_CHAINS, 1, &conn_hash_table_ops)) {
printf("%s: cannot create hash table\n", "async");
return ENOMEM;
}
}