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 | */ |