Subversion Repositories HelenOS

Rev

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

Rev 3022 Rev 4055
Line 65... Line 65...
65
#include <mm/slab.h>
65
#include <mm/slab.h>
66
#include <debug.h>
66
#include <debug.h>
67
#include <main/uinit.h>
67
#include <main/uinit.h>
68
#include <syscall/copy.h>
68
#include <syscall/copy.h>
69
#include <errno.h>
69
#include <errno.h>
-
 
70
 
-
 
71
 
70
#include <console/klog.h>
72
#ifndef LOADED_PROG_STACK_PAGES_NO
-
 
73
#define LOADED_PROG_STACK_PAGES_NO 1
-
 
74
#endif
71
 
75
 
72
 
76
 
73
/** Thread states */
77
/** Thread states */
74
char *thread_states[] = {
78
char *thread_states[] = {
75
    "Invalid",
79
    "Invalid",
Line 96... Line 100...
96
 
100
 
97
SPINLOCK_INITIALIZE(tidlock);
101
SPINLOCK_INITIALIZE(tidlock);
98
thread_id_t last_tid = 0;
102
thread_id_t last_tid = 0;
99
 
103
 
100
static slab_cache_t *thread_slab;
104
static slab_cache_t *thread_slab;
101
#ifdef ARCH_HAS_FPU
105
#ifdef CONFIG_FPU
102
slab_cache_t *fpu_context_slab;
106
slab_cache_t *fpu_context_slab;
103
#endif
107
#endif
104
 
108
 
105
/** Thread wrapper.
109
/** Thread wrapper.
106
 *
110
 *
Line 155... Line 159...
155
    link_initialize(&t->th_link);
159
    link_initialize(&t->th_link);
156
 
160
 
157
    /* call the architecture-specific part of the constructor */
161
    /* call the architecture-specific part of the constructor */
158
    thr_constructor_arch(t);
162
    thr_constructor_arch(t);
159
   
163
   
160
#ifdef ARCH_HAS_FPU
164
#ifdef CONFIG_FPU
161
#ifdef CONFIG_FPU_LAZY
165
#ifdef CONFIG_FPU_LAZY
162
    t->saved_fpu_context = NULL;
166
    t->saved_fpu_context = NULL;
163
#else
167
#else
164
    t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags);
168
    t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags);
165
    if (!t->saved_fpu_context)
169
    if (!t->saved_fpu_context)
166
        return -1;
170
        return -1;
167
#endif
171
#endif
168
#endif  
172
#endif
169
 
173
 
170
    t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags);
174
    t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags);
171
    if (!t->kstack) {
175
    if (!t->kstack) {
172
#ifdef ARCH_HAS_FPU
176
#ifdef CONFIG_FPU
173
        if (t->saved_fpu_context)
177
        if (t->saved_fpu_context)
174
            slab_free(fpu_context_slab, t->saved_fpu_context);
178
            slab_free(fpu_context_slab, t->saved_fpu_context);
175
#endif
179
#endif
176
        return -1;
180
        return -1;
177
    }
181
    }
178
 
182
 
-
 
183
#ifdef CONFIG_UDEBUG
-
 
184
    mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE);
-
 
185
#endif
-
 
186
 
179
    return 0;
187
    return 0;
180
}
188
}
181
 
189
 
182
/** Destruction of thread_t object */
190
/** Destruction of thread_t object */
183
static int thr_destructor(void *obj)
191
static int thr_destructor(void *obj)
Line 186... Line 194...
186
 
194
 
187
    /* call the architecture-specific part of the destructor */
195
    /* call the architecture-specific part of the destructor */
188
    thr_destructor_arch(t);
196
    thr_destructor_arch(t);
189
 
197
 
190
    frame_free(KA2PA(t->kstack));
198
    frame_free(KA2PA(t->kstack));
191
#ifdef ARCH_HAS_FPU
199
#ifdef CONFIG_FPU
192
    if (t->saved_fpu_context)
200
    if (t->saved_fpu_context)
193
        slab_free(fpu_context_slab, t->saved_fpu_context);
201
        slab_free(fpu_context_slab, t->saved_fpu_context);
194
#endif
202
#endif
195
    return 1; /* One page freed */
203
    return 1; /* One page freed */
196
}
204
}
Line 201... Line 209...
201
 *
209
 *
202
 */
210
 */
203
void thread_init(void)
211
void thread_init(void)
204
{
212
{
205
    THREAD = NULL;
213
    THREAD = NULL;
206
    atomic_set(&nrdy,0);
214
    atomic_set(&nrdy, 0);
207
    thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0,
215
    thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0,
208
        thr_constructor, thr_destructor, 0);
216
        thr_constructor, thr_destructor, 0);
209
 
217
 
210
#ifdef ARCH_HAS_FPU
218
#ifdef CONFIG_FPU
211
    fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t),
219
    fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t),
212
        FPU_CONTEXT_ALIGN, NULL, NULL, 0);
220
        FPU_CONTEXT_ALIGN, NULL, NULL, 0);
213
#endif
221
#endif
214
 
222
 
215
    avltree_create(&threads_tree);
223
    avltree_create(&threads_tree);
Line 269... Line 277...
269
 * @param arg       Thread's implementing function argument.
277
 * @param arg       Thread's implementing function argument.
270
 * @param task      Task to which the thread belongs. The caller must
278
 * @param task      Task to which the thread belongs. The caller must
271
 *          guarantee that the task won't cease to exist during the
279
 *          guarantee that the task won't cease to exist during the
272
 *          call. The task's lock may not be held.
280
 *          call. The task's lock may not be held.
273
 * @param flags     Thread flags.
281
 * @param flags     Thread flags.
274
 * @param name      Symbolic name.
282
 * @param name      Symbolic name (a copy is made).
275
 * @param uncounted Thread's accounting doesn't affect accumulated task
283
 * @param uncounted Thread's accounting doesn't affect accumulated task
276
 *          accounting.
284
 *          accounting.
277
 *
285
 *
278
 * @return      New thread's structure on success, NULL on failure.
286
 * @return      New thread's structure on success, NULL on failure.
279
 *
287
 *
Line 287... Line 295...
287
    t = (thread_t *) slab_alloc(thread_slab, 0);
295
    t = (thread_t *) slab_alloc(thread_slab, 0);
288
    if (!t)
296
    if (!t)
289
        return NULL;
297
        return NULL;
290
   
298
   
291
    /* Not needed, but good for debugging */
299
    /* Not needed, but good for debugging */
292
    memsetb((uintptr_t) t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES,
300
    memsetb(t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, 0);
293
        0);
-
 
294
   
301
   
295
    ipl = interrupts_disable();
302
    ipl = interrupts_disable();
296
    spinlock_lock(&tidlock);
303
    spinlock_lock(&tidlock);
297
    t->tid = ++last_tid;
304
    t->tid = ++last_tid;
298
    spinlock_unlock(&tidlock);
305
    spinlock_unlock(&tidlock);
Line 307... Line 314...
307
    ipl = interrupts_disable();
314
    ipl = interrupts_disable();
308
    t->saved_context.ipl = interrupts_read();
315
    t->saved_context.ipl = interrupts_read();
309
    interrupts_restore(ipl);
316
    interrupts_restore(ipl);
310
   
317
   
311
    memcpy(t->name, name, THREAD_NAME_BUFLEN);
318
    memcpy(t->name, name, THREAD_NAME_BUFLEN);
-
 
319
    t->name[THREAD_NAME_BUFLEN - 1] = '\0';
312
   
320
   
313
    t->thread_code = func;
321
    t->thread_code = func;
314
    t->thread_arg = arg;
322
    t->thread_arg = arg;
315
    t->ticks = -1;
323
    t->ticks = -1;
316
    t->cycles = 0;
324
    t->cycles = 0;
Line 342... Line 350...
342
    t->fpu_context_engaged = 0;
350
    t->fpu_context_engaged = 0;
343
 
351
 
344
    avltree_node_initialize(&t->threads_tree_node);
352
    avltree_node_initialize(&t->threads_tree_node);
345
    t->threads_tree_node.key = (uintptr_t) t;
353
    t->threads_tree_node.key = (uintptr_t) t;
346
 
354
 
-
 
355
#ifdef CONFIG_UDEBUG
-
 
356
    /* Init debugging stuff */
-
 
357
    udebug_thread_initialize(&t->udebug);
-
 
358
#endif
-
 
359
 
347
    /* might depend on previous initialization */
360
    /* might depend on previous initialization */
348
    thread_create_arch(t); 
361
    thread_create_arch(t); 
349
 
362
 
350
    if (!(flags & THREAD_FLAG_NOATTACH))
363
    if (!(flags & THREAD_FLAG_NOATTACH))
351
        thread_attach(t, task);
364
        thread_attach(t, task);
Line 404... Line 417...
404
void thread_attach(thread_t *t, task_t *task)
417
void thread_attach(thread_t *t, task_t *task)
405
{
418
{
406
    ipl_t ipl;
419
    ipl_t ipl;
407
 
420
 
408
    /*
421
    /*
409
     * Attach to the current task.
422
     * Attach to the specified task.
410
     */
423
     */
411
    ipl = interrupts_disable();
424
    ipl = interrupts_disable();
412
    spinlock_lock(&task->lock);
425
    spinlock_lock(&task->lock);
-
 
426
 
413
    atomic_inc(&task->refcount);
427
    atomic_inc(&task->refcount);
-
 
428
 
-
 
429
    /* Must not count kbox thread into lifecount */
-
 
430
    if (t->flags & THREAD_FLAG_USPACE)
414
    atomic_inc(&task->lifecount);
431
        atomic_inc(&task->lifecount);
-
 
432
 
415
    list_append(&t->th_link, &task->th_head);
433
    list_append(&t->th_link, &task->th_head);
416
    spinlock_unlock(&task->lock);
434
    spinlock_unlock(&task->lock);
417
 
435
 
418
    /*
436
    /*
419
     * Register this thread in the system-wide list.
437
     * Register this thread in the system-wide list.
Line 432... Line 450...
432
 */
450
 */
433
void thread_exit(void)
451
void thread_exit(void)
434
{
452
{
435
    ipl_t ipl;
453
    ipl_t ipl;
436
 
454
 
-
 
455
    if (THREAD->flags & THREAD_FLAG_USPACE) {
-
 
456
#ifdef CONFIG_UDEBUG
-
 
457
        /* Generate udebug THREAD_E event */
-
 
458
        udebug_thread_e_event();
-
 
459
#endif
437
    if (atomic_predec(&TASK->lifecount) == 0) {
460
        if (atomic_predec(&TASK->lifecount) == 0) {
438
        /*
461
            /*
439
         * We are the last thread in the task that still has not exited.
462
             * We are the last userspace thread in the task that
-
 
463
             * still has not exited. With the exception of the
440
         * With the exception of the moment the task was created, new
464
             * moment the task was created, new userspace threads
441
         * threads can only be created by threads of the same task.
465
             * can only be created by threads of the same task.
442
         * We are safe to perform cleanup.
466
             * We are safe to perform cleanup.
443
         */
467
             */
444
        if (THREAD->flags & THREAD_FLAG_USPACE) {
-
 
445
            ipc_cleanup();
468
            ipc_cleanup();
446
                futex_cleanup();
469
            futex_cleanup();
447
            klog_printf("Cleanup of task %llu completed.",
470
            LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid);
448
                TASK->taskid);
-
 
449
        }
471
        }
450
    }
472
    }
451
 
473
 
452
restart:
474
restart:
453
    ipl = interrupts_disable();
475
    ipl = interrupts_disable();
Line 579... Line 601...
579
    interrupts_restore(ipl);
601
    interrupts_restore(ipl);
580
}
602
}
581
 
603
 
582
static bool thread_walker(avltree_node_t *node, void *arg)
604
static bool thread_walker(avltree_node_t *node, void *arg)
583
{
605
{
584
    thread_t *t;
-
 
585
       
-
 
586
    t = avltree_get_instance(node, thread_t, threads_tree_node);
606
    thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node);
587
 
607
   
588
    uint64_t cycles;
608
    uint64_t cycles;
589
    char suffix;
609
    char suffix;
590
    order(t->cycles, &cycles, &suffix);
610
    order(t->cycles, &cycles, &suffix);
591
   
611
 
592
    if (sizeof(void *) == 4)
612
#ifdef __32_BITS__
593
        printf("%-6llu %-10s %#10zx %-8s %#10zx %-3ld %#10zx %#10zx %9llu%c ",
613
    printf("%-6" PRIu64" %-10s %10p %-8s %10p %-3" PRIu32 " %10p %10p %9" PRIu64 "%c ",
594
            t->tid, t->name, t, thread_states[t->state], t->task,
614
        t->tid, t->name, t, thread_states[t->state], t->task,
595
            t->task->context, t->thread_code, t->kstack, cycles, suffix);
615
        t->task->context, t->thread_code, t->kstack, cycles, suffix);
596
    else
616
#endif
-
 
617
 
-
 
618
#ifdef __64_BITS__
597
        printf("%-6llu %-10s %#18zx %-8s %#18zx %-3ld %#18zx %#18zx %9llu%c ",
619
    printf("%-6" PRIu64" %-10s %18p %-8s %18p %-3" PRIu32 " %18p %18p %9" PRIu64 "%c ",
598
            t->tid, t->name, t, thread_states[t->state], t->task,
620
        t->tid, t->name, t, thread_states[t->state], t->task,
599
            t->task->context, t->thread_code, t->kstack, cycles, suffix);
621
        t->task->context, t->thread_code, t->kstack, cycles, suffix);
-
 
622
#endif
600
           
623
           
601
    if (t->cpu)
624
    if (t->cpu)
602
        printf("%-4zd", t->cpu->id);
625
        printf("%-4u", t->cpu->id);
603
    else
626
    else
604
        printf("none");
627
        printf("none");
605
           
628
           
606
    if (t->state == Sleeping) {
629
    if (t->state == Sleeping) {
607
        if (sizeof(uintptr_t) == 4)
630
#ifdef __32_BITS__
608
            printf(" %#10zx", t->sleep_queue);
631
        printf(" %10p", t->sleep_queue);
609
        else
632
#endif
-
 
633
 
-
 
634
#ifdef __64_BITS__
610
            printf(" %#18zx", t->sleep_queue);
635
        printf(" %18p", t->sleep_queue);
-
 
636
#endif
611
    }
637
    }
612
           
638
           
613
    printf("\n");
639
    printf("\n");
614
 
640
 
615
    return true;
641
    return true;
Line 621... Line 647...
621
    ipl_t ipl;
647
    ipl_t ipl;
622
   
648
   
623
    /* Messing with thread structures, avoid deadlock */
649
    /* Messing with thread structures, avoid deadlock */
624
    ipl = interrupts_disable();
650
    ipl = interrupts_disable();
625
    spinlock_lock(&threads_lock);
651
    spinlock_lock(&threads_lock);
626
   
652
 
627
    if (sizeof(uintptr_t) == 4) {
653
#ifdef __32_BITS__  
628
        printf("tid    name       address    state    task       "
654
    printf("tid    name       address    state    task       "
629
            "ctx code       stack      cycles     cpu  "
655
        "ctx code       stack      cycles     cpu  "
630
            "waitqueue\n");
656
        "waitqueue\n");
631
        printf("------ ---------- ---------- -------- ---------- "
657
    printf("------ ---------- ---------- -------- ---------- "
632
            "--- ---------- ---------- ---------- ---- "
658
        "--- ---------- ---------- ---------- ---- "
633
            "----------\n");
659
        "----------\n");
634
    } else {
660
#endif
-
 
661
 
-
 
662
#ifdef __64_BITS__
635
        printf("tid    name       address            state    task               "
663
    printf("tid    name       address            state    task               "
636
            "ctx code               stack              cycles     cpu  "
664
        "ctx code               stack              cycles     cpu  "
637
            "waitqueue\n");
665
        "waitqueue\n");
638
        printf("------ ---------- ------------------ -------- ------------------ "
666
    printf("------ ---------- ------------------ -------- ------------------ "
639
            "--- ------------------ ------------------ ---------- ---- "
667
        "--- ------------------ ------------------ ---------- ---- "
640
            "------------------\n");
668
        "------------------\n");
641
    }
669
#endif
642
 
670
 
643
    avltree_walk(&threads_tree, thread_walker, NULL);
671
    avltree_walk(&threads_tree, thread_walker, NULL);
644
 
672
 
645
    spinlock_unlock(&threads_lock);
673
    spinlock_unlock(&threads_lock);
646
    interrupts_restore(ipl);
674
    interrupts_restore(ipl);
Line 662... Line 690...
662
    node = avltree_search(&threads_tree, (avltree_key_t) ((uintptr_t) t));
690
    node = avltree_search(&threads_tree, (avltree_key_t) ((uintptr_t) t));
663
   
691
   
664
    return node != NULL;
692
    return node != NULL;
665
}
693
}
666
 
694
 
667
 
-
 
668
/** Update accounting of current thread.
695
/** Update accounting of current thread.
669
 *
696
 *
670
 * Note that thread_lock on THREAD must be already held and
697
 * Note that thread_lock on THREAD must be already held and
671
 * interrupts must be already disabled.
698
 * interrupts must be already disabled.
672
 *
699
 *
Line 680... Line 707...
680
 
707
 
681
/** Process syscall to create new thread.
708
/** Process syscall to create new thread.
682
 *
709
 *
683
 */
710
 */
684
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name,
711
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name,
685
    thread_id_t *uspace_thread_id)
712
    size_t name_len, thread_id_t *uspace_thread_id)
686
{
713
{
687
    thread_t *t;
714
    thread_t *t;
688
    char namebuf[THREAD_NAME_BUFLEN];
715
    char namebuf[THREAD_NAME_BUFLEN];
689
    uspace_arg_t *kernel_uarg;
716
    uspace_arg_t *kernel_uarg;
690
    int rc;
717
    int rc;
691
 
718
 
-
 
719
    if (name_len > THREAD_NAME_BUFLEN - 1)
-
 
720
        name_len = THREAD_NAME_BUFLEN - 1;
-
 
721
 
692
    rc = copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN);
722
    rc = copy_from_uspace(namebuf, uspace_name, name_len);
693
    if (rc != 0)
723
    if (rc != 0)
694
        return (unative_t) rc;
724
        return (unative_t) rc;
695
 
725
 
-
 
726
    namebuf[name_len] = '\0';
-
 
727
 
696
    /*
728
    /*
697
     * In case of failure, kernel_uarg will be deallocated in this function.
729
     * In case of failure, kernel_uarg will be deallocated in this function.
698
     * In case of success, kernel_uarg will be freed in uinit().
730
     * In case of success, kernel_uarg will be freed in uinit().
699
     */
731
     */
700
    kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
732
    kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
Line 729... Line 761...
729
                free(kernel_uarg);
761
                free(kernel_uarg);
730
 
762
 
731
                return (unative_t) rc;
763
                return (unative_t) rc;
732
             }
764
             }
733
        }
765
        }
-
 
766
#ifdef CONFIG_UDEBUG
-
 
767
        /*
-
 
768
         * Generate udebug THREAD_B event and attach the thread.
-
 
769
         * This must be done atomically (with the debug locks held),
-
 
770
         * otherwise we would either miss some thread or receive
-
 
771
         * THREAD_B events for threads that already existed
-
 
772
         * and could be detected with THREAD_READ before.
-
 
773
         */
-
 
774
        udebug_thread_b_event_attach(t, TASK);
-
 
775
#else
734
        thread_attach(t, TASK);
776
        thread_attach(t, TASK);
-
 
777
#endif
735
        thread_ready(t);
778
        thread_ready(t);
736
 
779
 
737
        return 0;
780
        return 0;
738
    } else
781
    } else
739
        free(kernel_uarg);
782
        free(kernel_uarg);