From 4204087bd18680c056cf0279feacda8ef8f14de2 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 16 Feb 2024 00:40:48 +0100 Subject: [PATCH] Implement thread_join And use it for tinyc implementation --- core/process.c | 36 ++++++++++++++++++++++++++++++++++++ core/process.h | 1 + core/syscall.c | 13 +++++++++++-- core/syscall.h | 1 + core/thread.c | 17 +++++++++++++++-- core/thread.h | 2 ++ userspace/kernel/syscall.h | 1 + userspace/libc.c | 6 ++++++ userspace/main_user.c | 8 ++++++-- userspace/thread.h | 2 ++ userspace/tiny.c | 3 ++- userspace/tiny.h | 2 +- 12 files changed, 84 insertions(+), 8 deletions(-) diff --git a/core/process.c b/core/process.c index d76a040..cff0b38 100644 --- a/core/process.c +++ b/core/process.c @@ -191,3 +191,39 @@ pid_t processGetId(struct process *proc){ pid_t processGetNextTid(struct process *proc){ return proc->nextTid++; } + +//Should be called with IRQ disabled +struct thread *processGetThread(struct process *proc, pid_t tid) +{ + int count; + struct thread *th; + struct thread *thFound = NULL; + + list_foreach_named(proc->thList, th, count, prevInProcess, nextInProcess) + { + if (th->tid == tid) { + thFound = th; + break; + } + } + return thFound; +} + +int processJoinThread(struct process *proc, pid_t tid) +{ + uint32_t flags; + struct thread *th; + int ret = -1; + + disable_IRQs(flags); + + th = processGetThread(proc, tid); + if (th && th->wqExit) { + wait(th->wqExit); + ret = 0; + } + + restore_IRQs(flags); + + return ret; +} diff --git a/core/process.h b/core/process.h index a28895f..2aba9ef 100644 --- a/core/process.h +++ b/core/process.h @@ -22,3 +22,4 @@ struct uAddrSpace *processGetAddrSpace(struct process *proc); int processInitHeap(struct process *proc, uaddr_t lastUserAddr); pid_t processGetId(struct process *proc); pid_t processGetNextTid(struct process *proc); +int processJoinThread(struct process *proc, pid_t tid); diff --git a/core/syscall.c b/core/syscall.c index 283841a..c1e2dc3 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -172,11 +172,20 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) break; } case SYSCALL_ID_GETPID: { - ret = processGetId(getCurrentThread()->process); + ret = processGetId(getCurrentThread()->process); break; } case SYSCALL_ID_GETTID: { - ret = threadGetId(getCurrentThread()); + ret = threadGetId(getCurrentThread()); + break; + } + case SYSCALL_ID_THREAD_JOIN: { + thread_id_t tid; + + ret = syscallGet1arg(userCtx, (unsigned int *)&tid); + if (ret) + break; + ret = processJoinThread(getCurrentThread()->process, tid); break; } default: diff --git a/core/syscall.h b/core/syscall.h index ca46a20..40e82df 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -15,6 +15,7 @@ #define SYSCALL_ID_USLEEP 10 #define SYSCALL_ID_GETPID 11 #define SYSCALL_ID_GETTID 12 +#define SYSCALL_ID_THREAD_JOIN 13 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/thread.c b/core/thread.c index 206bef8..b83752e 100644 --- a/core/thread.c +++ b/core/thread.c @@ -89,8 +89,9 @@ struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, v (cpu_kstate_function_arg1_t *)threadExit, 0)) goto free_mem; - thread->state = READY; - thread->tid = nextTid++; + thread->state = READY; + thread->tid = nextTid++; + thread->wqExit = NULL; uint32_t flags; disable_IRQs(flags); list_add_tail(currentThread, thread); @@ -117,6 +118,14 @@ struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t } thread->stackSize = THREAD_DEFAULT_STACK_SIZE; + thread->wqExit = (struct wait_queue * )malloc(sizeof(struct wait_queue)); + if (!thread->wqExit) { + free((void *)thread->stackAddr); + free(thread); + return NULL; + } + waitQueueInit(thread->wqExit); + if (name) strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH); else @@ -151,6 +160,10 @@ void threadDelete(struct thread *thread) restore_IRQs(flags); assert(thread->state == EXITING); + if (thread->wqExit) { + waitUp(thread->wqExit); + } + if (thread->squattedContext) { threadChangeCurrentContext(NULL); } diff --git a/core/thread.h b/core/thread.h index 84a44dd..5941ed9 100644 --- a/core/thread.h +++ b/core/thread.h @@ -4,6 +4,7 @@ struct thread; #include "cpu_context.h" #include "mem.h" #include "process.h" +#include "wait.h" #define THREAD_NAME_MAX_LENGTH 32 #define THREAD_DEFAULT_STACK_SIZE PAGE_SIZE @@ -35,6 +36,7 @@ struct thread { // For User thread only struct thread *nextInProcess, *prevInProcess; struct process *process; + struct wait_queue *wqExit; // This will be signaled at thread exit (user only) /** * Address space currently "squatted" by the thread, or used to be diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index ca46a20..40e82df 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -15,6 +15,7 @@ #define SYSCALL_ID_USLEEP 10 #define SYSCALL_ID_GETPID 11 #define SYSCALL_ID_GETTID 12 +#define SYSCALL_ID_THREAD_JOIN 13 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index ba0c7b7..1050639 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -807,6 +807,12 @@ int thread_create(pthread_t *thread, start_routine *func, void *arg, size_t stac (unsigned int)arg, stackSize); } +int thread_join(pthread_t thread, void **retval){ + (void)retval; + return syscall1(SYSCALL_ID_THREAD_JOIN, (unsigned int)thread); +} + + int usleep(useconds_t usec) { return syscall1(SYSCALL_ID_USLEEP, (unsigned int)usec); } diff --git a/userspace/main_user.c b/userspace/main_user.c index 3c5382b..c48db8c 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -124,14 +124,15 @@ int func_munmap() static void *print_hello(void *arg) { (void)arg; printf("Hello World from thread %lu\n", gettid()); - usleep(100); return NULL; } int func_thread() { pthread_t id; + void *retval; thread_create(&id, print_hello, NULL, 4096); + thread_join(id, &retval); return 0; } @@ -163,7 +164,10 @@ int main(int argc, char *argv[]) { continue; } if (strcmp(buf, "tiny") == 0) { - func_tiny(); + pthread_t id; + void *retval; + thread_create(&id, func_tiny, NULL, 4096); + thread_join(id, &retval); continue; } if (strcmp(buf, "mmap") == 0) { diff --git a/userspace/thread.h b/userspace/thread.h index a3a78f6..786452c 100644 --- a/userspace/thread.h +++ b/userspace/thread.h @@ -4,3 +4,5 @@ typedef unsigned long int pthread_t; typedef void *(start_routine)(void *); int thread_create(pthread_t *thread, start_routine *func, void *arg, size_t stackSize); +/* retval is ignored ATM */ +int thread_join(pthread_t thread, void **retval); diff --git a/userspace/tiny.c b/userspace/tiny.c index 196d242..0b478b2 100644 --- a/userspace/tiny.c +++ b/userspace/tiny.c @@ -282,8 +282,9 @@ void run() /* Main program. */ -int func_tiny() +void * func_tiny(void *args) { + (void)args; printf("Enter your program then ESC\n\n"); printf("TinyC grammar\n"); printf(" ::= \n"); diff --git a/userspace/tiny.h b/userspace/tiny.h index 435c1e9..78f9747 100644 --- a/userspace/tiny.h +++ b/userspace/tiny.h @@ -1,4 +1,4 @@ #pragma once -int func_tiny(); +void * func_tiny(void *args);