Subversion Repositories HelenOS

Rev

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

Rev 2440 Rev 2446
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
#include <console/klog.h>
70
 
71
 
71
 
72
 
72
/** Thread states */
73
/** Thread states */
73
char *thread_states[] = {
74
char *thread_states[] = {
74
    "Invalid",
75
    "Invalid",
75
    "Running",
76
    "Running",
76
    "Sleeping",
77
    "Sleeping",
77
    "Ready",
78
    "Ready",
78
    "Entering",
79
    "Entering",
79
    "Exiting",
80
    "Exiting",
80
    "Undead"
81
    "JoinMe"
81
};
82
};
82
 
83
 
83
/** Lock protecting the threads_btree B+tree.
84
/** Lock protecting the threads_btree B+tree.
84
 *
85
 *
85
 * For locking rules, see declaration thereof.
86
 * For locking rules, see declaration thereof.
Line 326... Line 327...
326
 
327
 
327
    t->in_copy_from_uspace = false;
328
    t->in_copy_from_uspace = false;
328
    t->in_copy_to_uspace = false;
329
    t->in_copy_to_uspace = false;
329
 
330
 
330
    t->interrupted = false;
331
    t->interrupted = false;
331
    t->join_type = None;
-
 
332
    t->detached = false;
332
    t->detached = false;
333
    waitq_initialize(&t->join_wq);
333
    waitq_initialize(&t->join_wq);
334
   
334
   
335
    t->rwlock_holder_type = RWLOCK_NONE;
335
    t->rwlock_holder_type = RWLOCK_NONE;
336
       
336
       
Line 340... Line 340...
340
    t->fpu_context_engaged = 0;
340
    t->fpu_context_engaged = 0;
341
 
341
 
342
    /* might depend on previous initialization */
342
    /* might depend on previous initialization */
343
    thread_create_arch(t); 
343
    thread_create_arch(t); 
344
 
344
 
345
    ipl = interrupts_disable();  
-
 
346
    spinlock_lock(&task->lock);
-
 
347
    if (!task->accept_new_threads) {
-
 
348
        spinlock_unlock(&task->lock);
-
 
349
        slab_free(thread_slab, t);
-
 
350
        interrupts_restore(ipl);
-
 
351
        return NULL;
-
 
352
    } else {
-
 
353
        /*
-
 
354
         * Bump the reference count so that this task cannot be
-
 
355
         * destroyed while the new thread is being attached to it.
-
 
356
         */
-
 
357
        task->refcount++;
-
 
358
    }
-
 
359
    spinlock_unlock(&task->lock);
-
 
360
    interrupts_restore(ipl);
-
 
361
 
-
 
362
    if (!(flags & THREAD_FLAG_NOATTACH))
345
    if (!(flags & THREAD_FLAG_NOATTACH))
363
        thread_attach(t, task);
346
        thread_attach(t, task);
364
 
347
 
365
    return t;
348
    return t;
366
}
349
}
Line 371... Line 354...
371
 *
354
 *
372
 * Assume thread->lock is held!!
355
 * Assume thread->lock is held!!
373
 */
356
 */
374
void thread_destroy(thread_t *t)
357
void thread_destroy(thread_t *t)
375
{
358
{
376
    bool destroy_task = false;
-
 
377
 
-
 
378
    ASSERT(t->state == Exiting || t->state == Undead);
359
    ASSERT(t->state == Exiting || t->state == JoinMe);
379
    ASSERT(t->task);
360
    ASSERT(t->task);
380
    ASSERT(t->cpu);
361
    ASSERT(t->cpu);
381
 
362
 
382
    spinlock_lock(&t->cpu->lock);
363
    spinlock_lock(&t->cpu->lock);
383
    if (t->cpu->fpu_owner == t)
364
    if (t->cpu->fpu_owner == t)
Line 393... Line 374...
393
    /*
374
    /*
394
     * Detach from the containing task.
375
     * Detach from the containing task.
395
     */
376
     */
396
    spinlock_lock(&t->task->lock);
377
    spinlock_lock(&t->task->lock);
397
    list_remove(&t->th_link);
378
    list_remove(&t->th_link);
398
    if (--t->task->refcount == 0) {
-
 
399
        t->task->accept_new_threads = false;
-
 
400
        destroy_task = true;
-
 
401
    }
-
 
402
    spinlock_unlock(&t->task->lock);   
379
    spinlock_unlock(&t->task->lock);   
403
   
380
 
-
 
381
    /*
-
 
382
     * t is guaranteed to be the very last thread of its task.
404
    if (destroy_task)
383
     * It is safe to destroy the task.
-
 
384
     */
-
 
385
    if (atomic_predec(&t->task->refcount) == 0)
405
        task_destroy(t->task);
386
        task_destroy(t->task);
406
   
387
   
407
    /*
388
    /*
408
     * If the thread had a userspace context, free up its kernel_uarg
389
     * If the thread had a userspace context, free up its kernel_uarg
409
     * structure.
390
     * structure.
Line 429... Line 410...
429
    ipl_t ipl;
410
    ipl_t ipl;
430
 
411
 
431
    /*
412
    /*
432
     * Attach to the current task.
413
     * Attach to the current task.
433
     */
414
     */
434
    ipl = interrupts_disable();  
415
    ipl = interrupts_disable();
435
    spinlock_lock(&task->lock);
416
    spinlock_lock(&task->lock);
436
    ASSERT(task->refcount);
417
    atomic_inc(&task->refcount);
-
 
418
    atomic_inc(&task->lifecount);
437
    list_append(&t->th_link, &task->th_head);
419
    list_append(&t->th_link, &task->th_head);
438
    if (task->refcount == 1)
-
 
439
        task->main_thread = t;
-
 
440
    spinlock_unlock(&task->lock);
420
    spinlock_unlock(&task->lock);
441
 
421
 
442
    /*
422
    /*
443
     * Register this thread in the system-wide list.
423
     * Register this thread in the system-wide list.
444
     */
424
     */
Line 457... Line 437...
457
 */
437
 */
458
void thread_exit(void)
438
void thread_exit(void)
459
{
439
{
460
    ipl_t ipl;
440
    ipl_t ipl;
461
 
441
 
-
 
442
    if (atomic_predec(&TASK->lifecount) == 0) {
-
 
443
        /*
-
 
444
         * We are the last thread in the task that still has not exited.
-
 
445
         * With the exception of the moment the task was created, new
-
 
446
         * threads can only be created by threads of the same task.
-
 
447
         * We are safe to perform cleanup.
-
 
448
         */
-
 
449
        if (THREAD->flags & THREAD_FLAG_USPACE) {
-
 
450
            ipc_cleanup();
-
 
451
                futex_cleanup();
-
 
452
            klog_printf("Cleanup of task %llu completed.",
-
 
453
                TASK->taskid);
-
 
454
        }
-
 
455
    }
-
 
456
 
462
restart:
457
restart:
463
    ipl = interrupts_disable();
458
    ipl = interrupts_disable();
464
    spinlock_lock(&THREAD->lock);
459
    spinlock_lock(&THREAD->lock);
465
    if (THREAD->timeout_pending) {
460
    if (THREAD->timeout_pending) {
466
        /* busy waiting for timeouts in progress */
461
        /* busy waiting for timeouts in progress */
467
        spinlock_unlock(&THREAD->lock);
462
        spinlock_unlock(&THREAD->lock);
468
        interrupts_restore(ipl);
463
        interrupts_restore(ipl);
469
        goto restart;
464
        goto restart;
470
    }
465
    }
-
 
466
   
471
    THREAD->state = Exiting;
467
    THREAD->state = Exiting;
472
    spinlock_unlock(&THREAD->lock);
468
    spinlock_unlock(&THREAD->lock);
473
    scheduler();
469
    scheduler();
474
 
470
 
475
    /* Not reached */
471
    /* Not reached */
Line 522... Line 518...
522
    return rc; 
518
    return rc; 
523
}
519
}
524
 
520
 
525
/** Detach thread.
521
/** Detach thread.
526
 *
522
 *
527
 * Mark the thread as detached, if the thread is already in the Undead state,
523
 * Mark the thread as detached, if the thread is already in the JoinMe state,
528
 * deallocate its resources.
524
 * deallocate its resources.
529
 *
525
 *
530
 * @param t Thread to be detached.
526
 * @param t Thread to be detached.
531
 */
527
 */
532
void thread_detach(thread_t *t)
528
void thread_detach(thread_t *t)
Line 538... Line 534...
538
     * pointer to it must be still valid.
534
     * pointer to it must be still valid.
539
     */
535
     */
540
    ipl = interrupts_disable();
536
    ipl = interrupts_disable();
541
    spinlock_lock(&t->lock);
537
    spinlock_lock(&t->lock);
542
    ASSERT(!t->detached);
538
    ASSERT(!t->detached);
543
    if (t->state == Undead) {
539
    if (t->state == JoinMe) {
544
        thread_destroy(t);  /* unlocks &t->lock */
540
        thread_destroy(t);  /* unlocks &t->lock */
545
        interrupts_restore(ipl);
541
        interrupts_restore(ipl);
546
        return;
542
        return;
547
    } else {
543
    } else {
548
        t->detached = true;
544
        t->detached = true;
Line 700... Line 696...
700
            int rc;
696
            int rc;
701
 
697
 
702
            rc = copy_to_uspace(uspace_thread_id, &t->tid,
698
            rc = copy_to_uspace(uspace_thread_id, &t->tid,
703
                sizeof(t->tid));
699
                sizeof(t->tid));
704
            if (rc != 0) {
700
            if (rc != 0) {
705
                ipl_t ipl;
-
 
706
 
-
 
707
                /*
701
                /*
708
                 * We have encountered a failure, but the thread
702
                 * We have encountered a failure, but the thread
709
                 * has already been created. We need to undo its
703
                 * has already been created. We need to undo its
710
                 * creation now.
704
                 * creation now.
711
                 */
705
                 */
712
 
706
 
713
                /*
707
                /*
714
                 * The new thread structure is initialized,
708
                 * The new thread structure is initialized, but
715
                 * but is still not visible to the system.
709
                 * is still not visible to the system.
716
                 * We can safely deallocate it.
710
                 * We can safely deallocate it.
717
                 */
711
                 */
718
                slab_free(thread_slab, t);
712
                slab_free(thread_slab, t);
719
                free(kernel_uarg);
713
                free(kernel_uarg);
720
 
714
 
721
                /*
-
 
722
                 * Now we need to decrement the task reference
-
 
723
                 * counter. Because we are running within the
-
 
724
                 * same task, thread t is not the last thread
-
 
725
                 * in the task, so it is safe to merely
-
 
726
                 * decrement the counter.
-
 
727
                 */
-
 
728
                ipl = interrupts_disable();
-
 
729
                spinlock_lock(&TASK->lock);
-
 
730
                TASK->refcount--;
-
 
731
                spinlock_unlock(&TASK->lock);
-
 
732
                interrupts_restore(ipl);
-
 
733
 
-
 
734
                return (unative_t) rc;
715
                return (unative_t) rc;
735
             }
716
             }
736
        }
717
        }
737
        thread_attach(t, TASK);
718
        thread_attach(t, TASK);
738
        thread_ready(t);
719
        thread_ready(t);