Changes in kernel/generic/src/ipc/ipc.c [feeac0d:97b8ca9] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipc.c
rfeeac0d r97b8ca9 59 59 #include <ipc/irq.h> 60 60 61 static void ipc_forget_call(call_t *); 62 61 63 /** Open channel that is assigned automatically to new tasks */ 62 64 answerbox_t *ipc_phone_0 = NULL; … … 77 79 call->forget = false; 78 80 call->sender = NULL; 81 call->callerbox = NULL; 79 82 call->buffer = NULL; 80 83 } … … 185 188 phone->state = IPC_PHONE_FREE; 186 189 atomic_set(&phone->active_calls, 0); 190 } 191 192 /** Helper function to facilitate synchronous calls. 193 * 194 * @param phone Destination kernel phone structure. 195 * @param request Call structure with request. 196 * 197 * @return EOK on success or a negative error code. 198 * 199 */ 200 int ipc_call_sync(phone_t *phone, call_t *request) 201 { 202 answerbox_t *mybox = slab_alloc(ipc_answerbox_slab, 0); 203 ipc_answerbox_init(mybox, TASK); 204 205 /* We will receive data in a special box. */ 206 request->callerbox = mybox; 207 208 int rc = ipc_call(phone, request); 209 if (rc != EOK) { 210 slab_free(ipc_answerbox_slab, mybox); 211 return rc; 212 } 213 214 call_t *answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT, 215 SYNCH_FLAGS_INTERRUPTIBLE); 216 if (!answer) { 217 218 /* 219 * The sleep was interrupted. 220 * 221 * There are two possibilities now: 222 * 1) the call gets answered before we manage to forget it 223 * 2) we manage to forget the call before it gets answered 224 */ 225 226 spinlock_lock(&request->forget_lock); 227 spinlock_lock(&TASK->active_calls_lock); 228 229 ASSERT(!request->forget); 230 231 bool answered = !request->active; 232 if (!answered) { 233 /* 234 * The call is not yet answered and we won the race to 235 * forget it. 236 */ 237 ipc_forget_call(request); /* releases locks */ 238 rc = EINTR; 239 240 } else { 241 spinlock_unlock(&TASK->active_calls_lock); 242 spinlock_unlock(&request->forget_lock); 243 } 244 245 if (answered) { 246 /* 247 * The other side won the race to answer the call. 248 * It is safe to wait for the answer uninterruptibly 249 * now. 250 */ 251 answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT, 252 SYNCH_FLAGS_NONE); 253 } 254 } 255 ASSERT(!answer || request == answer); 256 257 slab_free(ipc_answerbox_slab, mybox); 258 return rc; 187 259 } 188 260 … … 220 292 spinlock_unlock(&call->forget_lock); 221 293 222 answerbox_t *callerbox = &call->sender->answerbox; 294 answerbox_t *callerbox = call->callerbox ? call->callerbox : 295 &call->sender->answerbox; 223 296 bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox)); 224 297 … … 255 328 } 256 329 257 static void _ipc_call_actions_internal(phone_t *phone, call_t *call) 330 static void _ipc_call_actions_internal(phone_t *phone, call_t *call, 331 bool preforget) 258 332 { 259 333 task_t *caller = phone->caller; 260 334 261 atomic_inc(&phone->active_calls);262 335 call->caller_phone = phone; 263 call->sender = caller; 264 265 call->active = true; 266 spinlock_lock(&caller->active_calls_lock); 267 list_append(&call->ta_link, &caller->active_calls); 268 spinlock_unlock(&caller->active_calls_lock); 336 337 if (preforget) { 338 call->forget = true; 339 } else { 340 atomic_inc(&phone->active_calls); 341 call->sender = caller; 342 call->active = true; 343 spinlock_lock(&caller->active_calls_lock); 344 list_append(&call->ta_link, &caller->active_calls); 345 spinlock_unlock(&caller->active_calls_lock); 346 } 269 347 270 348 call->data.phone = phone; … … 284 362 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err) 285 363 { 286 _ipc_call_actions_internal(phone, call );364 _ipc_call_actions_internal(phone, call, false); 287 365 IPC_SET_RETVAL(call->data, err); 288 366 _ipc_answer_free_call(call, false); … … 291 369 /** Unsafe unchecking version of ipc_call. 292 370 * 293 * @param phone Phone structure the call comes from. 294 * @param box Destination answerbox structure. 295 * @param call Call structure with request. 296 * 297 */ 298 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) 371 * @param phone Phone structure the call comes from. 372 * @param box Destination answerbox structure. 373 * @param call Call structure with request. 374 * @param preforget If true, the call will be delivered already forgotten. 375 * 376 */ 377 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call, 378 bool preforget) 299 379 { 300 380 task_t *caller = phone->caller; … … 306 386 307 387 if (!(call->flags & IPC_CALL_FORWARDED)) 308 _ipc_call_actions_internal(phone, call );388 _ipc_call_actions_internal(phone, call, preforget); 309 389 310 390 irq_spinlock_lock(&box->lock, true); … … 340 420 341 421 answerbox_t *box = phone->callee; 342 _ipc_call(phone, box, call );422 _ipc_call(phone, box, call, false); 343 423 344 424 mutex_unlock(&phone->lock); … … 378 458 call->request_method = IPC_M_PHONE_HUNGUP; 379 459 call->flags |= IPC_CALL_DISCARD_ANSWER; 380 _ipc_call(phone, box, call );460 _ipc_call(phone, box, call, false); 381 461 } 382 462 … … 537 617 phone_t *phone; 538 618 DEADLOCK_PROBE_INIT(p_phonelck); 539 540 call_t *call = notify_box ? ipc_call_alloc(0) : NULL;541 619 542 620 /* Disconnect all phones connected to our answerbox */ … … 559 637 560 638 if (notify_box) { 639 task_hold(phone->caller); 561 640 mutex_unlock(&phone->lock); 562 641 irq_spinlock_unlock(&box->lock, true); 563 642 564 // FIXME: phone can become deallocated at any time now565 566 643 /* 567 * Send one message to the answerbox for each 568 * phone. Used to make sure the kbox thread 569 * wakes up after the last phone has been 570 * disconnected. 644 * Send one call to the answerbox for each phone. 645 * Used to make sure the kbox thread wakes up after 646 * the last phone has been disconnected. The call is 647 * forgotten upon sending, so the "caller" may cease 648 * to exist as soon as we release it. 571 649 */ 650 call_t *call = ipc_call_alloc(0); 572 651 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); 573 652 call->request_method = IPC_M_PHONE_HUNGUP; 574 653 call->flags |= IPC_CALL_DISCARD_ANSWER; 575 _ipc_call(phone, box, call); 576 577 /* Allocate another call in advance */ 578 call = ipc_call_alloc(0); 654 _ipc_call(phone, box, call, true); 655 656 task_release(phone->caller); 579 657 580 658 /* Must start again */ … … 586 664 587 665 irq_spinlock_unlock(&box->lock, true); 588 589 /* Free unused call */ 590 if (call) 591 ipc_call_free(call); 666 } 667 668 static void ipc_forget_call(call_t *call) 669 { 670 ASSERT(spinlock_locked(&TASK->active_calls_lock)); 671 ASSERT(spinlock_locked(&call->forget_lock)); 672 673 /* 674 * Forget the call and donate it to the task which holds up the answer. 675 */ 676 677 call->forget = true; 678 call->sender = NULL; 679 list_remove(&call->ta_link); 680 681 /* 682 * The call may be freed by _ipc_answer_free_call() before we are done 683 * with it; to avoid working with a destroyed call_t structure, we 684 * must hold a reference to it. 685 */ 686 ipc_call_hold(call); 687 688 spinlock_unlock(&call->forget_lock); 689 spinlock_unlock(&TASK->active_calls_lock); 690 691 atomic_dec(&call->caller_phone->active_calls); 692 693 SYSIPC_OP(request_forget, call); 694 695 ipc_call_release(call); 592 696 } 593 697 … … 620 724 } 621 725 622 /* 623 * Forget the call and donate it to the task which holds up the answer. 624 */ 625 626 call->forget = true; 627 call->sender = NULL; 628 list_remove(&call->ta_link); 629 630 /* 631 * The call may be freed by _ipc_answer_free_call() before we are done 632 * with it; to avoid working with a destroyed call_t structure, we 633 * must hold a reference to it. 634 */ 635 ipc_call_hold(call); 636 637 spinlock_unlock(&call->forget_lock); 638 spinlock_unlock(&TASK->active_calls_lock); 639 640 atomic_dec(&call->caller_phone->active_calls); 641 642 SYSIPC_OP(request_forget, call); 643 644 ipc_call_release(call); 726 ipc_forget_call(call); 645 727 646 728 goto restart; … … 755 837 ipc_cleanup_call_list(&TASK->answerbox, 756 838 &TASK->answerbox.dispatched_calls); 757 839 758 840 ipc_forget_all_active_calls(); 759 841 ipc_wait_for_all_answered_calls();
Note:
See TracChangeset
for help on using the changeset viewer.