Subversion Repositories HelenOS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2787 decky 1
/** @addtogroup tdebug
2
 * @{
3
 */
4
 
5
/**
6
 * @file
7
 * @brief   Task Debugging.
8
 */
9
 
10
#include <arch.h>
11
#include <atomic.h>
12
#include <ipc/ipc.h>
13
#include <proc/task.h>
14
#include <synch/spinlock.h>
15
#include <synch/waitq.h>
16
#include <console/klog.h>
17
#include <errno.h>
18
//#include <arch/tdebug.h>
19
#include <tdebug/tdebug.h>
20
 
21
//FIXME: need to reset tdebug_thread structure for each thread
22
//either on monitor attach or on monitor detach
23
 
24
static void _tdebug_send_msg(task_t *ta, unative_t method, unative_t a1, unative_t a2,
25
    unative_t a3, unative_t a4, unative_t a5);
26
 
27
void tdebug_task_init(struct task *ta)
28
{
29
    atomic_set(&ta->tdebug.have_monitor, 0);
30
    ta->tdebug.monitor = NULL;
31
    list_initialize(&ta->tdebug.targets);
32
}
33
 
34
/**
35
 * Initialize the tdebug part of a thread structure.
36
 */
37
void tdebug_thread_init(struct thread *t)
38
{
39
    t->tdebug.stopped = 0;
40
    condvar_initialize(&t->tdebug.stopped_cv);
41
    t->tdebug.stop_request = 0;
42
    t->tdebug.event_mask = TDEBUG_EVMASK_SYSCALL | TDEBUG_EVMASK_EXCEPTION;
43
 
44
    t->tdebug.syscall_args = NULL;
45
}
46
 
47
/**
48
 * Clean-up all tdebug activities of the current task.
49
 */
50
void tdebug_cleanup(void)
51
{
52
    ipl_t ipl;
53
    task_t *mon_task;
54
 
55
    klog_printf("tdebug_cleanup()");
56
 
57
    /*
58
     * First detach any targets monitored by this task.
59
     */
60
loop_1:
61
    ipl = interrupts_disable();
62
    spinlock_lock(&TASK->lock);
63
 
64
    while (TASK->tdebug.targets.next != &TASK->tdebug.targets) {
65
        link_t *cur = TASK->tdebug.targets.next;
66
        task_t *ta;
67
        DEADLOCK_PROBE_INIT(p_target_lock);
68
 
69
        klog_printf(" - detaching a target");
70
 
71
        ta = list_get_instance(cur, task_t, tdebug.targets_link);
72
        if (!spinlock_trylock(&ta->lock)) {
73
            /*
74
             * Avoid deadlock by trying again.
75
             */
76
            spinlock_unlock(&TASK->lock);
77
            interrupts_restore(ipl);
78
            DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD);
79
            goto loop_1;
80
        }
81
 
82
        /* this task should be the target's monitor */
83
        ASSERT(TASK == ta->tdebug.monitor);
84
        ta->tdebug.monitor = NULL;
85
 
86
        list_remove(&ta->tdebug.targets_link);
87
        spinlock_unlock(&ta->lock);
88
    }
89
 
90
    spinlock_unlock(&TASK->lock);
91
    interrupts_restore(ipl);
92
 
93
    /*
94
     * Now if this task is being monitored, detach from the monitor.
95
     */
96
 
97
loop_2:
98
    ipl = interrupts_disable();
99
    spinlock_lock(&TASK->lock);
100
    if (TASK->tdebug.monitor != NULL) {
101
        /* yes, so detach */
102
        DEADLOCK_PROBE_INIT(p_monitor_lock);
103
 
104
        klog_printf(" - detaching from the monitor");
105
 
106
        mon_task = TASK->tdebug.monitor;
107
 
108
        if (!spinlock_trylock(&mon_task->lock)) {
109
            /*
110
             * Avoid deadlock by trying again.
111
             */
112
            spinlock_unlock(&TASK->lock);
113
            interrupts_restore(ipl);
114
            DEADLOCK_PROBE(p_monitor_lock, DEADLOCK_THRESHOLD);
115
            goto loop_2;
116
        }
117
 
118
        list_remove(&TASK->tdebug.targets_link);
119
        TASK->tdebug.monitor = NULL;
120
 
121
        spinlock_unlock(&mon_task->lock);
122
    }
123
 
124
    spinlock_unlock(&TASK->lock);
125
    interrupts_restore(ipl);
126
 
127
    klog_printf("tdebug_cleanup done");
128
}
129
 
130
static void _tdebug_clear_event_unsafe(void)
131
{
132
    THREAD->tdebug.stopped = 0;
133
    THREAD->tdebug.syscall_args = NULL;
134
}
135
 
136
 
137
static void _tdebug_reset_thread_struct_unsafe(void)
138
{
139
    _tdebug_clear_event_unsafe();
140
 
141
    THREAD->tdebug.stop_request = 0;
142
    THREAD->tdebug.event_mask = 0;
143
}
144
 
145
 
146
/**
147
 * Sleep until the thread is no longer stopped.
148
 *
149
 * Go to sleep iff the thread still has stopped==1
150
 * and sleep until it is resumed.
151
 *
152
 * This will also clear the debugging event.!!!!
153
 */
154
static void _tdebug_wait_and_clear(void)
155
{
156
    ipl_t ipl, ipl2;
157
    int rc;
158
    waitq_t *wq;
159
 
160
    /* wait until we are resumed */
161
 
162
    klog_printf("wait...");
163
    ipl = interrupts_disable();
164
    spinlock_lock(&THREAD->lock);
165
 
166
    wq = &THREAD->tdebug.stopped_cv.wq;
167
 
168
    /*
169
     * Waiting for THREAD->tdebug.stopped to become 0.
170
     *
171
     * This is almost the same as condvar_wait, except that
172
     * instead of a mutex, the THREAD->lock spinlock is used
173
     * for mutual exclusion.
174
     */
175
 
176
    while (THREAD->tdebug.stopped != 0) {
177
        spinlock_unlock(&THREAD->lock);
178
 
179
        /* "spinvar_wait()" */
180
        //printf("waitq_sleep_prepare...\n");
181
        ipl2 = waitq_sleep_prepare(wq);
182
        //printf("waitq_sleep_prepare... ok\n");
183
 
184
        wq->missed_wakeups = 0;
185
        rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
186
 
187
        spinlock_lock(&THREAD->lock);
188
        waitq_sleep_finish(wq, rc, ipl2);
189
    }
190
 
191
    _tdebug_clear_event_unsafe();
192
 
193
    spinlock_unlock(&THREAD->lock);
194
    interrupts_restore(ipl);
195
    klog_printf("done waiting");
196
}
197
 
198
 
199
/**
200
 * Send a notification to the monitoring task.
201
 *
202
 * Returns 0 on success or -1 if no debugger is present.
203
 */
204
static int _tdebug_notify_debugger(thread_id_t tid, unative_t a1,
205
    unative_t a2, unative_t a3)
206
{
207
    unative_t tid_lo, tid_hi;
208
    ipl_t ipl;
209
    task_t *monitor;
210
    DEADLOCK_PROBE_INIT(p_monitor_lock);
211
 
212
    tid_lo = tid & 0xffffffff;
213
    tid_hi = tid >> 16;
214
 
215
    /* send notification to the monitoring task */
216
 
217
loop:
218
    ipl = interrupts_disable();
219
    spinlock_lock(&TASK->lock);
220
    monitor = TASK->tdebug.monitor;
221
    if (monitor == NULL) {
222
        /* there's no monitor anymore */
223
        spinlock_unlock(&TASK->lock);
224
 
225
        /*
226
         * Reset the debugging struct
227
         */
228
        spinlock_lock(&THREAD->lock);
229
        _tdebug_reset_thread_struct_unsafe();
230
        spinlock_unlock(&THREAD->lock);
231
 
232
        interrupts_restore(ipl);
233
        return -1;
234
    }
235
 
236
    if (!spinlock_trylock(&monitor->lock)) {
237
        /*
238
         * Avoid deadlock by trying again
239
         */
240
        spinlock_unlock(&TASK->lock);
241
        interrupts_restore(ipl);
242
        DEADLOCK_PROBE(p_monitor_lock, DEADLOCK_THRESHOLD);
243
        goto loop;
244
    }
245
 
246
    _tdebug_send_msg(TASK->tdebug.monitor, TASK->tdebug.method,
247
        tid_lo, tid_hi, a1, a2, a3);
248
 
249
    spinlock_unlock(&TASK->lock);
250
    spinlock_unlock(&monitor->lock);
251
    interrupts_restore(ipl);
252
 
253
    return 0;
254
}
255
 
256
 
257
/**
258
 * Generate a syscall debug event.
259
 *
260
 * Called from syscall_handler() in syscall.c. The current task
261
 * may or may not have a monitor attached.
262
 * If a monitor is not attached or syscall events are not enabled,
263
 * no action is taken.
264
 */
265
void tdebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
266
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t sc_rc)
267
{
268
    unative_t sc_args[6];
269
    ipl_t ipl;
270
    thread_id_t tid;
271
 
272
    klog_printf("TASK %llu: Syscall id %lx", TASK->taskid, id);
273
    klog_printf("THREAD %llu", THREAD->tid);
274
 
275
    /* no need to lock this */
276
    tid = THREAD->tid;
277
 
278
    /* copy down arguments to an array */
279
    sc_args[0] = a1;
280
    sc_args[1] = a2;
281
    sc_args[2] = a3;
282
    sc_args[3] = a4;
283
    sc_args[4] = a5;
284
    sc_args[5] = a6;
285
 
286
    ipl = interrupts_disable();
287
    spinlock_lock(&THREAD->lock);
288
 
289
    if ((THREAD->tdebug.event_mask & TDEBUG_EVMASK_SYSCALL) == 0) {
290
        /* syscall event not enabled */
291
        spinlock_unlock(&THREAD->lock);
292
        interrupts_restore(ipl);
293
        return;
294
    }
295
 
296
    /* record the debugging event into our thread structure */
297
    THREAD->tdebug.syscall_args = sc_args;
298
    THREAD->tdebug.stopped = 1;
299
    THREAD->tdebug.current_event = TDEBUG_EV_SYSCALL;
300
 
301
    spinlock_unlock(&THREAD->lock);
302
    interrupts_restore(ipl);
303
 
304
    /*
305
     * Send notification to the monitoring task
306
     * This may fail as we needn't have a monitor attached
307
     */
308
    if (_tdebug_notify_debugger(tid, TDEBUG_EV_SYSCALL, id, sc_rc) == 0) {
309
        /* wait for resume */
310
        _tdebug_wait_and_clear();
311
    }
312
}
313
 
314
/**
315
 * Generate an exception debug event.
316
 *
317
 * Called from exc_dispatch() in interrupt.c. The current task
318
 * may or may not have a monitor attached.
319
 * If a monitor is not attached or exception events are not enabled,
320
 * no action is taken.
321
 */
322
void tdebug_exception_event(int n)
323
{
324
    ipl_t ipl;
325
    thread_id_t tid;
326
 
327
    klog_printf("TASK %llu: exception %d", TASK->taskid, n);
328
    klog_printf("THREAD %llu", THREAD->tid);
329
 
330
    /* no need to lock this */
331
    tid = THREAD->tid;
332
 
333
    ipl = interrupts_disable();
334
    spinlock_lock(&THREAD->lock);
335
 
336
    if ((THREAD->tdebug.event_mask & TDEBUG_EVMASK_EXCEPTION) == 0) {
337
        /* exception event not enabled */
338
        spinlock_unlock(&THREAD->lock);
339
        interrupts_restore(ipl);
340
        return;
341
    }
342
 
343
    /* record the debugging event into our thread structure */
344
    THREAD->tdebug.stopped = 1;
345
    THREAD->tdebug.current_event = TDEBUG_EV_EXCEPTION;
346
 
347
    spinlock_unlock(&THREAD->lock);
348
    interrupts_restore(ipl);
349
 
350
    /*
351
     * Send notification to the monitoring task
352
     * This may fail as we needn't have a monitor attached
353
     */
354
    if (_tdebug_notify_debugger(tid, TDEBUG_EV_EXCEPTION, n, 0) == 0) {
355
        /* wait for resume */
356
        _tdebug_wait_and_clear();
357
    }
358
}
359
 
360
 
361
/**
362
 * Stop the thread here if a stop request is pending.
363
 */
364
void tdebug_stopping_point(void)
365
{
366
    ipl_t ipl;
367
    thread_id_t tid;
368
 
369
    klog_printf("TASK %llu: stopping point", TASK->taskid);
370
    klog_printf("THREAD %llu", THREAD->tid);
371
 
372
    /* no need to lock this */
373
    tid = THREAD->tid;
374
 
375
    ipl = interrupts_disable();
376
    spinlock_lock(&THREAD->lock);
377
 
378
    if (THREAD->tdebug.stop_request == 0) {
379
        /* stop not requested */
380
        spinlock_unlock(&THREAD->lock);
381
        interrupts_restore(ipl);
382
        return;    
383
    }
384
 
385
    /* record the debugging event into our thread structure */
386
    THREAD->tdebug.stopped = 1;
387
    THREAD->tdebug.current_event = TDEBUG_EV_STOP;
388
 
389
    spinlock_unlock(&THREAD->lock);
390
    interrupts_restore(ipl);   
391
 
392
    /* send notification to the monitoring task */
393
    if (_tdebug_notify_debugger(tid, TDEBUG_EV_STOP, 0, 0) == 0) {
394
        /* wait for resume */
395
        _tdebug_wait_and_clear();
396
    }
397
}
398
 
399
 
400
/**
401
 * Send an IPC notification to a task.
402
 *
403
 * When calling the task's lock must be already held and interrupts
404
 * must be disabled.
405
 */
406
static void _tdebug_send_msg(task_t *ta, unative_t method, unative_t a1, unative_t a2,
407
    unative_t a3, unative_t a4, unative_t a5)
408
{
409
    call_t *call;
410
    answerbox_t *answerbox;
411
 
412
    /* prepare an IPC notification structure */
413
 
414
    call = ipc_call_alloc(FRAME_ATOMIC);
415
    if (!call) {
416
        return;
417
    }
418
 
419
    call->flags |= IPC_CALL_NOTIF;
420
    IPC_SET_METHOD(call->data, method);
421
    IPC_SET_ARG1(call->data, a1);
422
    IPC_SET_ARG2(call->data, a2);
423
    IPC_SET_ARG3(call->data, a3);
424
    IPC_SET_ARG4(call->data, a4);
425
    IPC_SET_ARG5(call->data, a5);
426
 
427
    answerbox = &ta->answerbox;
428
 
429
    /* analogy of send_call() from irq.c */
430
    spinlock_lock(&answerbox->irq_lock);
431
    list_append(&call->link, &answerbox->irq_notifs);
432
    spinlock_unlock(&answerbox->irq_lock);
433
 
434
    waitq_wakeup(&answerbox->wq, WAKEUP_FIRST);
435
}
436
 
437
/**
438
 * Start debugging a task.
439
 *
440
 * The specified task (target) is attached to the current task (monitor).
441
 * The monitoring task will be informed of debug events in the
442
 * target task through IPC notifications with the specified method number.
443
 */
444
int tdebug_attach_task(task_id_t taskid, unative_t method)
445
{
446
    task_t *ta;
447
    ipl_t ipl;
448
    DEADLOCK_PROBE_INIT(p_target_lock);
449
 
450
    //FIXME: pokud bychom si podrzeli tasks_lock, nemusime pokazde
451
    // znovu hledat ta podle id 
452
loop:
453
    ipl = interrupts_disable();
454
    spinlock_lock(&tasks_lock);
455
 
456
    spinlock_lock(&TASK->lock);
457
 
458
    ta = task_find_by_id(taskid);
459
    if (!ta) {
460
        spinlock_unlock(&tasks_lock);
461
        spinlock_unlock(&TASK->lock);
462
        interrupts_restore(ipl);
463
        klog_printf("fail: no such task\n");
464
        return ENOENT;
465
    }
466
 
467
    if (!spinlock_trylock(&ta->lock)) {
468
        /*
469
         * Avoid deadlock by trying again.
470
         */
471
        spinlock_unlock(&TASK->lock);
472
        spinlock_unlock(&tasks_lock);
473
        interrupts_restore(ipl);
474
        DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD);
475
        goto loop;
476
    }
477
 
478
    /* we don't need tasks_lock anymore */
479
    spinlock_unlock(&tasks_lock);
480
 
481
    if (ta->tdebug.monitor != NULL) {
482
        spinlock_unlock(&TASK->lock);
483
        spinlock_unlock(&ta->lock);
484
        interrupts_restore(ipl);
485
        klog_printf("fail: already being debugged\n");
486
        return EBUSY; /* task already being debugged */
487
    }
488
 
489
    atomic_set(&ta->tdebug.have_monitor, 1);
490
    ta->tdebug.monitor = TASK;
491
    ta->tdebug.method = method;
492
 
493
    /* insert ta into this task's debug-target list */
494
    list_append(&ta->tdebug.targets_link, &TASK->tdebug.targets);
495
 
496
    spinlock_unlock(&TASK->lock);
497
    spinlock_unlock(&ta->lock);
498
    interrupts_restore(ipl);
499
 
500
    return 0;
501
}
502
 
503
/**
504
 * Stop debugging a task.
505
 */
506
int tdebug_detach_task(task_id_t taskid)
507
{
508
    task_t *ta;
509
    ipl_t ipl;
510
    DEADLOCK_PROBE_INIT(p_target_lock);
511
 
512
    //FIXME: pokud bychom si podrzeli tasks_lock, nemusime pokazde
513
    // znovu hledat ta podle id 
514
loop:
515
    ipl = interrupts_disable();
516
    spinlock_lock(&tasks_lock);
517
 
518
    spinlock_lock(&TASK->lock);
519
 
520
    ta = task_find_by_id(taskid);
521
    if (!ta) {
522
        spinlock_unlock(&tasks_lock);
523
        spinlock_unlock(&TASK->lock);
524
        interrupts_restore(ipl);
525
        klog_printf("fail: no such task\n");
526
        return ENOENT;
527
    }
528
 
529
    if (!spinlock_trylock(&ta->lock)) {
530
        /*
531
         * Avoid deadlock by trying again.
532
         */
533
        spinlock_unlock(&TASK->lock);
534
        spinlock_unlock(&tasks_lock);
535
        interrupts_restore(ipl);
536
        DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD);
537
        goto loop;
538
    }
539
 
540
    /* we don't need tasks_lock anymore */
541
    spinlock_unlock(&tasks_lock);
542
 
543
    if (ta->tdebug.monitor == NULL) {
544
        spinlock_unlock(&TASK->lock);
545
        spinlock_unlock(&ta->lock);
546
        interrupts_restore(ipl);
547
        klog_printf("fail: not being debugged\n");
548
        return EINVAL; /* task not being debugged */
549
    }
550
 
551
    atomic_set(&ta->tdebug.have_monitor, 0);
552
    ta->tdebug.monitor = NULL;
553
    ta->tdebug.method = 0;
554
 
555
    /* remove target from this task's list */
556
    list_remove(&ta->tdebug.targets_link);
557
 
558
    spinlock_unlock(&TASK->lock);
559
    spinlock_unlock(&ta->lock);
560
    interrupts_restore(ipl);
561
 
562
    return 0;
563
}
564
 
565
/**
566
 * Resume a thread stopped in a debugging event.
567
 */
568
int tdebug_continue_thread(thread_id_t tid)
569
{
570
    thread_t *t;
571
    ipl_t ipl;
572
 
573
    klog_printf("sys_tdebug_continue_thread(%lld)", tid);
574
 
575
    //FIXME: need to verify that we are the monitor
576
 
577
    ipl = interrupts_disable();
578
    spinlock_lock(&threads_lock);
579
 
580
    t = thread_find_by_id(tid);
581
    if (t == NULL) {
582
        spinlock_unlock(&threads_lock);
583
        interrupts_restore(ipl);
584
        klog_printf("fail: no such thread\n");
585
        return ENOENT;
586
    }
587
 
588
    /* lock the thread */
589
    spinlock_lock(&t->lock);
590
 
591
    /* verify that the thread is stopped */
592
    if (t->tdebug.stopped == 0) {
593
        spinlock_unlock(&t->lock);
594
        interrupts_restore(ipl);
595
        return EINVAL;
596
    }
597
 
598
    t->tdebug.stopped = 0;
599
 
600
    /* no thread should be unlocked when calling waitq_wakeup */
601
    spinlock_unlock(&t->lock);
602
 
603
    /* "spincv_signal()" */
604
    waitq_wakeup(&t->tdebug.stopped_cv.wq, WAKEUP_FIRST);
605
 
606
    spinlock_unlock(&threads_lock);
607
    interrupts_restore(ipl);
608
 
609
    klog_printf("success\n");
610
    return 0;
611
}
612
 
613
/**
614
 * Retrieve the arguments of a syscall.
615
 *
616
 * When a thread is stopped in a TDEBUG_EV_SYSCALL event,
617
 * this function may be used to retrieve the arguments of the
618
 * corresponding syscall.
619
 */
620
int tdebug_get_syscall_args(thread_id_t tid, unative_t *sc_args)
621
{
622
    thread_t *t;
623
    ipl_t ipl;
624
 
625
    //FIXME: need to verify that we are the monitor
626
 
627
    ipl = interrupts_disable();
628
    spinlock_lock(&threads_lock);
629
 
630
    t = thread_find_by_id(tid);
631
    if (t == NULL) {
632
        spinlock_unlock(&threads_lock);
633
        interrupts_restore(ipl);
634
        klog_printf("fail: no such thread\n");
635
        return ENOENT;
636
    }
637
 
638
    /* keep a lock on the thread */
639
    spinlock_lock(&t->lock);
640
    spinlock_unlock(&threads_lock);
641
 
642
    /* verify that the thread is stopped in a syscall event*/
643
    if (t->tdebug.stopped == 0 ||
644
        t->tdebug.current_event != TDEBUG_EV_SYSCALL) {
645
        spinlock_unlock(&t->lock);
646
        interrupts_restore(ipl);
647
        return EINVAL;
648
    }
649
 
650
    /* copy syscall arguments */
651
    sc_args[0] = t->tdebug.syscall_args[0];
652
    sc_args[1] = t->tdebug.syscall_args[1];
653
    sc_args[2] = t->tdebug.syscall_args[2];
654
    sc_args[3] = t->tdebug.syscall_args[3];
655
    sc_args[4] = t->tdebug.syscall_args[4];
656
    sc_args[5] = t->tdebug.syscall_args[5];
657
 
658
    spinlock_unlock(&t->lock);
659
    interrupts_restore(ipl);
660
 
661
    return 0;
662
}
663
 
664
/**
665
 * Select which debug events will be generated.
666
 */
667
int tdebug_set_event_mask(thread_id_t tid, unative_t ev_mask)
668
{
669
    thread_t *t;
670
    ipl_t ipl;
671
    int rc;
672
 
673
    //FIXME: need to verify that we are the monitor
674
 
675
    ipl = interrupts_disable();
676
    spinlock_lock(&threads_lock);
677
 
678
    t = thread_find_by_id(tid);
679
    if (t == NULL) {
680
        spinlock_unlock(&threads_lock);
681
        interrupts_restore(ipl);
682
        klog_printf("fail: no such thread\n");
683
        return ENOENT;
684
    }
685
 
686
    /* keep a lock on the thread */
687
    spinlock_lock(&t->lock);
688
    spinlock_unlock(&threads_lock);
689
 
690
    /* verify that the thread is stopped */
691
    if (t->tdebug.stopped == 0) {
692
        spinlock_unlock(&t->lock);
693
        interrupts_restore(ipl);
694
        klog_printf("fail: thread not stopped\n");
695
        return EINVAL;
696
    }
697
 
698
    t->tdebug.event_mask = ev_mask;
699
 
700
    /* arch-specific update for IAFTER setting */
701
    //disable this as it would break compile for all archs except ia32
702
    //rc = tdebug_iafter_update(t);
703
    rc = 0;
704
 
705
    spinlock_unlock(&t->lock);
706
    interrupts_restore(ipl);
707
 
708
    return rc;
709
}
710
 
711
/**
712
 * Ask a thread to stop (without waiting for it to happen).
713
 */
714
int tdebug_stop_thread(thread_id_t tid)
715
{
716
    thread_t *t;
717
    ipl_t ipl;
718
 
719
    //FIXME: need to verify that we are the monitor
720
 
721
    ipl = interrupts_disable();
722
    spinlock_lock(&threads_lock);
723
 
724
    t = thread_find_by_id(tid);
725
    if (t == NULL) {
726
        spinlock_unlock(&threads_lock);
727
        interrupts_restore(ipl);
728
        klog_printf("fail: no such thread\n");
729
        return ENOENT;
730
    }
731
 
732
    /* keep a lock on the thread */
733
    spinlock_lock(&t->lock);
734
    spinlock_unlock(&threads_lock);
735
 
736
    /* verify that the thread isn't stopped */
737
    if (t->tdebug.stopped == 0) {
738
        spinlock_unlock(&t->lock);
739
        interrupts_restore(ipl);
740
        return EINVAL;
741
    }
742
 
743
    t->tdebug.stop_request = 1;
744
 
745
    spinlock_unlock(&t->lock);
746
    interrupts_restore(ipl);
747
 
748
    return 0;
749
}
750
 
751
/**
752
 * Ask all threads in a task to stop (without waiting for it to happen).
753
 */
754
int tdebug_stop_task(task_id_t taskid)
755
{
756
    return 0;
757
}