Changeset ba81cab in mainline
- Timestamp:
- 2006-03-18T01:06:13Z (19 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- fbcfd458
- Parents:
- 81c4c6da
- Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
generic/include/ipc/ipc.h
r81c4c6da rba81cab 172 172 extern call_t * ipc_call_alloc(void); 173 173 extern void ipc_answerbox_init(answerbox_t *box); 174 extern void ipc_call_init(call_t *call); 175 extern void ipc_forward(call_t *call, answerbox_t *newbox,answerbox_t *oldbox); 174 extern void ipc_call_static_init(call_t *call); 176 175 extern void task_print_list(void); 176 extern void ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox); 177 177 178 178 extern answerbox_t *ipc_phone_0; -
generic/include/ipc/ipcrsc.h
r81c4c6da rba81cab 31 31 32 32 call_t * get_call(__native callid); 33 phone_t * get_phone_and_lock(__native phoneid);34 33 int phone_alloc(void); 35 34 void phone_dealloc(int phoneid); -
generic/src/ipc/ipc.c
r81c4c6da rba81cab 50 50 static slab_cache_t *ipc_call_slab; 51 51 52 /* Initialize new call */ 53 static void _ipc_call_init(call_t *call) 54 { 55 memsetb((__address)call, sizeof(*call), 0); 56 call->callerbox = &TASK->answerbox; 57 call->sender = TASK; 58 } 59 52 60 /** Allocate & initialize call structure 53 61 * … … 60 68 61 69 call = slab_alloc(ipc_call_slab, 0); 62 memsetb((__address)call, sizeof(*call), 0); 63 call->callerbox = &TASK->answerbox; 64 call->sender = TASK; 70 _ipc_call_init(call); 65 71 66 72 return call; … … 68 74 69 75 /** Initialize allocated call */ 70 void ipc_call_init(call_t *call) 71 { 72 call->callerbox = &TASK->answerbox; 73 call->flags = IPC_CALL_STATIC_ALLOC; 74 call->sender = TASK; 76 void ipc_call_static_init(call_t *call) 77 { 78 _ipc_call_init(call); 79 call->flags |= IPC_CALL_STATIC_ALLOC; 75 80 } 76 81 … … 97 102 void ipc_phone_connect(phone_t *phone, answerbox_t *box) 98 103 { 104 spinlock_lock(&phone->lock); 105 99 106 ASSERT(!phone->callee); 100 107 phone->busy = 1; … … 104 111 list_append(&phone->list, &box->connected_phones); 105 112 spinlock_unlock(&box->lock); 113 114 spinlock_unlock(&phone->lock); 106 115 } 107 116 … … 115 124 } 116 125 117 /** Disconnect phone from answerbox */ 126 /** Disconnect phone from answerbox 127 * 128 * It is allowed to call disconnect on already disconnected phone\ 129 */ 118 130 void ipc_phone_destroy(phone_t *phone) 119 131 { … … 122 134 ASSERT(box); 123 135 124 spinlock_lock(&box->lock); 125 list_remove(&phone->list); 126 spinlock_unlock(&box->lock); 136 spinlock_lock(&phone->lock); 137 spinlock_lock(&box->lock); 138 139 if (phone->callee) { 140 list_remove(&phone->list); 141 phone->callee = NULL; 142 } 143 144 spinlock_unlock(&box->lock); 145 spinlock_unlock(&phone->lock); 127 146 } 128 147 … … 141 160 } 142 161 162 /** Answer message that was not dispatched and is not entered in 163 * any queue 164 */ 165 static void _ipc_answer_free_call(call_t *call) 166 { 167 answerbox_t *callerbox = call->callerbox; 168 169 call->flags &= ~IPC_CALL_DISPATCHED; 170 call->flags |= IPC_CALL_ANSWERED; 171 172 spinlock_lock(&callerbox->lock); 173 list_append(&call->list, &callerbox->answers); 174 spinlock_unlock(&callerbox->lock); 175 waitq_wakeup(&callerbox->wq, 0); 176 } 177 178 /** Answer message, that is in callee queue 179 * 180 * @param box Answerbox that is answering the message 181 * @param call Modified request that is being sent back 182 */ 183 void ipc_answer(answerbox_t *box, call_t *call) 184 { 185 /* Remove from active box */ 186 spinlock_lock(&box->lock); 187 list_remove(&call->list); 188 spinlock_unlock(&box->lock); 189 /* Send back answer */ 190 _ipc_answer_free_call(call); 191 } 192 143 193 /** Send a asynchronous request using phone to answerbox 144 194 * … … 148 198 void ipc_call(phone_t *phone, call_t *call) 149 199 { 150 answerbox_t *box = phone->callee; 151 152 ASSERT(box); 200 answerbox_t *box; 201 202 spinlock_lock(&phone->lock); 203 box = phone->callee; 204 if (!box) { 205 /* Trying to send over disconnected phone */ 206 IPC_SET_RETVAL(call->data, ENOENT); 207 _ipc_answer_free_call(call); 208 return; 209 } 153 210 154 211 spinlock_lock(&box->lock); … … 156 213 spinlock_unlock(&box->lock); 157 214 waitq_wakeup(&box->wq, 0); 215 216 spinlock_unlock(&phone->lock); 158 217 } 159 218 … … 164 223 * @param oldbox Old answerbox 165 224 */ 166 void ipc_forward(call_t *call, answerbox_t *newbox, answerbox_t *oldbox)225 void ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox) 167 226 { 168 227 spinlock_lock(&oldbox->lock); … … 170 229 spinlock_unlock(&oldbox->lock); 171 230 172 spinlock_lock(&newbox->lock); 173 list_append(&call->list, &newbox->calls); 174 spinlock_lock(&newbox->lock); 175 waitq_wakeup(&newbox->wq, 0); 176 } 177 178 /** Answer message back to phone 179 * 180 * @param box Answerbox that is answering the message 181 * @param request Modified request that is being sent back 182 */ 183 void ipc_answer(answerbox_t *box, call_t *request) 184 { 185 answerbox_t *callerbox = request->callerbox; 186 187 request->flags &= ~IPC_CALL_DISPATCHED; 188 request->flags |= IPC_CALL_ANSWERED; 189 190 spinlock_lock(&box->lock); 191 list_remove(&request->list); 192 spinlock_unlock(&box->lock); 193 194 spinlock_lock(&callerbox->lock); 195 list_append(&request->list, &callerbox->answers); 196 spinlock_unlock(&callerbox->lock); 197 waitq_wakeup(&callerbox->wq, 0); 198 } 231 ipc_call(newphone, call); 232 } 233 199 234 200 235 /** Wait for phone call -
generic/src/ipc/ipcrsc.c
r81c4c6da rba81cab 38 38 * - answer message to phone 39 39 * 40 * Locking strategy 41 * 42 * - To use a phone, disconnect a phone etc., the phone must be 43 * first locked and then checked that it is connected 44 * - To connect an allocated phone it need not be locked (assigning 45 * pointer is atomic on all platforms) 46 * 47 * - To find an empty phone slot, the TASK must be locked 48 * - To answer a message, the answerbox must be locked 49 * - The locking of phone and answerbox is done at the ipc_ level. 50 * It is perfectly correct to pass unconnected phone to these functions 51 * and proper reply will be generated. 52 * 53 * - There may be objection that a race may occur when the syscall finds 54 * an appropriate call and before executing ipc_send, the phone call might 55 * be disconnected and connected elsewhere. As there is no easy solution, 56 * the application will be notified by an 'PHONE_DISCONNECTED' message 57 * and the phone will not be allocated before the application notifies 58 * the kernel subsystem that it does not have any pending calls regarding 59 * this phone call. 60 * 61 * Locking order 62 * 63 * There are 2 possibilities 64 * - first phone, then answerbox 65 * + Easy locking on calls 66 * - Very hard traversing list of phones when disconnecting because 67 * the phones may disconnect during traversal of list of connected phones. 68 * The only possibility is try_lock with restart of list traversal. 69 * 70 * - first answerbox, then phone(s) 71 * + Easy phone disconnect 72 * - Multiple checks needed when sending message 73 * 74 * Because the answerbox destroyal is much less frequent operation, 75 * the first method is chosen. 76 * 77 * Cleanup strategy 78 * 79 * 1) Disconnect all phones. 80 * * Send message 'PHONE_DISCONNECTED' to the target application 81 * - Once all phones are disconnected, no further calls can arrive 82 * 83 * 2) Answer all messages in 'calls' and 'dispatched_calls' queues with 84 * appropriate error code. 85 * 86 * 3) Wait for all async answers to arrive 87 * Alternatively - we might try to invalidate all messages by setting some 88 * flag, that would dispose of the message once it is answered. This 89 * would need to link all calls in one big list, which we don't currently 90 * do. 91 * 40 92 * 41 93 */ … … 57 109 /* TODO: locking of call, ripping it from dispatched calls etc. */ 58 110 return (call_t *) callid; 59 }60 61 /** Return pointer to phone identified by phoneid or NULL if non-existent */62 phone_t * get_phone_and_lock(__native phoneid)63 {64 phone_t *phone;65 66 if (phoneid >= IPC_MAX_PHONES)67 return NULL;68 69 phone = &TASK->phones[phoneid];70 spinlock_lock(&phone->lock);71 if (!phone->callee) {72 spinlock_unlock(&phone->lock);73 return NULL;74 }75 /* TODO... */76 spinlock_unlock(&phone->lock);77 return phone;78 111 } 79 112 … … 112 145 } 113 146 147 /** Connect phone to a given answerbox 148 * 149 * @param phoneid The slot that will be connected 150 * 151 * The procedure _enforces_ that the user first marks the phone 152 * busy (e.g. via phone_alloc) and then connects the phone, otherwise 153 * race condition may appear. 154 */ 114 155 void phone_connect(int phoneid, answerbox_t *box) 115 156 { 116 157 phone_t *phone = &TASK->phones[phoneid]; 117 158 159 ASSERT(phone->busy); 118 160 ipc_phone_connect(phone, box); 119 161 } -
generic/src/ipc/sysipc.c
r81c4c6da rba81cab 47 47 * 48 48 */ 49 50 #define GET_CHECK_PHONE(phone,phoneid,err) { \ 51 if (phoneid > IPC_MAX_PHONES) { err; } \ 52 phone = &TASK->phones[phoneid]; \ 53 } 54 49 55 50 56 /** Return true if the method is a system method */ … … 151 157 return EPERM; 152 158 153 phone = get_phone_and_lock(phoneid); 154 if (!phone) 155 return ENOENT; 156 157 ipc_call_init(&call); 159 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 160 161 ipc_call_static_init(&call); 158 162 IPC_SET_METHOD(call.data, method); 159 163 IPC_SET_ARG1(call.data, arg1); … … 173 177 phone_t *phone; 174 178 175 ipc_call_ init(&call);179 ipc_call_static_init(&call); 176 180 copy_from_uspace(&call.data, question, sizeof(call.data)); 177 181 … … 179 183 return EPERM; 180 184 181 phone = get_phone_and_lock(phoneid); 182 if (!phone) 183 return ENOENT; 185 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 184 186 185 187 ipc_call_sync(phone, &call); … … 220 222 return IPC_CALLRET_TEMPORARY; 221 223 222 phone = get_phone_and_lock(phoneid); 223 if (!phone) 224 return IPC_CALLRET_FATAL; 224 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 225 225 226 226 call = ipc_call_alloc(); … … 246 246 return IPC_CALLRET_TEMPORARY; 247 247 248 phone = get_phone_and_lock(phoneid); 249 if (!phone) 250 return IPC_CALLRET_FATAL; 248 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 251 249 252 250 call = ipc_call_alloc(); … … 280 278 return ENOENT; 281 279 282 phone = get_phone_and_lock(phoneid); 283 if (!phone) { 280 GET_CHECK_PHONE(phone, phoneid, { 284 281 IPC_SET_RETVAL(call->data, EFORWARD); 285 282 ipc_answer(&TASK->answerbox, call); 286 283 return ENOENT; 287 } 284 }); 288 285 289 286 if (!is_forwardable(IPC_GET_METHOD(call->data))) { … … 304 301 } 305 302 306 ipc_forward(call, phone ->callee, &TASK->answerbox);303 ipc_forward(call, phone, &TASK->answerbox); 307 304 308 305 return 0; … … 372 369 phone_t *phone; 373 370 374 ipc_call_ init(&call);371 ipc_call_static_init(&call); 375 372 IPC_SET_METHOD(call.data, IPC_M_CONNECTTOME); 376 373 IPC_SET_ARG1(call.data, arg1); 377 374 IPC_SET_ARG2(call.data, arg2); 378 375 379 phone = get_phone_and_lock(phoneid); 380 if (!phone) 381 return ENOENT; 376 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 382 377 383 378 ipc_call_sync(phone, &call); … … 402 397 int newphid; 403 398 404 phone = get_phone_and_lock(phoneid); 405 if (!phone) 406 return ENOENT; 399 GET_CHECK_PHONE(phone, phoneid, return ENOENT); 407 400 408 401 newphid = phone_alloc(); … … 410 403 return ELIMIT; 411 404 412 ipc_call_ init(&call);405 ipc_call_static_init(&call); 413 406 IPC_SET_METHOD(call.data, IPC_M_CONNECTMETO); 414 407 IPC_SET_ARG1(call.data, arg1);
Note:
See TracChangeset
for help on using the changeset viewer.