Subversion Repositories HelenOS

Rev

Rev 3403 | Rev 3474 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3403 Rev 3448
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 425... Line 427...
425
 
427
 
426
/** Answer all calls from list with EHANGUP answer.
428
/** Answer all calls from list with EHANGUP answer.
427
 *
429
 *
428
 * @param lst       Head of the list to be cleaned up.
430
 * @param lst       Head of the list to be cleaned up.
429
 */
431
 */
430
static void ipc_cleanup_call_list(link_t *lst)
432
void ipc_cleanup_call_list(link_t *lst)
431
{
433
{
432
    call_t *call;
434
    call_t *call;
433
 
435
 
434
    while (!list_empty(lst)) {
436
    while (!list_empty(lst)) {
435
        call = list_get_instance(lst->next, call_t, link);
437
        call = list_get_instance(lst->next, call_t, link);
Line 440... Line 442...
440
        IPC_SET_RETVAL(call->data, EHANGUP);
442
        IPC_SET_RETVAL(call->data, EHANGUP);
441
        _ipc_answer_free_call(call);
443
        _ipc_answer_free_call(call);
442
    }
444
    }
443
}
445
}
444
 
446
 
445
/** Cleans up all IPC communication of the current task.
447
/** Disconnects all phones connected to an answerbox.
446
 *
448
 *
447
 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
449
 * @param box       Answerbox to disconnect phones from.
448
 * 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.
449
 */
452
 */
450
void ipc_cleanup(void)
453
void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
451
{
454
{
452
    int i;
-
 
453
    call_t *call;
-
 
454
    phone_t *phone;
455
    phone_t *phone;
455
    DEADLOCK_PROBE_INIT(p_phonelck);
456
    DEADLOCK_PROBE_INIT(p_phonelck);
-
 
457
    ipl_t ipl;
-
 
458
    call_t *call;
456
 
459
 
457
    /* Disconnect all our phones ('ipc_phone_hangup') */
-
 
458
    for (i = 0; i < IPC_MAX_PHONES; i++)
-
 
459
        ipc_phone_hangup(&TASK->phones[i]);
-
 
460
 
-
 
461
    /* Disconnect all connected irqs */
460
    call = notify_box ? ipc_call_alloc(0) : NULL;
462
    ipc_irq_cleanup(&TASK->answerbox);
-
 
463
 
461
 
464
    /* Disconnect all phones connected to our answerbox */
462
    /* Disconnect all phones connected to our answerbox */
465
restart_phones:
463
restart_phones:
-
 
464
    ipl = interrupts_disable();
466
    spinlock_lock(&TASK->answerbox.lock);
465
    spinlock_lock(&box->lock);
467
    while (!list_empty(&TASK->answerbox.connected_phones)) {
466
    while (!list_empty(&box->connected_phones)) {
468
        phone = list_get_instance(TASK->answerbox.connected_phones.next,
467
        phone = list_get_instance(box->connected_phones.next,
469
            phone_t, link);
468
            phone_t, link);
470
        if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
469
        if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
471
            spinlock_unlock(&TASK->answerbox.lock);
470
            spinlock_unlock(&box->lock);
-
 
471
            interrupts_restore(ipl);
472
            DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
472
            DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
473
            goto restart_phones;
473
            goto restart_phones;
474
        }
474
        }
475
       
475
       
476
        /* Disconnect phone */
476
        /* Disconnect phone */
477
        ASSERT(phone->state == IPC_PHONE_CONNECTED);
477
        ASSERT(phone->state == IPC_PHONE_CONNECTED);
478
        phone->state = IPC_PHONE_SLAMMED;
-
 
-
 
478
 
479
        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
        }
480
 
503
 
481
        mutex_unlock(&phone->lock);
504
        mutex_unlock(&phone->lock);
482
    }
505
    }
483
 
506
 
-
 
507
    spinlock_unlock(&box->lock);
-
 
508
    interrupts_restore(ipl);
-
 
509
 
-
 
510
    /* Free unused call */
-
 
511
    if (call) ipc_call_free(call);
-
 
512
}
-
 
513
 
-
 
514
/** Cleans up all IPC communication of the current task.
-
 
515
 *
-
 
516
 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
-
 
517
 * have to change it as well if you want to cleanup other tasks than TASK.
-
 
518
 */
-
 
519
void ipc_cleanup(void)
-
 
520
{
-
 
521
    int i;
-
 
522
    call_t *call;
-
 
523
 
-
 
524
    /* Disconnect all our phones ('ipc_phone_hangup') */
-
 
525
    for (i = 0; i < IPC_MAX_PHONES; i++)
-
 
526
        ipc_phone_hangup(&TASK->phones[i]);
-
 
527
 
-
 
528
    /* Disconnect all connected irqs */
-
 
529
    ipc_irq_cleanup(&TASK->answerbox);
-
 
530
 
-
 
531
    /* Disconnect all phones connected to our regular answerbox */
-
 
532
    ipc_answerbox_slam_phones(&TASK->answerbox, false);
-
 
533
 
-
 
534
#ifdef CONFIG_UDEBUG
-
 
535
    /* Clean up kbox thread and communications */
-
 
536
    ipc_kbox_cleanup();
-
 
537
#endif
-
 
538
 
484
    /* Answer all messages in 'calls' and 'dispatched_calls' queues */
539
    /* Answer all messages in 'calls' and 'dispatched_calls' queues */
-
 
540
    spinlock_lock(&TASK->answerbox.lock);
485
    ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
541
    ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
486
    ipc_cleanup_call_list(&TASK->answerbox.calls);
542
    ipc_cleanup_call_list(&TASK->answerbox.calls);
487
    spinlock_unlock(&TASK->answerbox.lock);
543
    spinlock_unlock(&TASK->answerbox.lock);
488
   
544
   
489
    /* Wait for all async answers to arrive */
545
    /* Wait for all async answers to arrive */