Subversion Repositories HelenOS

Rev

Rev 3441 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  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 generic
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file
  35.  * @brief   Udebug.
  36.  *
  37.  * Functions in this file are executed directly in each thread, which
  38.  * may or may not be the subject of debugging. The udebug_stoppable_begin/end()
  39.  * functions are also executed in the clock interrupt handler. To avoid
  40.  * deadlock, functions in this file are protected from the interrupt
  41.  * by locking the recursive lock THREAD->udebug.int_lock (just an atomic
  42.  * variable). This prevents udebug_stoppable_begin/end() from being
  43.  * executed in the interrupt handler (they are skipped).
  44.  *
  45.  * Functions in udebug_ops.c and udebug_ipc.c execute in different threads,
  46.  * so they needn't be protected from the (preemptible) interrupt-initiated
  47.  * code.
  48.  */
  49.  
  50. #include <synch/waitq.h>
  51. #include <print.h>
  52. #include <udebug/udebug.h>
  53. #include <errno.h>
  54. #include <arch.h>
  55.  
  56. static inline void udebug_int_lock(void)
  57. {
  58.     atomic_inc(&THREAD->udebug.int_lock);
  59. }
  60.  
  61. static inline void udebug_int_unlock(void)
  62. {
  63.     atomic_dec(&THREAD->udebug.int_lock);
  64. }
  65.  
  66. void udebug_task_init(udebug_task_t *ut)
  67. {
  68.     mutex_initialize(&ut->lock, MUTEX_PASSIVE);
  69.     ut->dt_state = UDEBUG_TS_INACTIVE;
  70.     ut->begin_call = NULL;
  71.     ut->not_stoppable_count = 0;
  72.     ut->evmask = 0;
  73. }
  74.  
  75. void udebug_thread_initialize(udebug_thread_t *ut)
  76. {
  77.     mutex_initialize(&ut->lock, MUTEX_PASSIVE);
  78.     waitq_initialize(&ut->go_wq);
  79.  
  80.     /*
  81.      * At the beginning the thread is stoppable, so int_lock be set, too.
  82.      */
  83.     atomic_set(&ut->int_lock, 1);
  84.  
  85.     ut->go_call = NULL;
  86.     ut->stop = true;
  87.     ut->stoppable = true;
  88.     ut->debug_active = false;
  89.     ut->cur_event = 0; /* none */
  90. }
  91.  
  92. static void udebug_wait_for_go(waitq_t *wq)
  93. {
  94.     int rc;
  95.     ipl_t ipl;
  96.  
  97.     ipl = waitq_sleep_prepare(wq);
  98.  
  99.     wq->missed_wakeups = 0; /* Enforce blocking. */
  100.     rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
  101.  
  102.     waitq_sleep_finish(wq, rc, ipl);
  103. }
  104.  
  105. /** Do a preliminary check that a debugging session is in progress.
  106.  *
  107.  * This only requires the THREAD->udebug.lock mutex (and not
  108.  * TASK->udebug.lock mutex). For an undebugged task, this will
  109.  * never block (while there could be collisions by different threads
  110.  * on the TASK mutex), thus improving SMP perormance for undebugged tasks.
  111.  */
  112. static bool udebug_thread_precheck(void)
  113. {
  114.     bool res;
  115.  
  116.     mutex_lock(&THREAD->udebug.lock);
  117.     res = THREAD->udebug.debug_active;
  118.     mutex_unlock(&THREAD->udebug.lock);
  119.  
  120.     return res;
  121. }
  122.  
  123. void udebug_stoppable_begin(void)
  124. {
  125.     int nsc;
  126.     call_t *db_call, *go_call;
  127.  
  128.     ASSERT(THREAD);
  129.     ASSERT(TASK);
  130.  
  131.     udebug_int_lock();
  132.  
  133.     /* Early check for undebugged tasks */
  134.     if (!udebug_thread_precheck()) {
  135.         udebug_int_unlock();
  136.         return;
  137.     }
  138.  
  139.     mutex_lock(&TASK->udebug.lock);
  140.  
  141.     nsc = --TASK->udebug.not_stoppable_count;
  142.  
  143.     /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */
  144.     mutex_lock(&THREAD->udebug.lock);
  145.     ASSERT(THREAD->udebug.stoppable == false);
  146.     THREAD->udebug.stoppable = true;
  147.  
  148.     if (TASK->udebug.dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
  149.         /*
  150.          * This was the last non-stoppable thread. Reply to
  151.          * DEBUG_BEGIN call.
  152.          */
  153.  
  154.         db_call = TASK->udebug.begin_call;
  155.         ASSERT(db_call);
  156.  
  157.         TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
  158.         TASK->udebug.begin_call = NULL;
  159.  
  160.         IPC_SET_RETVAL(db_call->data, 0);
  161.         ipc_answer(&TASK->answerbox, db_call);     
  162.  
  163.     } else if (TASK->udebug.dt_state == UDEBUG_TS_ACTIVE) {
  164.         /*
  165.          * Active debugging session
  166.          */
  167.  
  168.         if (THREAD->udebug.debug_active && THREAD->udebug.stop) {
  169.             /*
  170.              * Thread was requested to stop - answer go call
  171.              */
  172.  
  173.             /* Make sure nobody takes this call away from us */
  174.             go_call = THREAD->udebug.go_call;
  175.             THREAD->udebug.go_call = NULL;
  176.             ASSERT(go_call);
  177.  
  178.             IPC_SET_RETVAL(go_call->data, 0);
  179.             IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
  180.  
  181.             THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
  182.  
  183.                 ipc_answer(&TASK->answerbox, go_call);
  184.         }
  185.     }
  186.  
  187.     mutex_unlock(&THREAD->udebug.lock);
  188.         mutex_unlock(&TASK->udebug.lock);
  189. }
  190.  
  191. void udebug_stoppable_end(void)
  192. {
  193.     /* Early check for undebugged tasks */
  194.     if (!udebug_thread_precheck()) {
  195.         udebug_int_unlock();
  196.         return;
  197.     }
  198.  
  199. restart:
  200.     mutex_lock(&TASK->udebug.lock);
  201.     mutex_lock(&THREAD->udebug.lock);
  202.  
  203.     if (THREAD->udebug.debug_active &&
  204.         THREAD->udebug.stop == true) {
  205.         TASK->udebug.begin_call = NULL;
  206.         mutex_unlock(&THREAD->udebug.lock);
  207.         mutex_unlock(&TASK->udebug.lock);
  208.  
  209.         udebug_wait_for_go(&THREAD->udebug.go_wq);
  210.  
  211.         goto restart;
  212.         /* must try again - have to lose stoppability atomically */
  213.     } else {
  214.         ++TASK->udebug.not_stoppable_count;
  215.         ASSERT(THREAD->udebug.stoppable == true);
  216.         THREAD->udebug.stoppable = false;
  217.  
  218.         mutex_unlock(&THREAD->udebug.lock);
  219.         mutex_unlock(&TASK->udebug.lock);
  220.     }
  221.  
  222.     udebug_int_unlock();
  223. }
  224.  
  225. /** Upon being scheduled to run, check if the current thread should stop.
  226.  *
  227.  * This function is called from clock(). Preemption is enabled.
  228.  * interrupts are disabled, but since this is called after
  229.  * being scheduled-in, we can enable them, if we're careful enough
  230.  * not to allow arbitrary recursion or deadlock with the thread context.
  231.  */
  232. void udebug_before_thread_runs(void)
  233. {
  234.     ipl_t ipl;
  235.  
  236.     return;
  237.     ASSERT(!PREEMPTION_DISABLED);
  238.  
  239.     /*
  240.      * Prevent agains re-entering, such as when preempted inside this
  241.      * function.
  242.      */
  243.     if (atomic_get(&THREAD->udebug.int_lock) != 0)
  244.         return;
  245.  
  246.     udebug_int_lock();
  247.  
  248.     ipl = interrupts_enable();
  249.  
  250.     /* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */
  251.  
  252.     /* Check if we're supposed to stop */
  253.     udebug_stoppable_begin();
  254.     udebug_stoppable_end();
  255.  
  256.     interrupts_restore(ipl);
  257.  
  258.     udebug_int_unlock();
  259. }
  260.  
  261. void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
  262.     unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
  263.     bool end_variant)
  264. {
  265.     call_t *call;
  266.     udebug_event_t etype;
  267.  
  268.     etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
  269.  
  270.     udebug_int_lock();
  271.  
  272.     /* Early check for undebugged tasks */
  273.     if (!udebug_thread_precheck()) {
  274.         udebug_int_unlock();
  275.         return;
  276.     }
  277.  
  278.     mutex_lock(&TASK->udebug.lock);
  279.     mutex_lock(&THREAD->udebug.lock);
  280.  
  281.     /* Must only generate events when in debugging session and have go */
  282.     if (THREAD->udebug.debug_active != true ||
  283.         THREAD->udebug.stop == true ||
  284.         (TASK->udebug.evmask & UDEBUG_EVMASK(etype)) == 0) {
  285.         mutex_unlock(&THREAD->udebug.lock);
  286.         mutex_unlock(&TASK->udebug.lock);
  287.         return;
  288.     }
  289.  
  290.     //printf("udebug_syscall_event\n");
  291.     call = THREAD->udebug.go_call;
  292.     THREAD->udebug.go_call = NULL;
  293.  
  294.     IPC_SET_RETVAL(call->data, 0);
  295.     IPC_SET_ARG1(call->data, etype);
  296.     IPC_SET_ARG2(call->data, id);
  297.     IPC_SET_ARG3(call->data, rc);
  298.     //printf("udebug_syscall_event/ipc_answer\n");
  299.  
  300.     THREAD->udebug.syscall_args[0] = a1;
  301.     THREAD->udebug.syscall_args[1] = a2;
  302.     THREAD->udebug.syscall_args[2] = a3;
  303.     THREAD->udebug.syscall_args[3] = a4;
  304.     THREAD->udebug.syscall_args[4] = a5;
  305.     THREAD->udebug.syscall_args[5] = a6;
  306.  
  307.     /*
  308.      * Make sure udebug.stop is true when going to sleep
  309.      * in case we get woken up by DEBUG_END. (At which
  310.      * point it must be back to the initial true value).
  311.      */
  312.     THREAD->udebug.stop = true;
  313.     THREAD->udebug.cur_event = etype;
  314.  
  315.     ipc_answer(&TASK->answerbox, call);
  316.  
  317.     mutex_unlock(&THREAD->udebug.lock);
  318.     mutex_unlock(&TASK->udebug.lock);
  319.  
  320.     udebug_wait_for_go(&THREAD->udebug.go_wq);
  321.  
  322.     udebug_int_unlock();
  323. }
  324.  
  325. void udebug_thread_b_event(struct thread *t)
  326. {
  327.     call_t *call;
  328.  
  329.     udebug_int_lock();
  330.  
  331.     mutex_lock(&TASK->udebug.lock);
  332.     mutex_lock(&THREAD->udebug.lock);
  333.  
  334.     printf("udebug_thread_b_event\n");
  335.     printf("- check state\n");
  336.  
  337.     /* Must only generate events when in debugging session */
  338.     if (THREAD->udebug.debug_active != true) {
  339.         printf("- debug_active: %s, udebug.stop: %s\n",
  340.             THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
  341.             THREAD->udebug.stop ? "yes(-)" : "no(+)");
  342.         mutex_unlock(&THREAD->udebug.lock);
  343.         mutex_unlock(&TASK->udebug.lock);
  344.         return;
  345.     }
  346.  
  347.     printf("- trigger event\n");
  348.  
  349.     call = THREAD->udebug.go_call;
  350.     THREAD->udebug.go_call = NULL;
  351.     IPC_SET_RETVAL(call->data, 0);
  352.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B);
  353.     IPC_SET_ARG2(call->data, (unative_t)t);
  354.  
  355.     /*
  356.      * Make sure udebug.stop is true when going to sleep
  357.      * in case we get woken up by DEBUG_END. (At which
  358.      * point it must be back to the initial true value).
  359.      */
  360.     THREAD->udebug.stop = true;
  361.     THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B;
  362.  
  363.     ipc_answer(&TASK->answerbox, call);
  364.  
  365.     mutex_unlock(&THREAD->udebug.lock);
  366.     mutex_unlock(&TASK->udebug.lock);
  367.  
  368.     printf("- sleep\n");
  369.     udebug_wait_for_go(&THREAD->udebug.go_wq);
  370.  
  371.     udebug_int_unlock();
  372. }
  373.  
  374. void udebug_thread_e_event(void)
  375. {
  376.     call_t *call;
  377.  
  378.     udebug_int_lock();
  379.  
  380.     mutex_lock(&TASK->udebug.lock);
  381.     mutex_lock(&THREAD->udebug.lock);
  382.  
  383. //  printf("udebug_thread_e_event\n");
  384. //  printf("- check state\n");
  385.  
  386.     /* Must only generate events when in debugging session */
  387.     if (THREAD->udebug.debug_active != true) {
  388. /*      printf("- debug_active: %s, udebug.stop: %s\n",
  389.             THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
  390.             THREAD->udebug.stop ? "yes(-)" : "no(+)");*/
  391.         mutex_unlock(&THREAD->udebug.lock);
  392.         mutex_unlock(&TASK->udebug.lock);
  393.         return;
  394.     }
  395.  
  396. //  printf("- trigger event\n");
  397.  
  398.     call = THREAD->udebug.go_call;
  399.     THREAD->udebug.go_call = NULL;
  400.     IPC_SET_RETVAL(call->data, 0);
  401.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E);
  402.  
  403.     /* Prevent any further debug activity in thread */
  404.     THREAD->udebug.debug_active = false;
  405.     THREAD->udebug.cur_event = 0;       /* none */
  406.     THREAD->udebug.stop = true; /* set to initial value */
  407.  
  408.     ipc_answer(&TASK->answerbox, call);
  409.  
  410.     mutex_unlock(&THREAD->udebug.lock);
  411.     mutex_unlock(&TASK->udebug.lock);
  412.  
  413.     /* Leave int_lock enabled */
  414.     /* This event does not sleep - debugging has finished in this thread */
  415. }
  416.  
  417. /**
  418.  * Terminate task debugging session.
  419.  *
  420.  * \param ta->udebug.lock must be already locked.
  421.  * \return Zero on success or negative error code.
  422.  */
  423. int udebug_task_cleanup(struct task *ta)
  424. {
  425.     thread_t *t;
  426.     link_t *cur;
  427.     int flags;
  428.     ipl_t ipl;
  429.  
  430.     printf("udebug_task_cleanup()\n");
  431.     printf("task %llu\n", ta->taskid);
  432.  
  433.     udebug_int_lock();
  434.  
  435.     if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
  436.         ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
  437.         printf("udebug_task_cleanup(): task not being debugged\n");
  438.         return EINVAL;
  439.     }
  440.  
  441.     /* Finish debugging of all userspace threads */
  442.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  443.         t = list_get_instance(cur, thread_t, th_link);
  444.  
  445.         mutex_lock(&t->udebug.lock);
  446.  
  447.         ipl = interrupts_disable();
  448.         spinlock_lock(&t->lock);
  449.  
  450.         flags = t->flags;
  451.  
  452.         spinlock_unlock(&t->lock);
  453.         interrupts_restore(ipl);
  454.  
  455.         /* Only process userspace threads */
  456.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  457.             /* Prevent any further debug activity in thread */
  458.             t->udebug.debug_active = false;
  459.             t->udebug.cur_event = 0;    /* none */
  460.  
  461.             /* Still has go? */
  462.             if (t->udebug.stop == false) {
  463.                 /*
  464.                 * Yes, so clear go. As debug_active == false,
  465.                  * this doesn't affect anything.
  466.                  */
  467.                 t->udebug.stop = true; 
  468.  
  469.                 /* Answer GO call */
  470.                 printf("answer GO call with EVENT_FINISHED\n");
  471.                 IPC_SET_RETVAL(t->udebug.go_call->data, 0);
  472.                 IPC_SET_ARG1(t->udebug.go_call->data, UDEBUG_EVENT_FINISHED);
  473.  
  474.                 ipc_answer(&ta->answerbox, t->udebug.go_call);
  475.                 t->udebug.go_call = NULL;
  476.             } else {
  477.                 /*
  478.                  * Debug_stop is already at initial value.
  479.                  * Yet this means the thread needs waking up.
  480.                  */
  481.  
  482.                 /*
  483.                  * t's lock must not be held when calling
  484.                  * waitq_wakeup.
  485.                  */
  486.                 waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
  487.             }
  488.         }
  489.         mutex_unlock(&t->udebug.lock);
  490.     }
  491.  
  492.     ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
  493.     ta->udebug.debugger = NULL;
  494.  
  495.     udebug_int_unlock();
  496.  
  497.     return 0;
  498. }
  499.  
  500.  
  501. /** @}
  502.  */
  503.