Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 1965 → Rev 1968

/tags/0.2.0.1/uspace/libc/generic/async.c
0,0 → 1,808
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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
*/
 
/**
* 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() {
* async_manager();
* }
*
*
* client_connection(icallid, *icall) {
* if (want_refuse) {
* ipc_answer_fast(icallid, ELIMIT, 0, 0);
* return;
* }
* ipc_answer_fast(icallid, 0, 0, 0);
*
* callid = async_get_call(&call);
* handle(callid, call);
* ipc_answer_fast(callid, 1,2,3);
*
* callid = async_get_call(&call);
* ....
* }
*
* TODO: Detaching/joining dead psthreads?
*/
#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>
#include <time.h>
#include <arch/barrier.h>
 
atomic_t async_futex = FUTEX_INITIALIZER;
static hash_table_t conn_hash_table;
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 */
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 */
} awaiter_t;
 
typedef struct {
awaiter_t wdata;
 
int done; /**< If reply was received */
ipc_call_t *dataptr; /**< Pointer where the answer data
* is stored */
ipcarg_t retval;
} amsg_t;
 
typedef struct {
link_t link;
ipc_callid_t callid;
ipc_call_t call;
} msg_t;
 
typedef struct {
awaiter_t wdata;
 
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 */
/* 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 *);
} connection_t;
 
/** Identifier of incoming connection handled by current thread */
__thread connection_t *PS_connection;
/** If true, it is forbidden to use async_req functions and
* all preemption is disabled */
__thread int in_interrupt_handler;
 
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
static async_client_conn_t client_connection = default_client_connection;
static async_client_conn_t interrupt_received = default_interrupt_received;
 
/** Add microseconds to give timeval */
static void tv_add(struct timeval *tv, suseconds_t usecs)
{
tv->tv_sec += usecs / 1000000;
tv->tv_usec += usecs % 1000000;
if (tv->tv_usec > 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
 
/** Subtract 2 timevals, return microseconds difference */
static suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
{
suseconds_t result;
 
result = tv1->tv_usec - tv2->tv_usec;
result += (tv1->tv_sec - tv2->tv_sec) * 1000000;
 
return result;
}
 
/** Compare timeval
*
* @return 1 if tv1 > tv2, otherwise 0
*/
static int tv_gt(struct timeval *tv1, struct timeval *tv2)
{
if (tv1->tv_sec > tv2->tv_sec)
return 1;
if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec > tv2->tv_usec)
return 1;
return 0;
}
static int tv_gteq(struct timeval *tv1, struct timeval *tv2)
{
if (tv1->tv_sec > tv2->tv_sec)
return 1;
if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec >= tv2->tv_usec)
return 1;
return 0;
}
 
/* Hash table functions */
#define CONN_HASH_TABLE_CHAINS 32
 
static hash_index_t conn_hash(unsigned long *key)
{
assert(key);
return ((*key) >> 4) % CONN_HASH_TABLE_CHAINS;
}
 
static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
{
connection_t *hs;
 
hs = hash_table_get_instance(item, connection_t, link);
return key[0] == hs->in_phone_hash;
}
 
static void conn_remove(link_t *item)
{
free(hash_table_get_instance(item, connection_t, link));
}
 
 
/** Operations for NS hash table. */
static hash_table_operations_t conn_hash_table_ops = {
.hash = conn_hash,
.compare = conn_compare,
.remove_callback = conn_remove
};
 
/** Insert sort timeout msg into timeouts list
*
*/
static void insert_timeout(awaiter_t *wd)
{
link_t *tmp;
awaiter_t *cur;
 
wd->timedout = 0;
wd->inlist = 1;
 
tmp = timeout_list.next;
while (tmp != &timeout_list) {
cur = list_get_instance(tmp, awaiter_t, link);
if (tv_gteq(&cur->expires, &wd->expires))
break;
tmp = tmp->next;
}
list_append(&wd->link, tmp);
}
 
/*************************************************/
 
/** Try to route a call to an appropriate connection thread
*
*/
static int route_call(ipc_callid_t callid, ipc_call_t *call)
{
connection_t *conn;
msg_t *msg;
link_t *hlp;
unsigned long key;
 
futex_down(&async_futex);
 
key = call->in_phone_hash;
hlp = hash_table_find(&conn_hash_table, &key);
if (!hlp) {
futex_up(&async_futex);
return 0;
}
conn = hash_table_get_instance(hlp, connection_t, link);
 
msg = malloc(sizeof(*msg));
msg->callid = callid;
msg->call = *call;
list_append(&msg->link, &conn->msg_queue);
 
if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
conn->close_callid = callid;
/* If the call is waiting for event, run it */
if (!conn->wdata.active) {
/* If in timeout list, remove it */
if (conn->wdata.inlist) {
conn->wdata.inlist = 0;
list_remove(&conn->wdata.link);
}
conn->wdata.active = 1;
psthread_add_ready(conn->wdata.ptid);
}
 
futex_up(&async_futex);
 
return 1;
}
 
/** Return new incoming message for current(thread-local) connection */
ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
{
msg_t *msg;
ipc_callid_t callid;
connection_t *conn;
assert(PS_connection);
/* GCC 4.1.0 coughs on PS_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;
 
futex_down(&async_futex);
 
if (usecs) {
gettimeofday(&conn->wdata.expires, NULL);
tv_add(&conn->wdata.expires, usecs);
} else {
conn->wdata.inlist = 0;
}
/* If nothing in queue, wait until something appears */
while (list_empty(&conn->msg_queue)) {
if (usecs)
insert_timeout(&conn->wdata);
 
conn->wdata.active = 0;
psthread_schedule_next_adv(PS_TO_MANAGER);
/* Futex is up after getting back from async_manager
* get it again */
futex_down(&async_futex);
if (usecs && conn->wdata.timedout && \
list_empty(&conn->msg_queue)) {
/* If we timed out-> exit */
futex_up(&async_futex);
return 0;
}
}
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(&async_futex);
return callid;
}
 
/** Thread function that gets created on new connection
*
* This function is defined as a weak symbol - to be redefined in
* user code.
*/
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
{
ipc_answer_fast(callid, ENOENT, 0, 0);
}
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
{
}
 
/** Wrapper for client connection thread
*
* When new connection arrives, thread with this function is created.
* It calls client_connection and does final cleanup.
*
* @param arg Connection structure pointer
*/
static int connection_thread(void *arg)
{
unsigned long key;
msg_t *msg;
int close_answered = 0;
 
/* Setup thread local connection pointer */
PS_connection = (connection_t *)arg;
PS_connection->cthread(PS_connection->callid, &PS_connection->call);
/* Remove myself from connection hash table */
futex_down(&async_futex);
key = PS_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);
list_remove(&msg->link);
if (msg->callid == PS_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);
}
 
/** 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.
*
* @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
* opening the connection
* @return New thread 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 *))
{
pstid_t ptid;
connection_t *conn;
unsigned long key;
 
conn = malloc(sizeof(*conn));
if (!conn) {
ipc_answer_fast(callid, ENOMEM, 0, 0);
return NULL;
}
conn->in_phone_hash = in_phone_hash;
list_initialize(&conn->msg_queue);
conn->callid = callid;
conn->close_callid = 0;
if (call)
conn->call = *call;
conn->wdata.active = 1; /* We will activate it asap */
conn->cthread = cthread;
 
conn->wdata.ptid = psthread_create(connection_thread, conn);
if (!conn->wdata.ptid) {
free(conn);
ipc_answer_fast(callid, ENOMEM, 0, 0);
return NULL;
}
/* Add connection to hash table */
key = conn->in_phone_hash;
futex_down(&async_futex);
hash_table_insert(&conn_hash_table, &key, &conn->link);
futex_up(&async_futex);
 
psthread_add_ready(conn->wdata.ptid);
 
return conn->wdata.ptid;
}
 
/** Handle call that was received */
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
{
/* Unrouted call - do some default behaviour */
if ((callid & IPC_CALLID_NOTIFICATION)) {
in_interrupt_handler = 1;
(*interrupt_received)(callid,call);
in_interrupt_handler = 0;
return;
}
 
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);
return;
}
 
/* Try to route call through connection tables */
if (route_call(callid, call))
return;
 
/* Unknown call from unknown phone - hang it up */
ipc_answer_fast(callid, EHANGUP, 0, 0);
}
 
/** Fire all timeouts that expired
*
*/
static void handle_expired_timeouts(void)
{
struct timeval tv;
awaiter_t *waiter;
link_t *cur;
 
gettimeofday(&tv,NULL);
futex_down(&async_futex);
 
cur = timeout_list.next;
while (cur != &timeout_list) {
waiter = list_get_instance(cur,awaiter_t,link);
if (tv_gt(&waiter->expires, &tv))
break;
cur = cur->next;
list_remove(&waiter->link);
waiter->inlist = 0;
waiter->timedout = 1;
/* Redundant condition? The thread should not
* be active when it gets here.
*/
if (!waiter->active) {
waiter->active = 1;
psthread_add_ready(waiter->ptid);
}
}
 
futex_up(&async_futex);
}
 
/** Endless loop dispatching incoming calls and answers */
static int async_manager_worker(void)
{
ipc_call_t call;
ipc_callid_t callid;
int timeout;
awaiter_t *waiter;
struct timeval tv;
 
while (1) {
if (psthread_schedule_next_adv(PS_FROM_MANAGER)) {
futex_up(&async_futex); /* async_futex is always held
* when entering manager thread
*/
continue;
}
futex_down(&async_futex);
if (!list_empty(&timeout_list)) {
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();
continue;
} else
timeout = tv_sub(&waiter->expires, &tv);
} else
timeout = SYNCH_NO_TIMEOUT;
futex_up(&async_futex);
 
callid = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
 
if (!callid) {
handle_expired_timeouts();
continue;
}
 
if (callid & IPC_CALLID_ANSWERED) {
continue;
}
 
handle_call(callid, &call);
}
}
 
/** Function to start async_manager as a standalone thread
*
* When more kernel threads are used, one async manager should
* exist per thread. The particular implementation may change,
* currently one async_manager is started automatically per kernel
* thread except main thread.
*/
static int async_manager_thread(void *arg)
{
futex_up(&async_futex); /* async_futex is always locked when entering
* manager */
async_manager_worker();
}
 
/** 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, CONN_HASH_TABLE_CHAINS, 1, &conn_hash_table_ops)) {
printf("%s: cannot create hash table\n", "async");
return ENOMEM;
}
}
 
/** IPC handler for messages in async framework
*
* Notify thread that is waiting for this message, that it arrived
*/
static void reply_received(void *private, int retval,
ipc_call_t *data)
{
amsg_t *msg = (amsg_t *) private;
 
msg->retval = retval;
 
futex_down(&async_futex);
/* Copy data after futex_down, just in case the
* call was detached
*/
if (msg->dataptr)
*msg->dataptr = *data;
 
write_barrier();
/* Remove message from timeout list */
if (msg->wdata.inlist)
list_remove(&msg->wdata.link);
msg->done = 1;
if (! msg->wdata.active) {
msg->wdata.active = 1;
psthread_add_ready(msg->wdata.ptid);
}
futex_up(&async_futex);
}
 
/** Send message and return id of the sent message
*
* The return value can be used as input for async_wait() to wait
* for completion.
*/
aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
ipc_call_t *dataptr)
{
amsg_t *msg;
 
if (in_interrupt_handler) {
printf("Cannot send asynchronou request in interrupt handler.\n");
_exit(1);
}
 
msg = malloc(sizeof(*msg));
msg->done = 0;
msg->dataptr = dataptr;
 
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);
 
return (aid_t) msg;
}
 
/** Send message and return id of the sent message
*
* The return value can be used as input for async_wait() to wait
* for completion.
*/
aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
ipcarg_t arg3, ipc_call_t *dataptr)
{
amsg_t *msg;
 
if (in_interrupt_handler) {
printf("Cannot send asynchronou request in interrupt handler.\n");
_exit(1);
}
 
msg = malloc(sizeof(*msg));
msg->done = 0;
msg->dataptr = dataptr;
 
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);
 
return (aid_t) msg;
}
 
/** Wait for a message sent by async framework
*
* @param amsgid Message ID to wait for
* @param retval Pointer to variable where will be stored retval
* of the answered message. If NULL, it is ignored.
*
*/
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
{
amsg_t *msg = (amsg_t *) amsgid;
connection_t *conn;
 
futex_down(&async_futex);
if (msg->done) {
futex_up(&async_futex);
goto done;
}
 
msg->wdata.ptid = psthread_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...*/
done:
if (retval)
*retval = msg->retval;
free(msg);
}
 
/** Wait for a message sent by async framework with timeout
*
* @param amsgid Message ID to wait for
* @param retval Pointer to variable where will be stored retval
* of the answered message. If NULL, it is ignored.
* @param timeout Timeout in usecs
* @return 0 on success, ETIMEOUT if timeout expired
*
*/
int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
{
amsg_t *msg = (amsg_t *) amsgid;
connection_t *conn;
 
/* TODO: Let it go through the event read at least once */
if (timeout < 0)
return ETIMEOUT;
 
futex_down(&async_futex);
if (msg->done) {
futex_up(&async_futex);
goto done;
}
 
gettimeofday(&msg->wdata.expires, NULL);
tv_add(&msg->wdata.expires, timeout);
 
msg->wdata.ptid = psthread_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...*/
 
if (!msg->done)
return ETIMEOUT;
 
done:
if (retval)
*retval = msg->retval;
free(msg);
 
return 0;
}
 
/** Wait specified time, but in the meantime handle incoming events
*
* @param timeout Time in microseconds to wait
*/
void async_usleep(suseconds_t timeout)
{
amsg_t *msg;
if (in_interrupt_handler) {
printf("Cannot call async_usleep in interrupt handler.\n");
_exit(1);
}
 
msg = malloc(sizeof(*msg));
if (!msg)
return;
 
msg->wdata.ptid = psthread_get_id();
msg->wdata.active = 0;
 
gettimeofday(&msg->wdata.expires, NULL);
tv_add(&msg->wdata.expires, timeout);
 
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...*/
free(msg);
}
 
/** Set function that is called, IPC_M_CONNECT_ME_TO is received
*
* @param conn Function that will form new psthread.
*/
void async_set_client_connection(async_client_conn_t conn)
{
client_connection = conn;
}
void async_set_interrupt_received(async_client_conn_t conn)
{
interrupt_received = conn;
}
 
/* Primitive functions for simple communication */
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);
}
 
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);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/libc.c
0,0 → 1,80
/*
* Copyright (C) 2005 Martin Decky
* 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 lc Libc
* @brief HelenOS C library
* @{
* @}
*/
/** @addtogroup libc generic
* @ingroup lc
* @{
*/
/** @file
*/
 
#include <libc.h>
#include <unistd.h>
#include <thread.h>
#include <malloc.h>
#include <psthread.h>
#include <io/stream.h>
#include <ipc/ipc.h>
#include <async.h>
#include <as.h>
 
extern char _heap;
 
void _exit(int status) {
thread_exit(status);
}
 
void __main(void) {
psthread_data_t *pt;
 
(void) as_area_create(&_heap, 1, AS_AREA_WRITE | AS_AREA_READ);
_async_init();
pt = psthread_setup();
__tcb_set(pt->tcb);
}
 
void __io_init(void) {
open("stdin", 0);
open("stdout", 0);
open("stderr", 0);
}
 
void __exit(void) {
psthread_teardown(__tcb_get()->pst_data);
_exit(0);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/time.c
0,0 → 1,123
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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 <sys/time.h>
#include <unistd.h>
#include <ipc/ipc.h>
#include <stdio.h>
#include <arch/barrier.h>
#include <unistd.h>
#include <atomic.h>
#include <futex.h>
#include <ipc/services.h>
 
#include <sysinfo.h>
#include <as.h>
#include <ddi.h>
 
/* Pointers to public variables with time */
struct {
volatile sysarg_t seconds1;
volatile sysarg_t useconds;
volatile sysarg_t seconds2;
} *ktime = NULL;
 
 
/** POSIX gettimeofday
*
* The time variables are memory mapped(RO) from kernel, which updates
* them periodically. As it is impossible to read 2 values atomically, we
* use a trick: First read a seconds, then read microseconds, then
* read seconds again. If a second elapsed in the meantime, read
* useconds again. This provides assurance, that at least the
* sequence of subsequent gettimeofday calls is ordered.
*/
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
void *mapping;
sysarg_t s1, s2;
sysarg_t rights;
int res;
 
if (!ktime) {
mapping = as_get_mappable_page(PAGE_SIZE);
/* Get the mapping of kernel clock */
res = ipc_call_sync_3(PHONE_NS, IPC_M_AS_AREA_RECV,
mapping, PAGE_SIZE, SERVICE_MEM_REALTIME,
NULL,&rights,NULL);
if (res) {
printf("Failed to initialize timeofday memarea\n");
_exit(1);
}
if (! (rights & AS_AREA_READ)) {
printf("Received bad rights on time area: %X\n",
rights);
as_area_destroy(mapping);
_exit(1);
}
ktime = mapping;
}
if (tz) {
tz->tz_minuteswest = 0;
tz->tz_dsttime = DST_NONE;
}
 
s2 = ktime->seconds2;
read_barrier();
tv->tv_usec = ktime->useconds;
read_barrier();
s1 = ktime->seconds1;
if (s1 != s2) {
tv->tv_usec = 0;
tv->tv_sec = s1 > s2 ? s1 : s2;
} else
tv->tv_sec = s1;
 
return 0;
}
 
/** Wait unconditionally for specified microseconds */
void usleep(unsigned long usec)
{
atomic_t futex = FUTEX_INITIALIZER;
 
futex_initialize(&futex,0);
futex_down_timeout(&futex, usec, 0);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/ddi.c
0,0 → 1,95
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <ddi.h>
#include <libc.h>
#include <task.h>
#include <kernel/ddi/ddi_arg.h>
 
/** Map piece of physical memory to task.
*
* Caller of this function must have the CAP_MEM_MANAGER capability.
*
* @param pf Physical address of the starting frame.
* @param vp Virtual address of the sterting page.
* @param pages Number of pages to map.
* @param flags Flags for the new address space area.
*
* @return 0 on success, EPERM if the caller lacks the CAP_MEM_MANAGER capability,
* ENOENT if there is no task with specified ID and ENOMEM if there
* was some problem in creating address space area.
*/
int map_physmem(void *pf, void *vp, unsigned long pages, int flags)
{
return __SYSCALL4(SYS_MAP_PHYSMEM, (sysarg_t) pf, (sysarg_t)vp, pages, flags);
}
 
/** Enable I/O space range to task.
*
* Caller of this function must have the IO_MEM_MANAGER capability.
*
* @param id Task ID.
* @param ioaddr Starting address of the I/O range.
* @param size Size of the range.
*
* @return 0 on success, EPERM if the caller lacks the CAP_IO_MANAGER capability,
* ENOENT if there is no task with specified ID and ENOMEM if there
* was some problem in allocating memory.
*/
int iospace_enable(task_id_t id, void *ioaddr, unsigned long size)
{
task_id_t task_id;
ddi_ioarg_t arg;
 
arg.task_id = id;
arg.ioaddr = ioaddr;
arg.size = size;
 
return __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg);
}
 
/** Interrupt control
*
* @param enable 1 - enable interrupts, 0 - disable interrupts
*/
int preemption_control(int enable)
{
return __SYSCALL1(SYS_PREEMPT_CONTROL, (sysarg_t) enable);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/task.c
0,0 → 1,51
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <task.h>
#include <libc.h>
 
task_id_t task_get_id(void)
{
task_id_t task_id;
 
(void) __SYSCALL1(SYS_TASK_GET_ID, (sysarg_t) &task_id);
 
return task_id;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/cap.c
0,0 → 1,78
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/**
* @file cap.c
* @brief Functions to grant/revoke capabilities to/from a task.
*/
 
#include <cap.h>
#include <task.h>
#include <libc.h>
#include <kernel/syscall/sysarg64.h>
 
/** Grant capabilities to a task.
*
* @param id Destination task ID.
* @param caps Capabilities to grant.
*
* @return Zero on success or a value from @ref errno.h on failure.
*/
int cap_grant(task_id_t id, unsigned int caps)
{
sysarg64_t arg;
arg.value = (unsigned long long) id;
 
__SYSCALL2(SYS_CAP_GRANT, (sysarg_t) &arg, (sysarg_t) caps);
}
 
/** Revoke capabilities from a task.
*
* @param id Destination task ID.
* @param caps Capabilities to revoke.
*
* @return Zero on success or a value from @ref errno.h on failure.
*/
int cap_revoke(task_id_t id, unsigned int caps)
{
sysarg64_t arg;
arg.value = (unsigned long long) id;
 
__SYSCALL2(SYS_CAP_REVOKE, (sysarg_t) &arg, (sysarg_t) caps);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/as.c
0,0 → 1,154
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <as.h>
#include <libc.h>
#include <unistd.h>
#include <align.h>
 
/** Create address space area.
*
* @param address Virtual address where to place new address space area.
* @param size Size of the area.
* @param flags Flags describing type of the area.
*
* @return address on success, (void *) -1 otherwise.
*/
void *as_area_create(void *address, size_t size, int flags)
{
return (void *) __SYSCALL3(SYS_AS_AREA_CREATE, (sysarg_t ) address, (sysarg_t) size, (sysarg_t) flags);
}
 
/** Resize address space area.
*
* @param address Virtual address pointing into already existing address space area.
* @param size New requested size of the area.
* @param flags Currently unused.
*
* @return Zero on success or a code from @ref errno.h on failure.
*/
int as_area_resize(void *address, size_t size, int flags)
{
return __SYSCALL3(SYS_AS_AREA_RESIZE, (sysarg_t ) address, (sysarg_t) size, (sysarg_t) flags);
}
 
/** Destroy address space area.
*
* @param address Virtual address pointing into the address space area being destroyed.
*
* @return Zero on success or a code from @ref errno.h on failure.
*/
int as_area_destroy(void *address)
{
return __SYSCALL1(SYS_AS_AREA_DESTROY, (sysarg_t ) address);
}
 
static size_t heapsize = 0;
static size_t maxheapsize = (size_t)(-1);
 
static void * last_allocated = 0;
 
/* Start of heap linker symbol */
extern char _heap;
 
/** Sbrk emulation
*
* @param incr New area that should be allocated or negative,
if it should be shrinked
* @return Pointer to newly allocated area
*/
void *sbrk(ssize_t incr)
{
int rc;
void *res;
/* Check for invalid values */
if (incr < 0 && -incr > heapsize)
return NULL;
/* Check for too large value */
if (incr > 0 && incr+heapsize < heapsize)
return NULL;
/* Check for too small values */
if (incr < 0 && incr+heapsize > heapsize)
return NULL;
/* Check for user limit */
if ((maxheapsize!=(size_t)(-1)) && (heapsize + incr)>maxheapsize) return NULL;
 
rc = as_area_resize(&_heap, heapsize + incr,0);
if (rc != 0)
return NULL;
/* Compute start of new area */
res = (void *)&_heap + heapsize;
 
heapsize += incr;
 
return res;
}
 
/** Set maximum heap size and return pointer just after the heap */
void *set_maxheapsize(size_t mhs)
{
maxheapsize=mhs;
/* Return pointer to area not managed by sbrk */
return (void *)&_heap + maxheapsize;
 
}
 
/** Return pointer to some unmapped area, where fits new as_area
*
* TODO: make some first_fit/... algorithm, we are now just incrementing
* the pointer to last area
*/
void * as_get_mappable_page(size_t sz)
{
void *res;
 
/* Set heapsize to some meaningful value */
if (maxheapsize == -1)
set_maxheapsize(ALIGN_UP(USER_ADDRESS_SPACE_SIZE_ARCH>>1,PAGE_SIZE));
if (!last_allocated)
last_allocated = ALIGN_UP((void *)&_heap + maxheapsize, PAGE_SIZE);
sz = ALIGN_UP(sz, PAGE_SIZE);
res = last_allocated;
last_allocated += sz;
 
return res;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/string.c
0,0 → 1,314
/*
* Copyright (C) 2005 Martin Decky
* 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 <string.h>
#include <unistd.h>
#include <ctype.h>
#include <limits.h>
#include <align.h>
 
 
/* Dummy implementation of mem/ functions */
 
void * memset(void *s, int c, size_t n)
{
char *os = s;
while (n--)
*(os++) = c;
return s;
}
 
struct along {unsigned long n; } __attribute__ ((packed));
 
static void * unaligned_memcpy(void *dst, const void *src, size_t n)
{
int i, j;
struct along *adst = dst;
const struct along *asrc = src;
 
for (i = 0; i < n/sizeof(unsigned long); i++)
adst[i].n = asrc[i].n;
for (j = 0; j < n%sizeof(unsigned long); j++)
((unsigned char *)(((unsigned long *) dst) + i))[j] = ((unsigned char *)(((unsigned long *) src) + i))[j];
return (char *)src;
}
 
void * memcpy(void *dst, const void *src, size_t n)
{
int i, j;
 
if (((long)dst & (sizeof(long)-1)) || ((long)src & (sizeof(long)-1)))
return unaligned_memcpy(dst, src, n);
 
for (i = 0; i < n/sizeof(unsigned long); i++)
((unsigned long *) dst)[i] = ((unsigned long *) src)[i];
for (j = 0; j < n%sizeof(unsigned long); j++)
((unsigned char *)(((unsigned long *) dst) + i))[j] = ((unsigned char *)(((unsigned long *) src) + i))[j];
return (char *)src;
}
 
void * memmove(void *dst, const void *src, size_t n)
{
int i, j;
if (src > dst)
return memcpy(dst, src, n);
 
for (j = (n%sizeof(unsigned long))-1; j >= 0; j--)
((unsigned char *)(((unsigned long *) dst) + i))[j] = ((unsigned char *)(((unsigned long *) src) + i))[j];
 
for (i = n/sizeof(unsigned long)-1; i >=0 ; i--)
((unsigned long *) dst)[i] = ((unsigned long *) src)[i];
return (char *)src;
}
 
 
/** Count the number of characters in the string, not including terminating 0.
* @param str string
* @return number of characters in string.
*/
size_t strlen(const char *str)
{
size_t counter = 0;
 
while (str[counter] != 0) {
counter++;
}
 
return counter;
}
 
int strcmp(const char *a,const char *b)
{
int c=0;
while(a[c]&&b[c]&&(!(a[c]-b[c]))) c++;
return a[c]-b[c];
}
 
 
 
/** Return pointer to the first occurence of character c in string
* @param str scanned string
* @param c searched character (taken as one byte)
* @return pointer to the matched character or NULL if it is not found in given string.
*/
char *strchr(const char *str, int c)
{
while (*str != '\0') {
if (*str == (char)c)
return (char *)str;
str++;
}
 
return NULL;
}
 
/** Return pointer to the last occurence of character c in string
* @param str scanned string
* @param c searched character (taken as one byte)
* @return pointer to the matched character or NULL if it is not found in given string.
*/
char *strrchr(const char *str, int c)
{
char *retval = NULL;
 
while (*str != '\0') {
if (*str == (char)c)
retval = (char *)str;
str++;
}
 
return (char *)retval;
}
 
/** Convert string to a number.
* Core of strtol and strtoul functions.
* @param nptr pointer to string
* @param endptr if not NULL, function stores here pointer to the first invalid character
* @param base zero or number between 2 and 36 inclusive
* @param sgn its set to 1 if minus found
* @return result of conversion.
*/
static unsigned long _strtoul(const char *nptr, char **endptr, int base, char *sgn)
{
unsigned char c;
unsigned long result = 0;
unsigned long a, b;
const char *str = nptr;
const char *tmpptr;
while (isspace(*str))
str++;
if (*str == '-') {
*sgn = 1;
++str;
} else if (*str == '+')
++str;
if (base) {
if ((base == 1) || (base > 36)) {
/* FIXME: set errno to EINVAL */
return 0;
}
if ((base == 16) && (*str == '0') && ((str[1] == 'x') || (str[1] == 'X'))) {
str += 2;
}
} else {
base = 10;
if (*str == '0') {
base = 8;
if ((str[1] == 'X') || (str[1] == 'x')) {
base = 16;
str += 2;
}
}
}
tmpptr = str;
 
while (*str) {
c = *str;
c = ( c >= 'a'? c-'a'+10:(c >= 'A'?c-'A'+10:(c <= '9'?c-'0':0xff)));
if (c > base) {
break;
}
a = (result & 0xff) * base + c;
b = (result >> 8) * base + (a >> 8);
if (b > (ULONG_MAX >> 8)) {
/* overflow */
/* FIXME: errno = ERANGE*/
return ULONG_MAX;
}
result = (b << 8) + (a & 0xff);
++str;
}
if (str == tmpptr) {
/* no number was found => first invalid character is the first character of the string */
/* FIXME: set errno to EINVAL */
str = nptr;
result = 0;
}
if (endptr)
*endptr = (char *)str;
 
if (nptr == str) {
/*FIXME: errno = EINVAL*/
return 0;
}
 
return result;
}
 
/** Convert initial part of string to long int according to given base.
* The number may begin with an arbitrary number of whitespaces followed by optional sign (`+' or `-').
* If the base is 0 or 16, the prefix `0x' may be inserted and the number will be taken as hexadecimal one.
* If the base is 0 and the number begin with a zero, number will be taken as octal one (as with base 8).
* Otherwise the base 0 is taken as decimal.
* @param nptr pointer to string
* @param endptr if not NULL, function stores here pointer to the first invalid character
* @param base zero or number between 2 and 36 inclusive
* @return result of conversion.
*/
long int strtol(const char *nptr, char **endptr, int base)
{
char sgn = 0;
unsigned long number = 0;
number = _strtoul(nptr, endptr, base, &sgn);
 
if (number > LONG_MAX) {
if ((sgn) && (number == (unsigned long)(LONG_MAX) + 1)) {
/* FIXME: set 0 to errno */
return number;
}
/* FIXME: set ERANGE to errno */
return (sgn?LONG_MIN:LONG_MAX);
}
return (sgn?-number:number);
}
 
 
/** Convert initial part of string to unsigned long according to given base.
* The number may begin with an arbitrary number of whitespaces followed by optional sign (`+' or `-').
* If the base is 0 or 16, the prefix `0x' may be inserted and the number will be taken as hexadecimal one.
* If the base is 0 and the number begin with a zero, number will be taken as octal one (as with base 8).
* Otherwise the base 0 is taken as decimal.
* @param nptr pointer to string
* @param endptr if not NULL, function stores here pointer to the first invalid character
* @param base zero or number between 2 and 36 inclusive
* @return result of conversion.
*/
unsigned long strtoul(const char *nptr, char **endptr, int base)
{
char sgn = 0;
unsigned long number = 0;
number = _strtoul(nptr, endptr, base, &sgn);
 
return (sgn?-number:number);
}
 
char *strcpy(char *dest, const char *src)
{
while (*(dest++) = *(src++))
;
}
 
char *strncpy(char *dest, const char *src, size_t n)
{
while ((*(dest++) = *(src++)) && --n)
;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/thread.c
0,0 → 1,160
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <thread.h>
#include <libc.h>
#include <stdlib.h>
#include <arch/faddr.h>
#include <kernel/proc/uarg.h>
#include <psthread.h>
#include <string.h>
#include <async.h>
 
#include <stdio.h>
 
 
#ifndef THREAD_INITIAL_STACK_PAGES_NO
#define THREAD_INITIAL_STACK_PAGES_NO 1
#endif
 
static LIST_INITIALIZE(thread_garbage);
 
extern char _tdata_start;
extern char _tdata_end;
extern char _tbss_start;
extern char _tbss_end;
 
/** Create Thread Local storage area, return pointer to TCB(ThreadControlBlock)
*
* !! The code requires, that sections .tdata and .tbss are adjacent.
* It may be changed in the future.
*/
tcb_t * __make_tls(void)
{
void *data;
tcb_t *tcb;
size_t tls_size = &_tbss_end - &_tdata_start;
tcb = __alloc_tls(&data, tls_size);
memcpy(data, &_tdata_start, &_tdata_end - &_tdata_start);
memset(data + (&_tbss_start-&_tdata_start), 0, &_tbss_end-&_tbss_start);
return tcb;
}
 
void __free_tls(tcb_t *tcb)
{
size_t tls_size = &_tbss_end - &_tdata_start;
__free_tls_arch(tcb, tls_size);
}
 
/** Main thread function.
*
* This function is called from __thread_entry() and is used
* to call the thread's implementing function and perform cleanup
* and exit when thread returns back. Do not call this function
* directly.
*
* @param uarg Pointer to userspace argument structure.
*
* TODO: Thread stack pages memory leak
*/
void __thread_main(uspace_arg_t *uarg)
{
psthread_data_t *pt;
 
pt = psthread_setup();
__tcb_set(pt->tcb);
uarg->uspace_thread_function(uarg->uspace_thread_arg);
free(uarg->uspace_stack);
free(uarg);
 
/* If there is a manager, destroy it */
async_destroy_manager();
psthread_teardown(pt);
 
thread_exit(0);
}
 
/** Create userspace thread.
*
* This function creates new userspace thread and allocates userspace
* stack and userspace argument structure for it.
*
* @param function Function implementing the thread.
* @param arg Argument to be passed to thread.
* @param name Symbolic name of the thread.
*
* @param TID of the new thread on success or -1 on failure.
*/
int thread_create(void (* function)(void *), void *arg, char *name)
{
char *stack;
uspace_arg_t *uarg;
 
stack = (char *) malloc(getpagesize()*THREAD_INITIAL_STACK_PAGES_NO);
if (!stack)
return -1;
uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t));
if (!uarg) {
free(stack);
return -1;
}
uarg->uspace_entry = (void *) FADDR(__thread_entry);
uarg->uspace_stack = (void *) stack;
uarg->uspace_thread_function = function;
uarg->uspace_thread_arg = arg;
uarg->uspace_uarg = uarg;
return __SYSCALL2(SYS_THREAD_CREATE, (sysarg_t) uarg, (sysarg_t) name);
}
 
/** Terminate current thread.
*
* @param stat Exit status. Currently not used.
*/
void thread_exit(int status)
{
__SYSCALL1(SYS_THREAD_EXIT, (sysarg_t) status);
}
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/psthread.c
0,0 → 1,315
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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 <psthread.h>
#include <malloc.h>
#include <unistd.h>
#include <thread.h>
#include <stdio.h>
#include <kernel/arch/faddr.h>
#include <futex.h>
#include <assert.h>
#include <async.h>
 
#ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
#define PSTHREAD_INITIAL_STACK_PAGES_NO 1
#endif
 
static LIST_INITIALIZE(ready_list);
static LIST_INITIALIZE(serialized_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;
/** Count of real 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 of threads residing in async_manager */
static int threads_in_manager;
 
/** Setup PSthread information into TCB structure */
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;
}
 
tcb->pst_data = pt;
pt->tcb = tcb;
 
return pt;
}
 
void psthread_teardown(psthread_data_t *pt)
{
__free_tls(pt->tcb);
free(pt);
}
 
/** Function that is called on entry to new uspace thread */
void psthread_main(void)
{
psthread_data_t *pt = __tcb_get()->pst_data;
 
pt->retval = pt->func(pt->arg);
 
pt->finished = 1;
if (pt->waiter)
list_append(&pt->waiter->link, &ready_list);
 
psthread_schedule_next_adv(PS_FROM_DEAD);
}
 
/** Schedule next userspace pseudo thread.
*
* If calling with PS_TO_MANAGER parameter, the async_futex should be
* held.
*
* @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_adv(pschange_type ctype)
{
psthread_data_t *srcpt, *dstpt;
int retval = 0;
futex_down(&psthread_futex);
 
if (ctype == PS_PREEMPT && list_empty(&ready_list))
goto ret_0;
 
if (ctype == PS_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) && threads_in_manager <= serialized_threads) {
goto ret_0;
}
}
/* If we are going to manager and none exists, create it */
if (ctype == PS_TO_MANAGER || ctype == PS_FROM_DEAD) {
while (list_empty(&manager_list)) {
futex_up(&psthread_futex);
async_create_manager();
futex_down(&psthread_futex);
}
}
if (ctype != PS_FROM_DEAD) {
/* Save current state */
srcpt = __tcb_get()->pst_data;
if (!context_save(&srcpt->ctx)) {
if (serialization_count)
srcpt->flags &= ~PSTHREAD_SERIALIZED;
return 1; // futex_up already done here
}
 
/* Save myself to correct run list */
if (ctype == PS_PREEMPT)
list_append(&srcpt->link, &ready_list);
else if (ctype == PS_FROM_MANAGER) {
list_append(&srcpt->link, &manager_list);
threads_in_manager--;
} /* If ctype == PS_TO_MANAGER, don't save ourselves to any list, we should
* already be somewhere, or we will be lost */
}
 
/* Choose new thread to run */
if (ctype == PS_TO_MANAGER || ctype == PS_FROM_DEAD) {
dstpt = list_get_instance(manager_list.next,psthread_data_t, link);
if (serialization_count && ctype == PS_TO_MANAGER) {
serialized_threads++;
srcpt->flags |= PSTHREAD_SERIALIZED;
}
threads_in_manager++;
} else {
if (!list_empty(&serialized_list)) {
dstpt = list_get_instance(serialized_list.next, psthread_data_t, link);
serialized_threads--;
} else
dstpt = list_get_instance(ready_list.next, psthread_data_t, link);
}
list_remove(&dstpt->link);
 
futex_up(&psthread_futex);
context_restore(&dstpt->ctx);
 
ret_0:
futex_up(&psthread_futex);
return retval;
}
 
/** Wait for uspace pseudo thread to finish.
*
* @param psthrid Pseudo thread to wait for.
*
* @return Value returned by the finished thread.
*/
int psthread_join(pstid_t psthrid)
{
volatile psthread_data_t *pt, *mypt;
volatile int retval;
 
/* Handle psthrid = Kernel address -> it is wait for call */
pt = (psthread_data_t *) psthrid;
 
/* TODO */
printf("join unsupported\n");
_exit(1);
 
retval = pt->retval;
 
free(pt->stack);
psthread_teardown((void *)pt);
 
return retval;
}
 
/**
* Create a userspace thread
*
* @param func Pseudo thread function.
* @param arg Argument to pass to func.
*
* @return 0 on failure, TLS of the new pseudo thread.
*/
pstid_t psthread_create(int (*func)(void *), void *arg)
{
psthread_data_t *pt;
 
pt = psthread_setup();
if (!pt)
return 0;
pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
 
if (!pt->stack) {
psthread_teardown(pt);
return 0;
}
 
pt->arg= arg;
pt->func = func;
pt->finished = 0;
pt->waiter = NULL;
pt->flags = 0;
 
context_save(&pt->ctx);
context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(),
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);
if ((pt->flags & PSTHREAD_SERIALIZED))
list_append(&pt->link, &serialized_list);
else
list_append(&pt->link, &ready_list);
futex_up(&psthread_futex);
}
 
/** 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)) {
futex_up(&psthread_futex);
return;
}
list_remove(manager_list.next);
futex_up(&psthread_futex);
}
 
/** Return thread id of current running thread */
pstid_t psthread_get_id(void)
{
return (pstid_t)__tcb_get()->pst_data;
}
 
/** Disable preemption
*
* If the thread wants to send several message in 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 will can still be preempted.
*/
void psthread_inc_sercount(void)
{
serialization_count++;
}
 
void psthread_dec_sercount(void)
{
serialization_count--;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/ipc.c
0,0 → 1,458
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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
* @{
* @}
*/
 
/** @addtogroup libcipc IPC
* @brief HelenOS uspace IPC
* @{
* @ingroup libc
*/
/** @file
*/
 
#include <ipc/ipc.h>
#include <libc.h>
#include <malloc.h>
#include <errno.h>
#include <libadt/list.h>
#include <stdio.h>
#include <unistd.h>
#include <futex.h>
#include <kernel/synch/synch.h>
#include <async.h>
#include <psthread.h>
 
/** Structure used for keeping track of sent async msgs
* and queing unsent msgs
*
*/
typedef struct {
link_t list;
 
ipc_async_callback_t callback;
void *private;
union {
ipc_callid_t callid;
struct {
ipc_call_t data;
int phoneid;
} msg;
}u;
pstid_t ptid; /**< Thread waiting for sending this msg */
} async_call_t;
 
LIST_INITIALIZE(dispatched_calls);
 
/* queued_calls is protcted by async_futex, because if the
* call cannot be sent into kernel, async framework is used
* automatically
*/
LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted
* by kernel */
 
static atomic_t ipc_futex = FUTEX_INITIALIZER;
 
int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t *result)
{
ipc_call_t resdata;
int callres;
callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
(sysarg_t)&resdata);
if (callres)
return callres;
if (result)
*result = IPC_GET_ARG1(resdata);
return IPC_GET_RETVAL(resdata);
}
 
int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3,
ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
{
ipc_call_t data;
int callres;
 
IPC_SET_METHOD(data, method);
IPC_SET_ARG1(data, arg1);
IPC_SET_ARG2(data, arg2);
IPC_SET_ARG3(data, arg3);
 
callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t)&data,
(sysarg_t)&data);
if (callres)
return callres;
 
if (result1)
*result1 = IPC_GET_ARG1(data);
if (result2)
*result2 = IPC_GET_ARG2(data);
if (result3)
*result3 = IPC_GET_ARG3(data);
return IPC_GET_RETVAL(data);
}
 
/** Syscall to send asynchronous message */
static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
{
return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t)data);
}
 
/** Prolog to ipc_async_send functions */
static inline async_call_t *ipc_prepare_async(void *private, ipc_async_callback_t callback)
{
async_call_t *call;
 
call = malloc(sizeof(*call));
if (!call) {
if (callback)
callback(private, ENOMEM, NULL);
return NULL;
}
call->callback = callback;
call->private = private;
 
return call;
}
 
/** Epilogue of ipc_async_send functions */
static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
async_call_t *call, int can_preempt)
{
if (callid == IPC_CALLRET_FATAL) {
futex_up(&ipc_futex);
/* Call asynchronous handler with error code */
if (call->callback)
call->callback(call->private, ENOENT, NULL);
free(call);
return;
}
 
if (callid == IPC_CALLRET_TEMPORARY) {
futex_up(&ipc_futex);
 
call->u.msg.phoneid = phoneid;
futex_down(&async_futex);
list_append(&call->list, &queued_calls);
 
if (can_preempt) {
call->ptid = psthread_get_id();
psthread_schedule_next_adv(PS_TO_MANAGER);
/* Async futex unlocked by previous call */
} else {
call->ptid = 0;
futex_up(&async_futex);
}
return;
}
call->u.callid = callid;
/* Add call to list of dispatched calls */
list_append(&call->list, &dispatched_calls);
futex_up(&ipc_futex);
}
 
/** Send asynchronous message
*
* - if fatal error, call callback handler with proper error code
* - if message cannot be temporarily sent, add to queue
*/
void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, void *private,
ipc_async_callback_t callback, int can_preempt)
{
async_call_t *call;
ipc_callid_t callid;
 
call = ipc_prepare_async(private, callback);
if (!call)
return;
 
/* We need to make sure that we get callid before
* another thread accesses the queue again */
futex_down(&ipc_futex);
callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2);
 
if (callid == IPC_CALLRET_TEMPORARY) {
IPC_SET_METHOD(call->u.msg.data, method);
IPC_SET_ARG1(call->u.msg.data, arg1);
IPC_SET_ARG2(call->u.msg.data, arg2);
}
ipc_finish_async(callid, phoneid, call, can_preempt);
}
 
/** Send asynchronous message
*
* - if fatal error, call callback handler with proper error code
* - if message cannot be temporarily sent, add to queue
*/
void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
ipcarg_t arg2, ipcarg_t arg3, void *private,
ipc_async_callback_t callback, int can_preempt)
{
async_call_t *call;
ipc_callid_t callid;
 
call = ipc_prepare_async(private, callback);
if (!call)
return;
 
IPC_SET_METHOD(call->u.msg.data, method);
IPC_SET_ARG1(call->u.msg.data, arg1);
IPC_SET_ARG2(call->u.msg.data, arg2);
IPC_SET_ARG3(call->u.msg.data, arg3);
/* We need to make sure that we get callid before
* another thread accesses the queue again */
futex_down(&ipc_futex);
callid = _ipc_call_async(phoneid, &call->u.msg.data);
 
ipc_finish_async(callid, phoneid, call, can_preempt);
}
 
 
/** Send a fast answer to a received call.
*
* The fast answer makes use of passing retval and first two arguments in registers.
* If you need to return more, use the ipc_answer() instead.
*
* @param callid ID of the call being answered.
* @param retval Return value.
* @param arg1 First return argument.
* @param arg2 Second return argument.
*
* @return Zero on success or a value from @ref errno.h on failure.
*/
ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
ipcarg_t arg2)
{
return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2);
}
 
/** Send a full answer to a received call.
*
* @param callid ID of the call being answered.
* @param call Call data. Must be already initialized by the responder.
*
* @return Zero on success or a value from @ref errno.h on failure.
*/
ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call)
{
return __SYSCALL2(SYS_IPC_ANSWER, callid, (sysarg_t) call);
}
 
 
/** Try to dispatch queed calls from async queue */
static void try_dispatch_queued_calls(void)
{
async_call_t *call;
ipc_callid_t callid;
 
/* TODO: integrate intelligently ipc_futex, so that it
* is locked during ipc_call_async, until it is added
* to dispatched_calls
*/
futex_down(&async_futex);
while (!list_empty(&queued_calls)) {
call = list_get_instance(queued_calls.next, async_call_t,
list);
 
callid = _ipc_call_async(call->u.msg.phoneid,
&call->u.msg.data);
if (callid == IPC_CALLRET_TEMPORARY) {
break;
}
list_remove(&call->list);
 
futex_up(&async_futex);
if (call->ptid)
psthread_add_ready(call->ptid);
if (callid == IPC_CALLRET_FATAL) {
if (call->callback)
call->callback(call->private, ENOENT, NULL);
free(call);
} else {
call->u.callid = callid;
futex_down(&ipc_futex);
list_append(&call->list, &dispatched_calls);
futex_up(&ipc_futex);
}
futex_down(&async_futex);
}
futex_up(&async_futex);
}
 
/** Handle received answer
*
* TODO: Make it use hash table
*
* @param callid Callid (with first bit set) of the answered call
*/
static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
{
link_t *item;
async_call_t *call;
 
callid &= ~IPC_CALLID_ANSWERED;
futex_down(&ipc_futex);
for (item = dispatched_calls.next; item != &dispatched_calls;
item = item->next) {
call = list_get_instance(item, async_call_t, list);
if (call->u.callid == callid) {
list_remove(&call->list);
futex_up(&ipc_futex);
if (call->callback)
call->callback(call->private,
IPC_GET_RETVAL(*data),
data);
free(call);
return;
}
}
futex_up(&ipc_futex);
printf("Received unidentified answer: %P!!!\n", callid);
}
 
 
/** 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_cycle(ipc_call_t *call, uint32_t usec, int flags)
{
ipc_callid_t callid;
 
callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
/* Handle received answers */
if (callid & IPC_CALLID_ANSWERED) {
handle_answer(callid, call);
try_dispatch_queued_calls();
}
 
return callid;
}
 
/** Wait some time for an IPC call.
*
* - dispatch ASYNC reoutines in the background
* @param call Space where the message is stored
* @param usec Timeout in microseconds.
* @return Callid of the answer.
*/
ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
{
ipc_callid_t callid;
 
do {
callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
} while (callid & IPC_CALLID_ANSWERED);
 
return callid;
}
 
/** Check if there is an IPC call waiting to be picked up.
*
* - dispatch ASYNC reoutines in the background
* @param call Space where the message is stored
* @return Callid of the answer.
*/
ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
{
ipc_callid_t callid;
 
do {
callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING);
} while (callid & IPC_CALLID_ANSWERED);
 
return callid;
}
 
/** Ask destination to do a callback connection
*
* @return 0 - OK, error code
*/
int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone)
{
return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1,
arg2, 0, 0, 0, phone);
}
 
/** Ask through phone for a new connection to some service
*
* @return new phoneid - OK, error code
*/
int ipc_connect_me_to(int phoneid, int arg1, int arg2)
{
ipcarg_t newphid;
int res;
 
res = ipc_call_sync_3(phoneid, IPC_M_CONNECT_ME_TO, arg1,
arg2, 0, 0, 0, &newphid);
if (res)
return res;
return newphid;
}
 
/* Hang up specified phone */
int ipc_hangup(int phoneid)
{
return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
}
 
int ipc_register_irq(int irq, irq_code_t *ucode)
{
return __SYSCALL2(SYS_IPC_REGISTER_IRQ, irq, (sysarg_t) ucode);
}
 
int ipc_unregister_irq(int irq)
{
return __SYSCALL1(SYS_IPC_UNREGISTER_IRQ, irq);
}
 
int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
{
return __SYSCALL4(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1);
}
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/libadt/hash_table.c
0,0 → 1,182
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
/*
* 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;
}
}
}
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/libadt/list.c
0,0 → 1,92
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#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);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/stdlib.c
0,0 → 1,53
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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 <stdlib.h>
 
static long glbl_seed = 1;
 
long int random(void)
{
return glbl_seed = ((1366*glbl_seed + 150889) % RAND_MAX);
}
 
void srandom(unsigned int seed)
{
glbl_seed = seed;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/printf.c
0,0 → 1,64
/*
* Copyright (C) 2006 Josef Cejka
* 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 <io/printf_core.h>
#include <stdio.h>
#include <stdio.h>
 
/** Print formatted text.
* @param fmt format string
* \see For more details about format string see printf_core.
*/
int printf(const char *fmt, ...)
{
int ret;
va_list args;
 
va_start(args, fmt);
 
ret = vprintf(fmt, args);
va_end(args);
 
return ret;
}
 
 
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/snprintf.c
0,0 → 1,62
/*
* Copyright (C) 2006 Josef Cejka
* 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 <stdarg.h>
#include <stdio.h>
#include <io/printf_core.h>
 
/** Print formatted to the given buffer with limited size.
* @param str buffer
* @param size buffer size
* @param fmt format string
* \see For more details about format string see printf_core.
*/
int snprintf(char *str, size_t size, const char *fmt, ...)
{
int ret;
va_list args;
va_start(args, fmt);
ret = vsnprintf(str, size, fmt, args);
 
va_end(args);
 
return ret;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/sprintf.c
0,0 → 1,61
/*
* Copyright (C) 2006 Josef Cejka
* 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 <stdarg.h>
#include <stdio.h>
#include <io/printf_core.h>
 
/** Print formatted to the given buffer.
* @param str buffer
* @param fmt format string
* \see For more details about format string see printf_core.
*/
int sprintf(char *str, const char *fmt, ...)
{
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(str, fmt, args);
 
va_end(args);
 
return ret;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/io.c
0,0 → 1,118
/*
* Copyright (C) 2005 Martin Decky
* 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 <libc.h>
#include <unistd.h>
#include <stdio.h>
#include <io/io.h>
 
static char nl = '\n';
 
int puts(const char * str)
{
size_t count;
if (str == NULL) {
return putnchars("(NULL)",6 );
}
for (count = 0; str[count] != 0; count++);
if (write(1, (void * ) str, count) == count) {
if (write(1, &nl, 1) == 1)
return 0;
}
return EOF;
}
 
/** Put count chars from buffer to stdout without adding newline
* @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
* @param count
* @return 0 on succes, EOF on fail
*/
int putnchars(const char * buf, size_t count)
{
if (write(1, (void * ) buf, count) == count) {
return 0;
}
return EOF;
}
 
/** Same as puts, but does not print newline at end
*
*/
int putstr(const char * str)
{
size_t count;
if (str == NULL) {
return putnchars("(NULL)",6 );
}
 
for (count = 0; str[count] != 0; count++);
if (write(1, (void * ) str, count) == count) {
return 0;
}
return EOF;
}
 
int putchar(int c)
{
unsigned char ch = c;
if (write(1, (void *)&ch , 1) == 1) {
return c;
}
return EOF;
}
 
int getchar(void)
{
unsigned char c;
if (read(0, (void *)&c , 1) == 1) {
return c;
}
return EOF;
}
 
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/vprintf.c
0,0 → 1,65
/*
* Copyright (C) 2006 Josef Cejka
* 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 <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <io/printf_core.h>
 
int vprintf_write(const char *str, size_t count, void *unused);
 
int vprintf_write(const char *str, size_t count, void *unused)
{
return write(1, str, count);
}
 
/** Print formatted text.
* @param fmt format string
* @param ap format parameters
* \see For more details about format string see printf_core.
*/
int vprintf(const char *fmt, va_list ap)
{
struct printf_spec ps = {(int(*)(void *, size_t, void *))vprintf_write, NULL};
return printf_core(fmt, &ps, ap);
 
}
 
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/vsnprintf.c
0,0 → 1,117
/*
* Copyright (C) 2006 Josef Cejka
* 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 <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <io/printf_core.h>
 
 
struct vsnprintf_data {
size_t size; /* total space for string */
size_t len; /* count of currently used characters */
char *string; /* destination string */
};
 
int vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data);
 
/** Write string to given buffer.
* Write at most data->size characters including trailing zero. According to C99 has snprintf to return number
* of characters that would have been written if enough space had been available. Hence the return value is not
* number of really printed characters but size of input string. Number of really used characters
* is stored in data->len.
* @param str source string to print
* @param count size of source string
* @param data structure with destination string, counter of used space and total string size.
* @return number of characters to print (not characters really printed!)
*/
int vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data)
{
size_t i;
i = data->size - data->len;
 
if (i == 0) {
return count;
}
if (i == 1) {
/* We have only one free byte left in buffer => write there trailing zero */
data->string[data->size - 1] = 0;
data->len = data->size;
return count;
}
if (i <= count) {
/* We have not enought space for whole string with the trailing zero => print only a part of string */
memcpy((void *)(data->string + data->len), (void *)str, i - 1);
data->string[data->size - 1] = 0;
data->len = data->size;
return count;
}
/* Buffer is big enought to print whole string */
memcpy((void *)(data->string + data->len), (void *)str, count);
data->len += count;
/* Put trailing zero at end, but not count it into data->len so it could be rewritten next time */
data->string[data->len] = 0;
 
return count;
}
 
/** Print formatted to the given buffer with limited size.
* @param str buffer
* @param size buffer size
* @param fmt format string
* \see For more details about format string see printf_core.
*/
int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
{
struct vsnprintf_data data = {size, 0, str};
struct printf_spec ps = {(int(*)(void *, size_t, void *))vsnprintf_write, &data};
 
/* Print 0 at end of string - fix the case that nothing will be printed */
if (size > 0)
str[0] = 0;
/* vsnprintf_write ensures that str will be terminated by zero. */
return printf_core(fmt, &ps, ap);
}
 
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/printf_core.c
0,0 → 1,696
/*
* Copyright (C) 2001-2004 Jakub Jermar
* Copyright (C) 2006 Josef Cejka
* 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
* @brief Printing functions.
*/
 
#include <unistd.h>
#include <stdio.h>
#include <io/printf_core.h>
#include <ctype.h>
#include <string.h>
/* For serialization */
#include <async.h>
 
#define __PRINTF_FLAG_PREFIX 0x00000001 /**< show prefixes 0x or 0*/
#define __PRINTF_FLAG_SIGNED 0x00000002 /**< signed / unsigned number */
#define __PRINTF_FLAG_ZEROPADDED 0x00000004 /**< print leading zeroes */
#define __PRINTF_FLAG_LEFTALIGNED 0x00000010 /**< align to left */
#define __PRINTF_FLAG_SHOWPLUS 0x00000020 /**< always show + sign */
#define __PRINTF_FLAG_SPACESIGN 0x00000040 /**< print space instead of plus */
#define __PRINTF_FLAG_BIGCHARS 0x00000080 /**< show big characters */
#define __PRINTF_FLAG_NEGATIVE 0x00000100 /**< number has - sign */
 
#define PRINT_NUMBER_BUFFER_SIZE (64+5) /**< Buffer big enought for 64 bit number
* printed in base 2, sign, prefix and
* 0 to terminate string.. (last one is only for better testing
* end of buffer by zero-filling subroutine)
*/
/** Enumeration of possible arguments types.
*/
typedef enum {
PrintfQualifierByte = 0,
PrintfQualifierShort,
PrintfQualifierInt,
PrintfQualifierLong,
PrintfQualifierLongLong,
PrintfQualifierSizeT,
PrintfQualifierPointer
} qualifier_t;
 
static char digits_small[] = "0123456789abcdef"; /**< Small hexadecimal characters */
static char digits_big[] = "0123456789ABCDEF"; /**< Big hexadecimal characters */
 
/** Print count chars from buffer without adding newline
* @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
* @param count
* @param ps output method and its data
* @return number of printed characters
*/
static int printf_putnchars(const char * buf, size_t count, struct printf_spec *ps)
{
return ps->write((void *)buf, count, ps->data);
}
 
/** Print string without added newline
* @param str string to print
* @param ps write function specification and support data
* @return number of printed characters
*/
static int printf_putstr(const char * str, struct printf_spec *ps)
{
size_t count;
if (str == NULL) {
return printf_putnchars("(NULL)", 6, ps);
}
 
for (count = 0; str[count] != 0; count++);
 
if (ps->write((void *) str, count, ps->data) == count) {
return 0;
}
return EOF;
}
 
/** Print one character to output
* @param c one character
* @param ps output method
* @return number of printed characters
*/
static int printf_putchar(int c, struct printf_spec *ps)
{
unsigned char ch = c;
return ps->write((void *) &ch, 1, ps->data);
}
 
/** Print one formatted character
* @param c character to print
* @param width
* @param flags
* @return number of printed characters
*/
static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
{
int counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (--width > 0) { /* one space is consumed by character itself hence predecrement */
if (printf_putchar(' ', ps) > 0)
++counter;
}
}
if (printf_putchar(c, ps) > 0)
counter++;
while (--width > 0) { /* one space is consumed by character itself hence predecrement */
if (printf_putchar(' ', ps) > 0)
++counter;
}
return ++counter;
}
 
/** Print one string
* @param s string
* @param width
* @param precision
* @param flags
* @return number of printed characters
*/
static int print_string(char *s, int width, int precision, uint64_t flags, struct printf_spec *ps)
{
int counter = 0;
size_t size;
int retval;
 
if (s == NULL) {
return printf_putstr("(NULL)", ps);
}
size = strlen(s);
 
/* print leading spaces */
 
if (precision == 0)
precision = size;
 
width -= precision;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
 
while (precision > size) {
precision--;
if (printf_putchar(' ', ps) == 1)
++counter;
}
if ((retval = printf_putnchars(s, precision, ps)) < 0) {
return -counter;
}
 
counter += retval;
 
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
++counter;
}
return counter;
}
 
 
/** Print number in given base
*
* Print significant digits of a number in given
* base.
*
* @param num Number to print.
* @param width
* @param precision
* @param base Base to print the number in (should
* be in range 2 .. 16).
* @param flags output modifiers
* @return number of printed characters
*
*/
static int print_number(uint64_t num, int width, int precision, int base , uint64_t flags, struct printf_spec *ps)
{
char *digits = digits_small;
char d[PRINT_NUMBER_BUFFER_SIZE]; /* this is good enough even for base == 2, prefix and sign */
char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
int size = 0; /* size of number with all prefixes and signs */
int number_size; /* size of plain number */
char sgn;
int retval;
int counter = 0;
if (flags & __PRINTF_FLAG_BIGCHARS)
digits = digits_big;
*ptr-- = 0; /* Put zero at end of string */
 
if (num == 0) {
*ptr-- = '0';
size++;
} else {
do {
*ptr-- = digits[num % base];
size++;
} while (num /= base);
}
number_size = size;
 
/* Collect sum of all prefixes/signs/... to calculate padding and leading zeroes */
if (flags & __PRINTF_FLAG_PREFIX) {
switch(base) {
case 2: /* Binary formating is not standard, but usefull */
size += 2;
break;
case 8:
size++;
break;
case 16:
size += 2;
break;
}
}
 
sgn = 0;
if (flags & __PRINTF_FLAG_SIGNED) {
if (flags & __PRINTF_FLAG_NEGATIVE) {
sgn = '-';
size++;
} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
sgn = '+';
size++;
} else if (flags & __PRINTF_FLAG_SPACESIGN) {
sgn = ' ';
size++;
}
}
 
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
flags &= ~__PRINTF_FLAG_ZEROPADDED;
}
 
/* if number is leftaligned or precision is specified then zeropadding is ignored */
if (flags & __PRINTF_FLAG_ZEROPADDED) {
if ((precision == 0) && (width > size)) {
precision = width - size + number_size;
}
}
 
/* print leading spaces */
if (number_size > precision) /* We must print whole number not only a part */
precision = number_size;
 
width -= precision + size - number_size;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
/* print sign */
if (sgn) {
if (printf_putchar(sgn, ps) == 1)
counter++;
}
/* print prefix */
if (flags & __PRINTF_FLAG_PREFIX) {
switch(base) {
case 2: /* Binary formating is not standard, but usefull */
if (printf_putchar('0', ps) == 1)
counter++;
if (flags & __PRINTF_FLAG_BIGCHARS) {
if (printf_putchar('B', ps) == 1)
counter++;
} else {
if (printf_putchar('b', ps) == 1)
counter++;
}
break;
case 8:
if (printf_putchar('o', ps) == 1)
counter++;
break;
case 16:
if (printf_putchar('0', ps) == 1)
counter++;
if (flags & __PRINTF_FLAG_BIGCHARS) {
if (printf_putchar('X', ps) == 1)
counter++;
} else {
if (printf_putchar('x', ps) == 1)
counter++;
}
break;
}
}
 
/* print leading zeroes */
precision -= number_size;
while (precision-- > 0) {
if (printf_putchar('0', ps) == 1)
counter++;
}
 
/* print number itself */
 
if ((retval = printf_putstr(++ptr, ps)) > 0) {
counter += retval;
}
/* print ending spaces */
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
 
return counter;
}
 
 
/** Print formatted string.
*
* Print string formatted according to the fmt parameter
* and variadic arguments. Each formatting directive
* must have the following form:
*
* \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
*
* FLAGS:@n
* - "#" Force to print prefix.
* For conversion \%o the prefix is 0, for %x and \%X prefixes are 0x and 0X
* and for conversion \%b the prefix is 0b.
*
* - "-" Align to left.
*
* - "+" Print positive sign just as negative.
*
* - " " If the printed number is positive and "+" flag is not set, print space in
* place of sign.
*
* - "0" Print 0 as padding instead of spaces. Zeroes are placed between sign and the
* rest of the number. This flag is ignored if "-" flag is specified.
*
* WIDTH:@n
* - Specify minimal width of printed argument. If it is bigger, width is ignored.
* If width is specified with a "*" character instead of number, width is taken from
* parameter list. And integer parameter is expected before parameter for processed
* conversion specification. If this value is negative its absolute value is taken
* and the "-" flag is set.
*
* PRECISION:@n
* - Value precision. For numbers it specifies minimum valid numbers.
* Smaller numbers are printed with leading zeroes. Bigger numbers are not affected.
* Strings with more than precision characters are cut off.
* Just as with width, an "*" can be used used instead of a number.
* An integer value is then expected in parameters. When both width and precision
* are specified using "*", the first parameter is used for width and the second one
* for precision.
*
* TYPE:@n
* - "hh" Signed or unsigned char.@n
* - "h" Signed or usigned short.@n
* - "" Signed or usigned int (default value).@n
* - "l" Signed or usigned long int.@n
* - "ll" Signed or usigned long long int.@n
* - "z" Type size_t.@n
*
*
* CONVERSION:@n
* - % Print percentile character itself.
*
* - c Print single character.
*
* - s Print zero terminated string. If a NULL value is passed as value, "(NULL)" is printed instead.
*
* - P, p Print value of a pointer. Void * value is expected and it is printed in hexadecimal notation with prefix
* (as with '\%#X' or '\%#x' for 32bit or '\%#X' or '\%#x' for 64bit long pointers).
*
* - b Print value as unsigned binary number. Prefix is not printed by default. (Nonstandard extension.)
*
* - o Print value as unsigned octal number. Prefix is not printed by default.
*
* - d,i Print signed decimal number. There is no difference between d and i conversion.
*
* - u Print unsigned decimal number.
*
* - X, x Print hexadecimal number with upper- or lower-case. Prefix is not printed by default.
*
* All other characters from fmt except the formatting directives
* are printed in verbatim.
*
* @param fmt Formatting NULL terminated string.
* @return Number of printed characters or negative value on failure.
*/
int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
{
int i = 0, j = 0; /* i is index of currently processed char from fmt, j is index to the first not printed nonformating character */
int end;
int counter; /* counter of printed characters */
int retval; /* used to store return values from called functions */
char c;
qualifier_t qualifier; /* type of argument */
int base; /* base in which will be parameter (numbers only) printed */
uint64_t number; /* argument value */
size_t size; /* byte size of integer parameter */
int width, precision;
uint64_t flags;
/* Don't let other threads interfere */
async_serialize_start();
 
counter = 0;
while ((c = fmt[i])) {
/* control character */
if (c == '%' ) {
/* print common characters if any processed */
if (i > j) {
if ((retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps)) < 0) { /* error */
goto minus_out;
}
counter += retval;
}
j = i;
/* parse modifiers */
flags = 0;
end = 0;
do {
++i;
switch (c = fmt[i]) {
case '#': flags |= __PRINTF_FLAG_PREFIX; break;
case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
default: end = 1;
};
} while (end == 0);
/* width & '*' operator */
width = 0;
if (isdigit(fmt[i])) {
while (isdigit(fmt[i])) {
width *= 10;
width += fmt[i++] - '0';
}
} else if (fmt[i] == '*') {
/* get width value from argument list*/
i++;
width = (int)va_arg(ap, int);
if (width < 0) {
/* negative width means to set '-' flag */
width *= -1;
flags |= __PRINTF_FLAG_LEFTALIGNED;
}
}
/* precision and '*' operator */
precision = 0;
if (fmt[i] == '.') {
++i;
if (isdigit(fmt[i])) {
while (isdigit(fmt[i])) {
precision *= 10;
precision += fmt[i++] - '0';
}
} else if (fmt[i] == '*') {
/* get precision value from argument list*/
i++;
precision = (int)va_arg(ap, int);
if (precision < 0) {
/* negative precision means to ignore it */
precision = 0;
}
}
}
 
switch (fmt[i++]) {
/** TODO: unimplemented qualifiers:
* t ptrdiff_t - ISO C 99
*/
case 'h': /* char or short */
qualifier = PrintfQualifierShort;
if (fmt[i] == 'h') {
i++;
qualifier = PrintfQualifierByte;
}
break;
case 'l': /* long or long long*/
qualifier = PrintfQualifierLong;
if (fmt[i] == 'l') {
i++;
qualifier = PrintfQualifierLongLong;
}
break;
case 'z': /* size_t */
qualifier = PrintfQualifierSizeT;
break;
default:
qualifier = PrintfQualifierInt; /* default type */
--i;
}
base = 10;
 
switch (c = fmt[i]) {
 
/*
* String and character conversions.
*/
case 's':
if ((retval = print_string(va_arg(ap, char*), width, precision, flags, ps)) < 0) {
goto minus_out;
};
counter += retval;
j = i + 1;
goto next_char;
case 'c':
c = va_arg(ap, unsigned int);
if ((retval = print_char(c, width, flags, ps)) < 0) {
goto minus_out;
};
counter += retval;
j = i + 1;
goto next_char;
 
/*
* Integer values
*/
case 'P': /* pointer */
flags |= __PRINTF_FLAG_BIGCHARS;
case 'p':
flags |= __PRINTF_FLAG_PREFIX;
base = 16;
qualifier = PrintfQualifierPointer;
break;
case 'b':
base = 2;
break;
case 'o':
base = 8;
break;
case 'd':
case 'i':
flags |= __PRINTF_FLAG_SIGNED;
case 'u':
break;
case 'X':
flags |= __PRINTF_FLAG_BIGCHARS;
case 'x':
base = 16;
break;
/* percentile itself */
case '%':
j = i;
goto next_char;
/*
* Bad formatting.
*/
default:
/* Unknown format
* now, the j is index of '%' so we will
* print whole bad format sequence
*/
goto next_char;
}
/* Print integers */
/* print number */
switch (qualifier) {
case PrintfQualifierByte:
size = sizeof(unsigned char);
number = (uint64_t)va_arg(ap, unsigned int);
break;
case PrintfQualifierShort:
size = sizeof(unsigned short);
number = (uint64_t)va_arg(ap, unsigned int);
break;
case PrintfQualifierInt:
size = sizeof(unsigned int);
number = (uint64_t)va_arg(ap, unsigned int);
break;
case PrintfQualifierLong:
size = sizeof(unsigned long);
number = (uint64_t)va_arg(ap, unsigned long);
break;
case PrintfQualifierLongLong:
size = sizeof(unsigned long long);
number = (uint64_t)va_arg(ap, unsigned long long);
break;
case PrintfQualifierPointer:
size = sizeof(void *);
number = (uint64_t)(unsigned long)va_arg(ap, void *);
break;
case PrintfQualifierSizeT:
size = sizeof(size_t);
number = (uint64_t)va_arg(ap, size_t);
break;
default: /* Unknown qualifier */
goto minus_out;
}
if (flags & __PRINTF_FLAG_SIGNED) {
if (number & (0x1 << (size*8 - 1))) {
flags |= __PRINTF_FLAG_NEGATIVE;
if (size == sizeof(uint64_t)) {
number = -((int64_t)number);
} else {
number = ~number;
number &= (~((0xFFFFFFFFFFFFFFFFll) << (size * 8)));
number++;
}
}
}
 
if ((retval = print_number(number, width, precision, base, flags, ps)) < 0 ) {
goto minus_out;
};
 
counter += retval;
j = i + 1;
}
next_char:
++i;
}
if (i > j) {
if ((retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps)) < 0) { /* error */
goto minus_out;
}
counter += retval;
}
async_serialize_end();
return counter;
minus_out:
async_serialize_end();
return -counter;
}
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/stream.c
0,0 → 1,195
/*
* Copyright (C) 2006 Josef Cejka
* Copyright (C) 2006 Jakub Vana
* 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 <io/io.h>
#include <io/stream.h>
#include <string.h>
#include <malloc.h>
#include <libc.h>
#include <ipc/ipc.h>
#include <ipc/ns.h>
#include <ipc/fb.h>
#include <ipc/services.h>
#include <console.h>
#include <unistd.h>
#include <async.h>
 
#define FDS 32
 
typedef struct stream_t {
pwritefn_t w;
preadfn_t r;
void * param;
int phone;
} stream_t;
 
static int console_phone = -1;
static stream_t streams[FDS];
 
static ssize_t write_stderr(void *param, const void *buf, size_t count)
{
return count;
}
 
static ssize_t read_stdin(void *param, void *buf, size_t count)
{
ipcarg_t r0,r1;
size_t i = 0;
 
while (i < count) {
if (async_req_2(streams[0].phone, CONSOLE_GETCHAR, 0, 0, &r0, &r1) < 0) {
return -1;
}
((char *)buf)[i++] = r0;
}
return i;
}
 
static ssize_t write_stdout(void *param, const void *buf, size_t count)
{
int i;
ipcarg_t r0,r1;
 
for (i = 0; i < count; i++)
async_msg(streams[1].phone, CONSOLE_PUTCHAR, ((const char *)buf)[i]);
return count;
}
 
 
 
static stream_t open_stdin(void)
{
stream_t stream;
int phoneid;
int res;
if (console_phone < 0) {
while ((console_phone = ipc_connect_me_to(PHONE_NS, SERVICE_CONSOLE, 0)) < 0) {
usleep(10000);
}
}
stream.r = read_stdin;
stream.param = 0;
stream.phone = console_phone;
return stream;
}
 
static stream_t open_stdout(void)
{
stream_t stream;
int res;
 
if (console_phone < 0) {
while ((console_phone = ipc_connect_me_to(PHONE_NS, SERVICE_CONSOLE, 0)) < 0) {
usleep(10000);
}
}
stream.w = write_stdout;
stream.phone = console_phone;
stream.param = 0;
return stream;
}
 
static ssize_t write_null(void *param, const void *buf, size_t count)
{
return count;
}
 
 
fd_t open(const char *fname, int flags)
{
int c = 0;
 
while (((streams[c].w) || (streams[c].r)) && (c < FDS))
c++;
if (c == FDS)
return EMFILE;
if (!strcmp(fname, "stdin")) {
streams[c] = open_stdin();
return c;
}
if (!strcmp(fname, "stdout")) {
streams[c] = open_stdout();
return c;
}
if (!strcmp(fname, "stderr")) {
streams[c].w = write_stderr;
return c;
}
if (!strcmp(fname, "null")) {
streams[c].w = write_null;
return c;
}
}
 
 
ssize_t write(int fd, const void *buf, size_t count)
{
// __SYSCALL3(SYS_IO, 1, (sysarg_t)buf, (sysarg_t) count);
// return count;
if (fd < FDS)
return streams[fd].w(streams[fd].param, buf, count);
return 0;
}
 
ssize_t read(int fd, void *buf, size_t count)
{
if (fd < FDS)
return streams[fd].r(streams[fd].param, buf, count);
return 0;
}
 
int get_fd_phone(int fd)
{
if (fd >= FDS || fd < 0)
return -1;
return streams[fd].phone;
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/io/vsprintf.c
0,0 → 1,55
/*
* Copyright (C) 2006 Josef Cejka
* 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 <stdarg.h>
#include <stdio.h>
#include <io/printf_core.h>
 
/** Print formatted to the given buffer.
* @param str buffer
* @param fmt format string
* @param ap argument list
* \see For more details about format string see printf_core.
*/
int vsprintf(char *str, const char *fmt, va_list ap)
{
return vsnprintf(str, (size_t)-1, fmt, ap);
}
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/err.c
0,0 → 1,48
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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 <stdio.h>
#include <stdlib.h>
 
void errx (int __status, __const char *__format, ...)
{
printf("TODO...errx\n");
_exit(0);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/sysinfo.c
0,0 → 1,49
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <libc.h>
#include <sysinfo.h>
#include <string.h>
 
sysarg_t sysinfo_value(char *name)
{
return __SYSCALL2(SYS_SYSINFO_VALUE, (sysarg_t ) name, (sysarg_t) strlen(name) );
}
 
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/mmap.c
0,0 → 1,64
/*
* Copyright (C) 2006 Ondrej Palkovsky
* 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 <sys/mman.h>
#include <as.h>
#include <unistd.h>
 
void *mmap(void *start, size_t length, int prot, int flags, int fd,
off_t offset)
{
int rc;
 
if (!start)
start = as_get_mappable_page(length);
// if (! ((flags & MAP_SHARED) ^ (flags & MAP_PRIVATE)))
// return MAP_FAILED;
if (! (flags & MAP_ANONYMOUS))
return MAP_FAILED;
 
return as_area_create(start, length, prot);
}
 
int munmap(void *start, size_t length)
{
return as_area_destroy(start);
}
 
 
/** @}
*/
/tags/0.2.0.1/uspace/libc/generic/futex.c
0,0 → 1,180
/*
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <futex.h>
#include <atomic.h>
#include <libc.h>
#include <stdio.h>
#include <types.h>
#include <kernel/synch/synch.h>
 
/*
* Note about race conditions.
* Because of non-atomic nature of operations performed sequentially on the futex
* counter and the futex wait queue, there is a race condition:
*
* (wq->missed_wakeups == 1) && (futex->count = 1)
*
* Scenario 1 (wait queue timeout vs. futex_up()):
* 1. assume wq->missed_wakeups == 0 && futex->count == -1
* (ie. thread A sleeping, thread B in the critical section)
* 2. A receives timeout and gets removed from the wait queue
* 3. B wants to leave the critical section and calls futex_up()
* 4. B thus changes futex->count from -1 to 0
* 5. B has to call SYS_FUTEX_WAKEUP syscall to wake up the sleeping thread
* 6. B finds the wait queue empty and changes wq->missed_wakeups from 0 to 1
* 7. A fixes futex->count (i.e. the number of waiting threads) by changing it from 0 to 1
*
* Scenario 2 (conditional down operation vs. futex_up)
* 1. assume wq->missed_wakeups == 0 && futex->count == 0
* (i.e. thread A is in the critical section)
* 2. thread B performs futex_trydown() operation and changes futex->count from 0 to -1
* B is now obliged to call SYS_FUTEX_SLEEP syscall
* 3. A wants to leave the critical section and does futex_up()
* 4. A thus changes futex->count from -1 to 0 and must call SYS_FUTEX_WAKEUP syscall
* 5. B finds the wait queue empty and immediatelly aborts the conditional sleep
* 6. No thread is queueing in the wait queue so wq->missed_wakeups changes from 0 to 1
* 6. B fixes futex->count (i.e. the number of waiting threads) by changing it from 0 to 1
*
* Both scenarios allow two threads to be in the critical section simultaneously.
* One without kernel intervention and the other through wq->missed_wakeups being 1.
*
* To mitigate this problem, futex_down_timeout() detects that the syscall didn't sleep
* in the wait queue, fixes the futex counter and RETRIES the whole operation again.
*
*/
 
/** Initialize futex counter.
*
* @param futex Futex.
* @param val Initialization value.
*/
void futex_initialize(atomic_t *futex, int val)
{
atomic_set(futex, val);
}
 
int futex_down(atomic_t *futex)
{
return futex_down_timeout(futex, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
}
 
int futex_trydown(atomic_t *futex)
{
return futex_down_timeout(futex, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING);
}
 
/** Try to down the futex.
*
* @param futex Futex.
* @param usec Microseconds to wait. Zero value means sleep without timeout.
* @param flags Select mode of operation. See comment for waitq_sleep_timeout().
*
* @return ENOENT if there is no such virtual address. One of ESYNCH_OK_ATOMIC
* and ESYNCH_OK_BLOCKED on success or ESYNCH_TIMEOUT if the lock was
* not acquired because of a timeout or ESYNCH_WOULD_BLOCK if the
* operation could not be carried out atomically (if requested so).
*/
int futex_down_timeout(atomic_t *futex, uint32_t usec, int flags)
{
int rc;
while (atomic_predec(futex) < 0) {
rc = __SYSCALL3(SYS_FUTEX_SLEEP, (sysarg_t) &futex->count, (sysarg_t) usec, (sysarg_t) flags);
switch (rc) {
case ESYNCH_OK_ATOMIC:
/*
* Because of a race condition between timeout and futex_up()
* and between conditional futex_down_timeout() and futex_up(),
* we have to give up and try again in this special case.
*/
atomic_inc(futex);
break;
 
case ESYNCH_TIMEOUT:
atomic_inc(futex);
return ESYNCH_TIMEOUT;
break;
 
case ESYNCH_WOULD_BLOCK:
/*
* The conditional down operation should be implemented this way.
* The userspace-only variant tends to accumulate missed wakeups
* in the kernel futex wait queue.
*/
atomic_inc(futex);
return ESYNCH_WOULD_BLOCK;
break;
 
case ESYNCH_OK_BLOCKED:
/*
* Enter the critical section.
* The futex counter has already been incremented for us.
*/
return ESYNCH_OK_BLOCKED;
break;
default:
return rc;
}
}
 
/*
* Enter the critical section.
*/
return ESYNCH_OK_ATOMIC;
}
 
/** Up the futex.
*
* @param futex Futex.
*
* @return ENOENT if there is no such virtual address. Otherwise zero.
*/
int futex_up(atomic_t *futex)
{
long val;
val = atomic_postinc(futex);
if (val < 0)
return __SYSCALL1(SYS_FUTEX_WAKEUP, (sysarg_t) &futex->count);
return 0;
}
 
 
/** @}
*/