Subversion Repositories HelenOS

Rev

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
    }