1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
| // Copyright 2016 The Fuchsia Authors
// Copyright (c) 2008-2015 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
/**
* @file
* @brief Kernel threading
*
* This file is the core kernel threading interface.
*
* @defgroup thread Threads
* @{
*/
#include <kernel/thread.h>
#include <arch/exception.h>
#include <assert.h>
#include <debug.h>
#include <err.h>
#include <inttypes.h>
#include <kernel/atomic.h>
#include <kernel/dpc.h>
#include <kernel/mp.h>
#include <kernel/percpu.h>
#include <kernel/sched.h>
#include <kernel/stats.h>
#include <kernel/thread.h>
#include <kernel/timer.h>
#include <lib/counters.h>
#include <lib/heap.h>
#include <lib/ktrace.h>
#include <list.h>
#include <malloc.h>
#include <object/c_user_thread.h>
#include <platform.h>
#include <printf.h>
#include <string.h>
#include <target.h>
#include <vm/vm.h>
#include <zircon/types.h>
// kernel counters. TODO(cpu): remove LK-era counters
// The counters below never decrease.
//
// counts the number of thread_t succesfully created.
KCOUNTER(thread_create_count, "kernel.thread.create");
// counts the number of thread_t joined. Never decreases.
KCOUNTER(thread_join_count, "kernel.thread.join");
// counts the number of calls to suspend() that succeeded.
KCOUNTER(thread_suspend_count, "kernel.thread.suspend");
// counts the number of calls to resume() that succeeded.
KCOUNTER(thread_resume_count, "kernel.thread.resume");
/* global thread list */
static struct list_node thread_list = LIST_INITIAL_VALUE(thread_list);
/* master thread spinlock */
spin_lock_t thread_lock = SPIN_LOCK_INITIAL_VALUE;
/* local routines */
static void thread_exit_locked(thread_t* current_thread, int retcode) __NO_RETURN;
static void thread_do_suspend(void);
static void init_thread_struct(thread_t* t, const char* name) {
memset(t, 0, sizeof(thread_t));
t->magic = THREAD_MAGIC;
strlcpy(t->name, name, sizeof(t->name));
wait_queue_init(&t->retcode_wait_queue);
}
static void initial_thread_func(void) TA_REQ(thread_lock) __NO_RETURN;
static void initial_thread_func(void) {
int ret;
/* release the thread lock that was implicitly held across the reschedule */
spin_unlock(&thread_lock);
arch_enable_ints();
thread_t* ct = get_current_thread();
ret = ct->entry(ct->arg);
thread_exit(ret);
}
/**
* @brief Create a new thread
*
* This function creates a new thread. The thread is initially suspended, so you
* need to call thread_resume() to execute it.
*
* @param name Name of thread
* @param entry Entry point of thread
* @param arg Arbitrary argument passed to entry()
* @param priority Execution priority for the thread.
* @param stack_size Stack size for the thread.
* @param alt_trampoline If not NULL, an alternate trampoline for the thread
* to start on.
*
* Thread priority is an integer from 0 (lowest) to 31 (highest). Some standard
* prioritys are defined in <kernel/thread.h>:
*
* HIGHEST_PRIORITY
* DPC_PRIORITY
* HIGH_PRIORITY
* DEFAULT_PRIORITY
* LOW_PRIORITY
* IDLE_PRIORITY
* LOWEST_PRIORITY
*
* Stack size is typically set to DEFAULT_STACK_SIZE
*
* @return Pointer to thread object, or NULL on failure.
*/
thread_t* thread_create_etc(
thread_t* t,
const char* name,
thread_start_routine entry, void* arg,
int priority,
void* stack, void* unsafe_stack, size_t stack_size,
thread_trampoline_routine alt_trampoline) {
unsigned int flags = 0;
if (!t) {
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">t = malloc(sizeof(thread_t)); // allocation dynamique
</span> if (!t)
return NULL;
flags |= THREAD_FLAG_FREE_STRUCT;
}
init_thread_struct(t, name);
t->entry = entry;
t->arg = arg;
t->state = THREAD_INITIAL;
t->signals = 0;
t->blocking_wait_queue = NULL;
t->blocked_status = ZX_OK;
t->interruptable = false;
t->curr_cpu = INVALID_CPU;
t->last_cpu = INVALID_CPU;
t->cpu_affinity = CPU_MASK_ALL;
t->retcode = 0;
wait_queue_init(&t->retcode_wait_queue);
sched_init_thread(t, priority);
/* create the stack */
if (!stack) {
if (THREAD_STACK_BOUNDS_CHECK) {
stack_size += THREAD_STACK_PADDING_SIZE;
flags |= THREAD_FLAG_DEBUG_STACK_BOUNDS_CHECK;
}
t->stack = malloc(stack_size);
if (!t->stack) {
if (flags & THREAD_FLAG_FREE_STRUCT)
free(t);
return NULL;
}
flags |= THREAD_FLAG_FREE_STACK;
if (THREAD_STACK_BOUNDS_CHECK) {
memset(t->stack, STACK_DEBUG_BYTE, THREAD_STACK_PADDING_SIZE);
}
} else {
t->stack = stack;
}
#if __has_feature(safe_stack)
if (!unsafe_stack) {
DEBUG_ASSERT(!stack);
DEBUG_ASSERT(flags & THREAD_FLAG_FREE_STACK);
t->unsafe_stack = malloc(stack_size);
if (!t->unsafe_stack) {
free(t->stack);
if (flags & THREAD_FLAG_FREE_STRUCT)
free(t);
return NULL;
}
if (THREAD_STACK_BOUNDS_CHECK) {
memset(t->unsafe_stack, STACK_DEBUG_BYTE, THREAD_STACK_PADDING_SIZE);
}
} else {
DEBUG_ASSERT(stack);
t->unsafe_stack = unsafe_stack;
}
#else
DEBUG_ASSERT(!unsafe_stack);
#endif
t->stack_size = stack_size;
/* save whether or not we need to free the thread struct and/or stack */
t->flags = flags;
if (likely(alt_trampoline == NULL)) {
alt_trampoline = initial_thread_func;
}
/* set up the initial stack frame */
arch_thread_initialize(t, (vaddr_t)alt_trampoline);
/* add it to the global thread list */
THREAD_LOCK(state);
list_add_head(&thread_list, &t->thread_list_node);
THREAD_UNLOCK(state);
kcounter_add(thread_create_count, 1u);
return t;
} |
Partager