Subversion Repositories HelenOS

Rev

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

Rev 3431 Rev 3433
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/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>
Line 426... Line 427...
426
 
427
 
427
/** Answer all calls from list with EHANGUP answer.
428
/** Answer all calls from list with EHANGUP answer.
428
 *
429
 *
429
 * @param lst       Head of the list to be cleaned up.
430
 * @param lst       Head of the list to be cleaned up.
430
 */
431
 */
431
static void ipc_cleanup_call_list(link_t *lst)
432
void ipc_cleanup_call_list(link_t *lst)
432
{
433
{
433
    call_t *call;
434
    call_t *call;
434
 
435
 
435
    while (!list_empty(lst)) {
436
    while (!list_empty(lst)) {
436
        call = list_get_instance(lst->next, call_t, link);
437
        call = list_get_instance(lst->next, call_t, link);
Line 447... Line 448...
447
 *
448
 *
448
 * @param box       Answerbox to disconnect phones from.
449
 * @param box       Answerbox to disconnect phones from.
449
 * @param notify_box    If true, the answerbox will get a hangup message for
450
 * @param notify_box    If true, the answerbox will get a hangup message for
450
 *          each disconnected phone.
451
 *          each disconnected phone.
451
 */
452
 */
452
static void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
453
void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
453
{
454
{
454
    phone_t *phone;
455
    phone_t *phone;
455
    DEADLOCK_PROBE_INIT(p_phonelck);
456
    DEADLOCK_PROBE_INIT(p_phonelck);
456
    ipl_t ipl;
457
    ipl_t ipl;
457
    call_t *call;
458
    call_t *call;
Line 508... Line 509...
508
 
509
 
509
    /* Free unused call */
510
    /* Free unused call */
510
    if (call) ipc_call_free(call);
511
    if (call) ipc_call_free(call);
511
}
512
}
512
 
513
 
513
#ifdef CONFIG_UDEBUG
-
 
514
 
-
 
515
static void ipc_kbox_cleanup()
-
 
516
{
-
 
517
    bool have_kb_thread;
-
 
518
 
-
 
519
    /* Only hold kb_cleanup_lock while setting kb_finished - this is enough */
-
 
520
    mutex_lock(&TASK->kb_cleanup_lock);
-
 
521
    TASK->kb_finished = true;
-
 
522
    mutex_unlock(&TASK->kb_cleanup_lock);
-
 
523
 
-
 
524
    have_kb_thread = (TASK->kb_thread != NULL);
-
 
525
 
-
 
526
    /* From now on nobody will try to connect phones or attach kbox threads */
-
 
527
 
-
 
528
    /*
-
 
529
     * Disconnect all phones connected to our kbox. Passing true for
-
 
530
     * notify_box causes a HANGUP message to be inserted for each
-
 
531
     * disconnected phone. This ensures the kbox thread is going to
-
 
532
     * wake up and terminate.
-
 
533
     */
-
 
534
    ipc_answerbox_slam_phones(&TASK->kernel_box, have_kb_thread);
-
 
535
   
-
 
536
    if (have_kb_thread) {
-
 
537
        printf("join kb_thread..\n");
-
 
538
        thread_join(TASK->kb_thread);
-
 
539
        thread_detach(TASK->kb_thread);
-
 
540
        printf("join done\n");
-
 
541
        TASK->kb_thread = NULL;
-
 
542
    }
-
 
543
 
-
 
544
    /* Answer all messages in 'calls' and 'dispatched_calls' queues */
-
 
545
    spinlock_lock(&TASK->kernel_box.lock);
-
 
546
    ipc_cleanup_call_list(&TASK->kernel_box.dispatched_calls);
-
 
547
    ipc_cleanup_call_list(&TASK->kernel_box.calls);
-
 
548
    spinlock_unlock(&TASK->kernel_box.lock);
-
 
549
}
-
 
550
 
-
 
551
#endif
-
 
552
 
-
 
553
/** Cleans up all IPC communication of the current task.
514
/** Cleans up all IPC communication of the current task.
554
 *
515
 *
555
 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
516
 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
556
 * have to change it as well if you want to cleanup other tasks than TASK.
517
 * have to change it as well if you want to cleanup other tasks than TASK.
557
 */
518
 */
Line 726... Line 687...
726
 
687
 
727
    spinlock_unlock(&task->answerbox.lock);
688
    spinlock_unlock(&task->answerbox.lock);
728
    spinlock_unlock(&task->lock);
689
    spinlock_unlock(&task->lock);
729
}
690
}
730
 
691
 
731
#ifdef CONFIG_UDEBUG
-
 
732
 
-
 
733
#include <ipc/ipcrsc.h>
-
 
734
#include <print.h>
-
 
735
#include <udebug/udebug_ipc.h>
-
 
736
 
-
 
737
static void kbox_thread_proc(void *arg)
-
 
738
{
-
 
739
    call_t *call;
-
 
740
    int method;
-
 
741
    bool done;
-
 
742
    ipl_t ipl;
-
 
743
 
-
 
744
    (void)arg;
-
 
745
    printf("kbox_thread_proc()\n");
-
 
746
    done = false;
-
 
747
 
-
 
748
    while (!done) {
-
 
749
        //printf("kbox: wait for call\n");
-
 
750
        call = ipc_wait_for_call(&TASK->kernel_box, SYNCH_NO_TIMEOUT,
-
 
751
            SYNCH_FLAGS_NONE);
-
 
752
 
-
 
753
        if (call != NULL) {
-
 
754
            method = IPC_GET_METHOD(call->data);
-
 
755
 
-
 
756
            if (method == IPC_M_DEBUG_ALL) {
-
 
757
                udebug_call_receive(call);
-
 
758
            }
-
 
759
 
-
 
760
            if (method == IPC_M_PHONE_HUNGUP) {
-
 
761
                printf("kbox: handle hangup message\n");
-
 
762
 
-
 
763
                /* Was it our debugger, who hung up? */
-
 
764
                if (call->sender == TASK->udebug.debugger) {
-
 
765
                    /* Terminate debugging session (if any) */
-
 
766
                    printf("kbox: terminate debug session\n");
-
 
767
                    ipl = interrupts_disable();
-
 
768
                    spinlock_lock(&TASK->lock);
-
 
769
                    udebug_task_cleanup(TASK);
-
 
770
                    spinlock_unlock(&TASK->lock);
-
 
771
                    interrupts_restore(ipl);
-
 
772
                } else {
-
 
773
                    printf("kbox: was not debugger\n");
-
 
774
                }
-
 
775
 
-
 
776
                printf("kbox: continue with hangup message\n");
-
 
777
                IPC_SET_RETVAL(call->data, 0);
-
 
778
                ipc_answer(&TASK->kernel_box, call);
-
 
779
 
-
 
780
                ipl = interrupts_disable();
-
 
781
                spinlock_lock(&TASK->lock);
-
 
782
                spinlock_lock(&TASK->answerbox.lock);
-
 
783
                if (list_empty(&TASK->answerbox.connected_phones)) {
-
 
784
                    /* Last phone has been disconnected */
-
 
785
                    TASK->kb_thread = NULL;
-
 
786
                    done = true;
-
 
787
                    printf("phone list is empty\n");
-
 
788
                }
-
 
789
                spinlock_unlock(&TASK->answerbox.lock);
-
 
790
                spinlock_unlock(&TASK->lock);
-
 
791
                interrupts_restore(ipl);
-
 
792
            }
-
 
793
        }
-
 
794
    }
-
 
795
 
-
 
796
    printf("kbox: finished\n");
-
 
797
}
-
 
798
 
-
 
799
 
-
 
800
/**
-
 
801
 * Connect phone to a task kernel-box specified by id.
-
 
802
 *
-
 
803
 * Note that this is not completely atomic. For optimisation reasons,
-
 
804
 * The task might start cleaning up kbox after the phone has been connected
-
 
805
 * and before a kbox thread has been created. This must be taken into account
-
 
806
 * in the cleanup code.
-
 
807
 *
-
 
808
 * @return      Phone id on success, or negative error code.
-
 
809
 */
-
 
810
int ipc_connect_kbox(task_id_t taskid)
-
 
811
{
-
 
812
    int newphid;
-
 
813
    task_t *ta;
-
 
814
    thread_t *kb_thread;
-
 
815
    ipl_t ipl;
-
 
816
 
-
 
817
    ipl = interrupts_disable();
-
 
818
    spinlock_lock(&tasks_lock);
-
 
819
 
-
 
820
    ta = task_find_by_id(taskid);
-
 
821
    if (ta == NULL) {
-
 
822
        spinlock_unlock(&tasks_lock);
-
 
823
        interrupts_restore(ipl);
-
 
824
        return ENOENT;
-
 
825
    }
-
 
826
 
-
 
827
    atomic_inc(&ta->refcount);
-
 
828
 
-
 
829
    spinlock_unlock(&tasks_lock);
-
 
830
    interrupts_restore(ipl);
-
 
831
 
-
 
832
    mutex_lock(&ta->kb_cleanup_lock);
-
 
833
 
-
 
834
    if (atomic_predec(&ta->refcount) == 0) {
-
 
835
        mutex_unlock(&ta->kb_cleanup_lock);
-
 
836
        task_destroy(ta);
-
 
837
        return ENOENT;
-
 
838
    }
-
 
839
 
-
 
840
    if (ta->kb_finished != false) {
-
 
841
        mutex_unlock(&ta->kb_cleanup_lock);
-
 
842
        return EINVAL;
-
 
843
    }
-
 
844
 
-
 
845
    newphid = phone_alloc();
-
 
846
    if (newphid < 0) {
-
 
847
        mutex_unlock(&ta->kb_cleanup_lock);
-
 
848
        return ELIMIT;
-
 
849
    }
-
 
850
 
-
 
851
    /* Connect the newly allocated phone to the kbox */
-
 
852
    ipc_phone_connect(&TASK->phones[newphid], &ta->kernel_box);
-
 
853
 
-
 
854
    if (ta->kb_thread != NULL) {
-
 
855
        mutex_unlock(&ta->kb_cleanup_lock);
-
 
856
        return newphid;
-
 
857
    }
-
 
858
 
-
 
859
    /* Create a kbox thread */
-
 
860
    kb_thread = thread_create(kbox_thread_proc, NULL, ta, 0, "kbox", false);
-
 
861
    if (!kb_thread) {
-
 
862
        mutex_unlock(&ta->kb_cleanup_lock);
-
 
863
        return ENOMEM;
-
 
864
    }
-
 
865
 
-
 
866
    ta->kb_thread = kb_thread;
-
 
867
    thread_ready(kb_thread);
-
 
868
 
-
 
869
    mutex_unlock(&ta->kb_cleanup_lock);
-
 
870
 
-
 
871
    return newphid;
-
 
872
}
-
 
873
 
-
 
874
#endif /* defined(CONFIG_UDEBUG) */
-
 
875
 
-
 
876
/** @}
692
/** @}
877
 */
693
 */