Changes in kernel/generic/src/ipc/ipc.c [97b8ca9:466e95f7] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipc.c
r97b8ca9 r466e95f7 59 59 #include <ipc/irq.h> 60 60 61 static void ipc_forget_call(call_t *);62 63 61 /** Open channel that is assigned automatically to new tasks */ 64 62 answerbox_t *ipc_phone_0 = NULL; … … 79 77 call->forget = false; 80 78 call->sender = NULL; 81 call->callerbox = NULL;82 79 call->buffer = NULL; 83 80 } … … 188 185 phone->state = IPC_PHONE_FREE; 189 186 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 it223 * 2) we manage to forget the call before it gets answered224 */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 to235 * 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 uninterruptibly249 * 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;259 187 } 260 188 … … 292 220 spinlock_unlock(&call->forget_lock); 293 221 294 answerbox_t *callerbox = call->callerbox ? call->callerbox : 295 &call->sender->answerbox; 222 answerbox_t *callerbox = &call->sender->answerbox; 296 223 bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox)); 297 224 … … 328 255 } 329 256 330 static void _ipc_call_actions_internal(phone_t *phone, call_t *call, 331 bool preforget) 257 static void _ipc_call_actions_internal(phone_t *phone, call_t *call) 332 258 { 333 259 task_t *caller = phone->caller; 334 260 261 atomic_inc(&phone->active_calls); 335 262 call->caller_phone = phone; 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 } 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); 347 269 348 270 call->data.phone = phone; … … 362 284 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err) 363 285 { 364 _ipc_call_actions_internal(phone, call , false);286 _ipc_call_actions_internal(phone, call); 365 287 IPC_SET_RETVAL(call->data, err); 366 288 _ipc_answer_free_call(call, false); … … 369 291 /** Unsafe unchecking version of ipc_call. 370 292 * 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) 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) 379 299 { 380 300 task_t *caller = phone->caller; … … 386 306 387 307 if (!(call->flags & IPC_CALL_FORWARDED)) 388 _ipc_call_actions_internal(phone, call , preforget);308 _ipc_call_actions_internal(phone, call); 389 309 390 310 irq_spinlock_lock(&box->lock, true); … … 420 340 421 341 answerbox_t *box = phone->callee; 422 _ipc_call(phone, box, call , false);342 _ipc_call(phone, box, call); 423 343 424 344 mutex_unlock(&phone->lock); … … 458 378 call->request_method = IPC_M_PHONE_HUNGUP; 459 379 call->flags |= IPC_CALL_DISCARD_ANSWER; 460 _ipc_call(phone, box, call , false);380 _ipc_call(phone, box, call); 461 381 } 462 382 … … 617 537 phone_t *phone; 618 538 DEADLOCK_PROBE_INIT(p_phonelck); 539 540 call_t *call = notify_box ? ipc_call_alloc(0) : NULL; 619 541 620 542 /* Disconnect all phones connected to our answerbox */ … … 637 559 638 560 if (notify_box) { 639 task_hold(phone->caller);640 561 mutex_unlock(&phone->lock); 641 562 irq_spinlock_unlock(&box->lock, true); 642 563 564 // FIXME: phone can become deallocated at any time now 565 643 566 /* 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. 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. 649 571 */ 650 call_t *call = ipc_call_alloc(0);651 572 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP); 652 573 call->request_method = IPC_M_PHONE_HUNGUP; 653 574 call->flags |= IPC_CALL_DISCARD_ANSWER; 654 _ipc_call(phone, box, call, true); 655 656 task_release(phone->caller); 575 _ipc_call(phone, box, call); 576 577 /* Allocate another call in advance */ 578 call = ipc_call_alloc(0); 657 579 658 580 /* Must start again */ … … 664 586 665 587 irq_spinlock_unlock(&box->lock, true); 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); 588 589 /* Free unused call */ 590 if (call) 591 ipc_call_free(call); 696 592 } 697 593 … … 724 620 } 725 621 726 ipc_forget_call(call); 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); 727 645 728 646 goto restart; … … 837 755 ipc_cleanup_call_list(&TASK->answerbox, 838 756 &TASK->answerbox.dispatched_calls); 839 757 840 758 ipc_forget_all_active_calls(); 841 759 ipc_wait_for_all_answered_calls(); … … 856 774 static void ipc_print_call_list(list_t *list) 857 775 { 858 list_foreach(*list, ab_link, call_t, call) { 776 list_foreach(*list, cur) { 777 call_t *call = list_get_instance(cur, call_t, ab_link); 778 859 779 #ifdef __32_BITS__ 860 780 printf("%10p ", call);
Note:
See TracChangeset
for help on using the changeset viewer.