Subversion Repositories HelenOS

Rev

Rev 3601 | Rev 3613 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3601 Rev 3604
Line 33... Line 33...
33
/**
33
/**
34
 * @file
34
 * @file
35
 * @brief   Udebug hooks and data structure management.
35
 * @brief   Udebug hooks and data structure management.
36
 *
36
 *
37
 * Udebug is an interface that makes userspace debuggers possible.
37
 * Udebug is an interface that makes userspace debuggers possible.
38
 *
-
 
39
 * Functions in this file are executed directly in each thread, which
-
 
40
 * may or may not be the subject of debugging. The udebug_stoppable_begin/end()
-
 
41
 * functions are also executed in the clock interrupt handler. To avoid
-
 
42
 * deadlock, functions in this file are protected from the interrupt
-
 
43
 * by locking the recursive lock THREAD->udebug.int_lock (just an atomic
-
 
44
 * variable). This prevents udebug_stoppable_begin/end() from being
-
 
45
 * executed in the interrupt handler (they are skipped).
-
 
46
 *
-
 
47
 * Functions in udebug_ops.c and udebug_ipc.c execute in different threads,
-
 
48
 * so they needn't be protected from the (preemptible) interrupt-initiated
-
 
49
 * code.
-
 
50
 */
38
 */
51
 
39
 
52
#include <synch/waitq.h>
40
#include <synch/waitq.h>
53
#include <debug.h>
41
#include <debug.h>
54
#include <udebug/udebug.h>
42
#include <udebug/udebug.h>
55
#include <errno.h>
43
#include <errno.h>
56
#include <arch.h>
44
#include <arch.h>
57
 
45
 
58
static inline void udebug_int_lock(void)
-
 
59
{
-
 
60
    atomic_inc(&THREAD->udebug.int_lock);
-
 
61
}
-
 
62
 
-
 
63
static inline void udebug_int_unlock(void)
-
 
64
{
-
 
65
    atomic_dec(&THREAD->udebug.int_lock);
-
 
66
}
-
 
67
 
46
 
68
/** Initialize udebug part of task structure.
47
/** Initialize udebug part of task structure.
69
 *
48
 *
70
 * Called as part of task structure initialization.
49
 * Called as part of task structure initialization.
71
 * @param ut    Pointer to the structure to initialize.
50
 * @param ut    Pointer to the structure to initialize.
Line 87... Line 66...
87
void udebug_thread_initialize(udebug_thread_t *ut)
66
void udebug_thread_initialize(udebug_thread_t *ut)
88
{
67
{
89
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
68
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
90
    waitq_initialize(&ut->go_wq);
69
    waitq_initialize(&ut->go_wq);
91
 
70
 
92
    /*
-
 
93
     * At the beginning the thread is stoppable, so int_lock be set, too.
-
 
94
     */
-
 
95
    atomic_set(&ut->int_lock, 1);
-
 
96
 
-
 
97
    ut->go_call = NULL;
71
    ut->go_call = NULL;
98
    ut->go = false;
72
    ut->go = false;
99
    ut->stoppable = true;
73
    ut->stoppable = true;
100
    ut->debug_active = false;
74
    ut->debug_active = false;
101
    ut->cur_event = 0; /* none */
75
    ut->cur_event = 0; /* none */
Line 159... Line 133...
159
    call_t *db_call, *go_call;
133
    call_t *db_call, *go_call;
160
 
134
 
161
    ASSERT(THREAD);
135
    ASSERT(THREAD);
162
    ASSERT(TASK);
136
    ASSERT(TASK);
163
 
137
 
164
    udebug_int_lock();
-
 
165
 
-
 
166
    /* Early check for undebugged tasks */
138
    /* Early check for undebugged tasks */
167
    if (!udebug_thread_precheck()) {
139
    if (!udebug_thread_precheck()) {
168
        udebug_int_unlock();
-
 
169
        return;
140
        return;
170
    }
141
    }
171
 
142
 
172
    mutex_lock(&TASK->udebug.lock);
143
    mutex_lock(&TASK->udebug.lock);
173
 
144
 
Line 229... Line 200...
229
 */
200
 */
230
void udebug_stoppable_end(void)
201
void udebug_stoppable_end(void)
231
{
202
{
232
    /* Early check for undebugged tasks */
203
    /* Early check for undebugged tasks */
233
    if (!udebug_thread_precheck()) {
204
    if (!udebug_thread_precheck()) {
234
        udebug_int_unlock();
-
 
235
        return;
205
        return;
236
    }
206
    }
237
 
207
 
238
restart:
208
restart:
239
    mutex_lock(&TASK->udebug.lock);
209
    mutex_lock(&TASK->udebug.lock);
Line 255... Line 225...
255
        THREAD->udebug.stoppable = false;
225
        THREAD->udebug.stoppable = false;
256
 
226
 
257
        mutex_unlock(&THREAD->udebug.lock);
227
        mutex_unlock(&THREAD->udebug.lock);
258
        mutex_unlock(&TASK->udebug.lock);
228
        mutex_unlock(&TASK->udebug.lock);
259
    }
229
    }
260
 
-
 
261
    udebug_int_unlock();
-
 
262
}
230
}
263
 
231
 
264
/** Upon being scheduled to run, check if the current thread should stop.
232
/** Upon being scheduled to run, check if the current thread should stop.
265
 *
233
 *
266
 * This function is called from clock(). Preemption is enabled.
234
 * This function is called from clock(). Preemption is enabled.
Line 271... Line 239...
271
void udebug_before_thread_runs(void)
239
void udebug_before_thread_runs(void)
272
{
240
{
273
    ipl_t ipl;
241
    ipl_t ipl;
274
 
242
 
275
    return;
243
    return;
276
    ASSERT(!PREEMPTION_DISABLED);
-
 
277
 
-
 
278
    /*
-
 
279
     * Prevent agains re-entering, such as when preempted inside this
-
 
280
     * function.
-
 
281
     */
-
 
282
    if (atomic_get(&THREAD->udebug.int_lock) != 0)
-
 
283
        return;
-
 
284
 
-
 
285
    udebug_int_lock();
-
 
286
 
244
 
287
    ipl = interrupts_enable();
245
    ipl = interrupts_enable();
288
 
246
 
289
    /* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */
247
    /* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */
290
 
248
 
291
    /* Check if we're supposed to stop */
249
    /* Check if we're supposed to stop */
292
    udebug_stoppable_begin();
250
    udebug_stoppable_begin();
293
    udebug_stoppable_end();
251
    udebug_stoppable_end();
294
 
252
 
295
    interrupts_restore(ipl);
253
    interrupts_restore(ipl);
296
 
-
 
297
    udebug_int_unlock();
-
 
298
}
254
}
299
 
255
 
300
/** Syscall event hook.
256
/** Syscall event hook.
301
 *
257
 *
302
 * Must be called before and after servicing a system call. This generates
258
 * Must be called before and after servicing a system call. This generates
Line 309... Line 265...
309
    call_t *call;
265
    call_t *call;
310
    udebug_event_t etype;
266
    udebug_event_t etype;
311
 
267
 
312
    etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
268
    etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
313
 
269
 
314
    udebug_int_lock();
-
 
315
 
-
 
316
    /* Early check for undebugged tasks */
270
    /* Early check for undebugged tasks */
317
    if (!udebug_thread_precheck()) {
271
    if (!udebug_thread_precheck()) {
318
        udebug_int_unlock();
-
 
319
        return;
272
        return;
320
    }
273
    }
321
 
274
 
322
    mutex_lock(&TASK->udebug.lock);
275
    mutex_lock(&TASK->udebug.lock);
323
    mutex_lock(&THREAD->udebug.lock);
276
    mutex_lock(&THREAD->udebug.lock);
Line 360... Line 313...
360
 
313
 
361
    mutex_unlock(&THREAD->udebug.lock);
314
    mutex_unlock(&THREAD->udebug.lock);
362
    mutex_unlock(&TASK->udebug.lock);
315
    mutex_unlock(&TASK->udebug.lock);
363
 
316
 
364
    udebug_wait_for_go(&THREAD->udebug.go_wq);
317
    udebug_wait_for_go(&THREAD->udebug.go_wq);
365
 
-
 
366
    udebug_int_unlock();
-
 
367
}
318
}
368
 
319
 
369
/** Thread-creation event hook.
320
/** Thread-creation event hook.
370
 *
321
 *
371
 * Must be called when a new userspace thread is created in the debugged
322
 * Must be called when a new userspace thread is created in the debugged
Line 376... Line 327...
376
 */
327
 */
377
void udebug_thread_b_event(struct thread *t)
328
void udebug_thread_b_event(struct thread *t)
378
{
329
{
379
    call_t *call;
330
    call_t *call;
380
 
331
 
381
    udebug_int_lock();
-
 
382
 
-
 
383
    mutex_lock(&TASK->udebug.lock);
332
    mutex_lock(&TASK->udebug.lock);
384
    mutex_lock(&THREAD->udebug.lock);
333
    mutex_lock(&THREAD->udebug.lock);
385
 
334
 
386
    LOG("udebug_thread_b_event\n");
335
    LOG("udebug_thread_b_event\n");
387
    LOG("- check state\n");
336
    LOG("- check state\n");
Line 417... Line 366...
417
    mutex_unlock(&THREAD->udebug.lock);
366
    mutex_unlock(&THREAD->udebug.lock);
418
    mutex_unlock(&TASK->udebug.lock);
367
    mutex_unlock(&TASK->udebug.lock);
419
 
368
 
420
    LOG("- sleep\n");
369
    LOG("- sleep\n");
421
    udebug_wait_for_go(&THREAD->udebug.go_wq);
370
    udebug_wait_for_go(&THREAD->udebug.go_wq);
422
 
-
 
423
    udebug_int_unlock();
-
 
424
}
371
}
425
 
372
 
426
/** Thread-termination event hook.
373
/** Thread-termination event hook.
427
 *
374
 *
428
 * Must be called when the current thread is terminating.
375
 * Must be called when the current thread is terminating.
Line 430... Line 377...
430
 */
377
 */
431
void udebug_thread_e_event(void)
378
void udebug_thread_e_event(void)
432
{
379
{
433
    call_t *call;
380
    call_t *call;
434
 
381
 
435
    udebug_int_lock();
-
 
436
 
-
 
437
    mutex_lock(&TASK->udebug.lock);
382
    mutex_lock(&TASK->udebug.lock);
438
    mutex_lock(&THREAD->udebug.lock);
383
    mutex_lock(&THREAD->udebug.lock);
439
 
384
 
440
    LOG("udebug_thread_e_event\n");
385
    LOG("udebug_thread_e_event\n");
441
    LOG("- check state\n");
386
    LOG("- check state\n");
Line 465... Line 410...
465
    ipc_answer(&TASK->answerbox, call);
410
    ipc_answer(&TASK->answerbox, call);
466
 
411
 
467
    mutex_unlock(&THREAD->udebug.lock);
412
    mutex_unlock(&THREAD->udebug.lock);
468
    mutex_unlock(&TASK->udebug.lock);
413
    mutex_unlock(&TASK->udebug.lock);
469
 
414
 
470
    /* Leave int_lock enabled. */
415
    /*
471
    /* This event does not sleep - debugging has finished in this thread. */
416
     * This event does not sleep - debugging has finished
-
 
417
     * in this thread.
-
 
418
     */
472
}
419
}
473
 
420
 
474
/**
421
/**
475
 * Terminate task debugging session.
422
 * Terminate task debugging session.
476
 *
423
 *
Line 489... Line 436...
489
    ipl_t ipl;
436
    ipl_t ipl;
490
 
437
 
491
    LOG("udebug_task_cleanup()\n");
438
    LOG("udebug_task_cleanup()\n");
492
    LOG("task %" PRIu64 "\n", ta->taskid);
439
    LOG("task %" PRIu64 "\n", ta->taskid);
493
 
440
 
494
    udebug_int_lock();
-
 
495
 
-
 
496
    if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
441
    if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
497
        ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
442
        ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
498
        LOG("udebug_task_cleanup(): task not being debugged\n");
443
        LOG("udebug_task_cleanup(): task not being debugged\n");
499
        return EINVAL;
444
        return EINVAL;
500
    }
445
    }
Line 552... Line 497...
552
    }
497
    }
553
 
498
 
554
    ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
499
    ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
555
    ta->udebug.debugger = NULL;
500
    ta->udebug.debugger = NULL;
556
 
501
 
557
    udebug_int_unlock();
-
 
558
 
-
 
559
    return 0;
502
    return 0;
560
}
503
}
561
 
504
 
562
 
505
 
563
/** @}
506
/** @}