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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e6211f8 was 79ae36dd, checked in by Martin Decky <martin@…>, 15 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 21.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/synch.h>
41#include <synch/spinlock.h>
42#include <synch/mutex.h>
43#include <synch/waitq.h>
44#include <synch/synch.h>
45#include <ipc/ipc.h>
46#include <ipc/ipc_methods.h>
47#include <ipc/kbox.h>
48#include <ipc/event.h>
49#include <errno.h>
50#include <mm/slab.h>
51#include <arch.h>
52#include <proc/task.h>
53#include <memstr.h>
54#include <debug.h>
55#include <print.h>
56#include <console/console.h>
57#include <proc/thread.h>
58#include <arch/interrupt.h>
59#include <ipc/irq.h>
60
61/** Open channel that is assigned automatically to new tasks */
62answerbox_t *ipc_phone_0 = NULL;
63
64static slab_cache_t *ipc_call_slab;
65static slab_cache_t *ipc_answerbox_slab;
66
67/** Initialize a call structure.
68 *
69 * @param call Call structure to be initialized.
70 *
71 */
72static void _ipc_call_init(call_t *call)
73{
74 memsetb(call, sizeof(*call), 0);
75 call->callerbox = &TASK->answerbox;
76 call->sender = TASK;
77 call->buffer = NULL;
78}
79
80/** Allocate and initialize a call structure.
81 *
82 * The call is initialized, so that the reply will be directed to
83 * TASK->answerbox.
84 *
85 * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC).
86 *
87 * @return If flags permit it, return NULL, or initialized kernel
88 * call structure.
89 *
90 */
91call_t *ipc_call_alloc(unsigned int flags)
92{
93 call_t *call = slab_alloc(ipc_call_slab, flags);
94 if (call)
95 _ipc_call_init(call);
96
97 return call;
98}
99
100/** Deallocate a call structure.
101 *
102 * @param call Call structure to be freed.
103 *
104 */
105void ipc_call_free(call_t *call)
106{
107 /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
108 if (call->buffer)
109 free(call->buffer);
110 slab_free(ipc_call_slab, call);
111}
112
113/** Initialize an answerbox structure.
114 *
115 * @param box Answerbox structure to be initialized.
116 * @param task Task to which the answerbox belongs.
117 *
118 */
119void ipc_answerbox_init(answerbox_t *box, task_t *task)
120{
121 irq_spinlock_initialize(&box->lock, "ipc.box.lock");
122 irq_spinlock_initialize(&box->irq_lock, "ipc.box.irqlock");
123 waitq_initialize(&box->wq);
124 link_initialize(&box->sync_box_link);
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_head);
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/** Helper function to facilitate synchronous calls.
168 *
169 * @param phone Destination kernel phone structure.
170 * @param request Call structure with request.
171 *
172 * @return EOK on success or EINTR if the sleep was interrupted.
173 *
174 */
175int ipc_call_sync(phone_t *phone, call_t *request)
176{
177 answerbox_t *sync_box = slab_alloc(ipc_answerbox_slab, 0);
178 ipc_answerbox_init(sync_box, TASK);
179
180 /*
181 * Put the answerbox on the TASK's list of synchronous answerboxes so
182 * that it can be cleaned up if the call is interrupted.
183 */
184 irq_spinlock_lock(&TASK->lock, true);
185 list_append(&sync_box->sync_box_link, &TASK->sync_box_head);
186 irq_spinlock_unlock(&TASK->lock, true);
187
188 /* We will receive data in a special box. */
189 request->callerbox = sync_box;
190
191 ipc_call(phone, request);
192 if (!ipc_wait_for_call(sync_box, SYNCH_NO_TIMEOUT,
193 SYNCH_FLAGS_INTERRUPTIBLE)) {
194 /* The answerbox and the call will be freed by ipc_cleanup(). */
195 return EINTR;
196 }
197
198 /*
199 * The answer arrived without interruption so we can remove the
200 * answerbox from the TASK's list of synchronous answerboxes.
201 */
202 irq_spinlock_lock(&TASK->lock, true);
203 list_remove(&sync_box->sync_box_link);
204 irq_spinlock_unlock(&TASK->lock, true);
205
206 slab_free(ipc_answerbox_slab, sync_box);
207 return EOK;
208}
209
210/** Answer a message which was not dispatched and is not listed in any queue.
211 *
212 * @param call Call structure to be answered.
213 * @param selflocked If true, then TASK->answebox is locked.
214 *
215 */
216static void _ipc_answer_free_call(call_t *call, bool selflocked)
217{
218 answerbox_t *callerbox = call->callerbox;
219 bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
220
221 /* Count sent answer */
222 irq_spinlock_lock(&TASK->lock, true);
223 TASK->ipc_info.answer_sent++;
224 irq_spinlock_unlock(&TASK->lock, true);
225
226 call->flags |= IPC_CALL_ANSWERED;
227
228 if (call->flags & IPC_CALL_FORWARDED) {
229 if (call->caller_phone) {
230 /* Demasquerade the caller phone. */
231 call->data.phone = call->caller_phone;
232 }
233 }
234
235 if (do_lock)
236 irq_spinlock_lock(&callerbox->lock, true);
237
238 list_append(&call->link, &callerbox->answers);
239
240 if (do_lock)
241 irq_spinlock_unlock(&callerbox->lock, true);
242
243 waitq_wakeup(&callerbox->wq, WAKEUP_FIRST);
244}
245
246/** Answer a message which is in a callee queue.
247 *
248 * @param box Answerbox that is answering the message.
249 * @param call Modified request that is being sent back.
250 *
251 */
252void ipc_answer(answerbox_t *box, call_t *call)
253{
254 /* Remove from active box */
255 irq_spinlock_lock(&box->lock, true);
256 list_remove(&call->link);
257 irq_spinlock_unlock(&box->lock, true);
258
259 /* Send back answer */
260 _ipc_answer_free_call(call, false);
261}
262
263/** Simulate sending back a message.
264 *
265 * Most errors are better handled by forming a normal backward
266 * message and sending it as a normal answer.
267 *
268 * @param phone Phone structure the call should appear to come from.
269 * @param call Call structure to be answered.
270 * @param err Return value to be used for the answer.
271 *
272 */
273void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
274{
275 call->data.phone = phone;
276 atomic_inc(&phone->active_calls);
277 IPC_SET_RETVAL(call->data, err);
278 _ipc_answer_free_call(call, false);
279}
280
281/** Unsafe unchecking version of ipc_call.
282 *
283 * @param phone Phone structure the call comes from.
284 * @param box Destination answerbox structure.
285 * @param call Call structure with request.
286 *
287 */
288static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
289{
290 /* Count sent ipc call */
291 irq_spinlock_lock(&TASK->lock, true);
292 TASK->ipc_info.call_sent++;
293 irq_spinlock_unlock(&TASK->lock, true);
294
295 if (!(call->flags & IPC_CALL_FORWARDED)) {
296 atomic_inc(&phone->active_calls);
297 call->data.phone = phone;
298 call->data.task = TASK;
299 }
300
301 irq_spinlock_lock(&box->lock, true);
302 list_append(&call->link, &box->calls);
303 irq_spinlock_unlock(&box->lock, true);
304
305 waitq_wakeup(&box->wq, WAKEUP_FIRST);
306}
307
308/** Send an asynchronous request using a phone to an answerbox.
309 *
310 * @param phone Phone structure the call comes from and which is
311 * connected to the destination answerbox.
312 * @param call Call structure with request.
313 *
314 * @return Return 0 on success, ENOENT on error.
315 *
316 */
317int ipc_call(phone_t *phone, call_t *call)
318{
319 mutex_lock(&phone->lock);
320 if (phone->state != IPC_PHONE_CONNECTED) {
321 mutex_unlock(&phone->lock);
322 if (call->flags & IPC_CALL_FORWARDED) {
323 IPC_SET_RETVAL(call->data, EFORWARD);
324 _ipc_answer_free_call(call, false);
325 } else {
326 if (phone->state == IPC_PHONE_HUNGUP)
327 ipc_backsend_err(phone, call, EHANGUP);
328 else
329 ipc_backsend_err(phone, call, ENOENT);
330 }
331
332 return ENOENT;
333 }
334
335 answerbox_t *box = phone->callee;
336 _ipc_call(phone, box, call);
337
338 mutex_unlock(&phone->lock);
339 return 0;
340}
341
342/** Disconnect phone from answerbox.
343 *
344 * This call leaves the phone in the HUNGUP state. The change to 'free' is done
345 * lazily later.
346 *
347 * @param phone Phone structure to be hung up.
348 *
349 * @return 0 if the phone is disconnected.
350 * @return -1 if the phone was already disconnected.
351 *
352 */
353int ipc_phone_hangup(phone_t *phone)
354{
355 mutex_lock(&phone->lock);
356 if (phone->state == IPC_PHONE_FREE ||
357 phone->state == IPC_PHONE_HUNGUP ||
358 phone->state == IPC_PHONE_CONNECTING) {
359 mutex_unlock(&phone->lock);
360 return -1;
361 }
362
363 answerbox_t *box = phone->callee;
364 if (phone->state != IPC_PHONE_SLAMMED) {
365 /* Remove myself from answerbox */
366 irq_spinlock_lock(&box->lock, true);
367 list_remove(&phone->link);
368 irq_spinlock_unlock(&box->lock, true);
369
370 call_t *call = ipc_call_alloc(0);
371 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
372 call->flags |= IPC_CALL_DISCARD_ANSWER;
373 _ipc_call(phone, box, call);
374 }
375
376 phone->state = IPC_PHONE_HUNGUP;
377 mutex_unlock(&phone->lock);
378
379 return 0;
380}
381
382/** Forwards call from one answerbox to another one.
383 *
384 * @param call Call structure to be redirected.
385 * @param newphone Phone structure to target answerbox.
386 * @param oldbox Old answerbox structure.
387 * @param mode Flags that specify mode of the forward operation.
388 *
389 * @return 0 if forwarding succeeded or an error code if
390 * there was an error.
391 *
392 * The return value serves only as an information for the forwarder,
393 * the original caller is notified automatically with EFORWARD.
394 *
395 */
396int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox,
397 unsigned int mode)
398{
399 /* Count forwarded calls */
400 irq_spinlock_lock(&TASK->lock, true);
401 TASK->ipc_info.forwarded++;
402 irq_spinlock_pass(&TASK->lock, &oldbox->lock);
403 list_remove(&call->link);
404 irq_spinlock_unlock(&oldbox->lock, true);
405
406 if (mode & IPC_FF_ROUTE_FROM_ME) {
407 if (!call->caller_phone)
408 call->caller_phone = call->data.phone;
409 call->data.phone = newphone;
410 call->data.task = TASK;
411 }
412
413 return ipc_call(newphone, call);
414}
415
416
417/** Wait for a phone call.
418 *
419 * @param box Answerbox expecting the call.
420 * @param usec Timeout in microseconds. See documentation for
421 * waitq_sleep_timeout() for decription of its special
422 * meaning.
423 * @param flags Select mode of sleep operation. See documentation for
424 * waitq_sleep_timeout() for description of its special
425 * meaning.
426 *
427 * @return Recived call structure or NULL.
428 *
429 * To distinguish between a call and an answer, have a look at call->flags.
430 *
431 */
432call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, unsigned int flags)
433{
434 call_t *request;
435 uint64_t irq_cnt = 0;
436 uint64_t answer_cnt = 0;
437 uint64_t call_cnt = 0;
438 int rc;
439
440restart:
441 rc = waitq_sleep_timeout(&box->wq, usec, flags);
442 if (SYNCH_FAILED(rc))
443 return NULL;
444
445 irq_spinlock_lock(&box->lock, true);
446 if (!list_empty(&box->irq_notifs)) {
447 /* Count received IRQ notification */
448 irq_cnt++;
449
450 irq_spinlock_lock(&box->irq_lock, false);
451
452 request = list_get_instance(box->irq_notifs.next, call_t, link);
453 list_remove(&request->link);
454
455 irq_spinlock_unlock(&box->irq_lock, false);
456 } else if (!list_empty(&box->answers)) {
457 /* Count received answer */
458 answer_cnt++;
459
460 /* Handle asynchronous answers */
461 request = list_get_instance(box->answers.next, call_t, link);
462 list_remove(&request->link);
463 atomic_dec(&request->data.phone->active_calls);
464 } else if (!list_empty(&box->calls)) {
465 /* Count received call */
466 call_cnt++;
467
468 /* Handle requests */
469 request = list_get_instance(box->calls.next, call_t, link);
470 list_remove(&request->link);
471
472 /* Append request to dispatch queue */
473 list_append(&request->link, &box->dispatched_calls);
474 } else {
475 /* This can happen regularly after ipc_cleanup */
476 irq_spinlock_unlock(&box->lock, true);
477 goto restart;
478 }
479
480 irq_spinlock_pass(&box->lock, &TASK->lock);
481
482 TASK->ipc_info.irq_notif_received += irq_cnt;
483 TASK->ipc_info.answer_received += answer_cnt;
484 TASK->ipc_info.call_received += call_cnt;
485
486 irq_spinlock_unlock(&TASK->lock, true);
487
488 return request;
489}
490
491/** Answer all calls from list with EHANGUP answer.
492 *
493 * @param lst Head of the list to be cleaned up.
494 *
495 */
496void ipc_cleanup_call_list(link_t *lst)
497{
498 while (!list_empty(lst)) {
499 call_t *call = list_get_instance(lst->next, call_t, link);
500 if (call->buffer)
501 free(call->buffer);
502
503 list_remove(&call->link);
504
505 IPC_SET_RETVAL(call->data, EHANGUP);
506 _ipc_answer_free_call(call, true);
507 }
508}
509
510/** Disconnects all phones connected to an answerbox.
511 *
512 * @param box Answerbox to disconnect phones from.
513 * @param notify_box If true, the answerbox will get a hangup message for
514 * each disconnected phone.
515 *
516 */
517void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
518{
519 phone_t *phone;
520 DEADLOCK_PROBE_INIT(p_phonelck);
521
522 call_t *call = notify_box ? ipc_call_alloc(0) : NULL;
523
524 /* Disconnect all phones connected to our answerbox */
525restart_phones:
526 irq_spinlock_lock(&box->lock, true);
527 while (!list_empty(&box->connected_phones)) {
528 phone = list_get_instance(box->connected_phones.next,
529 phone_t, link);
530 if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
531 irq_spinlock_unlock(&box->lock, true);
532 DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
533 goto restart_phones;
534 }
535
536 /* Disconnect phone */
537 ASSERT(phone->state == IPC_PHONE_CONNECTED);
538
539 list_remove(&phone->link);
540 phone->state = IPC_PHONE_SLAMMED;
541
542 if (notify_box) {
543 mutex_unlock(&phone->lock);
544 irq_spinlock_unlock(&box->lock, true);
545
546 /*
547 * Send one message to the answerbox for each
548 * phone. Used to make sure the kbox thread
549 * wakes up after the last phone has been
550 * disconnected.
551 */
552 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
553 call->flags |= IPC_CALL_DISCARD_ANSWER;
554 _ipc_call(phone, box, call);
555
556 /* Allocate another call in advance */
557 call = ipc_call_alloc(0);
558
559 /* Must start again */
560 goto restart_phones;
561 }
562
563 mutex_unlock(&phone->lock);
564 }
565
566 irq_spinlock_unlock(&box->lock, true);
567
568 /* Free unused call */
569 if (call)
570 ipc_call_free(call);
571}
572
573/** Clean up all IPC communication of the current task.
574 *
575 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
576 * have to change it as well if you want to cleanup other tasks than TASK.
577 *
578 */
579void ipc_cleanup(void)
580{
581 /* Disconnect all our phones ('ipc_phone_hangup') */
582 size_t i;
583 for (i = 0; i < IPC_MAX_PHONES; i++)
584 ipc_phone_hangup(&TASK->phones[i]);
585
586 /* Unsubscribe from any event notifications. */
587 event_cleanup_answerbox(&TASK->answerbox);
588
589 /* Disconnect all connected irqs */
590 ipc_irq_cleanup(&TASK->answerbox);
591
592 /* Disconnect all phones connected to our regular answerbox */
593 ipc_answerbox_slam_phones(&TASK->answerbox, false);
594
595#ifdef CONFIG_UDEBUG
596 /* Clean up kbox thread and communications */
597 ipc_kbox_cleanup();
598#endif
599
600 /* Answer all messages in 'calls' and 'dispatched_calls' queues */
601 irq_spinlock_lock(&TASK->answerbox.lock, true);
602 ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
603 ipc_cleanup_call_list(&TASK->answerbox.calls);
604 irq_spinlock_unlock(&TASK->answerbox.lock, true);
605
606 /* Wait for all answers to interrupted synchronous calls to arrive */
607 ipl_t ipl = interrupts_disable();
608 while (!list_empty(&TASK->sync_box_head)) {
609 answerbox_t *box = list_get_instance(TASK->sync_box_head.next,
610 answerbox_t, sync_box_link);
611
612 list_remove(&box->sync_box_link);
613 call_t *call = ipc_wait_for_call(box, SYNCH_NO_TIMEOUT,
614 SYNCH_FLAGS_NONE);
615 ipc_call_free(call);
616 slab_free(ipc_answerbox_slab, box);
617 }
618 interrupts_restore(ipl);
619
620 /* Wait for all answers to asynchronous calls to arrive */
621 while (true) {
622 /*
623 * Go through all phones, until they are all FREE
624 * Locking is not needed, no one else should modify
625 * it when we are in cleanup
626 */
627 for (i = 0; i < IPC_MAX_PHONES; i++) {
628 if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
629 atomic_get(&TASK->phones[i].active_calls) == 0) {
630 TASK->phones[i].state = IPC_PHONE_FREE;
631 TASK->phones[i].callee = NULL;
632 }
633
634 /*
635 * Just for sure, we might have had some
636 * IPC_PHONE_CONNECTING phones
637 */
638 if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
639 ipc_phone_hangup(&TASK->phones[i]);
640
641 /*
642 * If the hangup succeeded, it has sent a HANGUP
643 * message, the IPC is now in HUNGUP state, we
644 * wait for the reply to come
645 */
646
647 if (TASK->phones[i].state != IPC_PHONE_FREE)
648 break;
649 }
650
651 /* Got into cleanup */
652 if (i == IPC_MAX_PHONES)
653 break;
654
655 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
656 SYNCH_FLAGS_NONE);
657 ASSERT((call->flags & IPC_CALL_ANSWERED) ||
658 (call->flags & IPC_CALL_NOTIF));
659
660 ipc_call_free(call);
661 }
662}
663
664/** Initilize IPC subsystem
665 *
666 */
667void ipc_init(void)
668{
669 ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL,
670 NULL, 0);
671 ipc_answerbox_slab = slab_cache_create("ipc_answerbox",
672 sizeof(answerbox_t), 0, NULL, NULL, 0);
673}
674
675/** List answerbox contents.
676 *
677 * @param taskid Task ID.
678 *
679 */
680void ipc_print_task(task_id_t taskid)
681{
682 irq_spinlock_lock(&tasks_lock, true);
683 task_t *task = task_find_by_id(taskid);
684
685 if (!task) {
686 irq_spinlock_unlock(&tasks_lock, true);
687 return;
688 }
689
690 /* Hand-over-hand locking */
691 irq_spinlock_exchange(&tasks_lock, &task->lock);
692
693 printf("[phone id] [calls] [state\n");
694
695 size_t i;
696 for (i = 0; i < IPC_MAX_PHONES; i++) {
697 if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) {
698 printf("%-10zu (mutex busy)\n", i);
699 continue;
700 }
701
702 if (task->phones[i].state != IPC_PHONE_FREE) {
703 printf("%-10zu %7" PRIun " ", i,
704 atomic_get(&task->phones[i].active_calls));
705
706 switch (task->phones[i].state) {
707 case IPC_PHONE_CONNECTING:
708 printf("connecting");
709 break;
710 case IPC_PHONE_CONNECTED:
711 printf("connected to %" PRIu64 " (%s)",
712 task->phones[i].callee->task->taskid,
713 task->phones[i].callee->task->name);
714 break;
715 case IPC_PHONE_SLAMMED:
716 printf("slammed by %p",
717 task->phones[i].callee);
718 break;
719 case IPC_PHONE_HUNGUP:
720 printf("hung up by %p",
721 task->phones[i].callee);
722 break;
723 default:
724 break;
725 }
726
727 printf("\n");
728 }
729
730 mutex_unlock(&task->phones[i].lock);
731 }
732
733 irq_spinlock_lock(&task->answerbox.lock, false);
734
735#ifdef __32_BITS__
736 printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4] [arg5]"
737 " [flags] [sender\n");
738#endif
739
740#ifdef __64_BITS__
741 printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4]"
742 " [arg5] [flags] [sender\n");
743#endif
744
745 link_t *cur;
746
747 printf(" --- incomming calls ---\n");
748 for (cur = task->answerbox.calls.next; cur != &task->answerbox.calls;
749 cur = cur->next) {
750 call_t *call = list_get_instance(cur, call_t, link);
751
752#ifdef __32_BITS__
753 printf("%10p ", call);
754#endif
755
756#ifdef __64_BITS__
757 printf("%18p ", call);
758#endif
759
760 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
761 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
762 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
763 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
764 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
765 call->flags, call->sender->taskid, call->sender->name);
766 }
767
768 printf(" --- dispatched calls ---\n");
769 for (cur = task->answerbox.dispatched_calls.next;
770 cur != &task->answerbox.dispatched_calls;
771 cur = cur->next) {
772 call_t *call = list_get_instance(cur, call_t, link);
773
774#ifdef __32_BITS__
775 printf("%10p ", call);
776#endif
777
778#ifdef __64_BITS__
779 printf("%18p ", call);
780#endif
781
782 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
783 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
784 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
785 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
786 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
787 call->flags, call->sender->taskid, call->sender->name);
788 }
789
790 printf(" --- incoming answers ---\n");
791 for (cur = task->answerbox.answers.next;
792 cur != &task->answerbox.answers;
793 cur = cur->next) {
794 call_t *call = list_get_instance(cur, call_t, link);
795
796#ifdef __32_BITS__
797 printf("%10p ", call);
798#endif
799
800#ifdef __64_BITS__
801 printf("%18p ", call);
802#endif
803
804 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
805 " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
806 IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
807 IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
808 IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
809 call->flags, call->sender->taskid, call->sender->name);
810 }
811
812 irq_spinlock_unlock(&task->answerbox.lock, false);
813 irq_spinlock_unlock(&task->lock, true);
814}
815
816/** @}
817 */
Note: See TracBrowser for help on using the repository browser.