Changeset c042bdd in mainline for libc/generic/async.c


Ignore:
Timestamp:
2006-05-28T23:41:42Z (19 years ago)
Author:
Ondrej Palkovsky <ondrap@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5bd03eb
Parents:
2d1fde3b
Message:

Added support for async_wait_timeout.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libc/generic/async.c

    r2d1fde3b rc042bdd  
    9191#include <assert.h>
    9292#include <errno.h>
     93#include <time.h>
     94#include <arch/barrier.h>
    9395
    9496static atomic_t async_futex = FUTEX_INITIALIZER;
    9597static hash_table_t conn_hash_table;
     98static LIST_INITIALIZE(timeout_list);
    9699
    97100typedef struct {
     
    101104        ipc_call_t *dataptr;         /**< Pointer where the answer data
    102105                                      *   should be stored */
     106        struct timeval expires;      /**< Expiration time for waiting thread */
     107        int has_timeout;             /**< If true, this struct is in timeout list */
     108        link_t link;
     109
    103110        ipcarg_t retval;
    104111} amsg_t;
     
    123130
    124131__thread connection_t *PS_connection;
     132
     133/** Add microseconds to give timeval */
     134static void tv_add(struct timeval *tv, suseconds_t usecs)
     135{
     136        tv->tv_sec += usecs / 1000000;
     137        tv->tv_usec += usecs % 1000000;
     138        if (tv->tv_usec > 1000000) {
     139                tv->tv_sec++;
     140                tv->tv_usec -= 1000000;
     141        }
     142}
     143
     144/** Subtract 2 timevals, return microseconds difference */
     145static suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
     146{
     147        suseconds_t result;
     148
     149        result = tv1->tv_usec - tv2->tv_usec;
     150        result += (tv1->tv_sec - tv2->tv_sec) * 1000000;
     151
     152        return result;
     153}
     154
     155/** Compare timeval
     156 *
     157 * @return 1 if tv1 > tv2, otherwise 0
     158 */
     159static int tv_gt(struct timeval *tv1, struct timeval *tv2)
     160{
     161        if (tv1->tv_sec > tv2->tv_sec)
     162                return 1;
     163        if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec > tv2->tv_usec)
     164                return 1;
     165        return 0;
     166}
    125167
    126168/* Hash table functions */
     
    327369}
    328370
     371/** Fire all timeouts that expired */
     372static void handle_expired_timeouts(void)
     373{
     374        struct timeval tv;
     375        amsg_t *amsg;
     376        link_t *cur;
     377
     378        gettimeofday(&tv,NULL);
     379        futex_down(&async_futex);
     380
     381        cur = timeout_list.next;
     382        while (cur != &timeout_list) {
     383                amsg = list_get_instance(cur,amsg_t,link);
     384                if (tv_gt(&amsg->expires, &tv))
     385                        break;
     386                cur = cur->next;
     387                list_remove(&amsg->link);
     388                amsg->has_timeout = 0;
     389                /* Redundant condition? The thread should not
     390                 * be active when it gets here.
     391                 */
     392                if (!amsg->active) {
     393                        amsg->active = 1;
     394                        psthread_add_ready(amsg->ptid);                 
     395                }
     396        }
     397
     398        futex_up(&async_futex);
     399}
     400
    329401/** Endless loop dispatching incoming calls and answers */
    330 int async_manager()
     402int async_manager(void)
    331403{
    332404        ipc_call_t call;
    333405        ipc_callid_t callid;
    334406        int timeout;
     407        amsg_t *amsg;
     408        struct timeval tv;
    335409
    336410        while (1) {
     
    341415                        continue;
    342416                }
    343 /*
    344                 if (expires)
    345                         timeout = .... ;
    346                 else
    347 */
     417                futex_down(&async_futex);
     418                if (!list_empty(&timeout_list)) {
     419                        amsg = list_get_instance(timeout_list.next,amsg_t,link);
     420                        gettimeofday(&tv,NULL);
     421                        if (tv_gt(&tv, &amsg->expires)) {
     422                                handle_expired_timeouts();
     423                                continue;
     424                        } else
     425                                timeout = tv_sub(&amsg->expires, &tv);
     426                } else
    348427                        timeout = SYNCH_NO_TIMEOUT;
     428                futex_up(&async_futex);
     429
    349430                callid = ipc_wait_cycle(&call, timeout, SYNCH_BLOCKING);
    350431
    351432                if (!callid) {
    352 //                      handle_expired_timeouts.......;
     433                        handle_expired_timeouts();
    353434                        continue;
    354435                }
     
    418499                *msg->dataptr = *data;
    419500
    420         /* TODO: memory barrier?? */
     501        write_barrier();
     502        /* Remove message from timeout list */
     503        if (msg->has_timeout)
     504                list_remove(&msg->link);
    421505        msg->done = 1;
    422506        if (! msg->active) {
     
    466550        msg->ptid = psthread_get_id();
    467551        msg->active = 0;
     552        msg->has_timeout = 0;
    468553        /* Leave locked async_futex when entering this function */
    469554        psthread_schedule_next_adv(PS_TO_MANAGER);
     
    475560}
    476561
    477 
    478 /* int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, int timeout) */
    479 /* { */
    480 /*      amsg_t *msg = (amsg_t *) amsgid; */
    481 /*      connection_t *conn; */
    482 
    483 /*      futex_down(&async_futex); */
    484 /*      if (msg->done) { */
    485 /*              futex_up(&async_futex); */
    486 /*              goto done; */
    487 /*      } */
    488 
    489 /*      msg->ptid = psthread_get_id(); */
    490 /*      msg->active = 0; */
    491 /*      msg->expires = gettime() + timeout; */
    492 /*      setup_timeouts_etc...(); */
    493 
    494 /*      /\* Leave locked async_futex when entering this function *\/ */
    495 /*      psthread_schedule_next_adv(PS_TO_MANAGER); */
    496 /*      /\* futex is up automatically after psthread_schedule_next...*\/ */
    497 
    498 /*      if (!msg->done) */
    499 /*              return casy-casy; */
    500 
    501 /*      /\* TODO: When memory barrier in reply_received, we can skip this *\/ */
    502 /*      futex_down(&async_futex); */
    503 /*      futex_up(&async_futex); */
    504 /* done: */
    505        
    506 /*      if (retval) */
    507 /*              *retval = msg->retval; */
    508 /*      free(msg); */
    509 /* } */
    510 
     562/** Insert sort timeout msg into timeouts list
     563 *
     564 * Assume async_futex is held
     565 */
     566static void insert_timeout(amsg_t *msg)
     567{
     568        link_t *tmp;
     569        amsg_t *cur;
     570
     571        tmp = timeout_list.next;
     572        while (tmp != &timeout_list) {
     573                cur = list_get_instance(tmp, amsg_t, link);
     574                if (tv_gt(&cur->expires, &msg->expires))
     575                        break;
     576                tmp = tmp->next;
     577        }
     578        list_append(&msg->link, tmp);
     579}
     580
     581/** Wait for a message sent by async framework with timeout
     582 *
     583 * @param amsgid Message ID to wait for
     584 * @param retval Pointer to variable where will be stored retval
     585 *               of the answered message. If NULL, it is ignored.
     586 * @param timeout Timeout in usecs
     587 * @return 0 on success, ETIMEOUT if timeout expired
     588 *
     589 */
     590int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
     591{
     592        amsg_t *msg = (amsg_t *) amsgid;
     593        connection_t *conn;
     594
     595        futex_down(&async_futex);
     596        if (msg->done) {
     597                futex_up(&async_futex);
     598                goto done;
     599        }
     600
     601        msg->ptid = psthread_get_id();
     602        msg->active = 0;
     603        msg->has_timeout = 1;
     604
     605        gettimeofday(&msg->expires, NULL);
     606        tv_add(&msg->expires, timeout);
     607        insert_timeout(msg);
     608
     609        /* Leave locked async_futex when entering this function */
     610        psthread_schedule_next_adv(PS_TO_MANAGER);
     611        /* futex is up automatically after psthread_schedule_next...*/
     612
     613        if (!msg->done)
     614                return ETIMEOUT;
     615
     616done:
     617        if (retval)
     618                *retval = msg->retval;
     619        free(msg);
     620
     621        return 0;
     622}
     623
Note: See TracChangeset for help on using the changeset viewer.