Subversion Repositories HelenOS

Rev

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

Rev 2488 Rev 2490
Line 70... Line 70...
70
 * {
70
 * {
71
 *  async_manager();
71
 *  async_manager();
72
 * }
72
 * }
73
 *
73
 *
74
 *
74
 *
75
 * client_connection(icallid, *icall)
75
 * my_client_connection(icallid, *icall)
76
 * {
76
 * {
77
 *  if (want_refuse) {
77
 *  if (want_refuse) {
78
 *      ipc_answer_fast(icallid, ELIMIT, 0, 0);
78
 *      ipc_answer_fast(icallid, ELIMIT, 0, 0);
79
 *      return;
79
 *      return;
80
 *  }
80
 *  }
Line 113... Line 113...
113
    /** If true, this struct is in the timeout list. */
113
    /** If true, this struct is in the timeout list. */
114
    int inlist;
114
    int inlist;
115
    /** Timeout list link. */
115
    /** Timeout list link. */
116
    link_t link;
116
    link_t link;
117
 
117
 
118
    /** Fibril waiting for this message. */
118
    /** Identification of and link to the waiting fibril. */
119
    fid_t fid;
119
    fid_t fid;
120
    /** If true, this fibril is currently active. */
120
    /** If true, this fibril is currently active. */
121
    int active;
121
    int active;
122
    /** If true, we have timed out. */
122
    /** If true, we have timed out. */
123
    int timedout;
123
    int timedout;
Line 132... Line 132...
132
    ipc_call_t *dataptr;
132
    ipc_call_t *dataptr;
133
 
133
 
134
    ipcarg_t retval;
134
    ipcarg_t retval;
135
} amsg_t;
135
} amsg_t;
136
 
136
 
-
 
137
/**
-
 
138
 * Structures of this type are used to group information about a call and a
-
 
139
 * message queue link.
-
 
140
 */
137
typedef struct {
141
typedef struct {
138
    link_t link;
142
    link_t link;
139
    ipc_callid_t callid;
143
    ipc_callid_t callid;
140
    ipc_call_t call;
144
    ipc_call_t call;
141
} msg_t;
145
} msg_t;
Line 165... Line 169...
165
} connection_t;
169
} connection_t;
166
 
170
 
167
/** Identifier of the incoming connection handled by the current fibril. */
171
/** Identifier of the incoming connection handled by the current fibril. */
168
__thread connection_t *FIBRIL_connection;
172
__thread connection_t *FIBRIL_connection;
169
 
173
 
-
 
174
/**
170
/** If true, it is forbidden to use async_req functions and all preemption is
175
 * If true, it is forbidden to use async_req functions and all preemption is
171
 * disabled. */
176
 * disabled.
-
 
177
 */
172
__thread int in_interrupt_handler;
178
__thread int in_interrupt_handler;
173
 
179
 
174
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
180
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
175
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
181
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
-
 
182
 
-
 
183
/**
-
 
184
 * Pointer to a fibril function that will be used to handle connections.
-
 
185
 */
176
static async_client_conn_t client_connection = default_client_connection;
186
static async_client_conn_t client_connection = default_client_connection;
-
 
187
/**
-
 
188
 * Pointer to a fibril function that will be used to handle interrupt
-
 
189
 * notifications.
-
 
190
 */
177
static async_client_conn_t interrupt_received = default_interrupt_received;
191
static async_client_conn_t interrupt_received = default_interrupt_received;
178
 
192
 
179
#define CONN_HASH_TABLE_CHAINS  32
193
#define CONN_HASH_TABLE_CHAINS  32
180
 
194
 
181
/** Compute hash into the connection hash table based on the source phone hash.
195
/** Compute hash into the connection hash table based on the source phone hash.
Line 249... Line 263...
249
    list_append(&wd->link, tmp);
263
    list_append(&wd->link, tmp);
250
}
264
}
251
 
265
 
252
/** Try to route a call to an appropriate connection fibril.
266
/** Try to route a call to an appropriate connection fibril.
253
 *
267
 *
-
 
268
 * If the proper connection fibril is found, a message with the call is added to
-
 
269
 * its message queue. If the fibril was not active, it is activated and all
-
 
270
 * timeouts are unregistered.
-
 
271
 *
-
 
272
 * @param callid    Hash of the incoming call.
-
 
273
 * @param call      Data of the incoming call.
-
 
274
 *
-
 
275
 * @return      Zero if the call doesn't match any connection.
-
 
276
 *          One if the call was passed to the respective connection
-
 
277
 *          fibril.
254
 */
278
 */
255
static int route_call(ipc_callid_t callid, ipc_call_t *call)
279
static int route_call(ipc_callid_t callid, ipc_call_t *call)
256
{
280
{
257
    connection_t *conn;
281
    connection_t *conn;
258
    msg_t *msg;
282
    msg_t *msg;
Line 275... Line 299...
275
    list_append(&msg->link, &conn->msg_queue);
299
    list_append(&msg->link, &conn->msg_queue);
276
 
300
 
277
    if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
301
    if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
278
        conn->close_callid = callid;
302
        conn->close_callid = callid;
279
   
303
   
280
    /* If the call is waiting for event, run it */
304
    /* If the connection fibril is waiting for an event, activate it */
281
    if (!conn->wdata.active) {
305
    if (!conn->wdata.active) {
282
        /* If in timeout list, remove it */
306
        /* If in timeout list, remove it */
283
        if (conn->wdata.inlist) {
307
        if (conn->wdata.inlist) {
284
            conn->wdata.inlist = 0;
308
            conn->wdata.inlist = 0;
285
            list_remove(&conn->wdata.link);
309
            list_remove(&conn->wdata.link);
Line 312... Line 336...
312
   
336
   
313
    assert(FIBRIL_connection);
337
    assert(FIBRIL_connection);
314
    /* GCC 4.1.0 coughs on FIBRIL_connection-> dereference,
338
    /* GCC 4.1.0 coughs on FIBRIL_connection-> dereference,
315
     * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
339
     * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
316
     *           I would never expect to find so many errors in
340
     *           I would never expect to find so many errors in
317
     *           compiler *($&$(*&$
341
     *           a compiler *($&$(*&$
318
     */
342
     */
319
    conn = FIBRIL_connection;
343
    conn = FIBRIL_connection;
320
 
344
 
321
    futex_down(&async_futex);
345
    futex_down(&async_futex);
322
 
346
 
Line 354... Line 378...
354
   
378
   
355
    futex_up(&async_futex);
379
    futex_up(&async_futex);
356
    return callid;
380
    return callid;
357
}
381
}
358
 
382
 
359
/** Fibril function that gets created on new connection
383
/** Default fibril function that gets called to handle new connection.
360
 *
384
 *
361
 * This function is defined as a weak symbol - to be redefined in user code.
385
 * This function is defined as a weak symbol - to be redefined in user code.
-
 
386
 *
-
 
387
 * @param callid    Hash of the incoming call.
-
 
388
 * @param call      Data of the incoming call.
362
 */
389
 */
363
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
390
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
364
{
391
{
365
    ipc_answer_fast(callid, ENOENT, 0, 0);
392
    ipc_answer_fast(callid, ENOENT, 0, 0);
366
}
393
}
-
 
394
 
-
 
395
/** Default fibril function that gets called to handle interrupt notifications.
-
 
396
 *
-
 
397
 * @param callid    Hash of the incoming call.
-
 
398
 * @param call      Data of the incoming call.
-
 
399
 */
367
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
400
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
368
{
401
{
369
}
402
}
370
 
403
 
371
/** Wrapper for client connection fibril.
404
/** Wrapper for client connection fibril.
372
 *
405
 *
373
 * When new connection arrives, a fibril with this implementing function is
406
 * When a new connection arrives, a fibril with this implementing function is
374
 * created. It calls client_connection() and does the final cleanup.
407
 * created. It calls client_connection() and does the final cleanup.
375
 *
408
 *
376
 * @param arg       Connection structure pointer
409
 * @param arg       Connection structure pointer.
377
 *
410
 *
378
 * @return      Always zero.
411
 * @return      Always zero.
379
 */
412
 */
380
static int connection_fibril(void  *arg)
413
static int connection_fibril(void  *arg)
381
{
414
{
Line 386... Line 419...
386
    /* Setup fibril-local connection pointer */
419
    /* Setup fibril-local connection pointer */
387
    FIBRIL_connection = (connection_t *) arg;
420
    FIBRIL_connection = (connection_t *) arg;
388
    FIBRIL_connection->cfibril(FIBRIL_connection->callid,
421
    FIBRIL_connection->cfibril(FIBRIL_connection->callid,
389
        &FIBRIL_connection->call);
422
        &FIBRIL_connection->call);
390
   
423
   
391
    /* Remove myself from connection hash table */
424
    /* Remove myself from the connection hash table */
392
    futex_down(&async_futex);
425
    futex_down(&async_futex);
393
    key = FIBRIL_connection->in_phone_hash;
426
    key = FIBRIL_connection->in_phone_hash;
394
    hash_table_remove(&conn_hash_table, &key, 1);
427
    hash_table_remove(&conn_hash_table, &key, 1);
395
    futex_up(&async_futex);
428
    futex_up(&async_futex);
396
   
429
   
397
    /* Answer all remaining messages with ehangup */
430
    /* Answer all remaining messages with EHANGUP */
398
    while (!list_empty(&FIBRIL_connection->msg_queue)) {
431
    while (!list_empty(&FIBRIL_connection->msg_queue)) {
399
        msg = list_get_instance(FIBRIL_connection->msg_queue.next,
432
        msg = list_get_instance(FIBRIL_connection->msg_queue.next,
400
            msg_t, link);
433
            msg_t, link);
401
        list_remove(&msg->link);
434
        list_remove(&msg->link);
402
        if (msg->callid == FIBRIL_connection->close_callid)
435
        if (msg->callid == FIBRIL_connection->close_callid)
Line 414... Line 447...
414
 *
447
 *
415
 * Creates new fibril for connection, fills in connection structures and inserts
448
 * Creates new fibril for connection, fills in connection structures and inserts
416
 * it into the hash table, so that later we can easily do routing of messages to
449
 * it into the hash table, so that later we can easily do routing of messages to
417
 * particular fibrils.
450
 * particular fibrils.
418
 *
451
 *
419
 * @param in_phone_hash Identification of the incoming connection
452
 * @param in_phone_hash Identification of the incoming connection.
420
 * @param callid    Callid of the IPC_M_CONNECT_ME_TO packet
453
 * @param callid    Hash of the opening IPC_M_CONNECT_ME_TO call.
421
 * @param call      Call data of the opening packet
454
 * @param call      Call data of the opening call.
422
 * @param cfibril   Fibril function that should be called upon
455
 * @param cfibril   Fibril function that should be called upon opening the
423
 *                  opening the connection
456
 *          connection.
-
 
457
 *
424
 * @return      New fibril id.
458
 * @return      New fibril id or NULL on failure.
425
 */
459
 */
426
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
460
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
427
    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
461
    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
428
{
462
{
429
    connection_t *conn;
463
    connection_t *conn;
Line 438... Line 472...
438
    list_initialize(&conn->msg_queue);
472
    list_initialize(&conn->msg_queue);
439
    conn->callid = callid;
473
    conn->callid = callid;
440
    conn->close_callid = 0;
474
    conn->close_callid = 0;
441
    if (call)
475
    if (call)
442
        conn->call = *call;
476
        conn->call = *call;
443
    conn->wdata.active = 1; /* We will activate it asap */
477
    conn->wdata.active = 1; /* We will activate the fibril ASAP */
444
    conn->cfibril = cfibril;
478
    conn->cfibril = cfibril;
445
 
479
 
446
    conn->wdata.fid = fibril_create(connection_fibril, conn);
480
    conn->wdata.fid = fibril_create(connection_fibril, conn);
447
    if (!conn->wdata.fid) {
481
    if (!conn->wdata.fid) {
448
        free(conn);
482
        free(conn);
449
        ipc_answer_fast(callid, ENOMEM, 0, 0);
483
        ipc_answer_fast(callid, ENOMEM, 0, 0);
450
        return NULL;
484
        return NULL;
451
    }
485
    }
452
    /* Add connection to hash table */
486
    /* Add connection to the connection hash table */
453
    key = conn->in_phone_hash;
487
    key = conn->in_phone_hash;
454
    futex_down(&async_futex);
488
    futex_down(&async_futex);
455
    hash_table_insert(&conn_hash_table, &key, &conn->link);
489
    hash_table_insert(&conn_hash_table, &key, &conn->link);
456
    futex_up(&async_futex);
490
    futex_up(&async_futex);
457
 
491
 
458
    fibril_add_ready(conn->wdata.fid);
492
    fibril_add_ready(conn->wdata.fid);
459
 
493
 
460
    return conn->wdata.fid;
494
    return conn->wdata.fid;
461
}
495
}
462
 
496
 
463
/** Handle a call that was received. */
497
/** Handle a call that was received.
-
 
498
 *
-
 
499
 * If the call has the IPC_M_CONNECT_ME_TO method, a new connection is created.
-
 
500
 * Otherwise the call is routed to its connection fibril.
-
 
501
 *
-
 
502
 * @param callid    Hash of the incoming call.
-
 
503
 * @param call      Data of the incoming call.
-
 
504
 */
464
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
505
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
465
{
506
{
466
    /* Unrouted call - do some default behaviour */
507
    /* Unrouted call - do some default behaviour */
467
    if ((callid & IPC_CALLID_NOTIFICATION)) {
508
    if ((callid & IPC_CALLID_NOTIFICATION)) {
468
        in_interrupt_handler = 1;
509
        in_interrupt_handler = 1;
Line 477... Line 518...
477
        async_new_connection(IPC_GET_ARG3(*call), callid, call,
518
        async_new_connection(IPC_GET_ARG3(*call), callid, call,
478
            client_connection);
519
            client_connection);
479
        return;
520
        return;
480
    }
521
    }
481
 
522
 
482
    /* Try to route call through connection tables */
523
    /* Try to route the call through the connection hash table */
483
    if (route_call(callid, call))
524
    if (route_call(callid, call))
484
        return;
525
        return;
485
 
526
 
486
    /* Unknown call from unknown phone - hang it up */
527
    /* Unknown call from unknown phone - hang it up */
487
    ipc_answer_fast(callid, EHANGUP, 0, 0);
528
    ipc_answer_fast(callid, EHANGUP, 0, 0);
Line 492... Line 533...
492
{
533
{
493
    struct timeval tv;
534
    struct timeval tv;
494
    awaiter_t *waiter;
535
    awaiter_t *waiter;
495
    link_t *cur;
536
    link_t *cur;
496
 
537
 
497
    gettimeofday(&tv,NULL);
538
    gettimeofday(&tv, NULL);
498
    futex_down(&async_futex);
539
    futex_down(&async_futex);
499
 
540
 
500
    cur = timeout_list.next;
541
    cur = timeout_list.next;
501
    while (cur != &timeout_list) {
542
    while (cur != &timeout_list) {
502
        waiter = list_get_instance(cur, awaiter_t, link);
543
        waiter = list_get_instance(cur, awaiter_t, link);
Line 504... Line 545...
504
            break;
545
            break;
505
        cur = cur->next;
546
        cur = cur->next;
506
        list_remove(&waiter->link);
547
        list_remove(&waiter->link);
507
        waiter->inlist = 0;
548
        waiter->inlist = 0;
508
        waiter->timedout = 1;
549
        waiter->timedout = 1;
-
 
550
        /*
509
        /* Redundant condition? The fibril should not
551
         * Redundant condition?
510
         * be active when it gets here.
552
         * The fibril should not be active when it gets here.
511
         */
553
         */
512
        if (!waiter->active) {
554
        if (!waiter->active) {
513
            waiter->active = 1;
555
            waiter->active = 1;
514
            fibril_add_ready(waiter->fid);
556
            fibril_add_ready(waiter->fid);
515
        }
557
        }
516
    }
558
    }
517
 
559
 
518
    futex_up(&async_futex);
560
    futex_up(&async_futex);
519
}
561
}
520
 
562
 
521
/** Endless loop dispatching incoming calls and answers */
563
/** Endless loop dispatching incoming calls and answers.
-
 
564
 *
-
 
565
 * @return      Never returns.
-
 
566
 */
522
static int async_manager_worker(void)
567
static int async_manager_worker(void)
523
{
568
{
524
    ipc_call_t call;
569
    ipc_call_t call;
525
    ipc_callid_t callid;
570
    ipc_callid_t callid;
526
    int timeout;
571
    int timeout;
Line 528... Line 573...
528
    struct timeval tv;
573
    struct timeval tv;
529
 
574
 
530
    while (1) {
575
    while (1) {
531
        if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) {
576
        if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) {
532
            futex_up(&async_futex);
577
            futex_up(&async_futex);
-
 
578
            /*
533
            /* async_futex is always held
579
             * async_futex is always held when entering a manager
534
             * when entering manager fibril
580
             * fibril.
535
             */
581
             */
536
            continue;
582
            continue;
537
        }
583
        }
538
        futex_down(&async_futex);
584
        futex_down(&async_futex);
539
        if (!list_empty(&timeout_list)) {
585
        if (!list_empty(&timeout_list)) {
Line 565... Line 611...
565
    }
611
    }
566
   
612
   
567
    return 0;
613
    return 0;
568
}
614
}
569
 
615
 
570
/** Function to start async_manager as a standalone fibril.
616
/** Function to start async_manager as a standalone fibril.
571
 *
617
 *
572
 * When more kernel threads are used, one async manager should
618
 * When more kernel threads are used, one async manager should exist per thread.
-
 
619
 *
-
 
620
 * @param arg       Unused.
-
 
621
 *
573
 * exist per thread.
622
 * @return      Never returns.
574
 */
623
 */
575
static int async_manager_fibril(void *arg)
624
static int async_manager_fibril(void *arg)
576
{
625
{
577
    futex_up(&async_futex);
626
    futex_up(&async_futex);
-
 
627
    /*
578
    /* async_futex is always locked when entering
628
     * async_futex is always locked when entering manager
579
     * manager */
629
     */
580
    async_manager_worker();
630
    async_manager_worker();
581
   
631
   
582
    return 0;
632
    return 0;
583
}
633
}
584
 
634
 
585
/** Add one manager to manager list */
635
/** Add one manager to manager list. */
586
void async_create_manager(void)
636
void async_create_manager(void)
587
{
637
{
588
    fid_t fid;
638
    fid_t fid;
589
 
639
 
590
    fid = fibril_create(async_manager_fibril, NULL);
640
    fid = fibril_create(async_manager_fibril, NULL);
Line 595... Line 645...
595
void async_destroy_manager(void)
645
void async_destroy_manager(void)
596
{
646
{
597
    fibril_remove_manager();
647
    fibril_remove_manager();
598
}
648
}
599
 
649
 
600
/** Initialize internal structures needed for async manager */
650
/** Initialize the async framework.
-
 
651
 *
-
 
652
 * @return      Zero on success or an error code.
-
 
653
 */
601
int _async_init(void)
654
int _async_init(void)
602
{
655
{
603
    if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
656
    if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
604
        &conn_hash_table_ops)) {
657
        &conn_hash_table_ops)) {
605
        printf("%s: cannot create hash table\n", "async");
658
        printf("%s: cannot create hash table\n", "async");
Line 607... Line 660...
607
    }
660
    }
608
   
661
   
609
    return 0;
662
    return 0;
610
}
663
}
611
 
664
 
-
 
665
/** Reply received callback.
-
 
666
 *
-
 
667
 * This function is called whenever a reply for an asynchronous message sent out
612
/** IPC handler for messages in async framework
668
 * by the asynchronous framework is received.
-
 
669
 *
-
 
670
 * Notify the fibril which is waiting for this message that it has arrived.
613
 *
671
 *
614
 * Notify the fibril which is waiting for this message, that it arrived
672
 * @param private   Pointer to the asynchronous message record.
-
 
673
 * @param retval    Value returned in the answer.
-
 
674
 * @param data      Call data of the answer.
615
 */
675
 */
616
static void reply_received(void *private, int retval, ipc_call_t *data)
676
static void reply_received(void *private, int retval, ipc_call_t *data)
617
{
677
{
618
    amsg_t *msg = (amsg_t *) private;
678
    amsg_t *msg = (amsg_t *) private;
619
 
679
 
620
    msg->retval = retval;
680
    msg->retval = retval;
621
 
681
 
622
    futex_down(&async_futex);
682
    futex_down(&async_futex);
623
    /* Copy data after futex_down, just in case the
683
    /* Copy data after futex_down, just in case the call was detached */
624
     * call was detached
-
 
625
     */
-
 
626
    if (msg->dataptr)
684
    if (msg->dataptr)
627
        *msg->dataptr = *data;
685
        *msg->dataptr = *data;
628
 
686
 
629
    write_barrier();
687
    write_barrier();
630
    /* Remove message from timeout list */
688
    /* Remove message from timeout list */
631
    if (msg->wdata.inlist)
689
    if (msg->wdata.inlist)
632
        list_remove(&msg->wdata.link);
690
        list_remove(&msg->wdata.link);
633
    msg->done = 1;
691
    msg->done = 1;
634
    if (! msg->wdata.active) {
692
    if (!msg->wdata.active) {
635
        msg->wdata.active = 1;
693
        msg->wdata.active = 1;
636
        fibril_add_ready(msg->wdata.fid);
694
        fibril_add_ready(msg->wdata.fid);
637
    }
695
    }
638
    futex_up(&async_futex);
696
    futex_up(&async_futex);
639
}
697
}
640
 
698
 
641
/** Send message and return id of the sent message
699
/** Send message and return id of the sent message.
-
 
700
 *
-
 
701
 * The return value can be used as input for async_wait() to wait for
-
 
702
 * completion.
-
 
703
 *
-
 
704
 * @param phoneid   Handle of the phone that will be used for the send.
-
 
705
 * @param method    Service-defined method.
-
 
706
 * @param arg1      Service-defined payload argument.
-
 
707
 * @param arg2      Service-defined payload argument.
-
 
708
 * @param dataptr   If non-NULL, storage where the reply data will be
-
 
709
 *          stored.
642
 *
710
 *
643
 * The return value can be used as input for async_wait() to wait
711
 * @return      Hash of the sent message.
644
 * for completion.
-
 
645
 */
712
 */
646
aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
713
aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
647
    ipc_call_t *dataptr)
714
    ipc_call_t *dataptr)
648
{
715
{
649
    amsg_t *msg;
716
    amsg_t *msg;
Line 656... Line 723...
656
 
723
 
657
    msg = malloc(sizeof(*msg));
724
    msg = malloc(sizeof(*msg));
658
    msg->done = 0;
725
    msg->done = 0;
659
    msg->dataptr = dataptr;
726
    msg->dataptr = dataptr;
660
 
727
 
661
    msg->wdata.active = 1; /* We may sleep in next method, but it
728
    /* We may sleep in the next method, but it will use its own mechanism */
662
                * will use it's own mechanism */
729
    msg->wdata.active = 1;
-
 
730
               
663
    ipc_call_async_2(phoneid, method, arg1, arg2, msg, reply_received, 1);
731
    ipc_call_async_2(phoneid, method, arg1, arg2, msg, reply_received, 1);
664
 
732
 
665
    return (aid_t) msg;
733
    return (aid_t) msg;
666
}
734
}
667
 
735
 
668
/** Send message and return id of the sent message
736
/** Send message and return id of the sent message
669
 *
737
 *
670
 * The return value can be used as input for async_wait() to wait
738
 * The return value can be used as input for async_wait() to wait for
671
 * for completion.
739
 * completion.
-
 
740
 *
-
 
741
 * @param phoneid   Handle of the phone that will be used for the send.
-
 
742
 * @param method    Service-defined method.
-
 
743
 * @param arg1      Service-defined payload argument.
-
 
744
 * @param arg2      Service-defined payload argument.
-
 
745
 * @param arg3      Service-defined payload argument.
-
 
746
 * @param dataptr   If non-NULL, storage where the reply data will be
-
 
747
 *          stored.
-
 
748
 *
-
 
749
 * @return      Hash of the sent message.
672
 */
750
 */
673
aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
751
aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
674
    ipcarg_t arg3, ipc_call_t *dataptr)
752
    ipcarg_t arg3, ipc_call_t *dataptr)
675
{
753
{
676
    amsg_t *msg;
754
    amsg_t *msg;
677
 
755
 
678
    if (in_interrupt_handler) {
756
    if (in_interrupt_handler) {
679
        printf("Cannot send asynchronous request in interrupt handler.\n");
757
        printf("Cannot send asynchronous request in interrupt "
-
 
758
            "handler.\n");
680
        _exit(1);
759
        _exit(1);
681
    }
760
    }
682
 
761
 
683
    msg = malloc(sizeof(*msg));
762
    msg = malloc(sizeof(*msg));
684
    msg->done = 0;
763
    msg->done = 0;
685
    msg->dataptr = dataptr;
764
    msg->dataptr = dataptr;
686
 
765
 
687
    msg->wdata.active = 1; /* We may sleep in next method, but it
766
    /* We may sleep in next method, but it will use its own mechanism */
688
                * will use it's own mechanism */
767
    msg->wdata.active = 1;
-
 
768
               
689
    ipc_call_async_3(phoneid, method, arg1, arg2, arg3, msg, reply_received,
769
    ipc_call_async_3(phoneid, method, arg1, arg2, arg3, msg, reply_received,
690
        1);
770
        1);
691
 
771
 
692
    return (aid_t) msg;
772
    return (aid_t) msg;
693
}
773
}
694
 
774
 
695
/** Wait for a message sent by async framework
775
/** Wait for a message sent by the async framework.
696
 *
776
 *
697
 * @param amsgid    Message ID to wait for
777
 * @param amsgid    Hash of the message to wait for.
698
 * @param retval    Pointer to variable where will be stored retval of the
778
 * @param retval    Pointer to storage where the retval of the answer will
699
 *          answered message. If NULL, it is ignored.
779
 *          be stored.
700
 */
780
 */
701
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
781
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
702
{
782
{
703
    amsg_t *msg = (amsg_t *) amsgid;
783
    amsg_t *msg = (amsg_t *) amsgid;
704
 
784
 
Line 709... Line 789...
709
    }
789
    }
710
 
790
 
711
    msg->wdata.fid = fibril_get_id();
791
    msg->wdata.fid = fibril_get_id();
712
    msg->wdata.active = 0;
792
    msg->wdata.active = 0;
713
    msg->wdata.inlist = 0;
793
    msg->wdata.inlist = 0;
714
    /* Leave locked async_futex when entering this function */
794
    /* Leave the async_futex locked when entering this function */
715
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
795
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
716
    /* futex is up automatically after fibril_schedule_next...*/
796
    /* futex is up automatically after fibril_schedule_next...*/
717
done:
797
done:
718
    if (retval)
798
    if (retval)
719
        *retval = msg->retval;
799
        *retval = msg->retval;
720
    free(msg);
800
    free(msg);
721
}
801
}
722
 
802
 
723
/** Wait for a message sent by async framework with timeout
803
/** Wait for a message sent by the async framework, timeout variant.
724
 *
804
 *
725
 * @param amsgid Message ID to wait for
805
 * @param amsgid    Hash of the message to wait for.
726
 * @param retval Pointer to variable where will be stored retval
806
 * @param retval    Pointer to storage where the retval of the answer will
727
 *               of the answered message. If NULL, it is ignored.
807
 *          be stored.
728
 * @param timeout Timeout in usecs
808
 * @param timeout   Timeout in microseconds.
729
 * @return 0 on success, ETIMEOUT if timeout expired
-
 
730
 *
809
 *
-
 
810
 * @return      Zero on success, ETIMEOUT if the timeout has expired.
731
 */
811
 */
732
int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
812
int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
733
{
813
{
734
    amsg_t *msg = (amsg_t *) amsgid;
814
    amsg_t *msg = (amsg_t *) amsgid;
735
 
815
 
Line 748... Line 828...
748
 
828
 
749
    msg->wdata.fid = fibril_get_id();
829
    msg->wdata.fid = fibril_get_id();
750
    msg->wdata.active = 0;
830
    msg->wdata.active = 0;
751
    insert_timeout(&msg->wdata);
831
    insert_timeout(&msg->wdata);
752
 
832
 
753
    /* Leave locked async_futex when entering this function */
833
    /* Leave the async_futex locked when entering this function */
754
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
834
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
755
    /* futex is up automatically after fibril_schedule_next...*/
835
    /* futex is up automatically after fibril_schedule_next...*/
756
 
836
 
757
    if (!msg->done)
837
    if (!msg->done)
758
        return ETIMEOUT;
838
        return ETIMEOUT;
Line 763... Line 843...
763
    free(msg);
843
    free(msg);
764
 
844
 
765
    return 0;
845
    return 0;
766
}
846
}
767
 
847
 
-
 
848
/** Wait for specified time.
-
 
849
 *
768
/** Wait specified time, but in the meantime handle incoming events
850
 * The current fibril is suspended but the thread continues to execute.
769
 *
851
 *
770
 * @param timeout Time in microseconds to wait
852
 * @param timeout   Duration of the wait in microseconds.
771
 */
853
 */
772
void async_usleep(suseconds_t timeout)
854
void async_usleep(suseconds_t timeout)
773
{
855
{
774
    amsg_t *msg;
856
    amsg_t *msg;
775
   
857
   
Line 788... Line 870...
788
    gettimeofday(&msg->wdata.expires, NULL);
870
    gettimeofday(&msg->wdata.expires, NULL);
789
    tv_add(&msg->wdata.expires, timeout);
871
    tv_add(&msg->wdata.expires, timeout);
790
 
872
 
791
    futex_down(&async_futex);
873
    futex_down(&async_futex);
792
    insert_timeout(&msg->wdata);
874
    insert_timeout(&msg->wdata);
793
    /* Leave locked the async_futex when entering this function */
875
    /* Leave the async_futex locked when entering this function */
794
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
876
    fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
795
    /* futex is up automatically after fibril_schedule_next_adv()...*/
877
    /* futex is up automatically after fibril_schedule_next_adv()...*/
796
    free(msg);
878
    free(msg);
797
}
879
}
798
 
880
 
799
/** Set function that is called when IPC_M_CONNECT_ME_TO is received.
881
/** Setter for client_connection function pointer.
800
 *
882
 *
801
 * @param conn Function that will form a new fibril.
883
 * @param conn      Function that will implement a new connection fibril.
802
 */
884
 */
803
void async_set_client_connection(async_client_conn_t conn)
885
void async_set_client_connection(async_client_conn_t conn)
804
{
886
{
805
    client_connection = conn;
887
    client_connection = conn;
806
}
888
}
-
 
889
 
-
 
890
/** Setter for interrupt_received function pointer.
-
 
891
 *
-
 
892
 * @param conn      Function that will implement a new interrupt
-
 
893
 *          notification fibril.
-
 
894
 */
807
void async_set_interrupt_received(async_client_conn_t conn)
895
void async_set_interrupt_received(async_client_conn_t conn)
808
{
896
{
809
    interrupt_received = conn;
897
    interrupt_received = conn;
810
}
898
}
811
 
899
 
Line 823... Line 911...
823
        !in_interrupt_handler);
911
        !in_interrupt_handler);
824
}
912
}
825
 
913
 
826
/** @}
914
/** @}
827
 */
915
 */
-
 
916