mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
scheduler: use a linked list for threads in a process instead of a table
This commit is contained in:
@@ -34,6 +34,7 @@ typedef struct thread_t {
|
|||||||
struct thread_t *prev;
|
struct thread_t *prev;
|
||||||
struct thread_t *sleepnext;
|
struct thread_t *sleepnext;
|
||||||
struct thread_t *sleepprev;
|
struct thread_t *sleepprev;
|
||||||
|
struct thread_t *procnext;
|
||||||
struct proc_t *proc;
|
struct proc_t *proc;
|
||||||
struct cpu_t *cpu;
|
struct cpu_t *cpu;
|
||||||
struct cpu_t *cputarget;
|
struct cpu_t *cputarget;
|
||||||
@@ -70,8 +71,9 @@ typedef struct proc_t {
|
|||||||
struct proc_t *child;
|
struct proc_t *child;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
cred_t cred;
|
cred_t cred;
|
||||||
thread_t **threads;
|
spinlock_t threadlistlock;
|
||||||
size_t threadtablesize;
|
thread_t *threadlist;
|
||||||
|
bool nomorethreads;
|
||||||
size_t runningthreadcount;
|
size_t runningthreadcount;
|
||||||
size_t fdcount;
|
size_t fdcount;
|
||||||
uintmax_t fdfirst;
|
uintmax_t fdfirst;
|
||||||
@@ -84,7 +86,6 @@ typedef struct proc_t {
|
|||||||
spinlock_t nodeslock;
|
spinlock_t nodeslock;
|
||||||
semaphore_t waitsem;
|
semaphore_t waitsem;
|
||||||
spinlock_t exiting;
|
spinlock_t exiting;
|
||||||
bool nomorethreads;
|
|
||||||
|
|
||||||
spinlock_t jobctllock;
|
spinlock_t jobctllock;
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
+24
-30
@@ -50,23 +50,14 @@ proc_t *sched_getprocfrompid(int pid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void rtdpc(context_t *, dpcarg_t arg) {
|
static void rtdpc(context_t *, dpcarg_t arg) {
|
||||||
proc_t *proc = arg;
|
|
||||||
// XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god
|
|
||||||
__assert(proc->threadtablesize == 1);
|
|
||||||
signal_signalproc(arg, SIGALRM);
|
signal_signalproc(arg, SIGALRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vtdpc(context_t *, dpcarg_t arg) {
|
static void vtdpc(context_t *, dpcarg_t arg) {
|
||||||
proc_t *proc = arg;
|
|
||||||
// XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god
|
|
||||||
__assert(proc->threadtablesize == 1);
|
|
||||||
signal_signalproc(arg, SIGVTALRM);
|
signal_signalproc(arg, SIGVTALRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void profdpc(context_t *, dpcarg_t arg) {
|
static void profdpc(context_t *, dpcarg_t arg) {
|
||||||
proc_t *proc = arg;
|
|
||||||
// XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god
|
|
||||||
__assert(proc->threadtablesize == 1);
|
|
||||||
signal_signalproc(arg, SIGPROF);
|
signal_signalproc(arg, SIGPROF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,15 +68,8 @@ proc_t *sched_newproc() {
|
|||||||
|
|
||||||
memset(proc, 0, sizeof(proc_t));
|
memset(proc, 0, sizeof(proc_t));
|
||||||
|
|
||||||
proc->threads = alloc(sizeof(thread_t *));
|
|
||||||
if (proc->threads == NULL) {
|
|
||||||
slab_free(processcache, proc);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO move this to slab
|
// TODO move this to slab
|
||||||
proc->state = SCHED_PROC_STATE_NORMAL;
|
proc->state = SCHED_PROC_STATE_NORMAL;
|
||||||
proc->threadtablesize = 1;
|
|
||||||
proc->runningthreadcount = 1;
|
proc->runningthreadcount = 1;
|
||||||
MUTEX_INIT(&proc->mutex);
|
MUTEX_INIT(&proc->mutex);
|
||||||
SPINLOCK_INIT(proc->nodeslock);
|
SPINLOCK_INIT(proc->nodeslock);
|
||||||
@@ -101,10 +85,10 @@ proc_t *sched_newproc() {
|
|||||||
itimer_init(&proc->timer.realtime, rtdpc, proc);
|
itimer_init(&proc->timer.realtime, rtdpc, proc);
|
||||||
itimer_init(&proc->timer.virtualtime, vtdpc, proc);
|
itimer_init(&proc->timer.virtualtime, vtdpc, proc);
|
||||||
itimer_init(&proc->timer.profiling, profdpc, proc);
|
itimer_init(&proc->timer.profiling, profdpc, proc);
|
||||||
|
SPINLOCK_INIT(proc->threadlistlock);
|
||||||
|
|
||||||
proc->fd = alloc(sizeof(fd_t) * 3);
|
proc->fd = alloc(sizeof(fd_t) * 3);
|
||||||
if (proc->fd == NULL) {
|
if (proc->fd == NULL) {
|
||||||
free(proc->threads);
|
|
||||||
slab_free(processcache, proc);
|
slab_free(processcache, proc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -117,7 +101,6 @@ proc_t *sched_newproc() {
|
|||||||
if (hashtable_set(&pidtable, proc, &proc->pid, sizeof(proc->pid), true)) {
|
if (hashtable_set(&pidtable, proc, &proc->pid, sizeof(proc->pid), true)) {
|
||||||
MUTEX_RELEASE(&sched_pidtablemutex);
|
MUTEX_RELEASE(&sched_pidtablemutex);
|
||||||
free(proc->fd);
|
free(proc->fd);
|
||||||
free(proc->threads);
|
|
||||||
slab_free(processcache, proc);
|
slab_free(processcache, proc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -168,7 +151,6 @@ void sched_destroythread(thread_t *thread) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sched_destroyproc(proc_t *proc) {
|
void sched_destroyproc(proc_t *proc) {
|
||||||
free(proc->threads);
|
|
||||||
free(proc->fd);
|
free(proc->fd);
|
||||||
slab_free(processcache, proc);
|
slab_free(processcache, proc);
|
||||||
}
|
}
|
||||||
@@ -353,8 +335,9 @@ void sched_procexit() {
|
|||||||
signal_signalproc(proc->parent, SIGCHLD);
|
signal_signalproc(proc->parent, SIGCHLD);
|
||||||
semaphore_signal(&proc->parent->waitsem);
|
semaphore_signal(&proc->parent->waitsem);
|
||||||
// TODO sigaction flag for this
|
// TODO sigaction flag for this
|
||||||
for (int i = 0; i < belowzombiecount; ++i)
|
for (int i = 0; i < belowzombiecount; ++i) {
|
||||||
semaphore_signal(&sched_initproc->waitsem);
|
semaphore_signal(&sched_initproc->waitsem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_inactiveproc(proc_t *proc) {
|
void sched_inactiveproc(proc_t *proc) {
|
||||||
@@ -469,21 +452,31 @@ __attribute__((no_caller_saved_registers)) void sched_userspacecheck(context_t *
|
|||||||
void sched_stopotherthreads() {
|
void sched_stopotherthreads() {
|
||||||
thread_t *thread = _cpu()->thread;
|
thread_t *thread = _cpu()->thread;
|
||||||
proc_t *proc = thread->proc;
|
proc_t *proc = thread->proc;
|
||||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&proc->threadlistlock);
|
||||||
|
|
||||||
proc->nomorethreads = true;
|
proc->nomorethreads = true;
|
||||||
|
thread_t *threadlist = proc->threadlist;
|
||||||
|
|
||||||
for (int i = 0; i < proc->threadtablesize; ++i) {
|
spinlock_release(&proc->threadlistlock);
|
||||||
if (proc->threads[i] == NULL || proc->threads[i] == thread)
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
while (threadlist) {
|
||||||
|
if (threadlist == thread) {
|
||||||
|
threadlist = threadlist->procnext;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
proc->threads[i]->shouldexit = true;
|
threadlist->shouldexit = true;
|
||||||
sched_wakeup(proc->threads[i], SCHED_WAKEUP_REASON_INTERRUPTED);
|
sched_wakeup(threadlist, SCHED_WAKEUP_REASON_INTERRUPTED);
|
||||||
proc->threads[i] = NULL;
|
threadlist = threadlist->procnext;
|
||||||
}
|
}
|
||||||
|
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
while (__atomic_load_n(&proc->runningthreadcount, __ATOMIC_SEQ_CST) > 1) {
|
||||||
|
arch_e9_puts("sched_stopotherthreads\n");
|
||||||
while (__atomic_load_n(&proc->runningthreadcount, __ATOMIC_SEQ_CST) > 1) sched_yield();
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
proc->nomorethreads = false;
|
proc->nomorethreads = false;
|
||||||
}
|
}
|
||||||
@@ -809,7 +802,8 @@ void sched_runinit() {
|
|||||||
thread_t *uthread = sched_newthread(entry, PAGE_SIZE * 16, 1, proc, stack);
|
thread_t *uthread = sched_newthread(entry, PAGE_SIZE * 16, 1, proc, stack);
|
||||||
__assert(uthread);
|
__assert(uthread);
|
||||||
|
|
||||||
proc->threads[0] = uthread;
|
proc->threadlist = uthread;
|
||||||
|
uthread->procnext = NULL;
|
||||||
|
|
||||||
uthread->vmmctx = vmmctx;
|
uthread->vmmctx = vmmctx;
|
||||||
sched_queue(uthread);
|
sched_queue(uthread);
|
||||||
|
|||||||
+21
-15
@@ -161,7 +161,6 @@ void signal_signalthread(struct thread_t *thread, int signal, bool urgent) {
|
|||||||
|
|
||||||
void signal_signalproc(struct proc_t *proc, int signal) {
|
void signal_signalproc(struct proc_t *proc, int signal) {
|
||||||
// first, check if any threads have the signal unmasked, and set as pending for the first one
|
// first, check if any threads have the signal unmasked, and set as pending for the first one
|
||||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
|
||||||
PROCESS_ENTER(proc);
|
PROCESS_ENTER(proc);
|
||||||
void *address = proc->signals.actions[signal].address;
|
void *address = proc->signals.actions[signal].address;
|
||||||
bool notignored = address != SIG_IGN && ((address == SIG_DFL && signal_defaultactions[signal] != ACTION_IGN) || address != SIG_DFL);
|
bool notignored = address != SIG_IGN && ((address == SIG_DFL && signal_defaultactions[signal] != ACTION_IGN) || address != SIG_DFL);
|
||||||
@@ -172,28 +171,31 @@ void signal_signalproc(struct proc_t *proc, int signal) {
|
|||||||
|
|
||||||
// TODO is one thread has a stop signal masked, the masked wait breaks completely
|
// TODO is one thread has a stop signal masked, the masked wait breaks completely
|
||||||
|
|
||||||
for (int i = 0; i < proc->threadtablesize; ++i) {
|
thread_t *thread = proc->threadlist;
|
||||||
if (proc->threads[i] == NULL || (proc->threads[i]->flags & SCHED_THREAD_FLAGS_DEAD))
|
while (thread) {
|
||||||
|
if (thread->flags & SCHED_THREAD_FLAGS_DEAD) {
|
||||||
|
thread = thread->procnext;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
THREAD_ENTER(proc->threads[i]);
|
THREAD_ENTER(thread);
|
||||||
|
|
||||||
if (SIGNAL_GET(&proc->threads[i]->signals.mask, signal) == 0 || notignorable) {
|
if (SIGNAL_GET(&thread->signals.mask, signal) == 0 || notignorable) {
|
||||||
SIGNAL_SETON(&proc->threads[i]->signals.pending, signal);
|
SIGNAL_SETON(&thread->signals.pending, signal);
|
||||||
if (notignored || notignorable) {
|
if (notignored || notignorable) {
|
||||||
int reason = SCHED_WAKEUP_REASON_INTERRUPTED;
|
int reason = SCHED_WAKEUP_REASON_INTERRUPTED;
|
||||||
if (proc->threads[i]->signals.stopped && (signal == SIGCONT || signal == SIGKILL)) {
|
if (thread->signals.stopped && (signal == SIGCONT || signal == SIGKILL)) {
|
||||||
// thread is stopped and we have to wake it up
|
// thread is stopped and we have to wake it up
|
||||||
proc->threads[i]->signals.stopped = false;
|
thread->signals.stopped = false;
|
||||||
reason = 0; // wake it up from the non interruptible sleep
|
reason = 0; // wake it up from the non interruptible sleep
|
||||||
threadcontinued = true;
|
threadcontinued = true;
|
||||||
} else if (signal == SIGCONT) {
|
} else if (signal == SIGCONT) {
|
||||||
// thread is not stopped, ignore SIGCONT
|
// thread is not stopped, ignore SIGCONT
|
||||||
SIGNAL_SETOFF(&proc->threads[i]->signals.pending, signal);
|
SIGNAL_SETOFF(&thread->signals.pending, signal);
|
||||||
goto threadleave;
|
goto threadleave;
|
||||||
}
|
}
|
||||||
|
|
||||||
sched_wakeup(proc->threads[i], reason);
|
sched_wakeup(thread, reason);
|
||||||
// TODO ipi if running isn't self
|
// TODO ipi if running isn't self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,19 +203,23 @@ void signal_signalproc(struct proc_t *proc, int signal) {
|
|||||||
// XXX possible race condition where a thread will change the process mask or the action of stopping signals
|
// XXX possible race condition where a thread will change the process mask or the action of stopping signals
|
||||||
// after it was sent to everyone
|
// after it was sent to everyone
|
||||||
if ((shouldstop || signal == SIGCONT) == false) {
|
if ((shouldstop || signal == SIGCONT) == false) {
|
||||||
THREAD_LEAVE(proc->threads[i]);
|
THREAD_LEAVE(thread);
|
||||||
PROCESS_LEAVE(proc);
|
PROCESS_LEAVE(proc);
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
spinlock_release(&proc->threadlistlock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
threadleave:
|
threadleave:
|
||||||
THREAD_LEAVE(proc->threads[i]);
|
THREAD_LEAVE(thread);
|
||||||
|
thread = thread->procnext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spinlock_release(&proc->threadlistlock);
|
||||||
|
|
||||||
// tell the parent that a child stopped
|
// tell the parent that a child stopped
|
||||||
// TODO when stopping make sure that a thread was actually stopped
|
// TODO when stopping make sure that a thread was actually stopped
|
||||||
|
// TODO protect parent with a spinlock
|
||||||
if ((notignorable || notignored) && signal_defaultactions[signal] == ACTION_STOP) {
|
if ((notignorable || notignored) && signal_defaultactions[signal] == ACTION_STOP) {
|
||||||
proc->status = 0x7f;
|
proc->status = 0x7f;
|
||||||
proc->status |= signal << 8;
|
proc->status |= signal << 8;
|
||||||
@@ -229,14 +235,14 @@ void signal_signalproc(struct proc_t *proc, int signal) {
|
|||||||
if (threadcontinued) {
|
if (threadcontinued) {
|
||||||
proc->status = 0xffff;
|
proc->status = 0xffff;
|
||||||
proc->signals.continueunwaited = true;
|
proc->signals.continueunwaited = true;
|
||||||
|
|
||||||
if (proc->parent && (proc->parent->signals.actions[SIGCHLD].flags & SA_NOCLDSTOP) == 0) {
|
if (proc->parent && (proc->parent->signals.actions[SIGCHLD].flags & SA_NOCLDSTOP) == 0) {
|
||||||
signal_signalproc(proc->parent, SIGCHLD);
|
signal_signalproc(proc->parent, SIGCHLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_signal(&proc->parent->waitsem);
|
semaphore_signal(&proc->parent->waitsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
|
||||||
|
|
||||||
// if its ignorable and there wasn't any thread with it unmasked, set it as pending for the whole process
|
// if its ignorable and there wasn't any thread with it unmasked, set it as pending for the whole process
|
||||||
// not ignorable signals will be sent to all threads individually
|
// not ignorable signals will be sent to all threads individually
|
||||||
if (notignorable == false && (threadcontinued || shouldstop) == false) {
|
if (notignorable == false && (threadcontinued || shouldstop) == false) {
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ syscallret_t syscall_fork(context_t *ctx) {
|
|||||||
nproc->umask = _cpu()->thread->proc->umask;
|
nproc->umask = _cpu()->thread->proc->umask;
|
||||||
nproc->root = sched_getroot();
|
nproc->root = sched_getroot();
|
||||||
nproc->cwd = sched_getcwd();
|
nproc->cwd = sched_getcwd();
|
||||||
nproc->threads[0] = nthread;
|
nproc->threadlist = nthread;
|
||||||
|
nthread->procnext = NULL;
|
||||||
|
|
||||||
ARCH_CONTEXT_THREADSAVE(nthread, ctx);
|
ARCH_CONTEXT_THREADSAVE(nthread, ctx);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ syscallret_t syscall_newthread(context_t *, void *entry, void *stack) {
|
|||||||
.ret = -1
|
.ret = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO perhaps clean up threads here as well
|
||||||
// if the kernel was specified to have no user threading in the cmdline
|
// if the kernel was specified to have no user threading in the cmdline
|
||||||
if (cmdline_get("nomultithread")) {
|
if (cmdline_get("nomultithread")) {
|
||||||
ret.errno = ENOSYS;
|
ret.errno = ENOSYS;
|
||||||
@@ -16,53 +17,37 @@ syscallret_t syscall_newthread(context_t *, void *entry, void *stack) {
|
|||||||
|
|
||||||
proc_t *proc = _cpu()->thread->proc;
|
proc_t *proc = _cpu()->thread->proc;
|
||||||
|
|
||||||
MUTEX_ACQUIRE(&proc->mutex, false);
|
thread_t *thread = sched_newthread(entry, 16 * PAGE_SIZE, 1, _cpu()->thread->proc, stack);
|
||||||
|
if (thread == NULL) {
|
||||||
|
ret.errno = ENOMEM;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// if we currently don't want any more threads to start
|
thread->vmmctx = _cpu()->thread->vmmctx;
|
||||||
if (proc->nomorethreads == true) {
|
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
bool intstatus = interrupt_set(false);
|
||||||
|
spinlock_acquire(&proc->threadlistlock);
|
||||||
|
|
||||||
|
bool shouldntstart = proc->nomorethreads;
|
||||||
|
if (shouldntstart == false) {
|
||||||
|
thread->procnext = proc->threadlist;
|
||||||
|
proc->threadlist = thread;
|
||||||
|
__atomic_fetch_add(&proc->runningthreadcount, 1, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&proc->threadlistlock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
if (shouldntstart) {
|
||||||
|
sched_destroythread(thread);
|
||||||
ret.errno = EAGAIN;
|
ret.errno = EAGAIN;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < proc->threadtablesize; ++i) {
|
|
||||||
thread_t *thread = proc->threads[i];
|
|
||||||
if (thread == NULL || (thread->flags & SCHED_THREAD_FLAGS_DEAD) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// reuse the slot in the threads table
|
|
||||||
sched_destroythread(thread);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == proc->threadtablesize) {
|
|
||||||
// resize it
|
|
||||||
void *tmp = realloc(proc->threads, (proc->threadtablesize + 1) * sizeof(thread_t *));
|
|
||||||
if (tmp == NULL) {
|
|
||||||
ret.errno = ENOMEM;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc->threads = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc->threads[i] = sched_newthread(entry, 16 * PAGE_SIZE, 1, _cpu()->thread->proc, stack);
|
|
||||||
if (proc->threads[i] == NULL) {
|
|
||||||
ret.errno = ENOMEM;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc->threads[i]->vmmctx = _cpu()->thread->vmmctx;
|
|
||||||
|
|
||||||
ret.errno = 0;
|
ret.errno = 0;
|
||||||
ret.ret = proc->threads[i]->tid;
|
ret.ret = thread->tid;
|
||||||
|
|
||||||
__atomic_fetch_add(&proc->runningthreadcount, 1, __ATOMIC_SEQ_CST);
|
if (shouldntstart == false)
|
||||||
|
sched_queue(thread);
|
||||||
sched_queue(proc->threads[i]);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,16 +102,26 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt
|
|||||||
|
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
MUTEX_RELEASE(&proc->mutex);
|
||||||
|
|
||||||
for (int i = 0; i < iterator->threadtablesize && zombie; ++i) {
|
if (zombie) {
|
||||||
if (iterator->threads[i] == NULL)
|
bool intstatus = interrupt_set(false);
|
||||||
continue;
|
spinlock_acquire(&iterator->threadlistlock);
|
||||||
|
|
||||||
volatile int *flags = (volatile int *)(&iterator->threads[i]->flags);
|
thread_t *threadlist = iterator->threadlist;
|
||||||
// wait until the thread can actually be unallocated
|
iterator->threadlist = NULL;
|
||||||
while ((*flags & SCHED_THREAD_FLAGS_DEAD) == 0)
|
|
||||||
sched_yield();
|
|
||||||
|
|
||||||
sched_destroythread(iterator->threads[i]);
|
spinlock_release(&iterator->threadlistlock);
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
|
||||||
|
while (threadlist) {
|
||||||
|
thread_t *freethread = threadlist;
|
||||||
|
threadlist = threadlist->procnext;
|
||||||
|
volatile int *flags = (volatile int *)(&freethread->flags);
|
||||||
|
// wait until the thread can actually be unallocated
|
||||||
|
while ((*flags & SCHED_THREAD_FLAGS_DEAD) == 0)
|
||||||
|
sched_yield();
|
||||||
|
|
||||||
|
sched_destroythread(freethread);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.ret = iterator->pid;
|
ret.ret = iterator->pid;
|
||||||
|
|||||||
Reference in New Issue
Block a user