Rev 4377 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 4377 | Rev 4692 | ||
|---|---|---|---|
| Line 96... | Line 96... | ||
| 96 | rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
96 | rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
| 97 | 97 | ||
| 98 | waitq_sleep_finish(wq, rc, ipl); |
98 | waitq_sleep_finish(wq, rc, ipl); |
| 99 | } |
99 | } |
| 100 | 100 | ||
| 101 | /** Do a preliminary check that a debugging session is in progress. |
- | |
| 102 | * |
- | |
| 103 | * This only requires the THREAD->udebug.lock mutex (and not TASK->udebug.lock |
- | |
| 104 | * mutex). For an undebugged task, this will never block (while there could be |
- | |
| 105 | * collisions by different threads on the TASK mutex), thus improving SMP |
- | |
| 106 | * perormance for undebugged tasks. |
- | |
| 107 | * |
- | |
| 108 | * @return True if the thread was in a debugging session when the function |
- | |
| 109 | * checked, false otherwise. |
- | |
| 110 | */ |
- | |
| 111 | static bool udebug_thread_precheck(void) |
- | |
| 112 | { |
- | |
| 113 | bool res; |
- | |
| 114 | - | ||
| 115 | mutex_lock(&THREAD->udebug.lock); |
- | |
| 116 | res = THREAD->udebug.active; |
- | |
| 117 | mutex_unlock(&THREAD->udebug.lock); |
- | |
| 118 | - | ||
| 119 | return res; |
- | |
| 120 | } |
- | |
| 121 | - | ||
| 122 | /** Start of stoppable section. |
101 | /** Start of stoppable section. |
| 123 | * |
102 | * |
| 124 | * A stoppable section is a section of code where if the thread can be stoped. In other words, |
103 | * A stoppable section is a section of code where if the thread can be stoped. In other words, |
| 125 | * if a STOP operation is issued, the thread is guaranteed not to execute |
104 | * if a STOP operation is issued, the thread is guaranteed not to execute |
| 126 | * any userspace instructions until the thread is resumed. |
105 | * any userspace instructions until the thread is resumed. |
| Line 135... | Line 114... | ||
| 135 | call_t *db_call, *go_call; |
114 | call_t *db_call, *go_call; |
| 136 | 115 | ||
| 137 | ASSERT(THREAD); |
116 | ASSERT(THREAD); |
| 138 | ASSERT(TASK); |
117 | ASSERT(TASK); |
| 139 | 118 | ||
| 140 | /* Early check for undebugged tasks */ |
- | |
| 141 | if (!udebug_thread_precheck()) { |
- | |
| 142 | return; |
- | |
| 143 | } |
- | |
| 144 | - | ||
| 145 | mutex_lock(&TASK->udebug.lock); |
119 | mutex_lock(&TASK->udebug.lock); |
| 146 | 120 | ||
| 147 | nsc = --TASK->udebug.not_stoppable_count; |
121 | nsc = --TASK->udebug.not_stoppable_count; |
| 148 | 122 | ||
| 149 | /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */ |
123 | /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */ |
| Line 200... | Line 174... | ||
| 200 | * This is the point where the thread will block if it is stopped. |
174 | * This is the point where the thread will block if it is stopped. |
| 201 | * (As, by definition, a stopped thread must not leave its stoppable section). |
175 | * (As, by definition, a stopped thread must not leave its stoppable section). |
| 202 | */ |
176 | */ |
| 203 | void udebug_stoppable_end(void) |
177 | void udebug_stoppable_end(void) |
| 204 | { |
178 | { |
| 205 | /* Early check for undebugged tasks */ |
- | |
| 206 | if (!udebug_thread_precheck()) { |
- | |
| 207 | return; |
- | |
| 208 | } |
- | |
| 209 | - | ||
| 210 | restart: |
179 | restart: |
| 211 | mutex_lock(&TASK->udebug.lock); |
180 | mutex_lock(&TASK->udebug.lock); |
| 212 | mutex_lock(&THREAD->udebug.lock); |
181 | mutex_lock(&THREAD->udebug.lock); |
| 213 | 182 | ||
| 214 | if (THREAD->udebug.active && THREAD->udebug.go == false) { |
183 | if (THREAD->udebug.active && THREAD->udebug.go == false) { |
| Line 253... | Line 222... | ||
| 253 | call_t *call; |
222 | call_t *call; |
| 254 | udebug_event_t etype; |
223 | udebug_event_t etype; |
| 255 | 224 | ||
| 256 | etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B; |
225 | etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B; |
| 257 | 226 | ||
| 258 | /* Early check for undebugged tasks */ |
- | |
| 259 | if (!udebug_thread_precheck()) { |
- | |
| 260 | return; |
- | |
| 261 | } |
- | |
| 262 | - | ||
| 263 | mutex_lock(&TASK->udebug.lock); |
227 | mutex_lock(&TASK->udebug.lock); |
| 264 | mutex_lock(&THREAD->udebug.lock); |
228 | mutex_lock(&THREAD->udebug.lock); |
| 265 | 229 | ||
| 266 | /* Must only generate events when in debugging session and is go. */ |
230 | /* Must only generate events when in debugging session and is go. */ |
| 267 | if (THREAD->udebug.active != true || THREAD->udebug.go == false || |
231 | if (THREAD->udebug.active != true || THREAD->udebug.go == false || |
| Line 269... | Line 233... | ||
| 269 | mutex_unlock(&THREAD->udebug.lock); |
233 | mutex_unlock(&THREAD->udebug.lock); |
| 270 | mutex_unlock(&TASK->udebug.lock); |
234 | mutex_unlock(&TASK->udebug.lock); |
| 271 | return; |
235 | return; |
| 272 | } |
236 | } |
| 273 | 237 | ||
| 274 | //printf("udebug_syscall_event\n"); |
238 | /* Fill in the GO response. */ |
| 275 | call = THREAD->udebug.go_call; |
239 | call = THREAD->udebug.go_call; |
| 276 | THREAD->udebug.go_call = NULL; |
240 | THREAD->udebug.go_call = NULL; |
| 277 | 241 | ||
| 278 | IPC_SET_RETVAL(call->data, 0); |
242 | IPC_SET_RETVAL(call->data, 0); |
| 279 | IPC_SET_ARG1(call->data, etype); |
243 | IPC_SET_ARG1(call->data, etype); |
| 280 | IPC_SET_ARG2(call->data, id); |
244 | IPC_SET_ARG2(call->data, id); |
| 281 | IPC_SET_ARG3(call->data, rc); |
245 | IPC_SET_ARG3(call->data, rc); |
| 282 | //printf("udebug_syscall_event/ipc_answer\n"); |
- | |
| 283 | 246 | ||
| 284 | THREAD->udebug.syscall_args[0] = a1; |
247 | THREAD->udebug.syscall_args[0] = a1; |
| 285 | THREAD->udebug.syscall_args[1] = a2; |
248 | THREAD->udebug.syscall_args[1] = a2; |
| 286 | THREAD->udebug.syscall_args[2] = a3; |
249 | THREAD->udebug.syscall_args[2] = a3; |
| 287 | THREAD->udebug.syscall_args[3] = a4; |
250 | THREAD->udebug.syscall_args[3] = a4; |
| Line 327... | Line 290... | ||
| 327 | mutex_lock(&TASK->udebug.lock); |
290 | mutex_lock(&TASK->udebug.lock); |
| 328 | mutex_lock(&THREAD->udebug.lock); |
291 | mutex_lock(&THREAD->udebug.lock); |
| 329 | 292 | ||
| 330 | thread_attach(t, ta); |
293 | thread_attach(t, ta); |
| 331 | 294 | ||
| 332 | LOG("udebug_thread_b_event\n"); |
- | |
| 333 | LOG("- check state\n"); |
295 | LOG("Check state"); |
| 334 | 296 | ||
| 335 | /* Must only generate events when in debugging session */ |
297 | /* Must only generate events when in debugging session */ |
| 336 | if (THREAD->udebug.active != true) { |
298 | if (THREAD->udebug.active != true) { |
| 337 | LOG("- udebug.active: %s, udebug.go: %s\n", |
299 | LOG("udebug.active: %s, udebug.go: %s", |
| 338 | THREAD->udebug.active ? "yes(+)" : "no(-)", |
300 | THREAD->udebug.active ? "Yes(+)" : "No", |
| 339 | THREAD->udebug.go ? "yes(-)" : "no(+)"); |
301 | THREAD->udebug.go ? "Yes(-)" : "No"); |
| 340 | mutex_unlock(&THREAD->udebug.lock); |
302 | mutex_unlock(&THREAD->udebug.lock); |
| 341 | mutex_unlock(&TASK->udebug.lock); |
303 | mutex_unlock(&TASK->udebug.lock); |
| 342 | return; |
304 | return; |
| 343 | } |
305 | } |
| 344 | 306 | ||
| 345 | LOG("- trigger event\n"); |
307 | LOG("Trigger event"); |
| 346 | - | ||
| 347 | call = THREAD->udebug.go_call; |
308 | call = THREAD->udebug.go_call; |
| 348 | THREAD->udebug.go_call = NULL; |
309 | THREAD->udebug.go_call = NULL; |
| 349 | IPC_SET_RETVAL(call->data, 0); |
310 | IPC_SET_RETVAL(call->data, 0); |
| 350 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B); |
311 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B); |
| 351 | IPC_SET_ARG2(call->data, (unative_t)t); |
312 | IPC_SET_ARG2(call->data, (unative_t)t); |
| Line 361... | Line 322... | ||
| 361 | ipc_answer(&TASK->answerbox, call); |
322 | ipc_answer(&TASK->answerbox, call); |
| 362 | 323 | ||
| 363 | mutex_unlock(&THREAD->udebug.lock); |
324 | mutex_unlock(&THREAD->udebug.lock); |
| 364 | mutex_unlock(&TASK->udebug.lock); |
325 | mutex_unlock(&TASK->udebug.lock); |
| 365 | 326 | ||
| 366 | LOG("- sleep\n"); |
327 | LOG("Wait for Go"); |
| 367 | udebug_wait_for_go(&THREAD->udebug.go_wq); |
328 | udebug_wait_for_go(&THREAD->udebug.go_wq); |
| 368 | } |
329 | } |
| 369 | 330 | ||
| 370 | /** Thread-termination event hook. |
331 | /** Thread-termination event hook. |
| 371 | * |
332 | * |
| Line 377... | Line 338... | ||
| 377 | call_t *call; |
338 | call_t *call; |
| 378 | 339 | ||
| 379 | mutex_lock(&TASK->udebug.lock); |
340 | mutex_lock(&TASK->udebug.lock); |
| 380 | mutex_lock(&THREAD->udebug.lock); |
341 | mutex_lock(&THREAD->udebug.lock); |
| 381 | 342 | ||
| 382 | LOG("udebug_thread_e_event\n"); |
- | |
| 383 | LOG("- check state\n"); |
343 | LOG("Check state"); |
| 384 | 344 | ||
| 385 | /* Must only generate events when in debugging session. */ |
345 | /* Must only generate events when in debugging session. */ |
| 386 | if (THREAD->udebug.active != true) { |
346 | if (THREAD->udebug.active != true) { |
| 387 | /* printf("- udebug.active: %s, udebug.go: %s\n", |
347 | LOG("udebug.active: %s, udebug.go: %s", |
| 388 | THREAD->udebug.active ? "yes(+)" : "no(-)", |
348 | THREAD->udebug.active ? "Yes" : "No", |
| 389 | THREAD->udebug.go ? "yes(-)" : "no(+)");*/ |
349 | THREAD->udebug.go ? "Yes" : "No"); |
| 390 | mutex_unlock(&THREAD->udebug.lock); |
350 | mutex_unlock(&THREAD->udebug.lock); |
| 391 | mutex_unlock(&TASK->udebug.lock); |
351 | mutex_unlock(&TASK->udebug.lock); |
| 392 | return; |
352 | return; |
| 393 | } |
353 | } |
| 394 | 354 | ||
| 395 | LOG("- trigger event\n"); |
355 | LOG("Trigger event"); |
| 396 | - | ||
| 397 | call = THREAD->udebug.go_call; |
356 | call = THREAD->udebug.go_call; |
| 398 | THREAD->udebug.go_call = NULL; |
357 | THREAD->udebug.go_call = NULL; |
| 399 | IPC_SET_RETVAL(call->data, 0); |
358 | IPC_SET_RETVAL(call->data, 0); |
| 400 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E); |
359 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E); |
| 401 | 360 | ||
| Line 486... | Line 445... | ||
| 486 | thread_t *t; |
445 | thread_t *t; |
| 487 | link_t *cur; |
446 | link_t *cur; |
| 488 | int flags; |
447 | int flags; |
| 489 | ipl_t ipl; |
448 | ipl_t ipl; |
| 490 | 449 | ||
| 491 | LOG("udebug_task_cleanup()\n"); |
- | |
| 492 | LOG("task %" PRIu64 "\n", ta->taskid); |
- | |
| 493 | - | ||
| 494 | if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING && |
450 | if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING && |
| 495 | ta->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
451 | ta->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
| 496 | LOG("udebug_task_cleanup(): task not being debugged\n"); |
- | |
| 497 | return EINVAL; |
452 | return EINVAL; |
| 498 | } |
453 | } |
| 499 | 454 | ||
| - | 455 | LOG("Task %" PRIu64, ta->taskid); |
|
| - | 456 | ||
| 500 | /* Finish debugging of all userspace threads */ |
457 | /* Finish debugging of all userspace threads */ |
| 501 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
458 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
| 502 | t = list_get_instance(cur, thread_t, th_link); |
459 | t = list_get_instance(cur, thread_t, th_link); |
| 503 | 460 | ||
| 504 | mutex_lock(&t->udebug.lock); |
461 | mutex_lock(&t->udebug.lock); |
| Line 524... | Line 481... | ||
| 524 | * this doesn't affect anything. |
481 | * this doesn't affect anything. |
| 525 | */ |
482 | */ |
| 526 | t->udebug.go = false; |
483 | t->udebug.go = false; |
| 527 | 484 | ||
| 528 | /* Answer GO call */ |
485 | /* Answer GO call */ |
| 529 | LOG("answer GO call with EVENT_FINISHED\n"); |
486 | LOG("Answer GO call with EVENT_FINISHED."); |
| 530 | IPC_SET_RETVAL(t->udebug.go_call->data, 0); |
487 | IPC_SET_RETVAL(t->udebug.go_call->data, 0); |
| 531 | IPC_SET_ARG1(t->udebug.go_call->data, |
488 | IPC_SET_ARG1(t->udebug.go_call->data, |
| 532 | UDEBUG_EVENT_FINISHED); |
489 | UDEBUG_EVENT_FINISHED); |
| 533 | 490 | ||
| 534 | ipc_answer(&ta->answerbox, t->udebug.go_call); |
491 | ipc_answer(&ta->answerbox, t->udebug.go_call); |