Changeset 2405bb5 in mainline
- Timestamp:
- 2012-08-15T19:28:43Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7975433
- Parents:
- 691d8d8
- Location:
- kernel/generic
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/include/ipc/ipc.h
r691d8d8 r2405bb5 106 106 107 107 typedef struct { 108 /** Task link. */ 108 /** 109 * Task link. 110 * Valid only when the call is not forgotten. 111 * Protected by the task's active_calls_lock. 112 */ 109 113 link_t ta_link; 110 114 … … 113 117 114 118 unsigned int flags; 119 120 /** Protects the forget member. */ 121 SPINLOCK_DECLARE(forget_lock); 122 123 /** 124 * True if the caller 'forgot' this call and donated it to the callee. 125 * Forgotten calls are discarded upon answering (the answer is not 126 * delivered) and answered calls cannot be forgotten. Forgotten calls 127 * also do not figure on the task's active call list. 128 * 129 * We keep this separate from the flags so that it is not necessary 130 * to take a lock when accessing them. 131 */ 132 bool forget; 115 133 116 /** Identification of the caller. */ 134 /** 135 * Identification of the caller. 136 * Valid only when the call is not forgotten. 137 */ 117 138 struct task *sender; 118 139 -
kernel/generic/src/ipc/ipc.c
r691d8d8 r2405bb5 71 71 { 72 72 memsetb(call, sizeof(*call), 0); 73 spinlock_initialize(&call->forget_lock, "forget_lock"); 74 call->forget = false; 73 75 call->sender = TASK; 74 76 call->buffer = NULL; … … 161 163 } 162 164 165 /** Demasquerade the caller phone. */ 166 static void ipc_caller_phone_demasquerade(call_t *call) 167 { 168 if (call->flags & IPC_CALL_FORWARDED) { 169 if (call->caller_phone) { 170 call->data.phone = call->caller_phone; 171 } 172 } 173 } 174 163 175 /** Answer a message which was not dispatched and is not listed in any queue. 164 176 * … … 169 181 static void _ipc_answer_free_call(call_t *call, bool selflocked) 170 182 { 171 answerbox_t *callerbox = &call->sender->answerbox;172 bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));173 174 183 /* Count sent answer */ 175 184 irq_spinlock_lock(&TASK->lock, true); 176 185 TASK->ipc_info.answer_sent++; 177 186 irq_spinlock_unlock(&TASK->lock, true); 187 188 spinlock_lock(&call->forget_lock); 189 if (call->forget) { 190 /* This is a forgotten call and call->sender is not valid. */ 191 spinlock_unlock(&call->forget_lock); 192 /* TODO: free the call and its resources */ 193 return; 194 } else { 195 /* 196 * Hold the sender task so that it does not suddenly disappear 197 * while we are working with it. 198 */ 199 task_hold(call->sender); 200 201 /* 202 * Remove the call from the sender's active call list. 203 * We enforce this locking order so that any potential 204 * concurrently executing forget operation is forced to 205 * release its active_calls_lock and lose the race to 206 * forget this soon to be answered call. 207 */ 208 spinlock_lock(&call->sender->active_calls_lock); 209 list_remove(&call->ta_link); 210 spinlock_unlock(&call->sender->active_calls_lock); 211 } 212 spinlock_unlock(&call->forget_lock); 213 214 answerbox_t *callerbox = &call->sender->answerbox; 215 bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox)); 178 216 179 217 call->flags |= IPC_CALL_ANSWERED; 180 218 181 if (call->flags & IPC_CALL_FORWARDED) { 182 if (call->caller_phone) { 183 /* Demasquerade the caller phone. */ 184 call->data.phone = call->caller_phone; 185 } 186 } 187 188 /* 189 * Remove the call from the sender's active call list. 190 */ 191 spinlock_lock(&call->sender->active_calls_lock); 192 list_remove(&call->ta_link); 193 spinlock_unlock(&call->sender->active_calls_lock); 219 ipc_caller_phone_demasquerade(call); 194 220 195 221 call->data.task_id = TASK->taskid; … … 204 230 205 231 waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); 232 233 task_release(call->sender); 206 234 } 207 235 … … 547 575 } 548 576 577 static void ipc_forget_all_active_calls(void) 578 { 579 call_t *call; 580 581 restart: 582 spinlock_lock(&TASK->active_calls_lock); 583 if (list_empty(&TASK->active_calls)) { 584 /* 585 * We are done, there are no more active calls. 586 * Nota bene: there may still be answers waiting for pick up. 587 */ 588 spinlock_unlock(&TASK->active_calls_lock); 589 return; 590 } 591 592 call = list_get_instance(list_first(&TASK->active_calls), call_t, 593 ta_link); 594 595 if (!spinlock_trylock(&call->forget_lock)) { 596 /* 597 * Avoid deadlock and let _ipc_answer_free_call() win the race 598 * to answer the first call on the list. 599 */ 600 spinlock_unlock(&TASK->active_calls_lock); 601 goto restart; 602 } 603 604 /* 605 * Forget the call and donate it to the task which holds up the answer. 606 */ 607 608 call->forget = true; 609 call->sender = NULL; 610 list_remove(&call->ta_link); 611 612 ipc_caller_phone_demasquerade(call); 613 atomic_dec(&call->data.phone->active_calls); 614 615 spinlock_unlock(&call->forget_lock); 616 spinlock_unlock(&TASK->active_calls_lock); 617 goto restart; 618 } 619 620 /** Wait for all answers to asynchronous calls to arrive. */ 621 static void ipc_wait_for_all_answered_calls(void) 622 { 623 call_t *call; 624 size_t i; 625 626 restart: 627 /* 628 * Go through all phones, until they are all FREE. Locking is not 629 * needed, no one else should modify it when we are in cleanup 630 */ 631 for (i = 0; i < IPC_MAX_PHONES; i++) { 632 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 633 atomic_get(&TASK->phones[i].active_calls) == 0) { 634 TASK->phones[i].state = IPC_PHONE_FREE; 635 TASK->phones[i].callee = NULL; 636 } 637 638 /* 639 * Just for sure, we might have had some IPC_PHONE_CONNECTING 640 * phones 641 */ 642 if (TASK->phones[i].state == IPC_PHONE_CONNECTED) 643 ipc_phone_hangup(&TASK->phones[i]); 644 645 /* 646 * If the hangup succeeded, it has sent a HANGUP message, the 647 * IPC is now in HUNGUP state, we wait for the reply to come 648 */ 649 if (TASK->phones[i].state != IPC_PHONE_FREE) 650 break; 651 } 652 653 /* Got into cleanup */ 654 if (i == IPC_MAX_PHONES) 655 return; 656 657 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 658 SYNCH_FLAGS_NONE); 659 ASSERT((call->flags & IPC_CALL_ANSWERED) || 660 (call->flags & IPC_CALL_NOTIF)); 661 662 ipc_call_free(call); 663 goto restart; 664 } 665 549 666 /** Clean up all IPC communication of the current task. 550 667 * … … 556 673 { 557 674 /* Disconnect all our phones ('ipc_phone_hangup') */ 558 size_t i; 559 for (i = 0; i < IPC_MAX_PHONES; i++) 675 for (size_t i = 0; i < IPC_MAX_PHONES; i++) 560 676 ipc_phone_hangup(&TASK->phones[i]); 561 677 … … 579 695 ipc_cleanup_call_list(&TASK->answerbox.calls); 580 696 irq_spinlock_unlock(&TASK->answerbox.lock, true); 581 582 /* Wait for all answers to asynchronous calls to arrive */ 583 while (true) { 584 /* 585 * Go through all phones, until they are all FREE 586 * Locking is not needed, no one else should modify 587 * it when we are in cleanup 588 */ 589 for (i = 0; i < IPC_MAX_PHONES; i++) { 590 if (TASK->phones[i].state == IPC_PHONE_HUNGUP && 591 atomic_get(&TASK->phones[i].active_calls) == 0) { 592 TASK->phones[i].state = IPC_PHONE_FREE; 593 TASK->phones[i].callee = NULL; 594 } 595 596 /* 597 * Just for sure, we might have had some 598 * IPC_PHONE_CONNECTING phones 599 */ 600 if (TASK->phones[i].state == IPC_PHONE_CONNECTED) 601 ipc_phone_hangup(&TASK->phones[i]); 602 603 /* 604 * If the hangup succeeded, it has sent a HANGUP 605 * message, the IPC is now in HUNGUP state, we 606 * wait for the reply to come 607 */ 608 609 if (TASK->phones[i].state != IPC_PHONE_FREE) 610 break; 611 } 612 613 /* Got into cleanup */ 614 if (i == IPC_MAX_PHONES) 615 break; 616 617 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, 618 SYNCH_FLAGS_NONE); 619 ASSERT((call->flags & IPC_CALL_ANSWERED) || 620 (call->flags & IPC_CALL_NOTIF)); 621 622 ipc_call_free(call); 623 } 697 698 ipc_forget_all_active_calls(); 699 ipc_wait_for_all_answered_calls(); 624 700 } 625 701 -
kernel/generic/src/ipc/sysipc.c
r691d8d8 r2405bb5 420 420 int rc = EOK; 421 421 422 spinlock_lock(&answer->forget_lock); 423 if (answer->forget) { 424 /* 425 * This is a forgotten call and answer->sender is not valid. 426 */ 427 spinlock_unlock(&answer->forget_lock); 428 /* TODO: free the call and its resources */ 429 return rc; 430 } else { 431 /* 432 * Hold the sender task so that it cannot suddenly disappear 433 * while we are working with it. 434 */ 435 task_hold(answer->sender); 436 } 437 spinlock_unlock(&answer->forget_lock); 438 422 439 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) { 423 440 /* In case of forward, hangup the forwared phone, … … 434 451 } 435 452 436 if (!olddata) 453 if (!olddata) { 454 task_release(answer->sender); 437 455 return rc; 456 } 438 457 439 458 switch (IPC_GET_IMETHOD(*olddata)) { … … 469 488 } 470 489 490 task_release(answer->sender); 491 471 492 return rc; 472 493 }
Note:
See TracChangeset
for help on using the changeset viewer.