From e288f35b5b252d0a1221af1052890b3779455684 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 3 Dec 2025 14:28:19 +0100 Subject: [PATCH 1/6] fixes to correct bug introduced by the MUSL support --- so3/arch/arm32/context.S | 1 - so3/arch/arm64/context.S | 1 - so3/arch/arm64/exception.S | 7 ++++--- so3/arch/arm64/traps.c | 2 +- so3/fs/vfs.c | 23 +++++++++++++---------- so3/include/vfs.h | 2 +- so3/kernel/process.c | 4 ++-- so3/kernel/syscalls.c | 5 ++--- so3/kernel/timer.c | 8 ++++---- usr/src/time.c | 5 +---- 10 files changed, 28 insertions(+), 30 deletions(-) diff --git a/so3/arch/arm32/context.S b/so3/arch/arm32/context.S index d49488436..21f0700f8 100644 --- a/so3/arch/arm32/context.S +++ b/so3/arch/arm32/context.S @@ -34,7 +34,6 @@ .global __exec_prologue_user .globl __get_syscall_args_ext -.globl __get_syscall_arg .global __mmu_switch_ttbr0 .global __exec diff --git a/so3/arch/arm64/context.S b/so3/arch/arm64/context.S index 05f34506c..a51490df5 100644 --- a/so3/arch/arm64/context.S +++ b/so3/arch/arm64/context.S @@ -31,7 +31,6 @@ .global __exec_prologue_user .globl __get_syscall_args_ext -.globl __get_syscall_arg .global __mmu_switch .global __exec diff --git a/so3/arch/arm64/exception.S b/so3/arch/arm64/exception.S index b47e9f8e4..4dadb33a4 100644 --- a/so3/arch/arm64/exception.S +++ b/so3/arch/arm64/exception.S @@ -495,13 +495,14 @@ __prepare_sig_handler: ldr x1, [x0, #OFFSET_SYS_SIGNUM] str x1, [sp, #OFFSET_X0] + // Set the handler to the PC ldr x1, [x0, #OFFSET_SYS_SA] ldr x2, [x1, #OFFSET_SA_HANDLER] - str x2, [sp, #OFFSET_X1] + str x2, [sp, #OFFSET_PC] - // Set the handler to the PC + // Set restorer to LR so the handler return to it. ldr x2, [x1, #OFFSET_SA_RESTORER] - str x2, [sp, #OFFSET_PC] + str x2, [sp, #OFFSET_LR] ret diff --git a/so3/arch/arm64/traps.c b/so3/arch/arm64/traps.c index 17ab61407..3289dbf92 100644 --- a/so3/arch/arm64/traps.c +++ b/so3/arch/arm64/traps.c @@ -247,7 +247,7 @@ void trap_handle(cpu_regs_t *regs) default: lprintk("### On CPU %d: ESR_Elx_EC(esr): 0x%lx\n", smp_processor_id(), ESR_ELx_EC(esr)); - trap_handle_error(regs->lr); + trap_handle_error(regs->pc); kernel_panic(); } } diff --git a/so3/fs/vfs.c b/so3/fs/vfs.c index 5f7f76dff..45328218c 100644 --- a/so3/fs/vfs.c +++ b/so3/fs/vfs.c @@ -467,7 +467,7 @@ static int do_write(int fd, const void *buffer, size_t count) } /* Low Level mmap */ -static int do_mmap(int fd, addr_t virt_addr, uint32_t page_count, off_t offset) +static long do_mmap(int fd, addr_t virt_addr, uint32_t page_count, off_t offset) { int gfd; struct file_operations *fops; @@ -499,7 +499,7 @@ static int do_mmap(int fd, addr_t virt_addr, uint32_t page_count, off_t offset) } /* Low Level mmap - Anonymous case */ -static int do_mmap_anon(int fd, addr_t virt_addr, uint32_t page_count, off_t offset) +static long do_mmap_anon(int fd, addr_t virt_addr, uint32_t page_count, off_t offset) { uint32_t page; pcb_t *pcb; @@ -526,7 +526,7 @@ static int do_mmap_anon(int fd, addr_t virt_addr, uint32_t page_count, off_t off memset((void *) virt_addr, 0, page_count * PAGE_SIZE); - /* WARNIMG - This is a simple/basic way to set the start virtual address: + /* WARNING - This is a simple/basic way to set the start virtual address: It only increment the start address after each mmap call, no algorithm to search for available spaces. */ @@ -1045,15 +1045,18 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec *, vec, unsigned l int total = 0; for (i = 0; i < vlen; i++) { - ret = do_write(fd, (const void *) vec[i].iov_base, vec[i].iov_len); - if (ret < 0) { - break; - } else if ((ret >= 0) && (ret < vec[i].iov_len)) { + /* Do nothing for empty buffer */ + if (vec[i].iov_len != 0) { + ret = do_write(fd, (const void *) vec[i].iov_base, vec[i].iov_len); + if (ret < 0) { + break; + } else if ((ret >= 0) && (ret < vec[i].iov_len)) { + total += ret; + break; + } + total += ret; - break; } - - total += ret; } if (total == 0) diff --git a/so3/include/vfs.h b/so3/include/vfs.h index 5c72e7208..d4e7b7a6d 100644 --- a/so3/include/vfs.h +++ b/so3/include/vfs.h @@ -92,7 +92,7 @@ #define DT_SOCK 12 /* Socket device */ /* mmap flags options */ -#define MAP_ANONYMOUS 0x10 /* don't use a file */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ /* Special value for dirfd used to indicate openat should use the current working directory. */ diff --git a/so3/kernel/process.c b/so3/kernel/process.c index c05540775..8fe002d94 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -74,9 +74,9 @@ static uint32_t pid_current = 1; static pcb_t *root_process = NULL; /* root process */ /* only the following sections are supported */ -#define SUPPORTED_SECTION_COUNT 6 +#define SUPPORTED_SECTION_COUNT 8 static const char *supported_section_names[SUPPORTED_SECTION_COUNT] = { - ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", + ".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", }; /* diff --git a/so3/kernel/syscalls.c b/so3/kernel/syscalls.c index 251dc1430..c661bd40b 100644 --- a/so3/kernel/syscalls.c +++ b/so3/kernel/syscalls.c @@ -31,8 +31,7 @@ #include #include -extern void __get_syscall_args_ext(uint32_t *syscall_no); -extern uint32_t __get_syscall_stack_arg(uint32_t nr); +extern void __get_syscall_args_ext(long *syscall_no); extern void test_malloc(int test_no); @@ -49,7 +48,7 @@ static const syscall_fn_t syscall_table[NR_SYSCALLS] = { long syscall_handle(syscall_args_t *syscall_args) { - uint32_t syscall_no; + long syscall_no; /* Get addtional args of the syscall according to the ARM & SO3 ABI */ __get_syscall_args_ext(&syscall_no); diff --git a/so3/kernel/timer.c b/so3/kernel/timer.c index 075b39c70..a6e34a17b 100644 --- a/so3/kernel/timer.c +++ b/so3/kernel/timer.c @@ -436,8 +436,8 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval *, ts, void *, tz) time = NOW(); - ts->tv_sec = time / (time_t) 1000000000; - ts->tv_usec = time / (time_t) 1000; + ts->tv_sec = time / SECONDS(1); + ts->tv_usec = (time % SECONDS(1)) / MICROSECS(1); return 0; } @@ -475,8 +475,8 @@ SYSCALL_DEFINE2(clock_gettime, int, clk_id, struct timespec *, ts) time = NOW(); - ts->tv_sec = time / (time_t) 1000000000; - ts->tv_nsec = time; + ts->tv_sec = time / SECONDS(1); + ts->tv_nsec = time % SECONDS(1); return 0; } diff --git a/usr/src/time.c b/usr/src/time.c index a45acbf40..47141b241 100644 --- a/usr/src/time.c +++ b/usr/src/time.c @@ -8,14 +8,11 @@ int main(int argc, char *argv[]) { - time_t t; struct timeval tv; while (true) { gettimeofday(&tv, NULL); - time(&t); - - printf("# time(s) : %lu time(us) : %lu\n", t, tv.tv_usec); + printf("# time(s) : %lu time(us) : %lu\n", tv.tv_sec, tv.tv_usec); } } From 5ed629389d366d387670b5590be740f90c5a3154 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 3 Dec 2025 16:11:59 +0100 Subject: [PATCH 2/6] rename rt_kill into kill in syscall.tbl --- so3/syscall.tbl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/syscall.tbl b/so3/syscall.tbl index b60972a7c..f64496b0b 100644 --- a/so3/syscall.tbl +++ b/so3/syscall.tbl @@ -41,7 +41,7 @@ futex pipe IPC_PIPE pipe2 IPC_PIPE rt_sigaction IPC_SIGNAL -rt_kill IPC_SIGNAL +kill IPC_SIGNAL sigreturn IPC_SIGNAL rt_sigreturn IPC_SIGNAL rt_sigprocmask IPC_SIGNAL From 493ca91960cb84bbc641efc33c091458e2b756fb Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 3 Dec 2025 16:15:37 +0100 Subject: [PATCH 3/6] rename thread_yield to sched_yield --- so3/include/thread.h | 2 +- so3/kernel/thread.c | 2 +- so3/syscall.tbl | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/so3/include/thread.h b/so3/include/thread.h index 78c7bdb8e..1091f2262 100644 --- a/so3/include/thread.h +++ b/so3/include/thread.h @@ -138,7 +138,7 @@ tcb_t *user_thread(clone_args_t *args); int thread_join(tcb_t *tcb); void thread_exit(int exit_status); void clean_thread(tcb_t *tcb); -SYSCALL_DECLARE(thread_yield, void); +SYSCALL_DECLARE(sched_yield, void); void *thread_idle(void *dummy); diff --git a/so3/kernel/thread.c b/so3/kernel/thread.c index 3c449106b..121140c55 100644 --- a/so3/kernel/thread.c +++ b/so3/kernel/thread.c @@ -339,7 +339,7 @@ void *thread_idle(void *dummy) /* * Yield to another thread, i.e. simply invoke a call to schedule() */ -SYSCALL_DEFINE0(thread_yield) +SYSCALL_DEFINE0(sched_yield) { schedule(); return 0; diff --git a/so3/syscall.tbl b/so3/syscall.tbl index f64496b0b..e72744194 100644 --- a/so3/syscall.tbl +++ b/so3/syscall.tbl @@ -38,6 +38,7 @@ mmap mmap2 nanosleep futex +sched_yield pipe IPC_PIPE pipe2 IPC_PIPE rt_sigaction IPC_SIGNAL From 41d17e147e34701378e69cd396a4c71eb4c84d70 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 10 Dec 2025 13:57:10 +0100 Subject: [PATCH 4/6] add missing fix on process --- so3/kernel/process.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/so3/kernel/process.c b/so3/kernel/process.c index 8fe002d94..d3bee955a 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -446,7 +446,7 @@ addr_t preserve_args_and_env(int argc, char **argv, char **envp) /* Save env strings and count how many there are */ saved->envc = 0; if (envp) { - do { + while (envp[saved->envc]) { str_len = strlen(envp[saved->envc]) + 1; /* Ensure the newly copied string will not exceed the buffer size. */ @@ -459,7 +459,9 @@ addr_t preserve_args_and_env(int argc, char **argv, char **envp) strcpy(&saved->arg_env[saved->strings_size], envp[saved->envc]); saved->strings_size += str_len; - } while (envp[saved->envc++]); + + saved->envc++; + } } return (addr_t) saved; @@ -477,11 +479,12 @@ void post_setup_image(args_env_t *args_env, elf_img_info_t *elf_img_info) args_base = (char *) arch_get_args_base(); /* Save argc as first arguments */ - *((int *) args_base) = args_env->argc; + *((long *) args_base) = args_env->argc; /* Get the base address for the array of pointer for args, env and aux */ - argv_p_base = (char **) (args_base + sizeof(int)); - env_p_base = (char **) ((addr_t) argv_p_base + args_env->argc * sizeof(char *)); + argv_p_base = (char **) (args_base + sizeof(long)); + /* Add one to account for the null termination of env */ + env_p_base = (char **) ((addr_t) argv_p_base + (args_env->argc + 1) * sizeof(char *)); /* Add one to account for the null termination of env */ aux_elf = (elf_addr_t *) ((addr_t) env_p_base + (args_env->envc + 1) * sizeof(char *)); From 6b1343a88f82e3fd295098b9575d0ecb21918504 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 17 Dec 2025 15:30:45 +0100 Subject: [PATCH 5/6] fix for userspace threads --- so3/arch/arm32/thread.c | 6 ++-- so3/arch/arm64/thread.c | 6 ++-- so3/arch/arm64/traps.c | 2 +- so3/kernel/futex.c | 12 ++++---- usr/src/CMakeLists.txt | 8 +----- usr/src/thread_example.c | 62 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 usr/src/thread_example.c diff --git a/so3/arch/arm32/thread.c b/so3/arch/arm32/thread.c index ba2ad7973..ff26aa07f 100644 --- a/so3/arch/arm32/thread.c +++ b/so3/arch/arm32/thread.c @@ -46,15 +46,15 @@ void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args) BUG_ON(args->stack == 0); arch_restart_user_thread(tcb, args->fn, args->stack); } else { + /* Copy userspace registers */ + *user_regs = *(cpu_regs_t *) arch_get_kernel_stack_frame(current()); + /* Normal userspace that will copy userspace registers */ if (args->stack) user_regs->sp_usr = args->stack; if (args->flags & CLONE_SETTLS) user_regs->tls_usr = args->tls; - - /* Copy userspace registers */ - *user_regs = *(cpu_regs_t *) arch_get_kernel_stack_frame(current()); } tcb->cpu_regs.lr = (unsigned long) ret_from_fork; diff --git a/so3/arch/arm64/thread.c b/so3/arch/arm64/thread.c index e9416929f..0daf82571 100644 --- a/so3/arch/arm64/thread.c +++ b/so3/arch/arm64/thread.c @@ -45,15 +45,15 @@ void arch_prepare_cpu_regs(tcb_t *tcb, clone_args_t *args) BUG_ON(args->stack == 0); arch_restart_user_thread(tcb, args->fn, args->stack); } else { + /* Copy userspace registers */ + *user_regs = *(cpu_regs_t *) arch_get_kernel_stack_frame(current()); + /* Normal userspace that will copy userspace registers */ if (args->stack) user_regs->sp_usr = args->stack; if (args->flags & CLONE_SETTLS) user_regs->tls_usr = args->tls; - - /* Copy userspace registers */ - *user_regs = *(cpu_regs_t *) arch_get_kernel_stack_frame(current()); } tcb->cpu_regs.lr = (unsigned long) ret_from_fork; diff --git a/so3/arch/arm64/traps.c b/so3/arch/arm64/traps.c index 3289dbf92..17ab61407 100644 --- a/so3/arch/arm64/traps.c +++ b/so3/arch/arm64/traps.c @@ -247,7 +247,7 @@ void trap_handle(cpu_regs_t *regs) default: lprintk("### On CPU %d: ESR_Elx_EC(esr): 0x%lx\n", smp_processor_id(), ESR_ELx_EC(esr)); - trap_handle_error(regs->pc); + trap_handle_error(regs->lr); kernel_panic(); } } diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index 0672ef76e..214b7f7bc 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -28,7 +28,7 @@ * @param val expected value of the futex word * @return 0 on success or error value */ -static int do_futex_wait(uint32_t *futex_w, uint32_t val) +static int do_futex_wait(uint32_t *futex_w, uint32_t val, const struct timespec *utime) { unsigned long flags; pcb_t *pcb = current()->pcb; @@ -36,6 +36,9 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) futex_t *futex; queue_thread_t f_element; + if (utime) + printk("[futex] utime parameter is not used in current implementation\n"); + flags = spin_lock_irqsave(&pcb->futex_lock); if (*futex_w != val) { @@ -116,7 +119,7 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) } /* wakes at most nr_wake of the waiters that are waiting */ - list_for_each_safe(pos, p, &futex->list) { + list_for_each_safe(pos, p, &futex->f_element) { f_element = list_entry(pos, queue_thread_t, list); if (idx == nr_wake) @@ -138,12 +141,9 @@ SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct t { int cmd = op & FUTEX_CMD_MASK; - if (utime) - printk("[futex] utime parameter is not used in current implementation\n"); - switch (cmd) { case FUTEX_WAIT: - return do_futex_wait(uaddr, val); + return do_futex_wait(uaddr, val, utime); case FUTEX_WAKE: return do_futex_wake(uaddr, val); case FUTEX_FD: diff --git a/usr/src/CMakeLists.txt b/usr/src/CMakeLists.txt index f388b89b1..8da5d119b 100644 --- a/usr/src/CMakeLists.txt +++ b/usr/src/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(sh.elf sh.c) add_executable(ls.elf ls.c) add_executable(more.elf more.c) add_executable(time.elf time.c) +add_executable(thread_example.elf thread_example.c) add_executable(ping.elf ping.c) add_executable(mydev_test.elf mydev_test.c) add_executable(lvgl_demo.elf lvgl_demo.c) @@ -11,13 +12,6 @@ add_executable(lvgl_perf.elf lvgl_perf.c) add_executable(lvgl_benchmark.elf lvgl_benchmark.c) add_executable(logs_example.elf logs_example.c) -target_link_libraries(init.elf) -target_link_libraries(sh.elf) -target_link_libraries(ls.elf) -target_link_libraries(more.elf) -target_link_libraries(time.elf) -target_link_libraries(ping.elf) -target_link_libraries(mydev_test.elf) target_link_libraries(lvgl_demo.elf slv lvgl lvgl_demos) target_link_libraries(lvgl_perf.elf slv lvgl lvgl_demos) target_link_libraries(lvgl_benchmark.elf slv lvgl lvgl_demos) diff --git a/usr/src/thread_example.c b/usr/src/thread_example.c new file mode 100644 index 000000000..0e5eabf93 --- /dev/null +++ b/usr/src/thread_example.c @@ -0,0 +1,62 @@ +#include +#include +#include + +struct thread_args { + int thread_id; + pthread_mutex_t *mutex; +}; + +void *simple_thread(void *ptr) +{ + struct thread_args *shared_ptr = ptr; + + printf("Thread %d: Executing\n", shared_ptr->thread_id); + + pthread_mutex_lock(shared_ptr->mutex); + printf("Thread %d: Locked mutex\n", shared_ptr->thread_id); + sleep(3); + printf("Thread %d: Unlocking mutex\n", shared_ptr->thread_id); + pthread_mutex_unlock(shared_ptr->mutex); + + printf("Thread %d: Thread finished\n", shared_ptr->thread_id); + return shared_ptr; +} + +int main(int argc, char **argv) +{ + pthread_t thread[2]; + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + struct thread_args args[2] = { + { + .thread_id = 1, + .mutex = &mutex, + }, + { + .thread_id = 2, + .mutex = &mutex, + }, + }; + + struct thread_args *ret[2]; + + /* Start the threads */ + pthread_create(&thread[0], NULL, *simple_thread, (void *) &args[0]); + pthread_create(&thread[1], NULL, *simple_thread, (void *) &args[1]); + + /* Wait until thread are finished. */ + pthread_join(thread[0], (void **)&ret[0]); + pthread_join(thread[1], (void **)&ret[1]); + + /* Simple test to see if thread return value is retrieved correctly. */ + if (ret[0] != &args[0]) { + printf("Unexpected return value for thread 1\n"); + } + if (ret[1] != &args[1]) { + printf("Unexpected return value for thread 2\n"); + } + + printf("All threads finished\n"); + return 0; +} From 35bbd890e88d1a14dc63861b5ab9be84aa01bee4 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 17 Dec 2025 15:40:05 +0100 Subject: [PATCH 6/6] add mising copyright --- usr/src/thread_example.c | 52 ++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/usr/src/thread_example.c b/usr/src/thread_example.c index 0e5eabf93..d51d3d1e7 100644 --- a/usr/src/thread_example.c +++ b/usr/src/thread_example.c @@ -1,9 +1,26 @@ +/* + * Copyright (C) 2025 Clément Dieperink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include #include #include struct thread_args { - int thread_id; + long thread_id; pthread_mutex_t *mutex; }; @@ -11,20 +28,22 @@ void *simple_thread(void *ptr) { struct thread_args *shared_ptr = ptr; - printf("Thread %d: Executing\n", shared_ptr->thread_id); + printf("Thread %ld: Executing\n", shared_ptr->thread_id); pthread_mutex_lock(shared_ptr->mutex); - printf("Thread %d: Locked mutex\n", shared_ptr->thread_id); + printf("Thread %ld: Locked mutex\n", shared_ptr->thread_id); sleep(3); - printf("Thread %d: Unlocking mutex\n", shared_ptr->thread_id); + printf("Thread %ld: Unlocking mutex\n", shared_ptr->thread_id); pthread_mutex_unlock(shared_ptr->mutex); - printf("Thread %d: Thread finished\n", shared_ptr->thread_id); - return shared_ptr; + printf("Thread %ld: Thread finished\n", shared_ptr->thread_id); + /* Return id to check if the value is correctly retrieved by main thread */ + return (void *) shared_ptr->thread_id; } int main(int argc, char **argv) { + int ret; pthread_t thread[2]; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -39,21 +58,28 @@ int main(int argc, char **argv) }, }; - struct thread_args *ret[2]; + long thread_ret[2]; /* Start the threads */ - pthread_create(&thread[0], NULL, *simple_thread, (void *) &args[0]); - pthread_create(&thread[1], NULL, *simple_thread, (void *) &args[1]); + ret = pthread_create(&thread[0], NULL, *simple_thread, (void *) &args[0]); + if (ret != 0) { + printf("Could not create thread 1\n"); + } + + ret = pthread_create(&thread[1], NULL, *simple_thread, (void *) &args[1]); + if (ret != 0) { + printf("Could not create thread 2\n"); + } /* Wait until thread are finished. */ - pthread_join(thread[0], (void **)&ret[0]); - pthread_join(thread[1], (void **)&ret[1]); + pthread_join(thread[0], (void **) &thread_ret[0]); + pthread_join(thread[1], (void **) &thread_ret[1]); /* Simple test to see if thread return value is retrieved correctly. */ - if (ret[0] != &args[0]) { + if (thread_ret[0] != 1) { printf("Unexpected return value for thread 1\n"); } - if (ret[1] != &args[1]) { + if (thread_ret[1] != 2) { printf("Unexpected return value for thread 2\n"); }