Rev 3022 | Rev 4201 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 3022 | Rev 4055 | ||
|---|---|---|---|
| Line 41... | Line 41... | ||
| 41 | #include <synch/spinlock.h> |
41 | #include <synch/spinlock.h> |
| 42 | #include <synch/mutex.h> |
42 | #include <synch/mutex.h> |
| 43 | #include <synch/waitq.h> |
43 | #include <synch/waitq.h> |
| 44 | #include <synch/synch.h> |
44 | #include <synch/synch.h> |
| 45 | #include <ipc/ipc.h> |
45 | #include <ipc/ipc.h> |
| - | 46 | #include <ipc/kbox.h> |
|
| 46 | #include <errno.h> |
47 | #include <errno.h> |
| 47 | #include <mm/slab.h> |
48 | #include <mm/slab.h> |
| 48 | #include <arch.h> |
49 | #include <arch.h> |
| 49 | #include <proc/task.h> |
50 | #include <proc/task.h> |
| 50 | #include <memstr.h> |
51 | #include <memstr.h> |
| 51 | #include <debug.h> |
52 | #include <debug.h> |
| 52 | 53 | ||
| 53 | #include <print.h> |
54 | #include <print.h> |
| - | 55 | #include <console/console.h> |
|
| 54 | #include <proc/thread.h> |
56 | #include <proc/thread.h> |
| 55 | #include <arch/interrupt.h> |
57 | #include <arch/interrupt.h> |
| 56 | #include <ipc/irq.h> |
58 | #include <ipc/irq.h> |
| 57 | 59 | ||
| 58 | /** Open channel that is assigned automatically to new tasks */ |
60 | /** Open channel that is assigned automatically to new tasks */ |
| Line 64... | Line 66... | ||
| 64 | * |
66 | * |
| 65 | * @param call Call structure to be initialized. |
67 | * @param call Call structure to be initialized. |
| 66 | */ |
68 | */ |
| 67 | static void _ipc_call_init(call_t *call) |
69 | static void _ipc_call_init(call_t *call) |
| 68 | { |
70 | { |
| 69 | memsetb((uintptr_t) call, sizeof(*call), 0); |
71 | memsetb(call, sizeof(*call), 0); |
| 70 | call->callerbox = &TASK->answerbox; |
72 | call->callerbox = &TASK->answerbox; |
| 71 | call->sender = TASK; |
73 | call->sender = TASK; |
| 72 | call->buffer = NULL; |
74 | call->buffer = NULL; |
| 73 | } |
75 | } |
| 74 | 76 | ||
| Line 85... | Line 87... | ||
| 85 | call_t *ipc_call_alloc(int flags) |
87 | call_t *ipc_call_alloc(int flags) |
| 86 | { |
88 | { |
| 87 | call_t *call; |
89 | call_t *call; |
| 88 | 90 | ||
| 89 | call = slab_alloc(ipc_call_slab, flags); |
91 | call = slab_alloc(ipc_call_slab, flags); |
| - | 92 | if (call) |
|
| 90 | _ipc_call_init(call); |
93 | _ipc_call_init(call); |
| 91 | 94 | ||
| 92 | return call; |
95 | return call; |
| 93 | } |
96 | } |
| 94 | 97 | ||
| 95 | /** Initialize a statically allocated call structure. |
98 | /** Initialize a statically allocated call structure. |
| Line 158... | Line 161... | ||
| 158 | * |
161 | * |
| 159 | * @param phone Phone structure to be initialized. |
162 | * @param phone Phone structure to be initialized. |
| 160 | */ |
163 | */ |
| 161 | void ipc_phone_init(phone_t *phone) |
164 | void ipc_phone_init(phone_t *phone) |
| 162 | { |
165 | { |
| 163 | mutex_initialize(&phone->lock); |
166 | mutex_initialize(&phone->lock, MUTEX_PASSIVE); |
| 164 | phone->callee = NULL; |
167 | phone->callee = NULL; |
| 165 | phone->state = IPC_PHONE_FREE; |
168 | phone->state = IPC_PHONE_FREE; |
| 166 | atomic_set(&phone->active_calls, 0); |
169 | atomic_set(&phone->active_calls, 0); |
| 167 | } |
170 | } |
| 168 | 171 | ||
| 169 | /** Helper function to facilitate synchronous calls. |
172 | /** Helper function to facilitate synchronous calls. |
| 170 | * |
173 | * |
| 171 | * @param phone Destination kernel phone structure. |
174 | * @param phone Destination kernel phone structure. |
| 172 | * @param request Call structure with request. |
175 | * @param request Call structure with request. |
| - | 176 | * |
|
| - | 177 | * @return EOK on success or EINTR if the sleep was interrupted. |
|
| 173 | */ |
178 | */ |
| 174 | void ipc_call_sync(phone_t *phone, call_t *request) |
179 | int ipc_call_sync(phone_t *phone, call_t *request) |
| 175 | { |
180 | { |
| 176 | answerbox_t sync_box; |
181 | answerbox_t sync_box; |
| 177 | 182 | ||
| 178 | ipc_answerbox_init(&sync_box, TASK); |
183 | ipc_answerbox_init(&sync_box, TASK); |
| 179 | 184 | ||
| 180 | /* We will receive data in a special box. */ |
185 | /* We will receive data in a special box. */ |
| 181 | request->callerbox = &sync_box; |
186 | request->callerbox = &sync_box; |
| 182 | 187 | ||
| 183 | ipc_call(phone, request); |
188 | ipc_call(phone, request); |
| 184 | ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
189 | if (!ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, |
| - | 190 | SYNCH_FLAGS_INTERRUPTIBLE)) |
|
| - | 191 | return EINTR; |
|
| - | 192 | return EOK; |
|
| 185 | } |
193 | } |
| 186 | 194 | ||
| 187 | /** Answer a message which was not dispatched and is not listed in any queue. |
195 | /** Answer a message which was not dispatched and is not listed in any queue. |
| 188 | * |
196 | * |
| 189 | * @param call Call structure to be answered. |
197 | * @param call Call structure to be answered. |
| Line 192... | Line 200... | ||
| 192 | { |
200 | { |
| 193 | answerbox_t *callerbox = call->callerbox; |
201 | answerbox_t *callerbox = call->callerbox; |
| 194 | 202 | ||
| 195 | call->flags |= IPC_CALL_ANSWERED; |
203 | call->flags |= IPC_CALL_ANSWERED; |
| 196 | 204 | ||
| - | 205 | if (call->flags & IPC_CALL_FORWARDED) { |
|
| - | 206 | if (call->caller_phone) { |
|
| - | 207 | /* Demasquerade the caller phone. */ |
|
| - | 208 | call->data.phone = call->caller_phone; |
|
| - | 209 | } |
|
| - | 210 | } |
|
| - | 211 | ||
| 197 | spinlock_lock(&callerbox->lock); |
212 | spinlock_lock(&callerbox->lock); |
| 198 | list_append(&call->link, &callerbox->answers); |
213 | list_append(&call->link, &callerbox->answers); |
| 199 | spinlock_unlock(&callerbox->lock); |
214 | spinlock_unlock(&callerbox->lock); |
| 200 | waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); |
215 | waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); |
| 201 | } |
216 | } |
| Line 344... | Line 359... | ||
| 344 | { |
359 | { |
| 345 | spinlock_lock(&oldbox->lock); |
360 | spinlock_lock(&oldbox->lock); |
| 346 | list_remove(&call->link); |
361 | list_remove(&call->link); |
| 347 | spinlock_unlock(&oldbox->lock); |
362 | spinlock_unlock(&oldbox->lock); |
| 348 | 363 | ||
| 349 | if (mode & IPC_FF_ROUTE_FROM_ME) |
364 | if (mode & IPC_FF_ROUTE_FROM_ME) { |
| - | 365 | if (!call->caller_phone) |
|
| - | 366 | call->caller_phone = call->data.phone; |
|
| 350 | call->data.phone = newphone; |
367 | call->data.phone = newphone; |
| - | 368 | } |
|
| 351 | 369 | ||
| 352 | return ipc_call(newphone, call); |
370 | return ipc_call(newphone, call); |
| 353 | } |
371 | } |
| 354 | 372 | ||
| 355 | 373 | ||
| Line 409... | Line 427... | ||
| 409 | 427 | ||
| 410 | /** Answer all calls from list with EHANGUP answer. |
428 | /** Answer all calls from list with EHANGUP answer. |
| 411 | * |
429 | * |
| 412 | * @param lst Head of the list to be cleaned up. |
430 | * @param lst Head of the list to be cleaned up. |
| 413 | */ |
431 | */ |
| 414 | static void ipc_cleanup_call_list(link_t *lst) |
432 | void ipc_cleanup_call_list(link_t *lst) |
| 415 | { |
433 | { |
| 416 | call_t *call; |
434 | call_t *call; |
| 417 | 435 | ||
| 418 | while (!list_empty(lst)) { |
436 | while (!list_empty(lst)) { |
| 419 | call = list_get_instance(lst->next, call_t, link); |
437 | call = list_get_instance(lst->next, call_t, link); |
| Line 424... | Line 442... | ||
| 424 | IPC_SET_RETVAL(call->data, EHANGUP); |
442 | IPC_SET_RETVAL(call->data, EHANGUP); |
| 425 | _ipc_answer_free_call(call); |
443 | _ipc_answer_free_call(call); |
| 426 | } |
444 | } |
| 427 | } |
445 | } |
| 428 | 446 | ||
| 429 | /** Cleans up all IPC communication of the current task. |
447 | /** Disconnects all phones connected to an answerbox. |
| 430 | * |
448 | * |
| 431 | * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
449 | * @param box Answerbox to disconnect phones from. |
| 432 | * have to change it as well if you want to cleanup other tasks than TASK. |
450 | * @param notify_box If true, the answerbox will get a hangup message for |
| - | 451 | * each disconnected phone. |
|
| 433 | */ |
452 | */ |
| 434 | void ipc_cleanup(void) |
453 | void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) |
| 435 | { |
454 | { |
| 436 | int i; |
- | |
| 437 | call_t *call; |
- | |
| 438 | phone_t *phone; |
455 | phone_t *phone; |
| 439 | DEADLOCK_PROBE_INIT(p_phonelck); |
456 | DEADLOCK_PROBE_INIT(p_phonelck); |
| - | 457 | ipl_t ipl; |
|
| - | 458 | call_t *call; |
|
| 440 | 459 | ||
| 441 | /* Disconnect all our phones ('ipc_phone_hangup') */ |
- | |
| 442 | for (i = 0; i < IPC_MAX_PHONES; i++) |
- | |
| 443 | ipc_phone_hangup(&TASK->phones[i]); |
- | |
| 444 | - | ||
| 445 | /* Disconnect all connected irqs */ |
460 | call = notify_box ? ipc_call_alloc(0) : NULL; |
| 446 | ipc_irq_cleanup(&TASK->answerbox); |
- | |
| 447 | 461 | ||
| 448 | /* Disconnect all phones connected to our answerbox */ |
462 | /* Disconnect all phones connected to our answerbox */ |
| 449 | restart_phones: |
463 | restart_phones: |
| - | 464 | ipl = interrupts_disable(); |
|
| 450 | spinlock_lock(&TASK->answerbox.lock); |
465 | spinlock_lock(&box->lock); |
| 451 | while (!list_empty(&TASK->answerbox.connected_phones)) { |
466 | while (!list_empty(&box->connected_phones)) { |
| 452 | phone = list_get_instance(TASK->answerbox.connected_phones.next, |
467 | phone = list_get_instance(box->connected_phones.next, |
| 453 | phone_t, link); |
468 | phone_t, link); |
| 454 | if (SYNCH_FAILED(mutex_trylock(&phone->lock))) { |
469 | if (SYNCH_FAILED(mutex_trylock(&phone->lock))) { |
| 455 | spinlock_unlock(&TASK->answerbox.lock); |
470 | spinlock_unlock(&box->lock); |
| - | 471 | interrupts_restore(ipl); |
|
| 456 | DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); |
472 | DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); |
| 457 | goto restart_phones; |
473 | goto restart_phones; |
| 458 | } |
474 | } |
| 459 | 475 | ||
| 460 | /* Disconnect phone */ |
476 | /* Disconnect phone */ |
| 461 | ASSERT(phone->state == IPC_PHONE_CONNECTED); |
477 | ASSERT(phone->state == IPC_PHONE_CONNECTED); |
| 462 | phone->state = IPC_PHONE_SLAMMED; |
- | |
| - | 478 | ||
| 463 | list_remove(&phone->link); |
479 | list_remove(&phone->link); |
| - | 480 | phone->state = IPC_PHONE_SLAMMED; |
|
| - | 481 | ||
| - | 482 | if (notify_box) { |
|
| - | 483 | mutex_unlock(&phone->lock); |
|
| - | 484 | spinlock_unlock(&box->lock); |
|
| - | 485 | interrupts_restore(ipl); |
|
| - | 486 | ||
| - | 487 | /* |
|
| - | 488 | * Send one message to the answerbox for each |
|
| - | 489 | * phone. Used to make sure the kbox thread |
|
| - | 490 | * wakes up after the last phone has been |
|
| - | 491 | * disconnected. |
|
| - | 492 | */ |
|
| - | 493 | IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); |
|
| - | 494 | call->flags |= IPC_CALL_DISCARD_ANSWER; |
|
| - | 495 | _ipc_call(phone, box, call); |
|
| - | 496 | ||
| - | 497 | /* Allocate another call in advance */ |
|
| - | 498 | call = ipc_call_alloc(0); |
|
| - | 499 | ||
| - | 500 | /* Must start again */ |
|
| - | 501 | goto restart_phones; |
|
| - | 502 | } |
|
| 464 | 503 | ||
| 465 | mutex_unlock(&phone->lock); |
504 | mutex_unlock(&phone->lock); |
| 466 | } |
505 | } |
| 467 | 506 | ||
| - | 507 | spinlock_unlock(&box->lock); |
|
| - | 508 | interrupts_restore(ipl); |
|
| - | 509 | ||
| - | 510 | /* Free unused call */ |
|
| - | 511 | if (call) |
|
| - | 512 | ipc_call_free(call); |
|
| - | 513 | } |
|
| - | 514 | ||
| - | 515 | /** Cleans up all IPC communication of the current task. |
|
| - | 516 | * |
|
| - | 517 | * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
|
| - | 518 | * have to change it as well if you want to cleanup other tasks than TASK. |
|
| - | 519 | */ |
|
| - | 520 | void ipc_cleanup(void) |
|
| - | 521 | { |
|
| - | 522 | int i; |
|
| - | 523 | call_t *call; |
|
| - | 524 | ||
| - | 525 | /* Disconnect all our phones ('ipc_phone_hangup') */ |
|
| - | 526 | for (i = 0; i < IPC_MAX_PHONES; i++) |
|
| - | 527 | ipc_phone_hangup(&TASK->phones[i]); |
|
| - | 528 | ||
| - | 529 | /* Disconnect all connected irqs */ |
|
| - | 530 | ipc_irq_cleanup(&TASK->answerbox); |
|
| - | 531 | ||
| - | 532 | /* Disconnect all phones connected to our regular answerbox */ |
|
| - | 533 | ipc_answerbox_slam_phones(&TASK->answerbox, false); |
|
| - | 534 | ||
| - | 535 | #ifdef CONFIG_UDEBUG |
|
| - | 536 | /* Clean up kbox thread and communications */ |
|
| - | 537 | ipc_kbox_cleanup(); |
|
| - | 538 | #endif |
|
| - | 539 | ||
| 468 | /* Answer all messages in 'calls' and 'dispatched_calls' queues */ |
540 | /* Answer all messages in 'calls' and 'dispatched_calls' queues */ |
| - | 541 | spinlock_lock(&TASK->answerbox.lock); |
|
| 469 | ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); |
542 | ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); |
| 470 | ipc_cleanup_call_list(&TASK->answerbox.calls); |
543 | ipc_cleanup_call_list(&TASK->answerbox.calls); |
| 471 | spinlock_unlock(&TASK->answerbox.lock); |
544 | spinlock_unlock(&TASK->answerbox.lock); |
| 472 | 545 | ||
| 473 | /* Wait for all async answers to arrive */ |
546 | /* Wait for all async answers to arrive */ |
| Line 499... | Line 572... | ||
| 499 | SYNCH_FLAGS_NONE); |
572 | SYNCH_FLAGS_NONE); |
| 500 | ASSERT((call->flags & IPC_CALL_ANSWERED) || |
573 | ASSERT((call->flags & IPC_CALL_ANSWERED) || |
| 501 | (call->flags & IPC_CALL_NOTIF)); |
574 | (call->flags & IPC_CALL_NOTIF)); |
| 502 | ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); |
575 | ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); |
| 503 | 576 | ||
| - | 577 | /* |
|
| - | 578 | * Record the receipt of this call in the current task's counter |
|
| - | 579 | * of active calls. IPC_M_PHONE_HUNGUP calls do not contribute |
|
| - | 580 | * to this counter so do not record answers to them either. |
|
| - | 581 | */ |
|
| - | 582 | if (!(call->flags & IPC_CALL_DISCARD_ANSWER)) |
|
| 504 | atomic_dec(&TASK->active_calls); |
583 | atomic_dec(&TASK->active_calls); |
| 505 | ipc_call_free(call); |
584 | ipc_call_free(call); |
| 506 | } |
585 | } |
| 507 | } |
586 | } |
| 508 | 587 | ||
| 509 | 588 | ||
| Line 560... | Line 639... | ||
| 560 | task->phones[i].callee); |
639 | task->phones[i].callee); |
| 561 | break; |
640 | break; |
| 562 | default: |
641 | default: |
| 563 | break; |
642 | break; |
| 564 | } |
643 | } |
| 565 | printf("active: %d\n", |
644 | printf("active: %ld\n", |
| 566 | atomic_get(&task->phones[i].active_calls)); |
645 | atomic_get(&task->phones[i].active_calls)); |
| 567 | } |
646 | } |
| 568 | mutex_unlock(&task->phones[i].lock); |
647 | mutex_unlock(&task->phones[i].lock); |
| 569 | } |
648 | } |
| 570 | 649 | ||
| Line 573... | Line 652... | ||
| 573 | spinlock_lock(&task->answerbox.lock); |
652 | spinlock_lock(&task->answerbox.lock); |
| 574 | printf("ABOX - CALLS:\n"); |
653 | printf("ABOX - CALLS:\n"); |
| 575 | for (tmp = task->answerbox.calls.next; tmp != &task->answerbox.calls; |
654 | for (tmp = task->answerbox.calls.next; tmp != &task->answerbox.calls; |
| 576 | tmp = tmp->next) { |
655 | tmp = tmp->next) { |
| 577 | call = list_get_instance(tmp, call_t, link); |
656 | call = list_get_instance(tmp, call_t, link); |
| 578 | printf("Callid: %p Srctask:%llu M:%d A1:%d A2:%d A3:%d " |
657 | printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun |
| - | 658 | " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun |
|
| 579 | "A4:%d A5:%d Flags:%x\n", call, call->sender->taskid, |
659 | " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call, |
| - | 660 | call->sender->taskid, |
|
| 580 | IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), |
661 | IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), |
| 581 | IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), |
662 | IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), |
| 582 | IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
663 | IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
| 583 | call->flags); |
664 | call->flags); |
| 584 | } |
665 | } |
| 585 | /* Print answerbox - calls */ |
666 | /* Print answerbox - calls */ |
| 586 | printf("ABOX - DISPATCHED CALLS:\n"); |
667 | printf("ABOX - DISPATCHED CALLS:\n"); |
| 587 | for (tmp = task->answerbox.dispatched_calls.next; |
668 | for (tmp = task->answerbox.dispatched_calls.next; |
| 588 | tmp != &task->answerbox.dispatched_calls; |
669 | tmp != &task->answerbox.dispatched_calls; |
| 589 | tmp = tmp->next) { |
670 | tmp = tmp->next) { |
| 590 | call = list_get_instance(tmp, call_t, link); |
671 | call = list_get_instance(tmp, call_t, link); |
| 591 | printf("Callid: %p Srctask:%llu M:%d A1:%d A2:%d A3:%d " |
672 | printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun |
| - | 673 | " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun |
|
| 592 | "A4:%d A5:%d Flags:%x\n", call, call->sender->taskid, |
674 | " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call, |
| - | 675 | call->sender->taskid, |
|
| 593 | IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), |
676 | IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), |
| 594 | IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), |
677 | IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), |
| 595 | IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
678 | IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
| 596 | call->flags); |
679 | call->flags); |
| 597 | } |
680 | } |
| 598 | /* Print answerbox - calls */ |
681 | /* Print answerbox - calls */ |
| 599 | printf("ABOX - ANSWERS:\n"); |
682 | printf("ABOX - ANSWERS:\n"); |
| 600 | for (tmp = task->answerbox.answers.next; tmp != &task->answerbox.answers; |
683 | for (tmp = task->answerbox.answers.next; |
| - | 684 | tmp != &task->answerbox.answers; |
|
| 601 | tmp = tmp->next) { |
685 | tmp = tmp->next) { |
| 602 | call = list_get_instance(tmp, call_t, link); |
686 | call = list_get_instance(tmp, call_t, link); |
| 603 | printf("Callid:%p M:%d A1:%d A2:%d A3:%d A4:%d A5:%d Flags:%x\n", |
687 | printf("Callid:%p M:%" PRIun " A1:%" PRIun " A2:%" PRIun |
| - | 688 | " A3:%" PRIun " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", |
|
| 604 | call, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), |
689 | call, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data), |
| 605 | IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), |
690 | IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), |
| 606 | IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
691 | IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
| 607 | call->flags); |
692 | call->flags); |
| 608 | } |
693 | } |