Rev 4342 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4342 | Rev 4389 | ||
---|---|---|---|
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 430... | Line 389... | ||
430 | thread_t *t; |
389 | thread_t *t; |
431 | link_t *cur; |
390 | link_t *cur; |
432 | int flags; |
391 | int flags; |
433 | ipl_t ipl; |
392 | ipl_t ipl; |
434 | 393 | ||
435 | LOG("udebug_task_cleanup()\n"); |
- | |
436 | LOG("task %" PRIu64 "\n", ta->taskid); |
- | |
437 | - | ||
438 | if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING && |
394 | if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING && |
439 | ta->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
395 | ta->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
440 | LOG("udebug_task_cleanup(): task not being debugged\n"); |
- | |
441 | return EINVAL; |
396 | return EINVAL; |
442 | } |
397 | } |
443 | 398 | ||
- | 399 | LOG("Task %" PRIu64, ta->taskid); |
|
- | 400 | ||
444 | /* Finish debugging of all userspace threads */ |
401 | /* Finish debugging of all userspace threads */ |
445 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
402 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
446 | t = list_get_instance(cur, thread_t, th_link); |
403 | t = list_get_instance(cur, thread_t, th_link); |
447 | 404 | ||
448 | mutex_lock(&t->udebug.lock); |
405 | mutex_lock(&t->udebug.lock); |
Line 468... | Line 425... | ||
468 | * this doesn't affect anything. |
425 | * this doesn't affect anything. |
469 | */ |
426 | */ |
470 | t->udebug.go = false; |
427 | t->udebug.go = false; |
471 | 428 | ||
472 | /* Answer GO call */ |
429 | /* Answer GO call */ |
473 | LOG("answer GO call with EVENT_FINISHED\n"); |
430 | LOG("Answer GO call with EVENT_FINISHED."); |
474 | IPC_SET_RETVAL(t->udebug.go_call->data, 0); |
431 | IPC_SET_RETVAL(t->udebug.go_call->data, 0); |
475 | IPC_SET_ARG1(t->udebug.go_call->data, |
432 | IPC_SET_ARG1(t->udebug.go_call->data, |
476 | UDEBUG_EVENT_FINISHED); |
433 | UDEBUG_EVENT_FINISHED); |
477 | 434 | ||
478 | ipc_answer(&ta->answerbox, t->udebug.go_call); |
435 | ipc_answer(&ta->answerbox, t->udebug.go_call); |