source: mainline/kernel/generic/src/ipc/ipc.c@ eb5560a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eb5560a was 53af6e8c, checked in by Jakub Jermar <jakub@…>, 13 years ago

No need to hold the sender task when the call is going to be answered.
The sender may no longer forget the call and, in fact, must wait for it.

  • Property mode set to 100644
File size: 22.5 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup genericipc
30 * @{
31 */
32/** @file
33 */
34
35/* Lock ordering
36 *
37 * First the answerbox, then the phone.
38 */
39
40#include <synch/spinlock.h>
41#include <synch/mutex.h>
42#include <synch/waitq.h>
43#include <ipc/ipc.h>
44#include <abi/ipc/methods.h>
45#include <ipc/kbox.h>
46#include <ipc/event.h>
47#include <ipc/sysipc_ops.h>
48#include <errno.h>
49#include <mm/slab.h>
50#include <arch.h>
51#include <proc/task.h>
52#include <memstr.h>
53#include <debug.h>
54#include <print.h>
55#include <console/console.h>
56#include <proc/thread.h>
57#include <arch/interrupt.h>
58#include <ipc/irq.h>
59
60/** Open channel that is assigned automatically to new tasks */
61answerbox_t *ipc_phone_0 = NULL;
62
63static slab_cache_t *ipc_call_slab;
64static slab_cache_t *ipc_answerbox_slab;
65
66/** Initialize a call structure.
67 *
68 * @param call Call structure to be initialized.
69 *
70 */
71static void _ipc_call_init(call_t *call)
72{
73 memsetb(call, sizeof(*call), 0);
74 spinlock_initialize(&call->forget_lock, "forget_lock");
75 call->active = false;
76 call->forget = false;
77 call->sender = TASK;
78 call->buffer = NULL;
79}
80
81/** Allocate and initialize a call structure.
82 *
83 * The call is initialized, so that the reply will be directed to
84 * TASK->answerbox.
85 *
86 * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC).
87 *
88 * @return If flags permit it, return NULL, or initialized kernel
89 * call structure.
90 *
91 */
92call_t *ipc_call_alloc(unsigned int flags)
93{
94 call_t *call = slab_alloc(ipc_call_slab, flags);
95 if (call)
96 _ipc_call_init(call);
97
98 return call;
99}
100
101/** Deallocate a call structure.
102 *
103 * @param call Call structure to be freed.
104 *
105 */
106void ipc_call_free(call_t *call)
107{
108 /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
109 if (call->buffer)
110 free(call->buffer);
111 slab_free(ipc_call_slab, call);
112}
113
114/** Initialize an answerbox structure.
115 *
116 * @param box Answerbox structure to be initialized.
117 * @param task Task to which the answerbox belongs.
118 *
119 */
120void ipc_answerbox_init(answerbox_t *box, task_t *task)
121{
122 irq_spinlock_initialize(&box->lock, "ipc.box.lock");
123 irq_spinlock_initialize(&box->irq_lock, "ipc.box.irqlock");
124 waitq_initialize(&box->wq);
125 list_initialize(&box->connected_phones);
126 list_initialize(&box->calls);
127 list_initialize(&box->dispatched_calls);
128 list_initialize(&box->answers);
129 list_initialize(&box->irq_notifs);
130 list_initialize(&box->irq_list);
131 box->task = task;
132}
133
134/** Connect a phone to an answerbox.
135 *
136 * @param phone Initialized phone structure.
137 * @param box Initialized answerbox structure.
138 *
139 */
140void ipc_phone_connect(phone_t *phone, answerbox_t *box)
141{
142 mutex_lock(&phone->lock);
143
144 phone->state = IPC_PHONE_CONNECTED;
145 phone->callee = box;
146
147 irq_spinlock_lock(&box->lock, true);
148 list_append(&phone->link, &box->connected_phones);
149 irq_spinlock_unlock(&box->lock, true);
150
151 mutex_unlock(&phone->lock);
152}
153
154/** Initialize a phone structure.
155 *
156 * @param phone Phone structure to be initialized.
157 *
158 */
159void ipc_phone_init(phone_t *phone)
160{
161 mutex_initialize(&phone->lock, MUTEX_PASSIVE);
162 phone->callee = NULL;
163 phone->state = IPC_PHONE_FREE;
164 atomic_set(&phone->active_calls, 0);
165}
166
167/** Demasquerade the caller phone. */
168static void ipc_caller_phone_demasquerade(call_t *call)
169{
170 if (call->flags & IPC_CALL_FORWARDED) {
171 if (call->caller_phone) {
172 call->data.phone = call->caller_phone;
173 }
174 }
175}
176
177/** Answer a message which was not dispatched and is not listed in any queue.
178 *
179 * @param call Call structure to be answered.
180 * @param selflocked If true, then TASK->answebox is locked.
181 *
182 */
183static void _ipc_answer_free_call(call_t *call, bool selflocked)
184{
185 /* Count sent answer */
186 irq_spinlock_lock(&TASK->lock, true);
187 TASK->ipc_info.answer_sent++;
188 irq_spinlock_unlock(&TASK->lock, true);
189
190 spinlock_lock(&call->forget_lock);
191 if (call->forget) {
192 /* This is a forgotten call and call->sender is not valid. */
193 spinlock_unlock(&call->forget_lock);
194 ipc_call_free(call);
195 return;
196 } else {
197 /*
198 * If the call is still active, i.e. it was answered
199 * in a non-standard way, remove the call from the
200 * sender's active call list.
201 */
202 if (call->active) {
203 spinlock_lock(&call->sender->active_calls_lock);
204 list_remove(&call->ta_link);
205 spinlock_unlock(&call->sender->active_calls_lock);
206 }
207 }
208 spinlock_unlock(&call->forget_lock);
209
210 answerbox_t *callerbox = &call->sender->answerbox;
211 bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
212
213 call->flags |= IPC_CALL_ANSWERED;
214
215 ipc_caller_phone_demasquerade(call);
216
217 call->data.task_id = TASK->taskid;
218
219 if (do_lock)
220 irq_spinlock_lock(&callerbox->lock, true);
221
222 list_append(&call->ab_link, &callerbox->answers);
223
224 if (do_lock)
225 irq_spinlock_unlock(&callerbox->lock, true);
226
227 waitq_wakeup(&callerbox->wq, WAKEUP_FIRST);
228}
229
230/** Answer a message which is in a callee queue.
231 *
232 * @param box Answerbox that is answering the message.
233 * @param call Modified request that is being sent back.
234 *
235 */
236void ipc_answer(answerbox_t *box, call_t *call)
237{
238 /* Remove from active box */
239 irq_spinlock_lock(&box->lock, true);
240 list_remove(&call->ab_link);
241 irq_spinlock_unlock(&box->lock, true);
242
243 /* Send back answer */
244 _ipc_answer_free_call(call, false);
245}
246
247/** Simulate sending back a message.
248 *
249 * Most errors are better handled by forming a normal backward
250 * message and sending it as a normal answer.
251 *
252 * @param phone Phone structure the call should appear to come from.
253 * @param call Call structure to be answered.
254 * @param err Return value to be used for the answer.
255 *
256 */
257void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
258{
259 call->data.phone = phone;
260 atomic_inc(&phone->active_calls);
261
262 spinlock_lock(&TASK->active_calls_lock);
263 list_append(&call->ta_link, &TASK->active_calls);
264 spinlock_unlock(&TASK->active_calls_lock);
265
266 IPC_SET_RETVAL(call->data, err);
267 _ipc_answer_free_call(call, false);
268}
269
270/** Unsafe unchecking version of ipc_call.
271 *
272 * @param phone Phone structure the call comes from.
273 * @param box Destination answerbox structure.
274 * @param call Call structure with request.
275 *
276 */
277static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
278{
279 /* Count sent ipc call */
280 irq_spinlock_lock(&TASK->lock, true);
281 TASK->ipc_info.call_sent++;
282 irq_spinlock_unlock(&TASK->lock, true);
283
284 if (!(call->flags & IPC_CALL_FORWARDED)) {
285 atomic_inc(&phone->active_calls);
286
287 call->active = true;
288
289 spinlock_lock(&TASK->active_calls_lock);
290 list_append(&call->ta_link, &TASK->active_calls);
291 spinlock_unlock(&TASK->active_calls_lock);
292
293 call->data.phone = phone;
294 call->data.task_id = TASK->taskid;
295 }
296
297 irq_spinlock_lock(&box->lock, true);
298 list_append(&call->ab_link, &box->calls);
299 irq_spinlock_unlock(&box->lock, true);
300
301 waitq_wakeup(&box->wq, WAKEUP_FIRST);
302}
303
304/** Send an asynchronous request using a phone to an answerbox.
305 *
306 * @param phone Phone structure the call comes from and which is
307 * connected to the destination answerbox.
308 * @param call Call structure with request.
309 *
310 * @return Return 0 on success, ENOENT on error.
311 *
312 */
313int ipc_call(phone_t *phone, call_t *call)
314{
315 mutex_lock(&phone->lock);
316 if (phone->state != IPC_PHONE_CONNECTED) {
317 mutex_unlock(&phone->lock);
318 if (call->flags & IPC_CALL_FORWARDED) {
319 IPC_SET_RETVAL(call->data, EFORWARD);
320 _ipc_answer_free_call(call, false);
321 } else {
322 if (phone->state == IPC_PHONE_HUNGUP)
323 ipc_backsend_err(phone, call, EHANGUP);
324 else
325 ipc_backsend_err(phone, call, ENOENT);
326 }
327
328 return ENOENT;
329 }
330
331 answerbox_t *box = phone->callee;
332 _ipc_call(phone, box, call);
333
334 mutex_unlock(&phone->lock);
335 return 0;
336}
337
338/** Disconnect phone from answerbox.
339 *
340 * This call leaves the phone in the HUNGUP state. The change to 'free' is done
341 * lazily later.
342 *
343 * @param phone Phone structure to be hung up.
344 *
345 * @return 0 if the phone is disconnected.
346 * @return -1 if the phone was already disconnected.
347 *
348 */
349int ipc_phone_hangup(phone_t *phone)
350{
351 mutex_lock(&phone->lock);
352 if (phone->state == IPC_PHONE_FREE ||
353 phone->state == IPC_PHONE_HUNGUP ||
354 phone->state == IPC_PHONE_CONNECTING) {
355 mutex_unlock(&phone->lock);
356 return -1;
357 }
358
359 answerbox_t *box = phone->callee;
360 if (phone->state != IPC_PHONE_SLAMMED) {
361 /* Remove myself from answerbox */
362 irq_spinlock_lock(&box->lock, true);
363 list_remove(&phone->link);
364 irq_spinlock_unlock(&box->lock, true);
365
366 call_t *call = ipc_call_alloc(0);
367 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
368 call->flags |= IPC_CALL_DISCARD_ANSWER;
369 _ipc_call(phone, box, call);
370 }
371
372 phone->state = IPC_PHONE_HUNGUP;
373 mutex_unlock(&phone->lock);
374
375 return 0;
376}
377
378/** Forwards call from one answerbox to another one.
379 *
380 * @param call Call structure to be redirected.
381 * @param newphone Phone structure to target answerbox.
382 * @param oldbox Old answerbox structure.
383 * @param mode Flags that specify mode of the forward operation.
384 *
385 * @return 0 if forwarding succeeded or an error code if
386 * there was an error.
387 *
388 * The return value serves only as an information for the forwarder,
389 * the original caller is notified automatically with EFORWARD.
390 *
391 */
392int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox,
393 unsigned int mode)
394{
395 /* Count forwarded calls */
396 irq_spinlock_lock(&TASK->lock, true);
397 TASK->ipc_info.forwarded++;
398 irq_spinlock_pass(&TASK->lock, &oldbox->lock);
399 list_remove(&call->ab_link);
400 irq_spinlock_unlock(&oldbox->lock, true);
401
402 if (mode & IPC_FF_ROUTE_FROM_ME) {
403 if (!call->caller_phone)
404 call->caller_phone = call->data.phone;
405 call->data.phone = newphone;
406 call->data.task_id = TASK->taskid;
407 }
408
409 return ipc_call(newphone, call);
410}
411
412
413/** Wait for a phone call.
414 *
415 * @param box Answerbox expecting the call.
416 * @param usec Timeout in microseconds. See documentation for
417 * waitq_sleep_timeout() for decription of its special
418 * meaning.
419 * @param flags Select mode of sleep operation. See documentation for
420 * waitq_sleep_timeout() for description of its special
421 * meaning.
422 *
423 * @return Recived call structure or NULL.
424 *
425 * To distinguish between a call and an answer, have a look at call->flags.
426 *
427 */
428call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, unsigned int flags)
429{
430 call_t *request;
431 uint64_t irq_cnt = 0;
432 uint64_t answer_cnt = 0;
433 uint64_t call_cnt = 0;
434 int rc;
435
436restart:
437 rc = waitq_sleep_timeout(&box->wq, usec, flags);
438 if (SYNCH_FAILED(rc))
439 return NULL;
440
441 irq_spinlock_lock(&box->lock, true);
442 if (!list_empty(&box->irq_notifs)) {
443 /* Count received IRQ notification */
444 irq_cnt++;
445
446 irq_spinlock_lock(&box->irq_lock, false);
447
448 request = list_get_instance(list_first(&box->irq_notifs),
449 call_t, ab_link);
450 list_remove(&request->ab_link);
451
452 irq_spinlock_unlock(&box->irq_lock, false);
453 } else if (!list_empty(&box->answers)) {
454 /* Count received answer */
455 answer_cnt++;
456
457 /* Handle asynchronous answers */
458 request = list_get_instance(list_first(&box->answers),
459 call_t, ab_link);
460 list_remove(&request->ab_link);
461 atomic_dec(&request->data.phone->active_calls);
462 } else if (!list_empty(&box->calls)) {
463 /* Count received call */
464 call_cnt++;
465
466 /* Handle requests */
467 request = list_get_instance(list_first(&box->calls),
468 call_t, ab_link);
469 list_remove(&request->ab_link);
470
471 /* Append request to dispatch queue */
472 list_append(&request->ab_link, &box->dispatched_calls);
473 } else {
474 /* This can happen regularly after ipc_cleanup */
475 irq_spinlock_unlock(&box->lock, true);
476 goto restart;
477 }
478
479 irq_spinlock_pass(&box->lock, &TASK->lock);
480
481 TASK->ipc_info.irq_notif_received += irq_cnt;
482 TASK->ipc_info.answer_received += answer_cnt;
483 TASK->ipc_info.call_received += call_cnt;
484
485 irq_spinlock_unlock(&TASK->lock, true);
486
487 return request;
488}
489
490/** Answer all calls from list with EHANGUP answer.
491 *
492 * @param lst Head of the list to be cleaned up.
493 *
494 */
495void ipc_cleanup_call_list(list_t *lst)
496{
497 while (!list_empty(lst)) {
498 call_t *call = list_get_instance(list_first(lst), call_t,
499 ab_link);
500
501 list_remove(&call->ab_link);
502
503 IPC_SET_RETVAL(call->data, EHANGUP);
504 _ipc_answer_free_call(call, true);
505 }
506}
507
508/** Disconnects all phones connected to an answerbox.
509 *
510 * @param box Answerbox to disconnect phones from.
511 * @param notify_box If true, the answerbox will get a hangup message for
512 * each disconnected phone.
513 *
514 */
515void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
516{
517 phone_t *phone;
518 DEADLOCK_PROBE_INIT(p_phonelck);
519
520 call_t *call = notify_box ? ipc_call_alloc(0) : NULL;
521
522 /* Disconnect all phones connected to our answerbox */
523restart_phones:
524 irq_spinlock_lock(&box->lock, true);
525 while (!list_empty(&box->connected_phones)) {
526 phone = list_get_instance(list_first(&box->connected_phones),
527 phone_t, link);
528 if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
529 irq_spinlock_unlock(&box->lock, true);
530 DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
531 goto restart_phones;
532 }
533
534 /* Disconnect phone */
535 ASSERT(phone->state == IPC_PHONE_CONNECTED);
536
537 list_remove(&phone->link);
538 phone->state = IPC_PHONE_SLAMMED;
539
540 if (notify_box) {
541 mutex_unlock(&phone->lock);
542 irq_spinlock_unlock(&box->lock, true);
543
544 /*
545 * Send one message to the answerbox for each
546 * phone. Used to make sure the kbox thread
547 * wakes up after the last phone has been
548 * disconnected.
549 */
550 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
551 call->flags |= IPC_CALL_DISCARD_ANSWER;
552 _ipc_call(phone, box, call);
553
554 /* Allocate another call in advance */
555 call = ipc_call_alloc(0);
556
557 /* Must start again */
558 goto restart_phones;
559 }
560
561 mutex_unlock(&phone->lock);
562 }
563
564 irq_spinlock_unlock(&box->lock, true);
565
566 /* Free unused call */
567 if (call)
568 ipc_call_free(call);
569}
570
571static void ipc_forget_all_active_calls(void)
572{
573 call_t *call;
574
575restart:
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() or
592 * _ipc_answer_free_call() win the race to dequeue the first
593 * 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 ipc_caller_phone_demasquerade(call);
608 atomic_dec(&call->data.phone->active_calls);
609
610 spinlock_unlock(&call->forget_lock);
611 spinlock_unlock(&TASK->active_calls_lock);
612
613 sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
614 if (ops->request_forget)
615 ops->request_forget(call);
616
617 goto restart;
618}
619
620/** Wait for all answers to asynchronous calls to arrive. */
621static void ipc_wait_for_all_answered_calls(void)
622{
623 call_t *call;
624 size_t i;
625
626restart:
627 /*
628 * Go through all phones, until they are all free.
629 * Locking is needed as there may be connection handshakes in progress.
630 */
631 for (i = 0; i < IPC_MAX_PHONES; i++) {
632 phone_t *phone = &TASK->phones[i];
633
634 mutex_lock(&phone->lock);
635 if ((phone->state == IPC_PHONE_HUNGUP) &&
636 (atomic_get(&phone->active_calls) == 0)) {
637 phone->state = IPC_PHONE_FREE;
638 phone->callee = NULL;
639 }
640
641 /*
642 * We might have had some IPC_PHONE_CONNECTING phones at the
643 * beginning of ipc_cleanup(). Depending on whether these were
644 * forgotten or answered, they will eventually enter the
645 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
646 * In the latter case, the other side may slam the open phones
647 * at any time, in which case we will get an IPC_PHONE_SLAMMED
648 * phone.
649 */
650 if ((phone->state == IPC_PHONE_CONNECTED) ||
651 (phone->state == IPC_PHONE_SLAMMED)) {
652 mutex_unlock(&phone->lock);
653 ipc_phone_hangup(phone);
654 /*
655 * Now there may be one extra active call, which needs
656 * to be forgotten.
657 */
658 ipc_forget_all_active_calls();
659 goto restart;
660 }
661
662 /*
663 * If the hangup succeeded, it has sent a HANGUP message, the
664 * IPC is now in HUNGUP state, we wait for the reply to come
665 */
666 if (phone->state != IPC_PHONE_FREE) {
667 mutex_unlock(&phone->lock);
668 break;
669 }
670
671 mutex_unlock(&phone->lock);
672 }
673
674 /* Got into cleanup */
675 if (i == IPC_MAX_PHONES)
676 return;
677
678 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
679 SYNCH_FLAGS_NONE);
680 ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
681 ipc_call_free(call);
682 goto restart;
683}
684
685/** Clean up all IPC communication of the current task.
686 *
687 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
688 * have to change it as well if you want to cleanup other tasks than TASK.
689 *
690 */
691void ipc_cleanup(void)
692{
693 /* Disconnect all our phones ('ipc_phone_hangup') */
694 for (size_t i = 0; i < IPC_MAX_PHONES; i++)
695 ipc_phone_hangup(&TASK->phones[i]);
696
697 /* Unsubscribe from any event notifications. */
698 event_cleanup_answerbox(&TASK->answerbox);
699
700 /* Disconnect all connected irqs */
701 ipc_irq_cleanup(&TASK->answerbox);
702
703 /* Disconnect all phones connected to our regular answerbox */
704 ipc_answerbox_slam_phones(&TASK->answerbox, false);
705
706#ifdef CONFIG_UDEBUG
707 /* Clean up kbox thread and communications */
708 ipc_kbox_cleanup();
709#endif
710
711 /* Answer all messages in 'calls' and 'dispatched_calls' queues */
712 irq_spinlock_lock(&TASK->answerbox.lock, true);
713 ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
714 ipc_cleanup_call_list(&TASK->answerbox.calls);
715 irq_spinlock_unlock(&TASK->answerbox.lock, true);
716
717 ipc_forget_all_active_calls();
718 ipc_wait_for_all_answered_calls();
719}
720
721/** Initilize IPC subsystem
722 *
723 */
724void ipc_init(void)
725{
726 ipc_call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,
727 NULL, 0);
728 ipc_answerbox_slab = slab_cache_create("answerbox_t",
729 sizeof(answerbox_t), 0, NULL, NULL, 0);
730}
731
732/** List answerbox contents.
733 *
734 * @param taskid Task ID.
735 *
736 */
737void ipc_print_task(task_id_t taskid)
738{
739 irq_spinlock_lock(&tasks_lock, true);
740 task_t *task = task_find_by_id(taskid);
741
742 if (!task) {
743 irq_spinlock_unlock(&tasks_lock, true);
744 return;
745 }
746
747 /* Hand-over-hand locking */
748 irq_spinlock_exchange(&tasks_lock, &task->lock);
749
750 printf("[phone id] [calls] [state\n");
751
752 size_t i;
753 for (i = 0; i < IPC_MAX_PHONES; i++) {
754 if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) {
755 printf("%-10zu (mutex busy)\n", i);
756 continue;
757 }
758
759 if (task->phones[i].state != IPC_PHONE_FREE) {
760 printf("%-10zu %7" PRIun " ", i,
761 atomic_get(&task->phones[i].active_calls));
762
763 switch (task->phones[i].state) {
764 case IPC_PHONE_CONNECTING:
765 printf("connecting");
766 break;
767 case IPC_PHONE_CONNECTED:
768 printf("connected to %" PRIu64 " (%s)",
769 task->phones[i].callee->task->taskid,
770 task->phones[i].callee->task->name);
771 break;
772 case IPC_PHONE_SLAMMED:
773 printf("slammed by %p",
774 task->phones[i].callee);
775 break;
776 case IPC_PHONE_HUNGUP:
777 printf("hung up by %p",
778 task->phones[i].callee);
779 break;
780 default:
781 break;
782 }
783
784 printf("\n");
785 }
786
787 mutex_unlock(&task->phones[i].lock);
788 }
789
790 irq_spinlock_lock(&task->answerbox.lock, false);
791
792#ifdef __32_BITS__
793 printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4] [arg5]"
794 " [flags] [sender\n");
795#endif
796
797#ifdef __64_BITS__
798 printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4]"
799 " [arg5] [flags] [sender\n");
800#endif
801
802 printf(" --- incomming calls ---\n");
803 list_foreach(task->answerbox.calls, cur) {
804 call_t *call = list_get_instance(cur, call_t, ab_link);
805
806#ifdef __32_BITS__
807 printf("%10p ", call);
808#endif
809
810#ifdef __64_BITS__
811 printf("%18p ", call);
812#endif
813
814 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
815 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
816 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
817 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
818 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
819 call->flags, call->sender->taskid, call->sender->name);
820 }
821
822 printf(" --- dispatched calls ---\n");
823 list_foreach(task->answerbox.dispatched_calls, cur) {
824 call_t *call = list_get_instance(cur, call_t, ab_link);
825
826#ifdef __32_BITS__
827 printf("%10p ", call);
828#endif
829
830#ifdef __64_BITS__
831 printf("%18p ", call);
832#endif
833
834 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
835 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
836 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
837 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
838 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
839 call->flags, call->sender->taskid, call->sender->name);
840 }
841
842 printf(" --- incoming answers ---\n");
843 list_foreach(task->answerbox.answers, cur) {
844 call_t *call = list_get_instance(cur, call_t, ab_link);
845
846#ifdef __32_BITS__
847 printf("%10p ", call);
848#endif
849
850#ifdef __64_BITS__
851 printf("%18p ", call);
852#endif
853
854 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
855 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
856 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
857 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
858 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
859 call->flags, call->sender->taskid, call->sender->name);
860 }
861
862 irq_spinlock_unlock(&task->answerbox.lock, false);
863 irq_spinlock_unlock(&task->lock, true);
864}
865
866/** @}
867 */
Note: See TracBrowser for help on using the repository browser.