/branches/tracing/kernel/generic/include/proc/thread.h |
---|
214,6 → 214,7 |
/** What type of event are we stopped in or 0 if none */ |
udebug_event_t cur_event; |
bool debug_stop; |
bool debug_stoppable; |
bool debug_active; /**< In a debugging session */ |
} thread_t; |
/branches/tracing/kernel/generic/include/udebug/udebug.h |
---|
148,6 → 148,7 |
typedef enum { |
UDEBUG_EVENT_FINISHED = 1, /**< Debuging session has finished */ |
UDEBUG_EVENT_STOP, /**< Stopped on DEBUG_STOP request */ |
UDEBUG_EVENT_SYSCALL, /**< A syscall has been executed */ |
UDEBUG_EVENT_NEW_THREAD /**< The task created a new thread */ |
} udebug_event_t; |
/branches/tracing/kernel/generic/include/udebug/udebug_ops.h |
---|
41,6 → 41,7 |
int udebug_end(void); |
int udebug_go(thread_t *t, call_t *call); |
int udebug_stop(thread_t *t, call_t *call); |
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n); |
int udebug_args_read(thread_t *t, void **buffer); |
/branches/tracing/kernel/generic/src/proc/thread.c |
---|
349,6 → 349,7 |
t->debug_go_call = NULL; |
t->uspace_state = NULL; |
t->debug_stop = true; |
t->debug_stoppable = true; |
t->debug_active = false; |
t->cur_event = 0; /* none */ |
/branches/tracing/kernel/generic/src/udebug/udebug_ipc.c |
---|
164,7 → 164,20 |
} |
} |
static void udebug_receive_stop(call_t *call) |
{ |
thread_t *t; |
int rc; |
klog_printf("debug_stop()"); |
t = (thread_t *)IPC_GET_ARG2(call->data); |
rc = udebug_stop(t, call); |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
} |
static void udebug_receive_thread_read(call_t *call) |
{ |
unative_t uspace_addr; |
421,6 → 434,9 |
case UDEBUG_M_GO: |
udebug_receive_go(call); |
break; |
case UDEBUG_M_STOP: |
udebug_receive_stop(call); |
break; |
case UDEBUG_M_THREAD_READ: |
udebug_receive_thread_read(call); |
break; |
/branches/tracing/kernel/generic/src/udebug/udebug.c |
---|
44,7 → 44,7 |
void udebug_stoppable_begin(void) |
{ |
int nsc; |
call_t *db_call; |
call_t *db_call, *go_call; |
ipl_t ipl; |
ipl = interrupts_disable(); |
59,6 → 59,16 |
} |
if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) { |
/* |
* This was the last non-stoppable thread. Reply to |
* DEBUG_BEGIN call. |
*/ |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
THREAD->debug_stoppable = true; |
spinlock_unlock(&THREAD->debug_lock); |
TASK->dt_state = UDEBUG_TS_ACTIVE; |
TASK->debug_begin_call = NULL; |
spinlock_unlock(&TASK->lock); |
67,7 → 77,53 |
IPC_SET_RETVAL(db_call->data, 0); |
klog_printf("udebug_stoppable_begin/ipc_answer"); |
ipc_answer(&TASK->answerbox, db_call); |
} else if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
/* |
* Active debugging session |
*/ |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
THREAD->debug_stoppable = true; |
if (THREAD->debug_stop) { |
/* |
* Thread was requested to stop - answer go call |
*/ |
/* Make sure nobody takes this call away from us */ |
go_call = THREAD->debug_go_call; |
THREAD->debug_go_call = NULL; |
IPC_SET_RETVAL(go_call->data, 0); |
IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP); |
THREAD->cur_event = UDEBUG_EVENT_STOP; |
spinlock_unlock(&THREAD->debug_lock); |
ipc_answer(&TASK->answerbox, go_call); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} else { |
/* |
* No stop request - nothing happens. |
*/ |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
} else { |
/* |
* All other cases - nothing special happens. |
*/ |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
THREAD->debug_stoppable = true; |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
81,10 → 137,19 |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
klog_printf("udebug_stoppable_end"); |
klog_printf("debug_stop=%d", THREAD->debug_stop); |
} |
if ((TASK->dt_state == UDEBUG_TS_BEGINNING || |
TASK->dt_state == UDEBUG_TS_ACTIVE) && |
THREAD->debug_stop == true) { |
TASK->debug_begin_call = NULL; |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
94,6 → 159,9 |
/* must try again - have to lose stoppability atomically */ |
} else { |
++TASK->not_stoppable_count; |
THREAD->debug_stoppable = false; |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
/branches/tracing/kernel/generic/src/udebug/udebug_ops.c |
---|
52,9 → 52,10 |
* but only if it verifies all conditions. |
* |
* Specifically, verifies that thread t exists, is a userspace thread, |
* and belongs to the current task (TASK). It also locks t->debug_lock, |
* making sure that t->debug_active is true - that the thread is |
* in a valid debugging session. |
* and belongs to the current task (TASK). Verifies, that the thread |
* has (or hasn't) go according to having_go (typically false). |
* It also locks t->debug_lock, making sure that t->debug_active is true |
* - that the thread is in a valid debugging session. |
* |
* Returns EOK if all went well, or an error code otherwise. |
* Interrupts must be already disabled when calling this function. |
61,7 → 62,7 |
* |
* Note: This function sports complicated locking. |
*/ |
static int _thread_op_begin(thread_t *t) |
static int _thread_op_begin(thread_t *t, bool having_go) |
{ |
int rc; |
task_id_t taskid; |
93,9 → 94,9 |
goto error_exit; |
} |
if ((t->debug_active != true) || (t->debug_stop != true)) { |
/* Not in debugging session or already has GO */ |
rc = ENOENT; |
if ((t->debug_active != true) || (!t->debug_stop != having_go)) { |
/* Not in debugging session or undesired GO state */ |
rc = EINVAL; |
goto error_exit; |
} |
213,7 → 214,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
234,7 → 235,60 |
return 0; |
} |
int udebug_stop(thread_t *t, call_t *call) |
{ |
ipl_t ipl; |
int rc; |
klog_printf("udebug_stop()"); |
ipl = interrupts_disable(); |
/* |
* On success, this will lock t->debug_lock. Note that this makes sure |
* the thread is not stopped. |
*/ |
rc = _thread_op_begin(t, true); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
} |
/* Take GO away from the thread */ |
t->debug_stop = true; |
if (!t->debug_stoppable) { |
/* Answer will be sent when the thread becomes stoppable */ |
_thread_op_end(t); |
interrupts_restore(ipl); |
return 0; |
} |
/* |
* Answer GO call |
*/ |
klog_printf("udebug_stop - answering go call"); |
/* Make sure nobody takes this call away from us */ |
call = t->debug_go_call; |
t->debug_go_call = NULL; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP); |
klog_printf("udebug_stop/ipc_answer"); |
THREAD->cur_event = UDEBUG_EVENT_STOP; |
_thread_op_end(t); |
spinlock_lock(&TASK->lock); |
ipc_answer(&TASK->answerbox, call); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
klog_printf("udebog_stop/done"); |
return 0; |
} |
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
{ |
thread_t *t; |
310,7 → 364,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
350,7 → 404,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
389,7 → 443,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |