Rev 2897 | Rev 2899 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2897 | Rev 2898 | ||
|---|---|---|---|
| Line 50... | Line 50... | ||
| 50 | * |
50 | * |
| 51 | * Simply put, return thread t with t->debug_lock held, |
51 | * Simply put, return thread t with t->debug_lock held, |
| 52 | * but only if it verifies all conditions. |
52 | * but only if it verifies all conditions. |
| 53 | * |
53 | * |
| 54 | * Specifically, verifies that thread t exists, is a userspace thread, |
54 | * Specifically, verifies that thread t exists, is a userspace thread, |
| 55 | * and belongs to the current task (TASK). It also locks t->debug_lock, |
55 | * and belongs to the current task (TASK). Verifies, that the thread |
| - | 56 | * has (or hasn't) go according to having_go (typically false). |
|
| 56 | * making sure that t->debug_active is true - that the thread is |
57 | * It also locks t->debug_lock, making sure that t->debug_active is true |
| 57 | * in a valid debugging session. |
58 | * - that the thread is in a valid debugging session. |
| 58 | * |
59 | * |
| 59 | * Returns EOK if all went well, or an error code otherwise. |
60 | * Returns EOK if all went well, or an error code otherwise. |
| 60 | * Interrupts must be already disabled when calling this function. |
61 | * Interrupts must be already disabled when calling this function. |
| 61 | * |
62 | * |
| 62 | * Note: This function sports complicated locking. |
63 | * Note: This function sports complicated locking. |
| 63 | */ |
64 | */ |
| 64 | static int _thread_op_begin(thread_t *t) |
65 | static int _thread_op_begin(thread_t *t, bool having_go) |
| 65 | { |
66 | { |
| 66 | int rc; |
67 | int rc; |
| 67 | task_id_t taskid; |
68 | task_id_t taskid; |
| 68 | 69 | ||
| 69 | taskid = TASK->taskid; |
70 | taskid = TASK->taskid; |
| Line 91... | Line 92... | ||
| 91 | /* It's not, deny its existence */ |
92 | /* It's not, deny its existence */ |
| 92 | rc = ENOENT; |
93 | rc = ENOENT; |
| 93 | goto error_exit; |
94 | goto error_exit; |
| 94 | } |
95 | } |
| 95 | 96 | ||
| 96 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
97 | if ((t->debug_active != true) || (!t->debug_stop != having_go)) { |
| 97 | /* Not in debugging session or already has GO */ |
98 | /* Not in debugging session or undesired GO state */ |
| 98 | rc = ENOENT; |
99 | rc = EINVAL; |
| 99 | goto error_exit; |
100 | goto error_exit; |
| 100 | } |
101 | } |
| 101 | 102 | ||
| 102 | spinlock_unlock(&threads_lock); |
103 | spinlock_unlock(&threads_lock); |
| 103 | spinlock_unlock(&t->lock); |
104 | spinlock_unlock(&t->lock); |
| Line 211... | Line 212... | ||
| 211 | klog_printf("udebug_go()"); |
212 | klog_printf("udebug_go()"); |
| 212 | 213 | ||
| 213 | ipl = interrupts_disable(); |
214 | ipl = interrupts_disable(); |
| 214 | 215 | ||
| 215 | /* On success, this will lock t->debug_lock */ |
216 | /* On success, this will lock t->debug_lock */ |
| 216 | rc = _thread_op_begin(t); |
217 | rc = _thread_op_begin(t, false); |
| 217 | if (rc != EOK) { |
218 | if (rc != EOK) { |
| 218 | interrupts_restore(ipl); |
219 | interrupts_restore(ipl); |
| 219 | return rc; |
220 | return rc; |
| 220 | } |
221 | } |
| 221 | 222 | ||
| Line 232... | Line 233... | ||
| 232 | interrupts_restore(ipl); |
233 | interrupts_restore(ipl); |
| 233 | 234 | ||
| 234 | return 0; |
235 | return 0; |
| 235 | } |
236 | } |
| 236 | 237 | ||
| - | 238 | int udebug_stop(thread_t *t, call_t *call) |
|
| - | 239 | { |
|
| - | 240 | ipl_t ipl; |
|
| - | 241 | int rc; |
|
| - | 242 | ||
| - | 243 | klog_printf("udebug_stop()"); |
|
| - | 244 | ||
| - | 245 | ipl = interrupts_disable(); |
|
| - | 246 | ||
| - | 247 | /* |
|
| - | 248 | * On success, this will lock t->debug_lock. Note that this makes sure |
|
| - | 249 | * the thread is not stopped. |
|
| - | 250 | */ |
|
| - | 251 | rc = _thread_op_begin(t, true); |
|
| - | 252 | if (rc != EOK) { |
|
| - | 253 | interrupts_restore(ipl); |
|
| - | 254 | return rc; |
|
| - | 255 | } |
|
| - | 256 | ||
| - | 257 | /* Take GO away from the thread */ |
|
| - | 258 | t->debug_stop = true; |
|
| - | 259 | ||
| - | 260 | if (!t->debug_stoppable) { |
|
| - | 261 | /* Answer will be sent when the thread becomes stoppable */ |
|
| - | 262 | _thread_op_end(t); |
|
| - | 263 | interrupts_restore(ipl); |
|
| - | 264 | return 0; |
|
| - | 265 | } |
|
| - | 266 | ||
| - | 267 | /* |
|
| - | 268 | * Answer GO call |
|
| - | 269 | */ |
|
| - | 270 | klog_printf("udebug_stop - answering go call"); |
|
| - | 271 | ||
| - | 272 | /* Make sure nobody takes this call away from us */ |
|
| - | 273 | call = t->debug_go_call; |
|
| - | 274 | t->debug_go_call = NULL; |
|
| - | 275 | ||
| - | 276 | IPC_SET_RETVAL(call->data, 0); |
|
| - | 277 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP); |
|
| - | 278 | klog_printf("udebug_stop/ipc_answer"); |
|
| - | 279 | ||
| - | 280 | THREAD->cur_event = UDEBUG_EVENT_STOP; |
|
| - | 281 | _thread_op_end(t); |
|
| - | 282 | ||
| - | 283 | spinlock_lock(&TASK->lock); |
|
| - | 284 | ipc_answer(&TASK->answerbox, call); |
|
| - | 285 | spinlock_unlock(&TASK->lock); |
|
| - | 286 | ||
| - | 287 | interrupts_restore(ipl); |
|
| - | 288 | klog_printf("udebog_stop/done"); |
|
| - | 289 | return 0; |
|
| - | 290 | } |
|
| 237 | 291 | ||
| 238 | int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
292 | int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
| 239 | { |
293 | { |
| 240 | thread_t *t; |
294 | thread_t *t; |
| 241 | link_t *cur; |
295 | link_t *cur; |
| Line 308... | Line 362... | ||
| 308 | if (!arg_buffer) return ENOMEM; |
362 | if (!arg_buffer) return ENOMEM; |
| 309 | 363 | ||
| 310 | ipl = interrupts_disable(); |
364 | ipl = interrupts_disable(); |
| 311 | 365 | ||
| 312 | /* On success, this will lock t->debug_lock */ |
366 | /* On success, this will lock t->debug_lock */ |
| 313 | rc = _thread_op_begin(t); |
367 | rc = _thread_op_begin(t, false); |
| 314 | if (rc != EOK) { |
368 | if (rc != EOK) { |
| 315 | interrupts_restore(ipl); |
369 | interrupts_restore(ipl); |
| 316 | return rc; |
370 | return rc; |
| 317 | } |
371 | } |
| 318 | 372 | ||
| Line 348... | Line 402... | ||
| 348 | if (!regs_buffer) return ENOMEM; |
402 | if (!regs_buffer) return ENOMEM; |
| 349 | 403 | ||
| 350 | ipl = interrupts_disable(); |
404 | ipl = interrupts_disable(); |
| 351 | 405 | ||
| 352 | /* On success, this will lock t->debug_lock */ |
406 | /* On success, this will lock t->debug_lock */ |
| 353 | rc = _thread_op_begin(t); |
407 | rc = _thread_op_begin(t, false); |
| 354 | if (rc != EOK) { |
408 | if (rc != EOK) { |
| 355 | interrupts_restore(ipl); |
409 | interrupts_restore(ipl); |
| 356 | return rc; |
410 | return rc; |
| 357 | } |
411 | } |
| 358 | 412 | ||
| Line 387... | Line 441... | ||
| 387 | /* Try to change the thread's uspace_state */ |
441 | /* Try to change the thread's uspace_state */ |
| 388 | 442 | ||
| 389 | ipl = interrupts_disable(); |
443 | ipl = interrupts_disable(); |
| 390 | 444 | ||
| 391 | /* On success, this will lock t->debug_lock */ |
445 | /* On success, this will lock t->debug_lock */ |
| 392 | rc = _thread_op_begin(t); |
446 | rc = _thread_op_begin(t, false); |
| 393 | if (rc != EOK) { |
447 | if (rc != EOK) { |
| 394 | interrupts_restore(ipl); |
448 | interrupts_restore(ipl); |
| 395 | return rc; |
449 | return rc; |
| 396 | } |
450 | } |
| 397 | 451 | ||