Rev 3431 | Rev 3471 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 3431 | Rev 3433 | ||
|---|---|---|---|
| Line 41... | Line 41... | ||
| 41 | #include <synch/spinlock.h> |
41 | #include <synch/spinlock.h> |
| 42 | #include <synch/mutex.h> |
42 | #include <synch/mutex.h> |
| 43 | #include <synch/waitq.h> |
43 | #include <synch/waitq.h> |
| 44 | #include <synch/synch.h> |
44 | #include <synch/synch.h> |
| 45 | #include <ipc/ipc.h> |
45 | #include <ipc/ipc.h> |
| - | 46 | #include <ipc/ipc_kbox.h> |
|
| 46 | #include <errno.h> |
47 | #include <errno.h> |
| 47 | #include <mm/slab.h> |
48 | #include <mm/slab.h> |
| 48 | #include <arch.h> |
49 | #include <arch.h> |
| 49 | #include <proc/task.h> |
50 | #include <proc/task.h> |
| 50 | #include <memstr.h> |
51 | #include <memstr.h> |
| Line 426... | Line 427... | ||
| 426 | 427 | ||
| 427 | /** Answer all calls from list with EHANGUP answer. |
428 | /** Answer all calls from list with EHANGUP answer. |
| 428 | * |
429 | * |
| 429 | * @param lst Head of the list to be cleaned up. |
430 | * @param lst Head of the list to be cleaned up. |
| 430 | */ |
431 | */ |
| 431 | static void ipc_cleanup_call_list(link_t *lst) |
432 | void ipc_cleanup_call_list(link_t *lst) |
| 432 | { |
433 | { |
| 433 | call_t *call; |
434 | call_t *call; |
| 434 | 435 | ||
| 435 | while (!list_empty(lst)) { |
436 | while (!list_empty(lst)) { |
| 436 | call = list_get_instance(lst->next, call_t, link); |
437 | call = list_get_instance(lst->next, call_t, link); |
| Line 447... | Line 448... | ||
| 447 | * |
448 | * |
| 448 | * @param box Answerbox to disconnect phones from. |
449 | * @param box Answerbox to disconnect phones from. |
| 449 | * @param notify_box If true, the answerbox will get a hangup message for |
450 | * @param notify_box If true, the answerbox will get a hangup message for |
| 450 | * each disconnected phone. |
451 | * each disconnected phone. |
| 451 | */ |
452 | */ |
| 452 | static void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) |
453 | void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) |
| 453 | { |
454 | { |
| 454 | phone_t *phone; |
455 | phone_t *phone; |
| 455 | DEADLOCK_PROBE_INIT(p_phonelck); |
456 | DEADLOCK_PROBE_INIT(p_phonelck); |
| 456 | ipl_t ipl; |
457 | ipl_t ipl; |
| 457 | call_t *call; |
458 | call_t *call; |
| Line 508... | Line 509... | ||
| 508 | 509 | ||
| 509 | /* Free unused call */ |
510 | /* Free unused call */ |
| 510 | if (call) ipc_call_free(call); |
511 | if (call) ipc_call_free(call); |
| 511 | } |
512 | } |
| 512 | 513 | ||
| 513 | #ifdef CONFIG_UDEBUG |
- | |
| 514 | - | ||
| 515 | static void ipc_kbox_cleanup() |
- | |
| 516 | { |
- | |
| 517 | bool have_kb_thread; |
- | |
| 518 | - | ||
| 519 | /* Only hold kb_cleanup_lock while setting kb_finished - this is enough */ |
- | |
| 520 | mutex_lock(&TASK->kb_cleanup_lock); |
- | |
| 521 | TASK->kb_finished = true; |
- | |
| 522 | mutex_unlock(&TASK->kb_cleanup_lock); |
- | |
| 523 | - | ||
| 524 | have_kb_thread = (TASK->kb_thread != NULL); |
- | |
| 525 | - | ||
| 526 | /* From now on nobody will try to connect phones or attach kbox threads */ |
- | |
| 527 | - | ||
| 528 | /* |
- | |
| 529 | * Disconnect all phones connected to our kbox. Passing true for |
- | |
| 530 | * notify_box causes a HANGUP message to be inserted for each |
- | |
| 531 | * disconnected phone. This ensures the kbox thread is going to |
- | |
| 532 | * wake up and terminate. |
- | |
| 533 | */ |
- | |
| 534 | ipc_answerbox_slam_phones(&TASK->kernel_box, have_kb_thread); |
- | |
| 535 | - | ||
| 536 | if (have_kb_thread) { |
- | |
| 537 | printf("join kb_thread..\n"); |
- | |
| 538 | thread_join(TASK->kb_thread); |
- | |
| 539 | thread_detach(TASK->kb_thread); |
- | |
| 540 | printf("join done\n"); |
- | |
| 541 | TASK->kb_thread = NULL; |
- | |
| 542 | } |
- | |
| 543 | - | ||
| 544 | /* Answer all messages in 'calls' and 'dispatched_calls' queues */ |
- | |
| 545 | spinlock_lock(&TASK->kernel_box.lock); |
- | |
| 546 | ipc_cleanup_call_list(&TASK->kernel_box.dispatched_calls); |
- | |
| 547 | ipc_cleanup_call_list(&TASK->kernel_box.calls); |
- | |
| 548 | spinlock_unlock(&TASK->kernel_box.lock); |
- | |
| 549 | } |
- | |
| 550 | - | ||
| 551 | #endif |
- | |
| 552 | - | ||
| 553 | /** Cleans up all IPC communication of the current task. |
514 | /** Cleans up all IPC communication of the current task. |
| 554 | * |
515 | * |
| 555 | * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
516 | * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
| 556 | * have to change it as well if you want to cleanup other tasks than TASK. |
517 | * have to change it as well if you want to cleanup other tasks than TASK. |
| 557 | */ |
518 | */ |
| Line 726... | Line 687... | ||
| 726 | 687 | ||
| 727 | spinlock_unlock(&task->answerbox.lock); |
688 | spinlock_unlock(&task->answerbox.lock); |
| 728 | spinlock_unlock(&task->lock); |
689 | spinlock_unlock(&task->lock); |
| 729 | } |
690 | } |
| 730 | 691 | ||
| 731 | #ifdef CONFIG_UDEBUG |
- | |
| 732 | - | ||
| 733 | #include <ipc/ipcrsc.h> |
- | |
| 734 | #include <print.h> |
- | |
| 735 | #include <udebug/udebug_ipc.h> |
- | |
| 736 | - | ||
| 737 | static void kbox_thread_proc(void *arg) |
- | |
| 738 | { |
- | |
| 739 | call_t *call; |
- | |
| 740 | int method; |
- | |
| 741 | bool done; |
- | |
| 742 | ipl_t ipl; |
- | |
| 743 | - | ||
| 744 | (void)arg; |
- | |
| 745 | printf("kbox_thread_proc()\n"); |
- | |
| 746 | done = false; |
- | |
| 747 | - | ||
| 748 | while (!done) { |
- | |
| 749 | //printf("kbox: wait for call\n"); |
- | |
| 750 | call = ipc_wait_for_call(&TASK->kernel_box, SYNCH_NO_TIMEOUT, |
- | |
| 751 | SYNCH_FLAGS_NONE); |
- | |
| 752 | - | ||
| 753 | if (call != NULL) { |
- | |
| 754 | method = IPC_GET_METHOD(call->data); |
- | |
| 755 | - | ||
| 756 | if (method == IPC_M_DEBUG_ALL) { |
- | |
| 757 | udebug_call_receive(call); |
- | |
| 758 | } |
- | |
| 759 | - | ||
| 760 | if (method == IPC_M_PHONE_HUNGUP) { |
- | |
| 761 | printf("kbox: handle hangup message\n"); |
- | |
| 762 | - | ||
| 763 | /* Was it our debugger, who hung up? */ |
- | |
| 764 | if (call->sender == TASK->udebug.debugger) { |
- | |
| 765 | /* Terminate debugging session (if any) */ |
- | |
| 766 | printf("kbox: terminate debug session\n"); |
- | |
| 767 | ipl = interrupts_disable(); |
- | |
| 768 | spinlock_lock(&TASK->lock); |
- | |
| 769 | udebug_task_cleanup(TASK); |
- | |
| 770 | spinlock_unlock(&TASK->lock); |
- | |
| 771 | interrupts_restore(ipl); |
- | |
| 772 | } else { |
- | |
| 773 | printf("kbox: was not debugger\n"); |
- | |
| 774 | } |
- | |
| 775 | - | ||
| 776 | printf("kbox: continue with hangup message\n"); |
- | |
| 777 | IPC_SET_RETVAL(call->data, 0); |
- | |
| 778 | ipc_answer(&TASK->kernel_box, call); |
- | |
| 779 | - | ||
| 780 | ipl = interrupts_disable(); |
- | |
| 781 | spinlock_lock(&TASK->lock); |
- | |
| 782 | spinlock_lock(&TASK->answerbox.lock); |
- | |
| 783 | if (list_empty(&TASK->answerbox.connected_phones)) { |
- | |
| 784 | /* Last phone has been disconnected */ |
- | |
| 785 | TASK->kb_thread = NULL; |
- | |
| 786 | done = true; |
- | |
| 787 | printf("phone list is empty\n"); |
- | |
| 788 | } |
- | |
| 789 | spinlock_unlock(&TASK->answerbox.lock); |
- | |
| 790 | spinlock_unlock(&TASK->lock); |
- | |
| 791 | interrupts_restore(ipl); |
- | |
| 792 | } |
- | |
| 793 | } |
- | |
| 794 | } |
- | |
| 795 | - | ||
| 796 | printf("kbox: finished\n"); |
- | |
| 797 | } |
- | |
| 798 | - | ||
| 799 | - | ||
| 800 | /** |
- | |
| 801 | * Connect phone to a task kernel-box specified by id. |
- | |
| 802 | * |
- | |
| 803 | * Note that this is not completely atomic. For optimisation reasons, |
- | |
| 804 | * The task might start cleaning up kbox after the phone has been connected |
- | |
| 805 | * and before a kbox thread has been created. This must be taken into account |
- | |
| 806 | * in the cleanup code. |
- | |
| 807 | * |
- | |
| 808 | * @return Phone id on success, or negative error code. |
- | |
| 809 | */ |
- | |
| 810 | int ipc_connect_kbox(task_id_t taskid) |
- | |
| 811 | { |
- | |
| 812 | int newphid; |
- | |
| 813 | task_t *ta; |
- | |
| 814 | thread_t *kb_thread; |
- | |
| 815 | ipl_t ipl; |
- | |
| 816 | - | ||
| 817 | ipl = interrupts_disable(); |
- | |
| 818 | spinlock_lock(&tasks_lock); |
- | |
| 819 | - | ||
| 820 | ta = task_find_by_id(taskid); |
- | |
| 821 | if (ta == NULL) { |
- | |
| 822 | spinlock_unlock(&tasks_lock); |
- | |
| 823 | interrupts_restore(ipl); |
- | |
| 824 | return ENOENT; |
- | |
| 825 | } |
- | |
| 826 | - | ||
| 827 | atomic_inc(&ta->refcount); |
- | |
| 828 | - | ||
| 829 | spinlock_unlock(&tasks_lock); |
- | |
| 830 | interrupts_restore(ipl); |
- | |
| 831 | - | ||
| 832 | mutex_lock(&ta->kb_cleanup_lock); |
- | |
| 833 | - | ||
| 834 | if (atomic_predec(&ta->refcount) == 0) { |
- | |
| 835 | mutex_unlock(&ta->kb_cleanup_lock); |
- | |
| 836 | task_destroy(ta); |
- | |
| 837 | return ENOENT; |
- | |
| 838 | } |
- | |
| 839 | - | ||
| 840 | if (ta->kb_finished != false) { |
- | |
| 841 | mutex_unlock(&ta->kb_cleanup_lock); |
- | |
| 842 | return EINVAL; |
- | |
| 843 | } |
- | |
| 844 | - | ||
| 845 | newphid = phone_alloc(); |
- | |
| 846 | if (newphid < 0) { |
- | |
| 847 | mutex_unlock(&ta->kb_cleanup_lock); |
- | |
| 848 | return ELIMIT; |
- | |
| 849 | } |
- | |
| 850 | - | ||
| 851 | /* Connect the newly allocated phone to the kbox */ |
- | |
| 852 | ipc_phone_connect(&TASK->phones[newphid], &ta->kernel_box); |
- | |
| 853 | - | ||
| 854 | if (ta->kb_thread != NULL) { |
- | |
| 855 | mutex_unlock(&ta->kb_cleanup_lock); |
- | |
| 856 | return newphid; |
- | |
| 857 | } |
- | |
| 858 | - | ||
| 859 | /* Create a kbox thread */ |
- | |
| 860 | kb_thread = thread_create(kbox_thread_proc, NULL, ta, 0, "kbox", false); |
- | |
| 861 | if (!kb_thread) { |
- | |
| 862 | mutex_unlock(&ta->kb_cleanup_lock); |
- | |
| 863 | return ENOMEM; |
- | |
| 864 | } |
- | |
| 865 | - | ||
| 866 | ta->kb_thread = kb_thread; |
- | |
| 867 | thread_ready(kb_thread); |
- | |
| 868 | - | ||
| 869 | mutex_unlock(&ta->kb_cleanup_lock); |
- | |
| 870 | - | ||
| 871 | return newphid; |
- | |
| 872 | } |
- | |
| 873 | - | ||
| 874 | #endif /* defined(CONFIG_UDEBUG) */ |
- | |
| 875 | - | ||
| 876 | /** @} |
692 | /** @} |
| 877 | */ |
693 | */ |