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 | } |