From 1c2cd75c72a7db4df527b5f928c08686856bd20b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 13 Feb 2024 00:19:39 +0100 Subject: [PATCH 01/12] Add new thread sys call --- core/syscall.c | 42 +++++++++++++++++++++++++++++++++++--- core/syscall.h | 1 + userspace/kernel/syscall.h | 1 + userspace/libc.c | 20 ++++++++++++++++++ userspace/libc.h | 3 +++ userspace/main_user.c | 21 +++++++++++++++++-- 6 files changed, 83 insertions(+), 5 deletions(-) diff --git a/core/syscall.c b/core/syscall.c index a760424..288d5a7 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -1,6 +1,8 @@ #include "syscall.h" +#include "kernel.h" #include "keyboard.h" #include "klibc.h" +#include "paging.h" #include "process.h" #include "stdarg.h" #include "thread.h" @@ -43,17 +45,17 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) printf("Got 5args from userspace %d %d %d %d %d\n", arg1, arg2, arg3, arg4, arg5); break; } - case SYSCALL_ID_BRK:{ + case SYSCALL_ID_BRK: { struct uAddrSpace *as; uaddr_t newHeapTop; - as = processGetAddrSpace(getCurrentThread()->process); + as = processGetAddrSpace(getCurrentThread()->process); ret = syscallGet1arg(userCtx, (unsigned int *)&newHeapTop); if (ret != 0) break; threadChangeCurrentContext(uAddrSpaceGetMMUContext(as)); - //TODO : what if *newHeapTop raise page fault? + // TODO : what if *newHeapTop raise page fault? ret = sysBrk(as, newHeapTop); threadChangeCurrentContext(NULL); break; @@ -110,6 +112,40 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) ret = uAddrSpaceUnmap(as, uaddr, size); break; } + case SYSCALL_ID_NEW_THREAD: { + struct uAddrSpace *as; + uaddr_t funcAddr; + uint32_t arg1, arg2; + size_t stackSize; + + ret = syscallGet4args(userCtx, (unsigned int *)&funcAddr, (unsigned int *)&arg1, + (unsigned int *)&arg2, (unsigned int *)&stackSize); + if (ret) + break; + if (stackSize <= 0) { + ret = -EINVAL; + break; + } + + as = processGetAddrSpace(getCurrentThread()->process); + stackSize = ALIGN(stackSize, PAGE_SIZE); + + uaddr_t stackAddr = 0; + ret = zeroMmap(as, &stackAddr, stackSize, PAGING_MEM_READ | PAGING_MEM_WRITE, 0); + + if (ret) + break; + + struct thread *th = threadCreateUser(NULL, getCurrentThread()->process, funcAddr, + arg1, arg2, stackAddr + stackSize); + + if (th == NULL) { + ret = -ENOMEM; + uAddrSpaceUnmap(as, stackAddr, stackSize); + } + + break; + } default: printf("Unknon syscall id %d\n", syscallId); ret = -ENOENT; diff --git a/core/syscall.h b/core/syscall.h index 444789b..72ccf9e 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -11,6 +11,7 @@ #define SYSCALL_ID_BRK 6 #define SYSCALL_ID_MMAP 7 #define SYSCALL_ID_MUNMAP 8 +#define SYSCALL_ID_NEW_THREAD 9 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index 444789b..72ccf9e 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -11,6 +11,7 @@ #define SYSCALL_ID_BRK 6 #define SYSCALL_ID_MMAP 7 #define SYSCALL_ID_MUNMAP 8 +#define SYSCALL_ID_NEW_THREAD 9 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index eec4ccc..ff91b25 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -745,3 +745,23 @@ int munmap(void *addr, size_t len) return syscall2(SYSCALL_ID_MUNMAP, (unsigned int)addr, len); } + +/* As when a new thread is run, the params are passed by register (See cpu_ustate_init), use + * this function to simplify new thread usage*/ +static void thread_runner() +{ + register unsigned long int reg_arg1 asm("%eax"); + register unsigned long int reg_arg2 asm("%ebx"); + + start_routine *func = (start_routine *)reg_arg1; + void *arg = (void *)reg_arg2; + + func(arg); + _exit(0); +} + +int new_thread(start_routine *func, void *arg, size_t stackSize) +{ + return syscall4(SYSCALL_ID_NEW_THREAD, (unsigned int)thread_runner, (unsigned int)func, + (unsigned int)arg, stackSize); +} diff --git a/userspace/libc.h b/userspace/libc.h index 378d023..12bcf9d 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -63,3 +63,6 @@ void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void free(void *ptr); + +typedef void *(start_routine)(void *); +int new_thread(start_routine *func, void *arg, size_t stackSize); diff --git a/userspace/main_user.c b/userspace/main_user.c index 65ce7c7..7354fdc 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -15,6 +15,7 @@ int func_help() printf(" tiny: a tiny C-like interpreter\n"); printf(" mmap: test mmap \n"); printf(" munmap: test munmap \n"); + printf(" thread: run a user thread\n"); return 0; } @@ -118,8 +119,20 @@ int func_munmap() return ret; } -int main(int argc, char *argv[]) -{ +static void *print_hello(void *arg) { + (void)arg; + printf("Hello World from thread\n"); + + return NULL; +} + +int func_thread() { + new_thread(print_hello, NULL, 4096); + + return 0; +} + +int main(int argc, char *argv[]) { (void)argc; (void)argv; char buf[64]; @@ -156,6 +169,10 @@ int main(int argc, char *argv[]) func_munmap(); continue; } + if (strcmp(buf, "thread") == 0) { + func_thread(); + continue; + } } return 0; } From f9ce88e7a313b53d9f384b1af520c2f89386bc70 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 14 Feb 2024 18:28:11 +0100 Subject: [PATCH 02/12] Makefile: use no intermediate file To speedup, a bit, the compilation, use -pipe option for gcc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 997769c..862e37d 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CPPFLAGS = -MMD AS=nasm ASFLAGS += -f elf32 LDFLAGS += -m elf_i386 -CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize -D__KERNEL__ +CFLAGS += -m32 -pipe -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize -D__KERNEL__ #keep .i and .s #CFLAGS += -save-temps #CFLAGS += -fanalyzer -Wno-analyzer-malloc-leak -Wno-analyzer-out-of-bounds From 90436a4f46dec5ce3cc341e981b9aaf9f4e79605 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 14 Feb 2024 18:43:47 +0100 Subject: [PATCH 03/12] Add usleep syscall --- core/syscall.c | 12 +++++++++++- core/syscall.h | 1 + core/thread.c | 11 ++++++++--- core/thread.h | 1 + userspace/kernel/syscall.h | 1 + userspace/libc.c | 5 +++++ userspace/main_user.c | 2 ++ userspace/unistd.h | 4 ++++ 8 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 userspace/unistd.h diff --git a/core/syscall.c b/core/syscall.c index 288d5a7..5a5151f 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -11,7 +11,6 @@ #include "uaddrspace.h" #include "zero.h" - int syscallExecute(int syscallId, const struct cpu_state *userCtx) { @@ -146,6 +145,17 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) break; } + case SYSCALL_ID_USLEEP: { + unsigned int sleep; + + ret = syscallGet1arg(userCtx, &sleep); + if (ret) + break; + + ret = threadUsleep(sleep); + + break; + } default: printf("Unknon syscall id %d\n", syscallId); ret = -ENOENT; diff --git a/core/syscall.h b/core/syscall.h index 72ccf9e..53cfa05 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -12,6 +12,7 @@ #define SYSCALL_ID_MMAP 7 #define SYSCALL_ID_MUNMAP 8 #define SYSCALL_ID_NEW_THREAD 9 +#define SYSCALL_ID_USLEEP 10 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/thread.c b/core/thread.c index ae0f293..cbb55af 100644 --- a/core/thread.c +++ b/core/thread.c @@ -292,6 +292,11 @@ int threadYield() } int threadMsleep(unsigned long msec) +{ + return threadUsleep(msec*1000); +} + +int threadUsleep(unsigned long usec) { uint32_t flags; struct thread *next, *current; @@ -299,12 +304,12 @@ int threadMsleep(unsigned long msec) disable_IRQs(flags); current = currentThread; - assertmsg(current->state == RUNNING, "thread %s is in state %d for %lu\n", current->name, - current->state, msec); + assertmsg(current->state == RUNNING, "thread %s is in state %d for %lu us\n", current->name, + current->state, usec); current->state = SLEEPING; current->sleepHaveTimeouted = 0; - current->jiffiesSleeping = msecs_to_jiffies(msec); + current->jiffiesSleeping = usecs_to_jiffies(usec); next = threadSelectNext(); assert(next != current); diff --git a/core/thread.h b/core/thread.h index 0997676..6da8cd7 100644 --- a/core/thread.h +++ b/core/thread.h @@ -83,6 +83,7 @@ int threadYield(); int threadWait(struct thread *current, struct thread *next, unsigned long msec); int threadUnsched(struct thread *th); int threadMsleep(unsigned long msec); +int threadUsleep(unsigned long usec); int threadOnJieffiesTick(); struct thread *getCurrentThread(); int threadAddThread(struct thread *th); diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index 72ccf9e..53cfa05 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -12,6 +12,7 @@ #define SYSCALL_ID_MMAP 7 #define SYSCALL_ID_MUNMAP 8 #define SYSCALL_ID_NEW_THREAD 9 +#define SYSCALL_ID_USLEEP 10 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index ff91b25..fa793c2 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -5,6 +5,7 @@ #include "swintr.h" #include "sys/mman.h" #include "syscall.h" +#include "unistd.h" int errno = 0; int memcmp(const void *aptr, const void *bptr, size_t size) @@ -765,3 +766,7 @@ int new_thread(start_routine *func, void *arg, size_t stackSize) return syscall4(SYSCALL_ID_NEW_THREAD, (unsigned int)thread_runner, (unsigned int)func, (unsigned int)arg, stackSize); } + +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 7354fdc..88128fd 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -4,6 +4,7 @@ #include "stddef.h" #include "sys/mman.h" #include "tiny.h" +#include "unistd.h" int func_help() { @@ -122,6 +123,7 @@ int func_munmap() static void *print_hello(void *arg) { (void)arg; printf("Hello World from thread\n"); + usleep(100); return NULL; } diff --git a/userspace/unistd.h b/userspace/unistd.h new file mode 100644 index 0000000..7d7da70 --- /dev/null +++ b/userspace/unistd.h @@ -0,0 +1,4 @@ +#pragma once + +typedef unsigned int useconds_t; +int usleep(useconds_t usec); From 0688afa76d144d79270ebd7c00babc00008ba269 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 14 Feb 2024 23:20:46 +0100 Subject: [PATCH 04/12] fix gettid==getpid for 1 thread --- core/process.c | 12 +++++++++++- core/process.h | 2 ++ core/syscall.c | 25 ++++++++++++++++++++++++- core/syscall.h | 2 ++ core/thread.c | 8 ++++++++ core/thread.h | 4 ++++ userspace/kernel/syscall.h | 2 ++ userspace/libc.c | 14 +++++++++++--- userspace/libc.h | 5 +++-- userspace/main_user.c | 7 +++++-- userspace/thread.h | 6 ++++++ userspace/unistd.h | 2 ++ 12 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 userspace/thread.h diff --git a/core/process.c b/core/process.c index 6d5b0a3..7024366 100644 --- a/core/process.c +++ b/core/process.c @@ -11,6 +11,7 @@ struct process { char name[PROCESS_NAME_MAX_LENGTH]; int ref; int pid; + int nextTid; struct uAddrSpace *addrSpace; struct thread *thList; @@ -47,7 +48,8 @@ struct process *processCreate(char *name) new->ref = 1; disable_IRQs(flags); - new->pid = nextPid++; + new->pid = nextPid++; + new->nextTid = new->pid; list_add_tail(processList, new); restore_IRQs(flags); @@ -180,3 +182,11 @@ struct uAddrSpace *processGetAddrSpace(struct process *proc){ int processInitHeap(struct process *proc, uaddr_t lastUserAddr){ return uAddrSpaceSetHeap(proc->addrSpace, lastUserAddr, 0); } + +int processGetId(struct process *proc){ + return proc->pid; +} + +int processGetNextTid(struct process *proc){ + return proc->nextTid++; +} diff --git a/core/process.h b/core/process.h index f5935f7..172aeb4 100644 --- a/core/process.h +++ b/core/process.h @@ -18,3 +18,5 @@ int processRemoveThread(struct thread *th); struct mmu_context *processGetMMUContext(struct process *th); struct uAddrSpace *processGetAddrSpace(struct process *proc); int processInitHeap(struct process *proc, uaddr_t lastUserAddr); +int processGetId(struct process *proc); +int processGetNextTid(struct process *proc); diff --git a/core/syscall.c b/core/syscall.c index 5a5151f..283841a 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -113,11 +113,14 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) } case SYSCALL_ID_NEW_THREAD: { struct uAddrSpace *as; + thread_id_t threadIdPtr; + thread_id_t threadId; uaddr_t funcAddr; uint32_t arg1, arg2; size_t stackSize; - ret = syscallGet4args(userCtx, (unsigned int *)&funcAddr, (unsigned int *)&arg1, + ret = syscallGet5args(userCtx, (unsigned int *)&threadIdPtr, + (unsigned int *)&funcAddr, (unsigned int *)&arg1, (unsigned int *)&arg2, (unsigned int *)&stackSize); if (ret) break; @@ -125,6 +128,11 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) ret = -EINVAL; break; } + if (memcpyFromUser((vaddr_t)&threadId, threadIdPtr, sizeof(threadId)) != + sizeof(threadId)) { + ret = -EFAULT; + break; + } as = processGetAddrSpace(getCurrentThread()->process); stackSize = ALIGN(stackSize, PAGE_SIZE); @@ -142,6 +150,13 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) ret = -ENOMEM; uAddrSpaceUnmap(as, stackAddr, stackSize); } + threadId = threadGetId(th); + + if (memcpyToUser(threadIdPtr, (vaddr_t)&threadId, sizeof(threadId)) != + sizeof(threadId)) { + ret = -EFAULT; + break; + } break; } @@ -156,6 +171,14 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) break; } + case SYSCALL_ID_GETPID: { + ret = processGetId(getCurrentThread()->process); + break; + } + case SYSCALL_ID_GETTID: { + ret = threadGetId(getCurrentThread()); + break; + } default: printf("Unknon syscall id %d\n", syscallId); ret = -ENOENT; diff --git a/core/syscall.h b/core/syscall.h index 53cfa05..ca46a20 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -13,6 +13,8 @@ #define SYSCALL_ID_MUNMAP 8 #define SYSCALL_ID_NEW_THREAD 9 #define SYSCALL_ID_USLEEP 10 +#define SYSCALL_ID_GETPID 11 +#define SYSCALL_ID_GETTID 12 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/thread.c b/core/thread.c index cbb55af..d450392 100644 --- a/core/thread.c +++ b/core/thread.c @@ -12,6 +12,12 @@ static struct thread *currentThread; static struct thread *threadWithTimeout; +static thread_id_t nextTid; // This is the TID for kernel thread ONLY + +thread_id_t threadGetId(struct thread *th) +{ + return th->tid; +} static void threadPrepareContext(struct thread *th); @@ -84,6 +90,7 @@ struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, v goto free_mem; thread->state = READY; + thread->tid = nextTid++; uint32_t flags; disable_IRQs(flags); list_add_tail(currentThread, thread); @@ -124,6 +131,7 @@ struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t goto free_mem; thread->state = READY; + thread->tid = processGetNextTid(proc); uint32_t flags; disable_IRQs(flags); list_add_tail(currentThread, thread); diff --git a/core/thread.h b/core/thread.h index 6da8cd7..84a44dd 100644 --- a/core/thread.h +++ b/core/thread.h @@ -17,8 +17,11 @@ typedef enum { EXITING } thread_state; +typedef unsigned long int thread_id_t; + struct thread { char name[THREAD_NAME_MAX_LENGTH]; + thread_id_t tid; struct cpu_state *cpuState; thread_state state; vaddr_t stackAddr; @@ -89,3 +92,4 @@ struct thread *getCurrentThread(); int threadAddThread(struct thread *th); int threadChangeCurrentContext(struct mmu_context *ctx); int threadCount(); +thread_id_t threadGetId(struct thread *th); diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index 53cfa05..ca46a20 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -13,6 +13,8 @@ #define SYSCALL_ID_MUNMAP 8 #define SYSCALL_ID_NEW_THREAD 9 #define SYSCALL_ID_USLEEP 10 +#define SYSCALL_ID_GETPID 11 +#define SYSCALL_ID_GETTID 12 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index fa793c2..7d5f071 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -5,6 +5,7 @@ #include "swintr.h" #include "sys/mman.h" #include "syscall.h" +#include "thread.h" #include "unistd.h" int errno = 0; @@ -761,12 +762,19 @@ static void thread_runner() _exit(0); } -int new_thread(start_routine *func, void *arg, size_t stackSize) -{ - return syscall4(SYSCALL_ID_NEW_THREAD, (unsigned int)thread_runner, (unsigned int)func, +int thread_create(pthread_t *thread, start_routine *func, void *arg, size_t stackSize) { + return syscall5(SYSCALL_ID_NEW_THREAD, (unsigned int)thread, (unsigned int)thread_runner, (unsigned int)func, (unsigned int)arg, stackSize); } int usleep(useconds_t usec) { return syscall1(SYSCALL_ID_USLEEP, (unsigned int)usec); } + +pid_t gettid(void) { + return syscall0(SYSCALL_ID_GETTID); +} + +pid_t getpid(void) { + return syscall0(SYSCALL_ID_GETPID); +} diff --git a/userspace/libc.h b/userspace/libc.h index 12bcf9d..9a12ba2 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -4,6 +4,7 @@ #include "stdint.h" #include "stddef.h" #include "minmax.h" +#include "unistd.h" #define islower(c) (('a' <= (c)) && ((c) <= 'z')) #define isupper(c) (('A' <= (c)) && ((c) <= 'Z')) @@ -63,6 +64,6 @@ void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void free(void *ptr); +pid_t gettid(void); +pid_t getpid(void); -typedef void *(start_routine)(void *); -int new_thread(start_routine *func, void *arg, size_t stackSize); diff --git a/userspace/main_user.c b/userspace/main_user.c index 88128fd..92dc49b 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -3,6 +3,7 @@ #include "stdarg.h" #include "stddef.h" #include "sys/mman.h" +#include "thread.h" #include "tiny.h" #include "unistd.h" @@ -122,14 +123,15 @@ int func_munmap() static void *print_hello(void *arg) { (void)arg; - printf("Hello World from thread\n"); + printf("Hello World from thread %d\n", gettid()); usleep(100); return NULL; } int func_thread() { - new_thread(print_hello, NULL, 4096); + pthread_t id; + thread_create(&id, print_hello, NULL, 4096); return 0; } @@ -138,6 +140,7 @@ int main(int argc, char *argv[]) { (void)argc; (void)argv; char buf[64]; + assert(getpid() == gettid()); printf("Shell starting... type \"help\" for help\n"); while (1) { printf(">"); diff --git a/userspace/thread.h b/userspace/thread.h new file mode 100644 index 0000000..a3a78f6 --- /dev/null +++ b/userspace/thread.h @@ -0,0 +1,6 @@ +#pragma once +#include + +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); diff --git a/userspace/unistd.h b/userspace/unistd.h index 7d7da70..e9675d3 100644 --- a/userspace/unistd.h +++ b/userspace/unistd.h @@ -2,3 +2,5 @@ typedef unsigned int useconds_t; int usleep(useconds_t usec); + +typedef int pid_t; From a38a674a5356d637e618b637e3515d5f9e2655e1 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 14 Feb 2024 23:20:46 +0100 Subject: [PATCH 05/12] userspace: fix printf for unsigned --- userspace/libc.c | 120 +++++++++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 40 deletions(-) diff --git a/userspace/libc.c b/userspace/libc.c index 7d5f071..ba0c7b7 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -265,8 +265,57 @@ int puts(const char *str) return ret; \ } +#define PRINT_UINT(name, type) \ + int print##name(type integer, char *str, size_t size) \ + { \ + char num[sizeof(integer) * 3]; \ + int i = 0; \ + int c = 0; \ + int ret = 0; \ + \ + do { \ + int digit = integer % 10; \ + num[i++] = (digit > 0) ? digit : -digit; \ + integer = integer / 10; \ + } while (integer != 0); \ + \ + for (i = i - 1; i >= 0; i--) { \ + if (str) { \ + if (size) { \ + str[c++] = num[i] + '0'; \ + size--; \ + ret++; \ + } else { \ + return ret; \ + } \ + } else { \ + ret++; \ + } \ + } \ + return ret; \ + } + PRINT_INT(Int, int); -PRINT_INT(Int64, long long int); +PRINT_INT(Lint, long int); +PRINT_INT(Llint, long long int); +PRINT_UINT(Uint, unsigned int); +PRINT_UINT(Luint, long unsigned int); +PRINT_UINT(Lluint, long long unsigned int); + +#define PRINT_PART(func, type, str, size, c, ret) \ + { \ + int s; \ + type d = va_arg(ap, type); \ + if (str) \ + s = func(d, &str[c], size); \ + else \ + s = func(d, NULL, size); \ + \ + size -= s; \ + c += s; \ + ret += s; \ + break; \ + } int vsnprintf(char *str, size_t size, const char *format, va_list ap) { @@ -274,24 +323,13 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap) int i = 0; int c = 0; - while (format[i] != '\0' && (size || !str)) { + while (format[i] != '\0' && (size|| !str)) { switch (format[i]) { case '%': switch (format[i + 1]) { case 'i': - case 'd': { - int s; - int d = va_arg(ap, int); - if (str) - s = printInt(d, &str[c], size); - else - s = printInt(d, NULL, size); - - size -= s; - c += s; - ret += s; - break; - } + case 'd': PRINT_PART(printInt, int, str, size, c, ret) + case 'u': PRINT_PART(printUint, uint, str, size, c, ret) case 'p': case 'x': { char val[sizeof(int) * 2]; @@ -352,24 +390,15 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap) switch (format[i + 2]) { case 'l': switch (format[i + 3]) { - case 'd': { - int s; - long long int d = va_arg(ap, long long int); - if (str) - s = printInt64(d, &str[c], size); - else - s = printInt64(d, NULL, size); - - size -= s; - c += s; - ret += s; - break; - } + case 'i': + case 'd': PRINT_PART(printLlint, long long int, str, size, c, ret) + case 'u': PRINT_PART(printLluint, long long unsigned int, str, size, c, ret) case 'p': case 'x': { char val[sizeof(long long int) * 2]; unsigned int valIdx = 0; - long long int d = va_arg(ap, long long int); + unsigned long long int d = + va_arg(ap, unsigned long long int); itoa(d, val, 16); if (str) { while (val[valIdx]) { @@ -390,17 +419,28 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap) i++; break; case 'i': - case 'd': { - int s; - long int d = va_arg(ap, long int); - if (str) - s = printInt64(d, &str[c], size); - else - s = printInt64(d, NULL, size); - - size -= s; - c += s; - ret += s; + case 'd': PRINT_PART(printLint, long int, str, size, c, ret) + case 'u': + PRINT_PART(printLuint, long unsigned int, str, size, c, ret) + case 'p': + case 'x': { + char val[sizeof(int) * 2]; + unsigned int valIdx = 0; + unsigned long int d = va_arg(ap, unsigned long int); + itoa(d, val, 16); + if (str) { + while (val[valIdx]) { + if (size) { + str[c++] = val[valIdx++]; + size--; + ret++; + } else { + return ret; + } + } + } else { + ret += strlen(val); + } break; } } From 70366fa7be99ee9477448b94f671728916ea702b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 15 Feb 2024 18:40:45 +0100 Subject: [PATCH 06/12] Set pid_t type --- core/process.c | 11 ++++++----- core/process.h | 8 +++++--- core/thread.c | 2 +- core/uaddrspace.h | 3 ++- drivers/zero.c | 1 + userspace/main_user.c | 2 +- userspace/unistd.h | 2 +- 7 files changed, 17 insertions(+), 12 deletions(-) diff --git a/core/process.c b/core/process.c index 7024366..d76a040 100644 --- a/core/process.c +++ b/core/process.c @@ -5,13 +5,14 @@ #include "list.h" #include "mmuContext.h" #include "types.h" +#include "thread.h" #include "uaddrspace.h" struct process { char name[PROCESS_NAME_MAX_LENGTH]; int ref; - int pid; - int nextTid; + pid_t pid; + pid_t nextTid; struct uAddrSpace *addrSpace; struct thread *thList; @@ -68,7 +69,7 @@ void processListPrint() struct thread *th; int nbTh; - printf("%d %s %d %d\n", proc->pid, proc->name, processCountThread(proc), proc->ref); + printf("%lu %s %d %d\n", proc->pid, proc->name, processCountThread(proc), proc->ref); list_foreach_named(proc->thList, th, nbTh, prevInProcess, nextInProcess) { if (th == cur) { @@ -183,10 +184,10 @@ int processInitHeap(struct process *proc, uaddr_t lastUserAddr){ return uAddrSpaceSetHeap(proc->addrSpace, lastUserAddr, 0); } -int processGetId(struct process *proc){ +pid_t processGetId(struct process *proc){ return proc->pid; } -int processGetNextTid(struct process *proc){ +pid_t processGetNextTid(struct process *proc){ return proc->nextTid++; } diff --git a/core/process.h b/core/process.h index 172aeb4..a28895f 100644 --- a/core/process.h +++ b/core/process.h @@ -1,9 +1,11 @@ #pragma once -#include "thread.h" +#include "types.h" #define PROCESS_NAME_MAX_LENGTH 32 +typedef unsigned long int pid_t; struct process; +struct thread; int processSetup(); struct process *processCreate(char *name); @@ -18,5 +20,5 @@ int processRemoveThread(struct thread *th); struct mmu_context *processGetMMUContext(struct process *th); struct uAddrSpace *processGetAddrSpace(struct process *proc); int processInitHeap(struct process *proc, uaddr_t lastUserAddr); -int processGetId(struct process *proc); -int processGetNextTid(struct process *proc); +pid_t processGetId(struct process *proc); +pid_t processGetNextTid(struct process *proc); diff --git a/core/thread.c b/core/thread.c index d450392..206bef8 100644 --- a/core/thread.c +++ b/core/thread.c @@ -14,7 +14,7 @@ static struct thread *currentThread; static struct thread *threadWithTimeout; static thread_id_t nextTid; // This is the TID for kernel thread ONLY -thread_id_t threadGetId(struct thread *th) +pid_t threadGetId(struct thread *th) { return th->tid; } diff --git a/core/uaddrspace.h b/core/uaddrspace.h index 9cf8cac..1456c4a 100644 --- a/core/uaddrspace.h +++ b/core/uaddrspace.h @@ -1,8 +1,9 @@ #pragma once #include "mmuContext.h" #include "process.h" +#include "stddef.h" +#include "stdint.h" #include "types.h" -#include struct uAddrSpace; struct uAddrVirtualReg; diff --git a/drivers/zero.c b/drivers/zero.c index 4a830f3..b55bec3 100644 --- a/drivers/zero.c +++ b/drivers/zero.c @@ -3,6 +3,7 @@ #include "alloc.h" #include "kernel.h" #include "klibc.h" +#include "mem.h" struct zeroMappedEntry { int refCnt; diff --git a/userspace/main_user.c b/userspace/main_user.c index 92dc49b..3c5382b 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -123,7 +123,7 @@ int func_munmap() static void *print_hello(void *arg) { (void)arg; - printf("Hello World from thread %d\n", gettid()); + printf("Hello World from thread %lu\n", gettid()); usleep(100); return NULL; diff --git a/userspace/unistd.h b/userspace/unistd.h index e9675d3..db3d631 100644 --- a/userspace/unistd.h +++ b/userspace/unistd.h @@ -3,4 +3,4 @@ typedef unsigned int useconds_t; int usleep(useconds_t usec); -typedef int pid_t; +typedef unsigned long int pid_t; From 9713f527a86426e5ac5dbb032333b6255749bd06 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 15 Feb 2024 23:35:51 +0100 Subject: [PATCH 07/12] Change userspace by partition type Userspace should be on the first Linux partition found --- core/main.c | 2 +- drivers/ata.c | 13 +++++++++++++ drivers/ata.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/main.c b/core/main.c index d04addd..c3a188f 100644 --- a/core/main.c +++ b/core/main.c @@ -46,7 +46,7 @@ void idleThread(void *arg) #define FILE_MAX_SIZE 64 // In nb of sectors void loadUserSpace() { - struct ata_partition *part = ATAGetPartition(1); + struct ata_partition *part = ATAGetPartitionByType(PART_TYPE_LINUX); if (part == NULL) { printf("No user partition found\n"); diff --git a/drivers/ata.c b/drivers/ata.c index fbd6aea..82922fa 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -521,6 +521,19 @@ struct ata_partition *ATAGetPartition(int id) return NULL; } +struct ata_partition *ATAGetPartitionByType(uint type) +{ + struct ata_partition *part; + int count; + list_foreach(partitions, part, count) + { + if (part->type == type) + return part; + } + + return NULL; +} + struct ata_partition *ATAPartitionCreate(uint type, uint size, uint32_t lba, struct ata_device *dev) { diff --git a/drivers/ata.h b/drivers/ata.h index b6180e3..304cb5b 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -104,5 +104,6 @@ int ATAReadPartitionSector(struct ata_partition *part, int offset, uint nbSector int ATAReadSector(struct ata_device *dev, int lba, uint nbSector, void *buf); int ATAWriteSector(struct ata_device *dev, int lba, uint nbSector, void *buf); struct ata_device *ATAGetDevice(int ctlId, int devId); +struct ata_partition *ATAGetPartitionByType(uint type); int ATAReadPartition(struct ata_device *dev); struct ata_partition *ATAGetPartition(int id); From 454f0875f5e4ac4c56c214b6ba919480dce9fba3 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 15 Feb 2024 23:41:58 +0100 Subject: [PATCH 08/12] Add isodebug target Allow to take benefit from elf symboles --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 862e37d..1ebe675 100644 --- a/Makefile +++ b/Makefile @@ -88,11 +88,16 @@ test: clean kernel disk.img run:kernel disk.img ## Run the OS on qemu qemu-system-x86_64 -kernel $< -serial stdio $(QEMU_OPT) -debug: CFLAGS += $(DEBUG_FLAGS) ## Run the OS on qemu and attach a debugger to it (may need a clean befor to have the debug symbols) +debug: CFLAGS += $(DEBUG_FLAGS) ## Run the OS on qemu and attach a debugger to it (may need a clean before to have the debug symbols) debug: CXXFLAGS += $(DEBUG_FLAGS) debug:kernel kernel.debug disk.img gdb -q -x debug.gdb +isodebug: CFLAGS += $(DEBUG_FLAGS) ## Same than previous but kernel is loaded by grub. So, for example, we can access the elf debug info +isodebug: CXXFLAGS += $(DEBUG_FLAGS) +isodebug:fd.iso disk.img + gdb -q -x debug.iso.gdb + debug_test: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST debug_test: debug From 4204087bd18680c056cf0279feacda8ef8f14de2 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 16 Feb 2024 00:40:48 +0100 Subject: [PATCH 09/12] 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); From e0c392c16e9023a1b04a724604ff5c8d7cf81c4e Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 16 Feb 2024 00:47:47 +0100 Subject: [PATCH 10/12] Fix usleep for small values --- core/thread.c | 2 ++ userspace/main_user.c | 1 + 2 files changed, 3 insertions(+) diff --git a/core/thread.c b/core/thread.c index b83752e..2f74f01 100644 --- a/core/thread.c +++ b/core/thread.c @@ -331,6 +331,8 @@ int threadUsleep(unsigned long usec) current->state = SLEEPING; current->sleepHaveTimeouted = 0; current->jiffiesSleeping = usecs_to_jiffies(usec); + if (!current->jiffiesSleeping) // sleep at least 1 jiffies + current->jiffiesSleeping = 1; next = threadSelectNext(); assert(next != current); diff --git a/userspace/main_user.c b/userspace/main_user.c index c48db8c..6711c9d 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -124,6 +124,7 @@ int func_munmap() static void *print_hello(void *arg) { (void)arg; printf("Hello World from thread %lu\n", gettid()); + usleep(100); return NULL; } From 1047400be2e07515a510b53f784de97588998227 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 26 Feb 2024 23:03:49 +0100 Subject: [PATCH 11/12] Add missing debug.iso.gdb file --- debug.iso.gdb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 debug.iso.gdb diff --git a/debug.iso.gdb b/debug.iso.gdb new file mode 100644 index 0000000..1816cc1 --- /dev/null +++ b/debug.iso.gdb @@ -0,0 +1,10 @@ +add-symbol-file userspace/user +# Thx to add-gnu-debuglink gdb should know that symbols are in kernel.debug. +# And by default, it should be looking at executable.debug +# But we still have to give him the executable he is suppose to debug (See https://sourceware.org/gdb/current/onlinedocs/gdb.html/Separate-Debug-Files.html) +#add-symbol-file kernel.debug +file kernel +source custom_gdb_extension.py +#For ASM sources +directory arch/x86/:core +target remote | qemu-system-i386 -S -gdb stdio -m 16M -serial file:serialOut -hda fd.iso -hdb disk.img From dc4c465e946a8f17729c2cb7177a5fee95bb5217 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 27 Feb 2024 23:14:09 +0100 Subject: [PATCH 12/12] Fix freeing squattedCtx when deleting thread --- arch/x86/exception.c | 8 ++++---- core/thread.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 512f8c5..61f5616 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -53,10 +53,12 @@ void print_handler(struct cpu_state *frame, ulong intr) void pagefault_handler(struct cpu_state *frame, ulong intr) { - + // PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S) + uint32_t error_code = cpu_context_get_EX_err(frame); struct thread *current = getCurrentThread(); - assert(frame == current->cpuState); + if (cpu_context_is_in_user_mode(current->cpuState)) { + assert(frame == current->cpuState); // pagefault in kernel not supported ATM struct uAddrSpace *as = processGetAddrSpace(current->process); vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); @@ -70,8 +72,6 @@ void pagefault_handler(struct cpu_state *frame, ulong intr) if (!uAddrSpaceHeapCheckNAlloc(as, faultAddr)) goto release_context; - // PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S) - uint32_t error_code = cpu_context_get_EX_err(frame); int ret = uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2); if (!ret) diff --git a/core/thread.c b/core/thread.c index 2f74f01..6e78c12 100644 --- a/core/thread.c +++ b/core/thread.c @@ -165,8 +165,9 @@ void threadDelete(struct thread *thread) } if (thread->squattedContext) { - threadChangeCurrentContext(NULL); + mmuContextUnref(thread->squattedContext); } + if (thread->process) processRemoveThread(thread);