Rev 3022 | Rev 4296 | 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 | } |