Subversion Repositories HelenOS

Rev

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

Rev 2484 Rev 2485
Line 254... Line 254...
254
        tmp = tmp->next;
254
        tmp = tmp->next;
255
    }
255
    }
256
    list_append(&wd->link, tmp);
256
    list_append(&wd->link, tmp);
257
}
257
}
258
 
258
 
259
/*************************************************/
-
 
260
 
-
 
261
/** Try to route a call to an appropriate connection thread
259
/** Try to route a call to an appropriate connection fibril
262
 *
260
 *
263
 */
261
 */
264
static int route_call(ipc_callid_t callid, ipc_call_t *call)
262
static int route_call(ipc_callid_t callid, ipc_call_t *call)
265
{
263
{
266
    connection_t *conn;
264
    connection_t *conn;
Line 300... Line 298...
300
    futex_up(&async_futex);
298
    futex_up(&async_futex);
301
 
299
 
302
    return 1;
300
    return 1;
303
}
301
}
304
 
302
 
305
/** Return new incoming message for current(thread-local) connection */
303
/** Return new incoming message for the current (fibril-local) connection */
306
ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
304
ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
307
{
305
{
308
    msg_t *msg;
306
    msg_t *msg;
309
    ipc_callid_t callid;
307
    ipc_callid_t callid;
310
    connection_t *conn;
308
    connection_t *conn;
Line 351... Line 349...
351
   
349
   
352
    futex_up(&async_futex);
350
    futex_up(&async_futex);
353
    return callid;
351
    return callid;
354
}
352
}
355
 
353
 
356
/** Thread function that gets created on new connection
354
/** Fibril function that gets created on new connection
357
 *
355
 *
358
 * This function is defined as a weak symbol - to be redefined in
356
 * This function is defined as a weak symbol - to be redefined in
359
 * user code.
357
 * user code.
360
 */
358
 */
361
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
359
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
Line 364... Line 362...
364
}
362
}
365
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
363
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
366
{
364
{
367
}
365
}
368
 
366
 
369
/** Wrapper for client connection thread
367
/** Wrapper for client connection fibril.
-
 
368
 *
-
 
369
 * When new connection arrives, a fibril with this implementing function is
-
 
370
 * created. It calls client_connection() and does the final cleanup.
370
 *
371
 *
371
 * When new connection arrives, thread with this function is created.
-
 
372
 * It calls client_connection and does final cleanup.
372
 * @param arg       Connection structure pointer
373
 *
373
 *
374
 * @param arg Connection structure pointer
374
 * @return      Always zero.
375
 */
375
 */
376
static int connection_fibril(void  *arg)
376
static int connection_fibril(void  *arg)
377
{
377
{
378
    unsigned long key;
378
    unsigned long key;
379
    msg_t *msg;
379
    msg_t *msg;
380
    int close_answered = 0;
380
    int close_answered = 0;
381
 
381
 
382
    /* Setup thread local connection pointer */
382
    /* Setup fibril-local connection pointer */
383
    FIBRIL_connection = (connection_t *) arg;
383
    FIBRIL_connection = (connection_t *) arg;
384
    FIBRIL_connection->cfibril(FIBRIL_connection->callid,
384
    FIBRIL_connection->cfibril(FIBRIL_connection->callid,
385
        &FIBRIL_connection->call);
385
        &FIBRIL_connection->call);
386
   
386
   
387
    /* Remove myself from connection hash table */
387
    /* Remove myself from connection hash table */
Line 404... Line 404...
404
        ipc_answer_fast(FIBRIL_connection->close_callid, 0, 0, 0);
404
        ipc_answer_fast(FIBRIL_connection->close_callid, 0, 0, 0);
405
   
405
   
406
    return 0;
406
    return 0;
407
}
407
}
408
 
408
 
409
/** Create new thread for a new connection
409
/** Create a new fibril for a new connection.
410
 *
410
 *
411
 * Creates new thread for connection, fills in connection
411
 * Creates new fibril for connection, fills in connection structures and inserts
412
 * structures and inserts it into the hash table, so that
-
 
413
 * later we can easily do routing of messages to particular
412
 * it into the hash table, so that later we can easily do routing of messages to
414
 * threads.
413
 * particular fibrils.
415
 *
414
 *
416
 * @param in_phone_hash Identification of the incoming connection
415
 * @param in_phone_hash Identification of the incoming connection
417
 * @param callid Callid of the IPC_M_CONNECT_ME_TO packet
416
 * @param callid    Callid of the IPC_M_CONNECT_ME_TO packet
418
 * @param call Call data of the opening packet
417
 * @param call      Call data of the opening packet
419
 * @param cfibril Fibril function that should be called upon
418
 * @param cfibril   Fibril function that should be called upon
420
 *                opening the connection
419
 *                  opening the connection
421
 * @return New fibril id.
420
 * @return      New fibril id.
422
 */
421
 */
423
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
422
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
424
    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
423
    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
425
{
424
{
426
    connection_t *conn;
425
    connection_t *conn;
Line 455... Line 454...
455
    fibril_add_ready(conn->wdata.fid);
454
    fibril_add_ready(conn->wdata.fid);
456
 
455
 
457
    return conn->wdata.fid;
456
    return conn->wdata.fid;
458
}
457
}
459
 
458
 
460
/** Handle call that was received */
459
/** Handle a call that was received. */
461
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
460
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
462
{
461
{
463
    /* Unrouted call - do some default behaviour */
462
    /* Unrouted call - do some default behaviour */
464
    if ((callid & IPC_CALLID_NOTIFICATION)) {
463
    if ((callid & IPC_CALLID_NOTIFICATION)) {
465
        in_interrupt_handler = 1;
464
        in_interrupt_handler = 1;
Line 468... Line 467...
468
        return;
467
        return;
469
    }      
468
    }      
470
 
469
 
471
    switch (IPC_GET_METHOD(*call)) {
470
    switch (IPC_GET_METHOD(*call)) {
472
    case IPC_M_CONNECT_ME_TO:
471
    case IPC_M_CONNECT_ME_TO:
473
        /* Open new connection with thread etc. */
472
        /* Open new connection with fibril etc. */
474
        async_new_connection(IPC_GET_ARG3(*call), callid, call,
473
        async_new_connection(IPC_GET_ARG3(*call), callid, call,
475
            client_connection);
474
            client_connection);
476
        return;
475
        return;
477
    }
476
    }
478
 
477
 
Line 482... Line 481...
482
 
481
 
483
    /* Unknown call from unknown phone - hang it up */
482
    /* Unknown call from unknown phone - hang it up */
484
    ipc_answer_fast(callid, EHANGUP, 0, 0);
483
    ipc_answer_fast(callid, EHANGUP, 0, 0);
485
}
484
}
486
 
485
 
487
/** Fire all timeouts that expired
486
/** Fire all timeouts that expired. */
488
 *
-
 
489
 */
-
 
490
static void handle_expired_timeouts(void)
487
static void handle_expired_timeouts(void)
491
{
488
{
492
    struct timeval tv;
489
    struct timeval tv;
493
    awaiter_t *waiter;
490
    awaiter_t *waiter;
494
    link_t *cur;
491
    link_t *cur;
Line 503... Line 500...
503
            break;
500
            break;
504
        cur = cur->next;
501
        cur = cur->next;
505
        list_remove(&waiter->link);
502
        list_remove(&waiter->link);
506
        waiter->inlist = 0;
503
        waiter->inlist = 0;
507
        waiter->timedout = 1;
504
        waiter->timedout = 1;
508
        /* Redundant condition? The thread should not
505
        /* Redundant condition? The fibril should not
509
         * be active when it gets here.
506
         * be active when it gets here.
510
         */
507
         */
511
        if (!waiter->active) {
508
        if (!waiter->active) {
512
            waiter->active = 1;
509
            waiter->active = 1;
513
            fibril_add_ready(waiter->fid);
510
            fibril_add_ready(waiter->fid);
Line 528... Line 525...
528
 
525
 
529
    while (1) {
526
    while (1) {
530
        if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) {
527
        if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) {
531
            futex_up(&async_futex);
528
            futex_up(&async_futex);
532
            /* async_futex is always held
529
            /* async_futex is always held
533
             * when entering manager thread
530
             * when entering manager fibril
534
             */
531
             */
535
            continue;
532
            continue;
536
        }
533
        }
537
        futex_down(&async_futex);
534
        futex_down(&async_futex);
538
        if (!list_empty(&timeout_list)) {
535
        if (!list_empty(&timeout_list)) {
Line 564... Line 561...
564
    }
561
    }
565
   
562
   
566
    return 0;
563
    return 0;
567
}
564
}
568
 
565
 
569
/** Function to start async_manager as a standalone thread
566
/** Function to start async_manager as a standalone fibril.
570
 *
567
 *
571
 * When more kernel threads are used, one async manager should
568
 * When more kernel threads are used, one async manager should
572
 * exist per thread. The particular implementation may change,
-
 
573
 * currently one async_manager is started automatically per kernel
-
 
574
 * thread except the main thread.
569
 * exist per thread.
575
 */
570
 */
576
static int async_manager_fibril(void *arg)
571
static int async_manager_fibril(void *arg)
577
{
572
{
578
    futex_up(&async_futex);
573
    futex_up(&async_futex);
579
    /* async_futex is always locked when entering
574
    /* async_futex is always locked when entering
Line 612... Line 607...
612
 
607
 
613
/** IPC handler for messages in async framework
608
/** IPC handler for messages in async framework
614
 *
609
 *
615
 * Notify the fibril which is waiting for this message, that it arrived
610
 * Notify the fibril which is waiting for this message, that it arrived
616
 */
611
 */
617
static void reply_received(void *private, int retval,
612
static void reply_received(void *private, int retval, ipc_call_t *data)
618
               ipc_call_t *data)
-
 
619
{
613
{
620
    amsg_t *msg = (amsg_t *) private;
614
    amsg_t *msg = (amsg_t *) private;
621
 
615
 
622
    msg->retval = retval;
616
    msg->retval = retval;
623
 
617
 
Line 644... Line 638...
644
 *
638
 *
645
 * The return value can be used as input for async_wait() to wait
639
 * The return value can be used as input for async_wait() to wait
646
 * for completion.
640
 * for completion.
647
 */
641
 */
648
aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
642
aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
649
           ipc_call_t *dataptr)
643
    ipc_call_t *dataptr)
650
{
644
{
651
    amsg_t *msg;
645
    amsg_t *msg;
652
 
646
 
653
    if (in_interrupt_handler) {
647
    if (in_interrupt_handler) {
654
        printf("Cannot send asynchronous request in interrupt "
648
        printf("Cannot send asynchronous request in interrupt "
Line 671... Line 665...
671
 *
665
 *
672
 * The return value can be used as input for async_wait() to wait
666
 * The return value can be used as input for async_wait() to wait
673
 * for completion.
667
 * for completion.
674
 */
668
 */
675
aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
669
aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
676
           ipcarg_t arg3, ipc_call_t *dataptr)
670
    ipcarg_t arg3, ipc_call_t *dataptr)
677
{
671
{
678
    amsg_t *msg;
672
    amsg_t *msg;
679
 
673
 
680
    if (in_interrupt_handler) {
674
    if (in_interrupt_handler) {
681
        printf("Cannot send asynchronous request in interrupt handler.\n");
675
        printf("Cannot send asynchronous request in interrupt handler.\n");
Line 694... Line 688...
694
    return (aid_t) msg;
688
    return (aid_t) msg;
695
}
689
}
696
 
690
 
697
/** Wait for a message sent by async framework
691
/** Wait for a message sent by async framework
698
 *
692
 *
699
 * @param amsgid Message ID to wait for
693
 * @param amsgid    Message ID to wait for
700
 * @param retval Pointer to variable where will be stored retval
694
 * @param retval    Pointer to variable where will be stored retval of the
701
 *               of the answered message. If NULL, it is ignored.
695
 *          answered message. If NULL, it is ignored.
702
 *
-
 
703
 */
696
 */
704
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
697
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
705
{
698
{
706
    amsg_t *msg = (amsg_t *) amsgid;
699
    amsg_t *msg = (amsg_t *) amsgid;
707
 
700
 
Line 791... Line 784...
791
    gettimeofday(&msg->wdata.expires, NULL);
784
    gettimeofday(&msg->wdata.expires, NULL);
792
    tv_add(&msg->wdata.expires, timeout);
785
    tv_add(&msg->wdata.expires, timeout);
793
 
786
 
794
    futex_down(&async_futex);
787
    futex_down(&async_futex);
795
    insert_timeout(&msg->wdata);
788
    insert_timeout(&msg->wdata);
796
    /* Leave locked async_futex when entering this function */
789
    /* Leave locked the async_futex when entering this function */
797
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
790
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
798
    /* futex is up automatically after fibril_schedule_next...*/
791
    /* futex is up automatically after fibril_schedule_next_adv()...*/
799
    free(msg);
792
    free(msg);
800
}
793
}
801
 
794
 
802
/** Set function that is called, IPC_M_CONNECT_ME_TO is received
795
/** Set function that is called when IPC_M_CONNECT_ME_TO is received.
803
 *
796
 *
804
 * @param conn Function that will form new psthread.
797
 * @param conn Function that will form a new fibril.
805
 */
798
 */
806
void async_set_client_connection(async_client_conn_t conn)
799
void async_set_client_connection(async_client_conn_t conn)
807
{
800
{
808
    client_connection = conn;
801
    client_connection = conn;
809
}
802
}