Changes in kernel/generic/src/ipc/ipc.c [97b8ca9:48bcf49] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipc.c
r97b8ca9 r48bcf49 38 38 */ 39 39 40 #include <assert.h> 40 41 #include <synch/spinlock.h> 41 42 #include <synch/mutex.h> 42 43 #include <synch/waitq.h> 43 44 #include <ipc/ipc.h> 45 #include <ipc/ipcrsc.h> 44 46 #include <abi/ipc/methods.h> 45 47 #include <ipc/kbox.h> … … 51 53 #include <arch.h> 52 54 #include <proc/task.h> 53 #include <memstr.h> 54 #include <debug.h> 55 #include <mem.h> 55 56 #include <print.h> 56 57 #include <console/console.h> … … 58 59 #include <arch/interrupt.h> 59 60 #include <ipc/irq.h> 61 #include <cap/cap.h> 60 62 61 63 static void ipc_forget_call(call_t *); … … 64 66 answerbox_t *ipc_phone_0 = NULL; 65 67 66 static slab_cache_t *ipc_call_slab; 67 static slab_cache_t *ipc_answerbox_slab; 68 static slab_cache_t *call_slab; 69 static slab_cache_t *answerbox_slab; 70 71 slab_cache_t *phone_slab = NULL; 68 72 69 73 /** Initialize a call structure. … … 93 97 if (call->buffer) 94 98 free(call->buffer); 95 slab_free( ipc_call_slab, call);99 slab_free(call_slab, call); 96 100 } 97 101 } … … 110 114 call_t *ipc_call_alloc(unsigned int flags) 111 115 { 112 call_t *call = slab_alloc( ipc_call_slab, flags);116 call_t *call = slab_alloc(call_slab, flags); 113 117 if (call) { 114 118 _ipc_call_init(call); … … 145 149 list_initialize(&box->answers); 146 150 list_initialize(&box->irq_notifs); 147 list_initialize(&box->irq_list);148 151 box->task = task; 149 152 } … … 151 154 /** Connect a phone to an answerbox. 152 155 * 153 * @param phone Initialized phone structure. 154 * @param box Initialized answerbox structure. 155 * @return True if the phone was connected, false otherwise. 156 * This function must be passed a reference to phone->kobject. 157 * 158 * @param phone Initialized phone structure. 159 * @param box Initialized answerbox structure. 160 * @return True if the phone was connected, false otherwise. 156 161 */ 157 162 bool ipc_phone_connect(phone_t *phone, answerbox_t *box) … … 166 171 phone->state = IPC_PHONE_CONNECTED; 167 172 phone->callee = box; 173 /* Pass phone->kobject reference to box->connected_phones */ 168 174 list_append(&phone->link, &box->connected_phones); 169 175 } … … 171 177 irq_spinlock_unlock(&box->lock, true); 172 178 mutex_unlock(&phone->lock); 179 180 if (!active) { 181 /* We still have phone->kobject's reference; drop it */ 182 kobject_put(phone->kobject); 183 } 173 184 174 185 return active; … … 188 199 phone->state = IPC_PHONE_FREE; 189 200 atomic_set(&phone->active_calls, 0); 201 phone->kobject = NULL; 190 202 } 191 203 … … 200 212 int ipc_call_sync(phone_t *phone, call_t *request) 201 213 { 202 answerbox_t *mybox = slab_alloc( ipc_answerbox_slab, 0);214 answerbox_t *mybox = slab_alloc(answerbox_slab, 0); 203 215 ipc_answerbox_init(mybox, TASK); 204 216 … … 208 220 int rc = ipc_call(phone, request); 209 221 if (rc != EOK) { 210 slab_free( ipc_answerbox_slab, mybox);222 slab_free(answerbox_slab, mybox); 211 223 return rc; 212 224 } … … 227 239 spinlock_lock(&TASK->active_calls_lock); 228 240 229 ASSERT(!request->forget);241 assert(!request->forget); 230 242 231 243 bool answered = !request->active; … … 253 265 } 254 266 } 255 ASSERT(!answer || request == answer);256 257 slab_free( ipc_answerbox_slab, mybox);267 assert(!answer || request == answer); 268 269 slab_free(answerbox_slab, mybox); 258 270 return rc; 259 271 } … … 453 465 list_remove(&phone->link); 454 466 irq_spinlock_unlock(&box->lock, true); 467 468 /* Drop the answerbox reference */ 469 kobject_put(phone->kobject); 455 470 456 471 call_t *call = ipc_call_alloc(0); … … 631 646 632 647 /* Disconnect phone */ 633 ASSERT(phone->state == IPC_PHONE_CONNECTED);648 assert(phone->state == IPC_PHONE_CONNECTED); 634 649 635 650 list_remove(&phone->link); … … 655 670 656 671 task_release(phone->caller); 672 673 kobject_put(phone->kobject); 657 674 658 675 /* Must start again */ … … 661 678 662 679 mutex_unlock(&phone->lock); 680 kobject_put(phone->kobject); 663 681 } 664 682 … … 668 686 static void ipc_forget_call(call_t *call) 669 687 { 670 ASSERT(spinlock_locked(&TASK->active_calls_lock));671 ASSERT(spinlock_locked(&call->forget_lock));688 assert(spinlock_locked(&TASK->active_calls_lock)); 689 assert(spinlock_locked(&call->forget_lock)); 672 690 673 691 /* … … 707 725 * Nota bene: there may still be answers waiting for pick up. 708 726 */ 709 spinlock_unlock(&TASK->active_calls_lock); 727 spinlock_unlock(&TASK->active_calls_lock); 710 728 return; 711 729 } … … 720 738 * call on the list. 721 739 */ 722 spinlock_unlock(&TASK->active_calls_lock); 740 spinlock_unlock(&TASK->active_calls_lock); 723 741 goto restart; 724 742 } … … 727 745 728 746 goto restart; 747 } 748 749 static bool phone_cap_wait_cb(cap_t *cap, void *arg) 750 { 751 phone_t *phone = cap->kobject->phone; 752 bool *restart = (bool *) arg; 753 754 mutex_lock(&phone->lock); 755 if ((phone->state == IPC_PHONE_HUNGUP) && 756 (atomic_get(&phone->active_calls) == 0)) { 757 phone->state = IPC_PHONE_FREE; 758 phone->callee = NULL; 759 } 760 761 /* 762 * We might have had some IPC_PHONE_CONNECTING phones at the beginning 763 * of ipc_cleanup(). Depending on whether these were forgotten or 764 * answered, they will eventually enter the IPC_PHONE_FREE or 765 * IPC_PHONE_CONNECTED states, respectively. In the latter case, the 766 * other side may slam the open phones at any time, in which case we 767 * will get an IPC_PHONE_SLAMMED phone. 768 */ 769 if ((phone->state == IPC_PHONE_CONNECTED) || 770 (phone->state == IPC_PHONE_SLAMMED)) { 771 mutex_unlock(&phone->lock); 772 ipc_phone_hangup(phone); 773 /* 774 * Now there may be one extra active call, which needs to be 775 * forgotten. 776 */ 777 ipc_forget_all_active_calls(); 778 *restart = true; 779 return false; 780 } 781 782 /* 783 * If the hangup succeeded, it has sent a HANGUP message, the IPC is now 784 * in HUNGUP state, we wait for the reply to come 785 */ 786 if (phone->state != IPC_PHONE_FREE) { 787 mutex_unlock(&phone->lock); 788 return false; 789 } 790 791 mutex_unlock(&phone->lock); 792 return true; 729 793 } 730 794 … … 733 797 { 734 798 call_t *call; 735 size_t i;799 bool restart; 736 800 737 801 restart: … … 740 804 * Locking is needed as there may be connection handshakes in progress. 741 805 */ 742 for (i = 0; i < IPC_MAX_PHONES; i++) { 743 phone_t *phone = &TASK->phones[i]; 744 745 mutex_lock(&phone->lock); 746 if ((phone->state == IPC_PHONE_HUNGUP) && 747 (atomic_get(&phone->active_calls) == 0)) { 748 phone->state = IPC_PHONE_FREE; 749 phone->callee = NULL; 750 } 751 752 /* 753 * We might have had some IPC_PHONE_CONNECTING phones at the 754 * beginning of ipc_cleanup(). Depending on whether these were 755 * forgotten or answered, they will eventually enter the 756 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively. 757 * In the latter case, the other side may slam the open phones 758 * at any time, in which case we will get an IPC_PHONE_SLAMMED 759 * phone. 760 */ 761 if ((phone->state == IPC_PHONE_CONNECTED) || 762 (phone->state == IPC_PHONE_SLAMMED)) { 763 mutex_unlock(&phone->lock); 764 ipc_phone_hangup(phone); 765 /* 766 * Now there may be one extra active call, which needs 767 * to be forgotten. 768 */ 769 ipc_forget_all_active_calls(); 770 goto restart; 771 } 772 773 /* 774 * If the hangup succeeded, it has sent a HANGUP message, the 775 * IPC is now in HUNGUP state, we wait for the reply to come 776 */ 777 if (phone->state != IPC_PHONE_FREE) { 778 mutex_unlock(&phone->lock); 779 break; 780 } 781 782 mutex_unlock(&phone->lock); 783 } 784 785 /* Got into cleanup */ 786 if (i == IPC_MAX_PHONES) 806 restart = false; 807 if (caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE, 808 phone_cap_wait_cb, &restart)) { 809 /* Got into cleanup */ 787 810 return; 788 811 } 812 if (restart) 813 goto restart; 814 789 815 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 790 816 SYNCH_FLAGS_NONE); 791 ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));817 assert(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF)); 792 818 793 819 SYSIPC_OP(answer_process, call); … … 795 821 ipc_call_free(call); 796 822 goto restart; 823 } 824 825 static bool phone_cap_cleanup_cb(cap_t *cap, void *arg) 826 { 827 ipc_phone_hangup(cap->kobject->phone); 828 return true; 829 } 830 831 static bool irq_cap_cleanup_cb(cap_t *cap, void *arg) 832 { 833 ipc_irq_unsubscribe(&TASK->answerbox, cap->handle); 834 return true; 797 835 } 798 836 … … 816 854 817 855 /* Disconnect all our phones ('ipc_phone_hangup') */ 818 for (size_t i = 0; i < IPC_MAX_PHONES; i++)819 ipc_phone_hangup(&TASK->phones[i]);856 caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE, 857 phone_cap_cleanup_cb, NULL); 820 858 821 859 /* Unsubscribe from any event notifications. */ 822 860 event_cleanup_answerbox(&TASK->answerbox); 823 861 824 /* Disconnect all connected irqs */ 825 ipc_irq_cleanup(&TASK->answerbox); 862 /* Disconnect all connected IRQs */ 863 caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_IRQ, irq_cap_cleanup_cb, 864 NULL); 826 865 827 866 /* Disconnect all phones connected to our regular answerbox */ … … 847 886 void ipc_init(void) 848 887 { 849 ipc_call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,888 call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL, 850 889 NULL, 0); 851 ipc_answerbox_slab = slab_cache_create("answerbox_t", 852 sizeof(answerbox_t), 0, NULL, NULL, 0); 890 phone_slab = slab_cache_create("phone_t", sizeof(phone_t), 0, NULL, 891 NULL, 0); 892 answerbox_slab = slab_cache_create("answerbox_t", sizeof(answerbox_t), 893 0, NULL, NULL, 0); 853 894 } 854 895 … … 885 926 } 886 927 928 static bool print_task_phone_cb(cap_t *cap, void *arg) 929 { 930 phone_t *phone = cap->kobject->phone; 931 932 mutex_lock(&phone->lock); 933 if (phone->state != IPC_PHONE_FREE) { 934 printf("%-11d %7" PRIun " ", cap->handle, 935 atomic_get(&phone->active_calls)); 936 937 switch (phone->state) { 938 case IPC_PHONE_CONNECTING: 939 printf("connecting"); 940 break; 941 case IPC_PHONE_CONNECTED: 942 printf("connected to %" PRIu64 " (%s)", 943 phone->callee->task->taskid, 944 phone->callee->task->name); 945 break; 946 case IPC_PHONE_SLAMMED: 947 printf("slammed by %p", phone->callee); 948 break; 949 case IPC_PHONE_HUNGUP: 950 printf("hung up by %p", phone->callee); 951 break; 952 default: 953 break; 954 } 955 956 printf("\n"); 957 } 958 mutex_unlock(&phone->lock); 959 960 return true; 961 } 962 887 963 /** List answerbox contents. 888 964 * … … 894 970 irq_spinlock_lock(&tasks_lock, true); 895 971 task_t *task = task_find_by_id(taskid); 896 897 972 if (!task) { 898 973 irq_spinlock_unlock(&tasks_lock, true); 899 974 return; 900 975 } 901 902 /* Hand-over-hand locking */ 903 irq_spinlock_exchange(&tasks_lock, &task->lock); 904 905 printf("[phone id] [calls] [state\n"); 906 907 size_t i; 908 for (i = 0; i < IPC_MAX_PHONES; i++) { 909 if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) { 910 printf("%-10zu (mutex busy)\n", i); 911 continue; 912 } 913 914 if (task->phones[i].state != IPC_PHONE_FREE) { 915 printf("%-10zu %7" PRIun " ", i, 916 atomic_get(&task->phones[i].active_calls)); 917 918 switch (task->phones[i].state) { 919 case IPC_PHONE_CONNECTING: 920 printf("connecting"); 921 break; 922 case IPC_PHONE_CONNECTED: 923 printf("connected to %" PRIu64 " (%s)", 924 task->phones[i].callee->task->taskid, 925 task->phones[i].callee->task->name); 926 break; 927 case IPC_PHONE_SLAMMED: 928 printf("slammed by %p", 929 task->phones[i].callee); 930 break; 931 case IPC_PHONE_HUNGUP: 932 printf("hung up by %p", 933 task->phones[i].callee); 934 break; 935 default: 936 break; 937 } 938 939 printf("\n"); 940 } 941 942 mutex_unlock(&task->phones[i].lock); 943 } 944 976 task_hold(task); 977 irq_spinlock_unlock(&tasks_lock, true); 978 979 printf("[phone cap] [calls] [state\n"); 980 981 caps_apply_to_kobject_type(task, KOBJECT_TYPE_PHONE, 982 print_task_phone_cb, NULL); 983 984 irq_spinlock_lock(&task->lock, true); 945 985 irq_spinlock_lock(&task->answerbox.lock, false); 946 986 … … 964 1004 irq_spinlock_unlock(&task->answerbox.lock, false); 965 1005 irq_spinlock_unlock(&task->lock, true); 1006 1007 task_release(task); 966 1008 } 967 1009
Note:
See TracChangeset
for help on using the changeset viewer.