Changes in kernel/generic/src/ipc/ipc.c [48bcf49:97b8ca9] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipc.c
r48bcf49 r97b8ca9 38 38 */ 39 39 40 #include <assert.h>41 40 #include <synch/spinlock.h> 42 41 #include <synch/mutex.h> 43 42 #include <synch/waitq.h> 44 43 #include <ipc/ipc.h> 45 #include <ipc/ipcrsc.h>46 44 #include <abi/ipc/methods.h> 47 45 #include <ipc/kbox.h> … … 53 51 #include <arch.h> 54 52 #include <proc/task.h> 55 #include <mem.h> 53 #include <memstr.h> 54 #include <debug.h> 56 55 #include <print.h> 57 56 #include <console/console.h> … … 59 58 #include <arch/interrupt.h> 60 59 #include <ipc/irq.h> 61 #include <cap/cap.h>62 60 63 61 static void ipc_forget_call(call_t *); … … 66 64 answerbox_t *ipc_phone_0 = NULL; 67 65 68 static slab_cache_t *call_slab; 69 static slab_cache_t *answerbox_slab; 70 71 slab_cache_t *phone_slab = NULL; 66 static slab_cache_t *ipc_call_slab; 67 static slab_cache_t *ipc_answerbox_slab; 72 68 73 69 /** Initialize a call structure. … … 97 93 if (call->buffer) 98 94 free(call->buffer); 99 slab_free( call_slab, call);95 slab_free(ipc_call_slab, call); 100 96 } 101 97 } … … 114 110 call_t *ipc_call_alloc(unsigned int flags) 115 111 { 116 call_t *call = slab_alloc( call_slab, flags);112 call_t *call = slab_alloc(ipc_call_slab, flags); 117 113 if (call) { 118 114 _ipc_call_init(call); … … 149 145 list_initialize(&box->answers); 150 146 list_initialize(&box->irq_notifs); 147 list_initialize(&box->irq_list); 151 148 box->task = task; 152 149 } … … 154 151 /** Connect a phone to an answerbox. 155 152 * 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. 153 * @param phone Initialized phone structure. 154 * @param box Initialized answerbox structure. 155 * @return True if the phone was connected, false otherwise. 161 156 */ 162 157 bool ipc_phone_connect(phone_t *phone, answerbox_t *box) … … 171 166 phone->state = IPC_PHONE_CONNECTED; 172 167 phone->callee = box; 173 /* Pass phone->kobject reference to box->connected_phones */174 168 list_append(&phone->link, &box->connected_phones); 175 169 } … … 177 171 irq_spinlock_unlock(&box->lock, true); 178 172 mutex_unlock(&phone->lock); 179 180 if (!active) {181 /* We still have phone->kobject's reference; drop it */182 kobject_put(phone->kobject);183 }184 173 185 174 return active; … … 199 188 phone->state = IPC_PHONE_FREE; 200 189 atomic_set(&phone->active_calls, 0); 201 phone->kobject = NULL;202 190 } 203 191 … … 212 200 int ipc_call_sync(phone_t *phone, call_t *request) 213 201 { 214 answerbox_t *mybox = slab_alloc( answerbox_slab, 0);202 answerbox_t *mybox = slab_alloc(ipc_answerbox_slab, 0); 215 203 ipc_answerbox_init(mybox, TASK); 216 204 … … 220 208 int rc = ipc_call(phone, request); 221 209 if (rc != EOK) { 222 slab_free( answerbox_slab, mybox);210 slab_free(ipc_answerbox_slab, mybox); 223 211 return rc; 224 212 } … … 239 227 spinlock_lock(&TASK->active_calls_lock); 240 228 241 assert(!request->forget);229 ASSERT(!request->forget); 242 230 243 231 bool answered = !request->active; … … 265 253 } 266 254 } 267 assert(!answer || request == answer);268 269 slab_free( answerbox_slab, mybox);255 ASSERT(!answer || request == answer); 256 257 slab_free(ipc_answerbox_slab, mybox); 270 258 return rc; 271 259 } … … 465 453 list_remove(&phone->link); 466 454 irq_spinlock_unlock(&box->lock, true); 467 468 /* Drop the answerbox reference */469 kobject_put(phone->kobject);470 455 471 456 call_t *call = ipc_call_alloc(0); … … 646 631 647 632 /* Disconnect phone */ 648 assert(phone->state == IPC_PHONE_CONNECTED);633 ASSERT(phone->state == IPC_PHONE_CONNECTED); 649 634 650 635 list_remove(&phone->link); … … 670 655 671 656 task_release(phone->caller); 672 673 kobject_put(phone->kobject);674 657 675 658 /* Must start again */ … … 678 661 679 662 mutex_unlock(&phone->lock); 680 kobject_put(phone->kobject);681 663 } 682 664 … … 686 668 static void ipc_forget_call(call_t *call) 687 669 { 688 assert(spinlock_locked(&TASK->active_calls_lock));689 assert(spinlock_locked(&call->forget_lock));670 ASSERT(spinlock_locked(&TASK->active_calls_lock)); 671 ASSERT(spinlock_locked(&call->forget_lock)); 690 672 691 673 /* … … 725 707 * Nota bene: there may still be answers waiting for pick up. 726 708 */ 727 spinlock_unlock(&TASK->active_calls_lock); 709 spinlock_unlock(&TASK->active_calls_lock); 728 710 return; 729 711 } … … 738 720 * call on the list. 739 721 */ 740 spinlock_unlock(&TASK->active_calls_lock); 722 spinlock_unlock(&TASK->active_calls_lock); 741 723 goto restart; 742 724 } … … 745 727 746 728 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 beginning763 * of ipc_cleanup(). Depending on whether these were forgotten or764 * answered, they will eventually enter the IPC_PHONE_FREE or765 * IPC_PHONE_CONNECTED states, respectively. In the latter case, the766 * other side may slam the open phones at any time, in which case we767 * 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 be775 * 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 now784 * in HUNGUP state, we wait for the reply to come785 */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;793 729 } 794 730 … … 797 733 { 798 734 call_t *call; 799 bool restart;735 size_t i; 800 736 801 737 restart: … … 804 740 * Locking is needed as there may be connection handshakes in progress. 805 741 */ 806 restart = false; 807 if (caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE, 808 phone_cap_wait_cb, &restart)) { 809 /* Got into cleanup */ 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) 810 787 return; 811 } 812 if (restart) 813 goto restart; 814 788 815 789 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 816 790 SYNCH_FLAGS_NONE); 817 assert(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));791 ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF)); 818 792 819 793 SYSIPC_OP(answer_process, call); … … 821 795 ipc_call_free(call); 822 796 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;835 797 } 836 798 … … 854 816 855 817 /* Disconnect all our phones ('ipc_phone_hangup') */ 856 caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,857 phone_cap_cleanup_cb, NULL);818 for (size_t i = 0; i < IPC_MAX_PHONES; i++) 819 ipc_phone_hangup(&TASK->phones[i]); 858 820 859 821 /* Unsubscribe from any event notifications. */ 860 822 event_cleanup_answerbox(&TASK->answerbox); 861 823 862 /* Disconnect all connected IRQs */ 863 caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_IRQ, irq_cap_cleanup_cb, 864 NULL); 824 /* Disconnect all connected irqs */ 825 ipc_irq_cleanup(&TASK->answerbox); 865 826 866 827 /* Disconnect all phones connected to our regular answerbox */ … … 886 847 void ipc_init(void) 887 848 { 888 call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,849 ipc_call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL, 889 850 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); 851 ipc_answerbox_slab = slab_cache_create("answerbox_t", 852 sizeof(answerbox_t), 0, NULL, NULL, 0); 894 853 } 895 854 … … 926 885 } 927 886 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 963 887 /** List answerbox contents. 964 888 * … … 970 894 irq_spinlock_lock(&tasks_lock, true); 971 895 task_t *task = task_find_by_id(taskid); 896 972 897 if (!task) { 973 898 irq_spinlock_unlock(&tasks_lock, true); 974 899 return; 975 900 } 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); 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 985 945 irq_spinlock_lock(&task->answerbox.lock, false); 986 946 … … 1004 964 irq_spinlock_unlock(&task->answerbox.lock, false); 1005 965 irq_spinlock_unlock(&task->lock, true); 1006 1007 task_release(task);1008 966 } 1009 967
Note:
See TracChangeset
for help on using the changeset viewer.