Changes in kernel/generic/src/ipc/ipc.c [c33f39f:cd529c4] in mainline
- File:
-
- 1 edited
-
kernel/generic/src/ipc/ipc.c (modified) (20 diffs)
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/ipc.c
rc33f39f rcd529c4 45 45 #include <ipc/kbox.h> 46 46 #include <ipc/event.h> 47 #include <ipc/sysipc_ops.h>48 #include <ipc/sysipc_priv.h>49 47 #include <errno.h> 50 48 #include <mm/slab.h> … … 73 71 { 74 72 memsetb(call, sizeof(*call), 0); 75 spinlock_initialize(&call->forget_lock, "forget_lock");76 call->active = false;77 call->forget = false;78 73 call->sender = TASK; 79 74 call->buffer = NULL; … … 137 132 * @param phone Initialized phone structure. 138 133 * @param box Initialized answerbox structure. 139 * @return True if the phone was connected, false otherwise. 140 */ 141 bool ipc_phone_connect(phone_t *phone, answerbox_t *box) 142 { 143 bool active; 144 134 * 135 */ 136 void ipc_phone_connect(phone_t *phone, answerbox_t *box) 137 { 145 138 mutex_lock(&phone->lock); 139 140 phone->state = IPC_PHONE_CONNECTED; 141 phone->callee = box; 142 146 143 irq_spinlock_lock(&box->lock, true); 147 148 active = box->active; 149 if (active) { 150 phone->state = IPC_PHONE_CONNECTED; 151 phone->callee = box; 152 list_append(&phone->link, &box->connected_phones); 153 } 154 144 list_append(&phone->link, &box->connected_phones); 155 145 irq_spinlock_unlock(&box->lock, true); 146 156 147 mutex_unlock(&phone->lock); 157 158 return active;159 148 } 160 149 … … 178 167 * 179 168 */ 180 void _ipc_answer_free_call(call_t *call, bool selflocked) 181 { 169 static void _ipc_answer_free_call(call_t *call, bool selflocked) 170 { 171 answerbox_t *callerbox = &call->sender->answerbox; 172 bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox)); 173 182 174 /* Count sent answer */ 183 175 irq_spinlock_lock(&TASK->lock, true); 184 176 TASK->ipc_info.answer_sent++; 185 177 irq_spinlock_unlock(&TASK->lock, true); 186 187 spinlock_lock(&call->forget_lock); 188 if (call->forget) { 189 /* This is a forgotten call and call->sender is not valid. */ 190 spinlock_unlock(&call->forget_lock); 191 ipc_call_free(call); 192 return; 193 } else { 194 /* 195 * If the call is still active, i.e. it was answered 196 * in a non-standard way, remove the call from the 197 * sender's active call list. 198 */ 199 if (call->active) { 200 spinlock_lock(&call->sender->active_calls_lock); 201 list_remove(&call->ta_link); 202 spinlock_unlock(&call->sender->active_calls_lock); 178 179 call->flags |= IPC_CALL_ANSWERED; 180 181 if (call->flags & IPC_CALL_FORWARDED) { 182 if (call->caller_phone) { 183 /* Demasquerade the caller phone. */ 184 call->data.phone = call->caller_phone; 203 185 } 204 186 } 205 spinlock_unlock(&call->forget_lock); 206 207 answerbox_t *callerbox = &call->sender->answerbox; 208 bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox)); 209 210 call->flags |= IPC_CALL_ANSWERED; 211 187 212 188 call->data.task_id = TASK->taskid; 213 189 … … 215 191 irq_spinlock_lock(&callerbox->lock, true); 216 192 217 list_append(&call-> ab_link, &callerbox->answers);193 list_append(&call->link, &callerbox->answers); 218 194 219 195 if (do_lock) … … 233 209 /* Remove from active box */ 234 210 irq_spinlock_lock(&box->lock, true); 235 list_remove(&call-> ab_link);211 list_remove(&call->link); 236 212 irq_spinlock_unlock(&box->lock, true); 237 213 … … 252 228 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err) 253 229 { 254 call->caller_phone = phone;255 230 call->data.phone = phone; 256 231 atomic_inc(&phone->active_calls); 257 258 spinlock_lock(&TASK->active_calls_lock);259 list_append(&call->ta_link, &TASK->active_calls);260 spinlock_unlock(&TASK->active_calls_lock);261 262 232 IPC_SET_RETVAL(call->data, err); 263 233 _ipc_answer_free_call(call, false); … … 280 250 if (!(call->flags & IPC_CALL_FORWARDED)) { 281 251 atomic_inc(&phone->active_calls); 282 283 call->caller_phone = phone;284 call->active = true;285 286 spinlock_lock(&TASK->active_calls_lock);287 list_append(&call->ta_link, &TASK->active_calls);288 spinlock_unlock(&TASK->active_calls_lock);289 290 252 call->data.phone = phone; 291 253 call->data.task_id = TASK->taskid; … … 293 255 294 256 irq_spinlock_lock(&box->lock, true); 295 list_append(&call-> ab_link, &box->calls);257 list_append(&call->link, &box->calls); 296 258 irq_spinlock_unlock(&box->lock, true); 297 259 … … 313 275 if (phone->state != IPC_PHONE_CONNECTED) { 314 276 mutex_unlock(&phone->lock); 315 if (!(call->flags & IPC_CALL_FORWARDED)) { 277 if (call->flags & IPC_CALL_FORWARDED) { 278 IPC_SET_RETVAL(call->data, EFORWARD); 279 _ipc_answer_free_call(call, false); 280 } else { 316 281 if (phone->state == IPC_PHONE_HUNGUP) 317 282 ipc_backsend_err(phone, call, EHANGUP); … … 391 356 TASK->ipc_info.forwarded++; 392 357 irq_spinlock_pass(&TASK->lock, &oldbox->lock); 393 list_remove(&call-> ab_link);358 list_remove(&call->link); 394 359 irq_spinlock_unlock(&oldbox->lock, true); 395 360 396 361 if (mode & IPC_FF_ROUTE_FROM_ME) { 362 if (!call->caller_phone) 363 call->caller_phone = call->data.phone; 397 364 call->data.phone = newphone; 398 365 call->data.task_id = TASK->taskid; … … 439 406 440 407 request = list_get_instance(list_first(&box->irq_notifs), 441 call_t, ab_link);442 list_remove(&request-> ab_link);408 call_t, link); 409 list_remove(&request->link); 443 410 444 411 irq_spinlock_unlock(&box->irq_lock, false); … … 449 416 /* Handle asynchronous answers */ 450 417 request = list_get_instance(list_first(&box->answers), 451 call_t, ab_link);452 list_remove(&request-> ab_link);453 atomic_dec(&request-> caller_phone->active_calls);418 call_t, link); 419 list_remove(&request->link); 420 atomic_dec(&request->data.phone->active_calls); 454 421 } else if (!list_empty(&box->calls)) { 455 422 /* Count received call */ … … 458 425 /* Handle requests */ 459 426 request = list_get_instance(list_first(&box->calls), 460 call_t, ab_link);461 list_remove(&request-> ab_link);427 call_t, link); 428 list_remove(&request->link); 462 429 463 430 /* Append request to dispatch queue */ 464 list_append(&request-> ab_link, &box->dispatched_calls);431 list_append(&request->link, &box->dispatched_calls); 465 432 } else { 466 433 /* This can happen regularly after ipc_cleanup */ … … 482 449 /** Answer all calls from list with EHANGUP answer. 483 450 * 484 * @param box Answerbox with the list.485 451 * @param lst Head of the list to be cleaned up. 486 * /487 void ipc_cleanup_call_list(answerbox_t *box, list_t *lst) 488 { 489 irq_spinlock_lock(&box->lock, true); 452 * 453 */ 454 void ipc_cleanup_call_list(list_t *lst) 455 { 490 456 while (!list_empty(lst)) { 491 call_t *call = list_get_instance(list_first(lst), call_t, 492 ab_link); 493 494 list_remove(&call->ab_link); 495 496 irq_spinlock_unlock(&box->lock, true); 497 498 ipc_data_t old = call->data; 457 call_t *call = list_get_instance(list_first(lst), call_t, link); 458 if (call->buffer) 459 free(call->buffer); 460 461 list_remove(&call->link); 462 499 463 IPC_SET_RETVAL(call->data, EHANGUP); 500 answer_preprocess(call, &old);501 464 _ipc_answer_free_call(call, true); 502 503 irq_spinlock_lock(&box->lock, true); 504 } 505 irq_spinlock_unlock(&box->lock, true); 465 } 506 466 } 507 467 … … 569 529 } 570 530 571 static void ipc_forget_all_active_calls(void)572 {573 call_t *call;574 575 restart:576 spinlock_lock(&TASK->active_calls_lock);577 if (list_empty(&TASK->active_calls)) {578 /*579 * We are done, there are no more active calls.580 * Nota bene: there may still be answers waiting for pick up.581 */582 spinlock_unlock(&TASK->active_calls_lock);583 return;584 }585 586 call = list_get_instance(list_first(&TASK->active_calls), call_t,587 ta_link);588 589 if (!spinlock_trylock(&call->forget_lock)) {590 /*591 * Avoid deadlock and let async_answer() or592 * _ipc_answer_free_call() win the race to dequeue the first593 * call on the list.594 */595 spinlock_unlock(&TASK->active_calls_lock);596 goto restart;597 }598 599 /*600 * Forget the call and donate it to the task which holds up the answer.601 */602 603 call->forget = true;604 call->sender = NULL;605 list_remove(&call->ta_link);606 607 spinlock_unlock(&call->forget_lock);608 spinlock_unlock(&TASK->active_calls_lock);609 610 atomic_dec(&call->caller_phone->active_calls);611 612 sysipc_ops_t *ops = sysipc_ops_get(call->request_method);613 if (ops->request_forget)614 ops->request_forget(call);615 616 goto restart;617 }618 619 /** Wait for all answers to asynchronous calls to arrive. */620 static void ipc_wait_for_all_answered_calls(void)621 {622 call_t *call;623 size_t i;624 625 restart:626 /*627 * Go through all phones, until they are all free.628 * Locking is needed as there may be connection handshakes in progress.629 */630 for (i = 0; i < IPC_MAX_PHONES; i++) {631 phone_t *phone = &TASK->phones[i];632 633 mutex_lock(&phone->lock);634 if ((phone->state == IPC_PHONE_HUNGUP) &&635 (atomic_get(&phone->active_calls) == 0)) {636 phone->state = IPC_PHONE_FREE;637 phone->callee = NULL;638 }639 640 /*641 * We might have had some IPC_PHONE_CONNECTING phones at the642 * beginning of ipc_cleanup(). Depending on whether these were643 * forgotten or answered, they will eventually enter the644 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.645 * In the latter case, the other side may slam the open phones646 * at any time, in which case we will get an IPC_PHONE_SLAMMED647 * phone.648 */649 if ((phone->state == IPC_PHONE_CONNECTED) ||650 (phone->state == IPC_PHONE_SLAMMED)) {651 mutex_unlock(&phone->lock);652 ipc_phone_hangup(phone);653 /*654 * Now there may be one extra active call, which needs655 * to be forgotten.656 */657 ipc_forget_all_active_calls();658 goto restart;659 }660 661 /*662 * If the hangup succeeded, it has sent a HANGUP message, the663 * IPC is now in HUNGUP state, we wait for the reply to come664 */665 if (phone->state != IPC_PHONE_FREE) {666 mutex_unlock(&phone->lock);667 break;668 }669 670 mutex_unlock(&phone->lock);671 }672 673 /* Got into cleanup */674 if (i == IPC_MAX_PHONES)675 return;676 677 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,678 SYNCH_FLAGS_NONE);679 ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));680 ipc_call_free(call);681 goto restart;682 }683 684 531 /** Clean up all IPC communication of the current task. 685 532 * … … 690 537 void ipc_cleanup(void) 691 538 { 692 /*693 * Mark the answerbox as inactive.694 *695 * The main purpose for doing this is to prevent any pending callback696 * connections from getting established beyond this point.697 */698 irq_spinlock_lock(&TASK->answerbox.lock, true);699 TASK->answerbox.active = false;700 irq_spinlock_unlock(&TASK->answerbox.lock, true);701 702 539 /* Disconnect all our phones ('ipc_phone_hangup') */ 703 for (size_t i = 0; i < IPC_MAX_PHONES; i++) 540 size_t i; 541 for (i = 0; i < IPC_MAX_PHONES; i++) 704 542 ipc_phone_hangup(&TASK->phones[i]); 705 543 … … 719 557 720 558 /* Answer all messages in 'calls' and 'dispatched_calls' queues */ 721 ipc_cleanup_call_list(&TASK->answerbox, 722 &TASK->answerbox.dispatched_calls); 723 ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls); 724 725 ipc_forget_all_active_calls(); 726 ipc_wait_for_all_answered_calls(); 559 irq_spinlock_lock(&TASK->answerbox.lock, true); 560 ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); 561 ipc_cleanup_call_list(&TASK->answerbox.calls); 562 irq_spinlock_unlock(&TASK->answerbox.lock, true); 563 564 /* Wait for all answers to asynchronous calls to arrive */ 565 while (true) { 566 /* 567 * Go through all phones, until they are all FREE 568 * Locking is not needed, no one else should modify 569 * it when we are in cleanup 570 */ 571 for (i = 0; i < IPC_MAX_PHONES; i++) { 572 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 573 atomic_get(&TASK->phones[i].active_calls) == 0) { 574 TASK->phones[i].state = IPC_PHONE_FREE; 575 TASK->phones[i].callee = NULL; 576 } 577 578 /* 579 * Just for sure, we might have had some 580 * IPC_PHONE_CONNECTING phones 581 */ 582 if (TASK->phones[i].state == IPC_PHONE_CONNECTED) 583 ipc_phone_hangup(&TASK->phones[i]); 584 585 /* 586 * If the hangup succeeded, it has sent a HANGUP 587 * message, the IPC is now in HUNGUP state, we 588 * wait for the reply to come 589 */ 590 591 if (TASK->phones[i].state != IPC_PHONE_FREE) 592 break; 593 } 594 595 /* Got into cleanup */ 596 if (i == IPC_MAX_PHONES) 597 break; 598 599 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 600 SYNCH_FLAGS_NONE); 601 ASSERT((call->flags & IPC_CALL_ANSWERED) || 602 (call->flags & IPC_CALL_NOTIF)); 603 604 ipc_call_free(call); 605 } 727 606 } 728 607 … … 736 615 ipc_answerbox_slab = slab_cache_create("answerbox_t", 737 616 sizeof(answerbox_t), 0, NULL, NULL, 0); 738 }739 740 741 static void ipc_print_call_list(list_t *list)742 {743 list_foreach(*list, cur) {744 call_t *call = list_get_instance(cur, call_t, ab_link);745 746 #ifdef __32_BITS__747 printf("%10p ", call);748 #endif749 750 #ifdef __64_BITS__751 printf("%18p ", call);752 #endif753 754 spinlock_lock(&call->forget_lock);755 756 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun757 " %-6" PRIun " %-6" PRIun " %-7x",758 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),759 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),760 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),761 call->flags);762 763 if (call->forget) {764 printf(" ? (call forgotten)\n");765 } else {766 printf(" %" PRIu64 " (%s)\n",767 call->sender->taskid, call->sender->name);768 }769 770 spinlock_unlock(&call->forget_lock);771 }772 617 } 773 618 … … 843 688 844 689 printf(" --- incomming calls ---\n"); 845 ipc_print_call_list(&task->answerbox.calls); 690 list_foreach(task->answerbox.calls, cur) { 691 call_t *call = list_get_instance(cur, call_t, link); 692 693 #ifdef __32_BITS__ 694 printf("%10p ", call); 695 #endif 696 697 #ifdef __64_BITS__ 698 printf("%18p ", call); 699 #endif 700 701 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 702 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 703 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 704 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 705 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 706 call->flags, call->sender->taskid, call->sender->name); 707 } 708 846 709 printf(" --- dispatched calls ---\n"); 847 ipc_print_call_list(&task->answerbox.dispatched_calls); 710 list_foreach(task->answerbox.dispatched_calls, cur) { 711 call_t *call = list_get_instance(cur, call_t, link); 712 713 #ifdef __32_BITS__ 714 printf("%10p ", call); 715 #endif 716 717 #ifdef __64_BITS__ 718 printf("%18p ", call); 719 #endif 720 721 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 722 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 723 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 724 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 725 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 726 call->flags, call->sender->taskid, call->sender->name); 727 } 728 848 729 printf(" --- incoming answers ---\n"); 849 ipc_print_call_list(&task->answerbox.answers); 730 list_foreach(task->answerbox.answers, cur) { 731 call_t *call = list_get_instance(cur, call_t, link); 732 733 #ifdef __32_BITS__ 734 printf("%10p ", call); 735 #endif 736 737 #ifdef __64_BITS__ 738 printf("%18p ", call); 739 #endif 740 741 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun 742 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n", 743 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data), 744 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), 745 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), 746 call->flags, call->sender->taskid, call->sender->name); 747 } 850 748 851 749 irq_spinlock_unlock(&task->answerbox.lock, false);
Note:
See TracChangeset
for help on using the changeset viewer.
