Subversion Repositories HelenOS

Rev

Rev 4420 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4420 Rev 4537
Line 93... Line 93...
93
 
93
 
94
#include <futex.h>
94
#include <futex.h>
95
#include <async.h>
95
#include <async.h>
96
#include <fibril.h>
96
#include <fibril.h>
97
#include <stdio.h>
97
#include <stdio.h>
98
#include <libadt/hash_table.h>
98
#include <adt/hash_table.h>
99
#include <libadt/list.h>
99
#include <adt/list.h>
100
#include <ipc/ipc.h>
100
#include <ipc/ipc.h>
101
#include <assert.h>
101
#include <assert.h>
102
#include <errno.h>
102
#include <errno.h>
103
#include <sys/time.h>
103
#include <sys/time.h>
104
#include <arch/barrier.h>
104
#include <arch/barrier.h>
Line 172... Line 172...
172
    /** Fibril function that will be used to handle the connection. */
172
    /** Fibril function that will be used to handle the connection. */
173
    void (*cfibril)(ipc_callid_t, ipc_call_t *);
173
    void (*cfibril)(ipc_callid_t, ipc_call_t *);
174
} connection_t;
174
} connection_t;
175
 
175
 
176
/** Identifier of the incoming connection handled by the current fibril. */
176
/** Identifier of the incoming connection handled by the current fibril. */
177
__thread connection_t *FIBRIL_connection;
177
fibril_local connection_t *FIBRIL_connection;
178
 
178
 
179
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
179
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
180
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
180
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
-
 
181
static void default_pending(void);
181
 
182
 
182
/**
183
/**
183
 * Pointer to a fibril function that will be used to handle connections.
184
 * Pointer to a fibril function that will be used to handle connections.
184
 */
185
 */
185
static async_client_conn_t client_connection = default_client_connection;
186
static async_client_conn_t client_connection = default_client_connection;
Line 188... Line 189...
188
 * Pointer to a fibril function that will be used to handle interrupt
189
 * Pointer to a fibril function that will be used to handle interrupt
189
 * notifications.
190
 * notifications.
190
 */
191
 */
191
static async_client_conn_t interrupt_received = default_interrupt_received;
192
static async_client_conn_t interrupt_received = default_interrupt_received;
192
 
193
 
-
 
194
/**
-
 
195
 * Pointer to a fibril function that will be used to handle pending
-
 
196
 * operations.
-
 
197
 */
-
 
198
static async_pending_t pending = default_pending;
193
 
199
 
194
static hash_table_t conn_hash_table;
200
static hash_table_t conn_hash_table;
195
static LIST_INITIALIZE(timeout_list);
201
static LIST_INITIALIZE(timeout_list);
196
 
202
 
197
 
-
 
198
#define CONN_HASH_TABLE_CHAINS  32
203
#define CONN_HASH_TABLE_CHAINS  32
199
 
204
 
200
/** Compute hash into the connection hash table based on the source phone hash.
205
/** Compute hash into the connection hash table based on the source phone hash.
201
 *
206
 *
202
 * @param key Pointer to source phone hash.
207
 * @param key Pointer to source phone hash.
Line 374... Line 379...
374
   
379
   
375
    futex_up(&async_futex);
380
    futex_up(&async_futex);
376
    return true;
381
    return true;
377
}
382
}
378
 
383
 
-
 
384
/** Pending fibril.
-
 
385
 *
-
 
386
 * After each call the pending operations are executed in a separate
-
 
387
 * fibril. The function pending() is c.
-
 
388
 *
-
 
389
 * @param arg Unused.
-
 
390
 *
-
 
391
 * @return Always zero.
-
 
392
 *
-
 
393
 */
-
 
394
static int pending_fibril(void *arg)
-
 
395
{
-
 
396
    pending();
-
 
397
   
-
 
398
    return 0;
-
 
399
}
-
 
400
 
-
 
401
/** Process pending actions.
-
 
402
 *
-
 
403
 * A new fibril is created which would process the pending operations.
-
 
404
 *
-
 
405
 * @return False if an error occured.
-
 
406
 *         True if the execution was passed to the pending fibril.
-
 
407
 *
-
 
408
 */
-
 
409
static bool process_pending(void)
-
 
410
{
-
 
411
    futex_down(&async_futex);
-
 
412
   
-
 
413
    fid_t fid = fibril_create(pending_fibril, NULL);
-
 
414
    fibril_add_ready(fid);
-
 
415
   
-
 
416
    futex_up(&async_futex);
-
 
417
    return true;
-
 
418
}
-
 
419
 
379
/** Return new incoming message for the current (fibril-local) connection.
420
/** Return new incoming message for the current (fibril-local) connection.
380
 *
421
 *
381
 * @param call  Storage where the incoming call data will be stored.
422
 * @param call  Storage where the incoming call data will be stored.
382
 * @param usecs Timeout in microseconds. Zero denotes no timeout.
423
 * @param usecs Timeout in microseconds. Zero denotes no timeout.
383
 *
424
 *
Line 470... Line 511...
470
 */
511
 */
471
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
512
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
472
{
513
{
473
}
514
}
474
 
515
 
-
 
516
/** Default fibril function that gets called to handle pending operations.
-
 
517
 *
-
 
518
 * This function is defined as a weak symbol - to be redefined in user code.
-
 
519
 *
-
 
520
 */
-
 
521
static void default_pending(void)
-
 
522
{
-
 
523
}
-
 
524
 
475
/** Wrapper for client connection fibril.
525
/** Wrapper for client connection fibril.
476
 *
526
 *
477
 * When a new connection arrives, a fibril with this implementing function is
527
 * When a new connection arrives, a fibril with this implementing function is
478
 * created. It calls client_connection() and does the final cleanup.
528
 * created. It calls client_connection() and does the final cleanup.
479
 *
529
 *
Line 498... Line 548...
498
    hash_table_remove(&conn_hash_table, &key, 1);
548
    hash_table_remove(&conn_hash_table, &key, 1);
499
    futex_up(&async_futex);
549
    futex_up(&async_futex);
500
   
550
   
501
    /* Answer all remaining messages with EHANGUP */
551
    /* Answer all remaining messages with EHANGUP */
502
    while (!list_empty(&FIBRIL_connection->msg_queue)) {
552
    while (!list_empty(&FIBRIL_connection->msg_queue)) {
503
        msg_t *msg
553
        msg_t *msg;
504
            = list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link);
-
 
505
       
554
       
-
 
555
        msg = list_get_instance(FIBRIL_connection->msg_queue.next,
-
 
556
            msg_t, link);
506
        list_remove(&msg->link);
557
        list_remove(&msg->link);
507
        ipc_answer_0(msg->callid, EHANGUP);
558
        ipc_answer_0(msg->callid, EHANGUP);
508
        free(msg);
559
        free(msg);
509
    }
560
    }
510
   
561
   
Line 561... Line 612...
561
            ipc_answer_0(callid, ENOMEM);
612
            ipc_answer_0(callid, ENOMEM);
562
        return NULL;
613
        return NULL;
563
    }
614
    }
564
   
615
   
565
    /* Add connection to the connection hash table */
616
    /* Add connection to the connection hash table */
566
    ipcarg_t key = conn->in_phone_hash;
617
    unsigned long key = conn->in_phone_hash;
567
   
618
   
568
    futex_down(&async_futex);
619
    futex_down(&async_futex);
569
    hash_table_insert(&conn_hash_table, &key, &conn->link);
620
    hash_table_insert(&conn_hash_table, &key, &conn->link);
570
    futex_up(&async_futex);
621
    futex_up(&async_futex);
571
   
622
   
Line 586... Line 637...
586
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
637
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
587
{
638
{
588
    /* Unrouted call - do some default behaviour */
639
    /* Unrouted call - do some default behaviour */
589
    if ((callid & IPC_CALLID_NOTIFICATION)) {
640
    if ((callid & IPC_CALLID_NOTIFICATION)) {
590
        process_notification(callid, call);
641
        process_notification(callid, call);
591
        return;
642
        goto out;
592
    }
643
    }
593
   
644
   
594
    switch (IPC_GET_METHOD(*call)) {
645
    switch (IPC_GET_METHOD(*call)) {
595
    case IPC_M_CONNECT_ME:
646
    case IPC_M_CONNECT_ME:
596
    case IPC_M_CONNECT_ME_TO:
647
    case IPC_M_CONNECT_ME_TO:
597
        /* Open new connection with fibril etc. */
648
        /* Open new connection with fibril etc. */
598
        async_new_connection(IPC_GET_ARG5(*call), callid, call,
649
        async_new_connection(IPC_GET_ARG5(*call), callid, call,
599
            client_connection);
650
            client_connection);
600
        return;
651
        goto out;
601
    }
652
    }
602
   
653
   
603
    /* Try to route the call through the connection hash table */
654
    /* Try to route the call through the connection hash table */
604
    if (route_call(callid, call))
655
    if (route_call(callid, call))
605
        return;
656
        goto out;
606
   
657
   
607
    /* Unknown call from unknown phone - hang it up */
658
    /* Unknown call from unknown phone - hang it up */
608
    ipc_answer_0(callid, EHANGUP);
659
    ipc_answer_0(callid, EHANGUP);
-
 
660
    return;
-
 
661
   
-
 
662
out:
-
 
663
    process_pending();
609
}
664
}
610
 
665
 
611
/** Fire all timeouts that expired. */
666
/** Fire all timeouts that expired. */
612
static void handle_expired_timeouts(void)
667
static void handle_expired_timeouts(void)
613
{
668
{
Line 661... Line 716...
661
       
716
       
662
        futex_down(&async_futex);
717
        futex_down(&async_futex);
663
       
718
       
664
        suseconds_t timeout;
719
        suseconds_t timeout;
665
        if (!list_empty(&timeout_list)) {
720
        if (!list_empty(&timeout_list)) {
666
            awaiter_t *waiter
721
            awaiter_t *waiter = list_get_instance(timeout_list.next,
667
                = list_get_instance(timeout_list.next, awaiter_t, link);
722
                awaiter_t, link);
668
           
723
           
669
            struct timeval tv;
724
            struct timeval tv;
670
            gettimeofday(&tv, NULL);
725
            gettimeofday(&tv, NULL);
671
           
726
           
672
            if (tv_gteq(&tv, &waiter->expires)) {
727
            if (tv_gteq(&tv, &waiter->expires)) {
Line 679... Line 734...
679
            timeout = SYNCH_NO_TIMEOUT;
734
            timeout = SYNCH_NO_TIMEOUT;
680
       
735
       
681
        futex_up(&async_futex);
736
        futex_up(&async_futex);
682
       
737
       
683
        ipc_call_t call;
738
        ipc_call_t call;
684
        ipc_callid_t callid
739
        ipc_callid_t callid = ipc_wait_cycle(&call, timeout,
685
            = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
740
            SYNCH_FLAGS_NONE);
686
       
741
       
687
        if (!callid) {
742
        if (!callid) {
688
            handle_expired_timeouts();
743
            handle_expired_timeouts();
689
            continue;
744
            continue;
690
        }
745
        }
Line 757... Line 812...
757
 * @param retval Value returned in the answer.
812
 * @param retval Value returned in the answer.
758
 * @param data   Call data of the answer.
813
 * @param data   Call data of the answer.
759
 */
814
 */
760
static void reply_received(void *arg, int retval, ipc_call_t *data)
815
static void reply_received(void *arg, int retval, ipc_call_t *data)
761
{
816
{
-
 
817
    futex_down(&async_futex);
-
 
818
   
762
    amsg_t *msg = (amsg_t *) arg;
819
    amsg_t *msg = (amsg_t *) arg;
763
    msg->retval = retval;
820
    msg->retval = retval;
764
   
821
   
765
    futex_down(&async_futex);
-
 
766
   
-
 
767
    /* Copy data after futex_down, just in case the call was detached */
822
    /* Copy data after futex_down, just in case the call was detached */
768
    if (msg->dataptr)
823
    if ((msg->dataptr) && (data))
769
        *msg->dataptr = *data;
824
        *msg->dataptr = *data;
770
   
825
   
771
    write_barrier();
826
    write_barrier();
772
   
827
   
773
    /* Remove message from timeout list */
828
    /* Remove message from timeout list */
Line 992... Line 1047...
992
void async_set_interrupt_received(async_client_conn_t intr)
1047
void async_set_interrupt_received(async_client_conn_t intr)
993
{
1048
{
994
    interrupt_received = intr;
1049
    interrupt_received = intr;
995
}
1050
}
996
 
1051
 
-
 
1052
/** Setter for pending function pointer.
-
 
1053
 *
-
 
1054
 * @param pend Function that will implement a new pending
-
 
1055
 *             operations fibril.
-
 
1056
 */
-
 
1057
void async_set_pending(async_pending_t pend)
-
 
1058
{
-
 
1059
    pending = pend;
-
 
1060
}
-
 
1061
 
997
/** Pseudo-synchronous message sending - fast version.
1062
/** Pseudo-synchronous message sending - fast version.
998
 *
1063
 *
999
 * Send message asynchronously and return only after the reply arrives.
1064
 * Send message asynchronously and return only after the reply arrives.
1000
 *
1065
 *
1001
 * This function can only transfer 4 register payload arguments. For
1066
 * This function can only transfer 4 register payload arguments. For