summaryrefslogtreecommitdiff
path: root/components/lwp/syscall/syscall_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp/syscall/syscall_thread.c')
-rw-r--r--components/lwp/syscall/syscall_thread.c1075
1 files changed, 1075 insertions, 0 deletions
diff --git a/components/lwp/syscall/syscall_thread.c b/components/lwp/syscall/syscall_thread.c
new file mode 100644
index 0000000000..6ec936f468
--- /dev/null
+++ b/components/lwp/syscall/syscall_thread.c
@@ -0,0 +1,1075 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "syscall_internal.h"
+
+/**
+ * @brief Creates a new thread.
+ *
+ * This system call creates a new thread within the calling process. The newly created
+ * thread starts executing the function specified by the `arg` argument, which typically
+ * contains the necessary arguments or function pointer for the thread's execution.
+ *
+ * @param[in] arg An array of arguments that will be passed to the function executed
+ * by the new thread. This can include function pointers, structures,
+ * or any necessary data the thread will need to execute its work.
+ *
+ * @return rt_thread_t Returns a handle to the newly created thread. If the thread
+ * creation fails, `NULL` is returned.
+ *
+ * @warning Ensure that the system has sufficient resources to create a new thread.
+ * Thread creation failures can occur if system limits are exceeded or resources
+ * are unavailable.
+ */
+rt_thread_t sys_thread_create(void *arg[])
+{
+ int tid = 0;
+ void *user_stack = 0;
+ struct rt_lwp *lwp = 0;
+ rt_thread_t thread = RT_NULL;
+
+ lwp = rt_thread_self()->lwp;
+ lwp_ref_inc(lwp);
+
+#ifdef ARCH_MM_MMU
+ user_stack = lwp_map_user(lwp, 0, (size_t)arg[3], 0);
+ if (!user_stack)
+ {
+ goto fail;
+ }
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ goto fail;
+ }
+ thread = rt_thread_create((const char *)arg[0],
+ _crt_thread_entry,
+ (void *)arg[2],
+ ALLOC_KERNEL_STACK_SIZE,
+ (rt_uint8_t)(size_t)arg[4],
+ (rt_uint32_t)(rt_size_t)arg[5]);
+ if (!thread)
+ {
+ goto fail;
+ }
+
+#ifdef RT_USING_SMP
+ RT_SCHED_CTX(thread).bind_cpu = lwp->bind_cpu;
+#endif
+ thread->cleanup = lwp_cleanup;
+ thread->user_entry = (void (*)(void *))arg[1];
+ thread->user_stack = (void *)user_stack;
+ thread->user_stack_size = (rt_size_t)arg[3];
+#else
+ rt_uint32_t kstack_size = (rt_uint32_t)arg[7];
+ if (kstack_size < ALLOC_KERNEL_STACK_SIZE_MIN)
+ {
+ /* When kstack size is 0, the default size of the kernel stack is used */
+ kstack_size = kstack_size ? ALLOC_KERNEL_STACK_SIZE_MIN : ALLOC_KERNEL_STACK_SIZE;
+ }
+ else if (kstack_size > ALLOC_KERNEL_STACK_SIZE_MAX)
+ {
+ kstack_size = ALLOC_KERNEL_STACK_SIZE_MAX;
+ }
+
+ user_stack = (void *)arg[3];
+ if ((!user_stack) || ((rt_uint32_t)arg[6] == RT_NULL))
+ {
+ goto fail;
+ }
+
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ goto fail;
+ }
+
+ thread = rt_thread_create((const char *)arg[0], _crt_thread_entry, (void *)arg[2], kstack_size, (rt_uint8_t)(size_t)arg[5], (rt_uint32_t)arg[6]);
+ if (!thread)
+ {
+ goto fail;
+ }
+ thread->cleanup = lwp_cleanup;
+ thread->user_entry = (void (*)(void *))arg[1];
+ thread->user_stack = (void *)user_stack;
+ thread->user_stack_size = (uint32_t)arg[4];
+ rt_memset(thread->user_stack, '#', thread->user_stack_size);
+#endif /* ARCH_MM_MMU */
+
+ thread->lwp = (void *)lwp;
+ thread->tid = tid;
+ lwp_tid_set_thread(tid, thread);
+
+ if (lwp->debug)
+ {
+ rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
+ }
+
+ LWP_LOCK(lwp);
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+ LWP_UNLOCK(lwp);
+
+ return thread;
+
+fail:
+ lwp_tid_put(tid);
+ if (lwp)
+ {
+ lwp_ref_dec(lwp);
+ }
+ return RT_NULL;
+}
+
+#ifdef ARCH_MM_MMU
+
+long _sys_clone(void *arg[])
+{
+ struct rt_lwp *lwp = 0;
+ rt_thread_t thread = RT_NULL;
+ rt_thread_t self = RT_NULL;
+ int tid = 0;
+ rt_err_t err;
+
+ unsigned long flags = 0;
+ void *user_stack = RT_NULL;
+ int *new_tid = RT_NULL;
+ void *tls = RT_NULL;
+ /*
+ musl call flags (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
+ | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
+ | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED);
+ */
+
+ /* check args */
+ if (!lwp_user_accessable(arg, sizeof(void *[SYS_CLONE_ARGS_NR])))
+ {
+ return -EFAULT;
+ }
+
+ flags = (unsigned long)(size_t)arg[0];
+ if ((flags & (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM)) != (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
+ {
+ return -EINVAL;
+ }
+
+ user_stack = arg[1];
+ new_tid = (int *)arg[2];
+ tls = (void *)arg[3];
+
+ if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
+ {
+ if (!lwp_user_accessable(new_tid, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ }
+
+ self = rt_thread_self();
+ lwp = self->lwp;
+ lwp_ref_inc(lwp);
+ if (!user_stack)
+ {
+ SET_ERRNO(EINVAL);
+ goto fail;
+ }
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ thread = rt_thread_create(self->parent.name,
+ RT_NULL,
+ RT_NULL,
+ self->stack_size,
+ RT_SCHED_PRIV(self).init_priority,
+ RT_SCHED_PRIV(self).init_tick);
+ if (!thread)
+ {
+ goto fail;
+ }
+
+#ifdef RT_USING_SMP
+ RT_SCHED_CTX(self).bind_cpu = lwp->bind_cpu;
+#endif
+ thread->cleanup = lwp_cleanup;
+ thread->user_entry = RT_NULL;
+ thread->user_stack = RT_NULL;
+ thread->user_stack_size = 0;
+ thread->lwp = (void *)lwp;
+ thread->tid = tid;
+
+ if ((flags & CLONE_SETTLS) == CLONE_SETTLS)
+ {
+ thread->thread_idr = tls;
+ }
+ if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
+ {
+ *new_tid = (int)(tid);
+ }
+ if ((flags & CLONE_CHILD_CLEARTID) == CLONE_CHILD_CLEARTID)
+ {
+ thread->clear_child_tid = (int *)arg[4];
+ }
+
+ if (lwp->debug)
+ {
+ rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
+ }
+
+ LWP_LOCK(lwp);
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+ LWP_UNLOCK(lwp);
+
+ /* copy origin stack */
+ lwp_memcpy(thread->stack_addr, self->stack_addr, thread->stack_size);
+ lwp_tid_set_thread(tid, thread);
+ arch_set_thread_context(arch_clone_exit,
+ (void *)((char *)thread->stack_addr + thread->stack_size),
+ user_stack, &thread->sp);
+ /* new thread never reach there */
+ rt_thread_startup(thread);
+ return (long)tid;
+fail:
+ err = GET_ERRNO();
+ RT_ASSERT(err < 0);
+
+ lwp_tid_put(tid);
+ if (thread)
+ {
+ rt_thread_delete(thread);
+ }
+ if (lwp)
+ {
+ lwp_ref_dec(lwp);
+ }
+ return (long)err;
+}
+
+/**
+ * @brief Creates a new process or thread (clone).
+ *
+ * This system call creates a new process or thread by duplicating the calling process.
+ * The new process/thread begins execution by calling the function specified in the
+ * `arg[]` array, which typically contains the necessary arguments or function pointer.
+ * It is used to implement process/thread creation in the system and is often a lower-level
+ * operation in process management.
+ *
+ * @param[in] arg An array of arguments passed to the new process or thread. This could
+ * include function pointers, structures, or any necessary data the
+ * new process/thread will need to execute its work.
+ *
+ * @return long Returns a status code or the process/thread ID of the newly created
+ * process/thread. On success, it may return a positive value (such as a
+ * thread ID). On failure, a negative value indicating the error is returned.
+ *
+ * @warning Be cautious when using this function as improper management of process/thread
+ * creation can lead to resource exhaustion, deadlocks, or other synchronization issues.
+ */
+rt_weak long sys_clone(void *arg[])
+{
+ return _sys_clone(arg);
+}
+
+static void lwp_struct_copy(struct rt_lwp *dst, struct rt_lwp *src)
+{
+#ifdef ARCH_MM_MMU
+ dst->end_heap = src->end_heap;
+#endif
+ dst->lwp_type = src->lwp_type;
+ dst->text_entry = src->text_entry;
+ dst->text_size = src->text_size;
+ dst->data_entry = src->data_entry;
+ dst->data_size = src->data_size;
+ dst->args = src->args;
+ dst->background = src->background;
+ dst->tty = src->tty;
+
+ /* terminal API */
+ dst->term_ctrlterm = src->term_ctrlterm;
+
+ rt_memcpy(dst->cmd, src->cmd, RT_NAME_MAX);
+ if (src->exe_file)
+ {
+ if (dst->exe_file)
+ {
+ rt_free(dst->exe_file);
+ }
+ dst->exe_file = strndup(src->exe_file, DFS_PATH_MAX);
+ }
+
+ rt_memcpy(&dst->signal.sig_action, &src->signal.sig_action, sizeof(dst->signal.sig_action));
+ rt_memcpy(&dst->signal.sig_action_mask, &src->signal.sig_action_mask, sizeof(dst->signal.sig_action_mask));
+ rt_memcpy(&dst->signal.sig_action_nodefer, &src->signal.sig_action_nodefer, sizeof(dst->signal.sig_action_nodefer));
+ rt_memcpy(&dst->signal.sig_action_onstack, &src->signal.sig_action_onstack, sizeof(dst->signal.sig_action_onstack));
+ rt_memcpy(&dst->signal.sig_action_restart, &dst->signal.sig_action_restart, sizeof(dst->signal.sig_action_restart));
+ rt_memcpy(&dst->signal.sig_action_siginfo, &dst->signal.sig_action_siginfo, sizeof(dst->signal.sig_action_siginfo));
+ rt_memcpy(&dst->signal.sig_action_nocldstop, &dst->signal.sig_action_nocldstop, sizeof(dst->signal.sig_action_nocldstop));
+ rt_memcpy(&dst->signal.sig_action_nocldwait, &dst->signal.sig_action_nocldwait, sizeof(dst->signal.sig_action_nocldwait));
+ rt_strcpy(dst->working_directory, src->working_directory);
+}
+
+static int lwp_copy_files(struct rt_lwp *dst, struct rt_lwp *src)
+{
+ struct dfs_fdtable *dst_fdt;
+ struct dfs_fdtable *src_fdt;
+
+ src_fdt = &src->fdt;
+ dst_fdt = &dst->fdt;
+ /* init fds */
+ dst_fdt->fds = rt_calloc(src_fdt->maxfd, sizeof(void *));
+ if (dst_fdt->fds)
+ {
+ struct dfs_file *d_s;
+ int i;
+
+ dst_fdt->maxfd = src_fdt->maxfd;
+
+ dfs_file_lock();
+ /* dup files */
+ for (i = 0; i < src_fdt->maxfd; i++)
+ {
+ d_s = fdt_get_file(src_fdt, i);
+ if (d_s)
+ {
+ dst_fdt->fds[i] = d_s;
+ d_s->ref_count++;
+ }
+ }
+ dfs_file_unlock();
+ return 0;
+ }
+ return -RT_ERROR;
+}
+
+sysret_t _sys_fork(void)
+{
+ int tid = 0;
+ sysret_t falival = 0;
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_lwp *self_lwp = RT_NULL;
+ rt_thread_t thread = RT_NULL;
+ rt_thread_t self_thread = RT_NULL;
+ void *user_stack = RT_NULL;
+ rt_processgroup_t group;
+
+ /* new lwp */
+ lwp = lwp_create(LWP_CREATE_FLAG_ALLOC_PID);
+ if (!lwp)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* new tid */
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* user space init */
+ if (lwp_user_space_init(lwp, 1) != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ self_lwp = lwp_self();
+
+ /* copy address space of process from this proc to forked one */
+ if (lwp_fork_aspace(lwp, self_lwp) != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* copy lwp struct data */
+ lwp_struct_copy(lwp, self_lwp);
+
+ /* copy files */
+ if (lwp_copy_files(lwp, self_lwp) != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* create thread */
+ self_thread = rt_thread_self();
+
+ thread = rt_thread_create(self_thread->parent.name,
+ RT_NULL,
+ RT_NULL,
+ self_thread->stack_size,
+ RT_SCHED_PRIV(self_thread).init_priority,
+ RT_SCHED_PRIV(self_thread).init_tick);
+ if (!thread)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ thread->cleanup = self_thread->cleanup;
+ thread->user_entry = self_thread->user_entry;
+ thread->user_stack = self_thread->user_stack;
+ thread->user_stack_size = self_thread->user_stack_size;
+ thread->signal.sigset_mask = self_thread->signal.sigset_mask;
+ thread->thread_idr = self_thread->thread_idr;
+ thread->clear_child_tid = self_thread->clear_child_tid;
+ thread->lwp = (void *)lwp;
+ thread->tid = tid;
+
+ LWP_LOCK(self_lwp);
+ /* add thread to lwp process */
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+ LWP_UNLOCK(self_lwp);
+
+ lwp_children_register(self_lwp, lwp);
+
+ /* set pgid and sid */
+ group = lwp_pgrp_find(lwp_pgid_get_byprocess(self_lwp));
+ if (group)
+ {
+ lwp_pgrp_insert(group, lwp);
+ }
+ else
+ {
+ LOG_W("the process group of pid: %d cannot be found", lwp_pgid_get_byprocess(self_lwp));
+ }
+
+ /* copy kernel stack context from self thread */
+ lwp_memcpy(thread->stack_addr, self_thread->stack_addr, self_thread->stack_size);
+ lwp_tid_set_thread(tid, thread);
+
+ /* duplicate user objects */
+ lwp_user_object_dup(lwp, self_lwp);
+
+ user_stack = arch_get_user_sp();
+ arch_set_thread_context(arch_fork_exit,
+ (void *)((char *)thread->stack_addr + thread->stack_size),
+ user_stack, &thread->sp);
+
+ rt_thread_startup(thread);
+ return lwp_to_pid(lwp);
+fail:
+ falival = GET_ERRNO();
+
+ if (tid != 0)
+ {
+ lwp_tid_put(tid);
+ }
+ if (thread)
+ {
+ rt_thread_delete(thread);
+ }
+ if (lwp)
+ {
+ lwp_ref_dec(lwp);
+ }
+ return falival;
+}
+
+/* arm needs to wrap fork/clone call to preserved lr & caller saved regs */
+
+/**
+ * @brief Creates a child process by duplicating the calling process.
+ *
+ * This system call creates a new child process by duplicating the calling process. The
+ * new child process is a copy of the parent process, except for the returned value.
+ * The child process starts executing from the point of the fork, but the return value
+ * differs between the parent and child: the parent receives the process ID (PID) of the
+ * child, and the child receives a return value of 0.
+ *
+ * @return sysret_t Returns a status code indicating the result of the operation:
+ * - A positive value (the child's PID) is returned to the parent.
+ * - A value of 0 is returned to the child process.
+ * - A negative value indicates an error (e.g., resource limits exceeded).
+ *
+ * @note This function is commonly used in operating systems to create new processes.
+ *
+ * @warning Be aware that improper management of child processes (such as failing to handle
+ * process termination or excessive forking) can lead to resource exhaustion or
+ * other system issues. Ensure proper process handling in the parent and child
+ * processes to avoid leaks and inconsistencies.
+ */
+rt_weak sysret_t sys_fork(void)
+{
+ return _sys_fork();
+}
+
+/**
+ * @brief Creates a child process using vfork-compatible semantics.
+ *
+ * This implementation delegates to `sys_fork`.
+ *
+ * @return sysret_t The child process ID in the parent or a negative error code.
+ */
+rt_weak sysret_t sys_vfork(void)
+{
+ return sys_fork();
+}
+
+#define _swap_lwp_data(lwp_used, lwp_new, type, member) \
+ do \
+ { \
+ type tmp; \
+ tmp = lwp_used->member; \
+ lwp_used->member = lwp_new->member; \
+ lwp_new->member = tmp; \
+ } while (0)
+
+/**
+ * @brief Executes a program in the current process.
+ *
+ * This system call replaces the current process image with a new program specified by the
+ * `path` argument. It loads the program located at the given `path` and passes the arguments
+ * (`argv`) and environment variables (`envp`) to it. This effectively replaces the calling
+ * process with a new one, and if successful, it never returns. If there is an error, the current
+ * process continues to execute, and an error code is returned.
+ *
+ * @param[in] path The path to the executable file to be executed. This should be an
+ * absolute or relative file path to the program.
+ * @param[in] argv An array of arguments to pass to the new program. The first element
+ * (`argv[0]`) should typically be the name of the program, and the array
+ * should be terminated with a `NULL` pointer.
+ * @param[in] envp An array of environment variables to pass to the new program. This is
+ * typically in the form of `key=value` strings, with the array terminated
+ * by a `NULL` pointer.
+ *
+ * @return sysret_t Returns a status code:
+ * - `0`: The program was successfully executed (this value is
+ * never returned since the process is replaced).
+ * - Other error codes may indicate issues with the program execution
+ *
+ * @note If `execve` is successful, it does not return to the calling function. The process
+ * image is replaced by the new program.
+ */
+sysret_t sys_execve(const char *path, char * const argv[], char * const envp[])
+{
+ rt_err_t error = -1;
+ size_t len;
+ struct rt_lwp *new_lwp = NULL;
+ struct rt_lwp *lwp;
+ int uni_thread;
+ rt_thread_t thread;
+ struct process_aux *aux;
+ struct lwp_args_info args_info;
+ char *kpath = RT_NULL;
+
+ lwp = lwp_self();
+ thread = rt_thread_self();
+ uni_thread = 1;
+
+ LWP_LOCK(lwp);
+ if (lwp->t_grp.prev != &thread->sibling)
+ {
+ uni_thread = 0;
+ }
+ if (lwp->t_grp.next != &thread->sibling)
+ {
+ uni_thread = 0;
+ }
+ LWP_UNLOCK(lwp);
+
+ if (!uni_thread)
+ {
+ return -EINVAL;
+ }
+
+ len = lwp_user_strlen(path);
+ if (len <= 0)
+ {
+ return -EFAULT;
+ }
+
+ kpath = rt_malloc(len + 1);
+ if (!kpath)
+ {
+ return -ENOMEM;
+ }
+
+ if (lwp_get_from_user(kpath, (void *)path, len) != len)
+ {
+ rt_free(kpath);
+ return -EFAULT;
+ }
+ kpath[len] = '\0';
+
+ if (access(kpath, X_OK) != 0)
+ {
+ error = rt_get_errno();
+ rt_free(kpath);
+ return (sysret_t)error;
+ }
+
+ /* setup args */
+ error = lwp_args_init(&args_info);
+ if (error)
+ {
+ rt_free(kpath);
+ return -ENOMEM;
+ }
+
+ if (argv)
+ {
+ error = lwp_args_put_argv(&args_info, (void *)argv);
+ if (error)
+ {
+ error = -EFAULT;
+ goto quit;
+ }
+ }
+
+ if (envp)
+ {
+ error = lwp_args_put_envp(&args_info, (void *)envp);
+ if (error)
+ {
+ error = -EFAULT;
+ goto quit;
+ }
+ }
+
+ /* alloc new lwp to operation */
+ new_lwp = lwp_create(LWP_CREATE_FLAG_NONE);
+ if (!new_lwp)
+ {
+ error = -ENOMEM;
+ goto quit;
+ }
+
+ error = lwp_user_space_init(new_lwp, 0);
+ if (error != 0)
+ {
+ error = -ENOMEM;
+ goto quit;
+ }
+
+ /* file is a script ? */
+ path = kpath;
+ while (1)
+ {
+ error = lwp_args_load_script(&args_info, path);
+ if (error != 0)
+ {
+ break;
+ }
+ path = lwp_args_get_argv_0(&args_info);
+ }
+
+ /* now load elf */
+ if ((aux = lwp_argscopy(new_lwp, &args_info)) == NULL)
+ {
+ error = -ENOMEM;
+ goto quit;
+ }
+ error = lwp_load(path, new_lwp, RT_NULL, 0, aux);
+ if (error == RT_EOK)
+ {
+ int off = 0;
+ int last_backslash = 0;
+
+ /* clear all user objects */
+ lwp_user_object_clear(lwp);
+
+ /* find last \ or / to get base name */
+ while (1)
+ {
+ char c = path[off++];
+
+ if (c == '\0')
+ {
+ break;
+ }
+ if (c == '\\' || c == '/')
+ {
+ last_backslash = off;
+ }
+ }
+
+ /**
+ * Set thread name and swap the data of lwp and new_lwp.
+ * Since no other threads can access the lwp field, it't uneccessary to
+ * take a lock here
+ */
+ RT_ASSERT(rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling) == thread);
+
+ strncpy(thread->parent.name, path + last_backslash, RT_NAME_MAX - 1);
+ strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX);
+ rt_free(lwp->exe_file);
+ lwp->exe_file = strndup(new_lwp->exe_file, DFS_PATH_MAX);
+
+#ifdef ARCH_MM_MMU
+ _swap_lwp_data(lwp, new_lwp, struct rt_aspace *, aspace);
+ _swap_lwp_data(lwp, new_lwp, size_t, end_heap);
+#endif
+
+ _swap_lwp_data(lwp, new_lwp, uint8_t, lwp_type);
+ _swap_lwp_data(lwp, new_lwp, void *, text_entry);
+ _swap_lwp_data(lwp, new_lwp, uint32_t, text_size);
+ _swap_lwp_data(lwp, new_lwp, void *, data_entry);
+ _swap_lwp_data(lwp, new_lwp, uint32_t, data_size);
+
+ _swap_lwp_data(lwp, new_lwp, void *, args);
+
+ lwp_thread_signal_detach(&thread->signal);
+ rt_memset(&thread->signal.sigset_mask, 0, sizeof(thread->signal.sigset_mask));
+
+ lwp_signal_detach(&lwp->signal);
+ lwp_signal_init(&lwp->signal);
+
+ /* to do: clsoe files with flag CLOEXEC, recy sub-thread */
+
+ lwp_aspace_switch(thread);
+
+ lwp_ref_dec(new_lwp);
+ arch_start_umode(lwp->args,
+ lwp->text_entry,
+ (void *)USER_STACK_VEND,
+ (char *)thread->stack_addr + thread->stack_size);
+ /* never reach here */
+ }
+ error = -EINVAL;
+quit:
+ if (kpath)
+ {
+ rt_free(kpath);
+ }
+ lwp_args_detach(&args_info);
+ if (new_lwp)
+ {
+ lwp_ref_dec(new_lwp);
+ }
+ return error;
+}
+#endif /* ARCH_MM_MMU */
+
+/**
+ * @brief Deletes a thread.
+ *
+ * This system call is used to delete an existing thread. The specified thread is terminated,
+ * and its resources are released. If the thread is currently running, it will be forcefully
+ * terminated. The thread identifier (`thread`) refers to the thread that is to be deleted.
+ *
+ * @param[in] thread The identifier of the thread to be deleted.
+ *
+ * @return sysret_t Returns a status code:
+ * - `SYSRET_OK`: The thread was successfully deleted.
+ * - Other error codes may indicate additional failures.
+ *
+ * @note This function should be used carefully, as forcefully terminating a thread may
+ * lead to resource leaks or inconsistent state if the thread is performing critical
+ * operations at the time of termination.
+ *
+ * @warning Ensure that the thread being deleted has completed its necessary operations
+ * and that there are no outstanding resources or critical tasks before deleting
+ * it. Otherwise, it might lead to undefined behavior or resource leaks.
+ */
+sysret_t sys_thread_delete(rt_thread_t thread)
+{
+#ifdef ARCH_MM_MMU
+ return rt_thread_delete(thread);
+#else
+ sysret_t ret = 0;
+
+ if (thread->parent.type != RT_Object_Class_Thread)
+ {
+ ret = -EINVAL;
+ goto __exit;
+ }
+
+ ret = rt_thread_delete(thread);
+
+ if (rt_thread_self() == thread)
+ {
+ rt_schedule();
+ }
+
+__exit:
+ return ret;
+#endif
+}
+
+/**
+ * @brief Starts a previously created thread.
+ *
+ * This system call is used to start a thread that was created but has not yet started running.
+ * It initiates the thread's execution, allowing it to begin performing its assigned task.
+ * The `thread` parameter refers to the thread that is to be started.
+ *
+ * @param[in] thread The identifier of the thread to be started.
+ *
+ * @return sysret_t Returns a status code:
+ * - `0`: The thread was successfully started.
+ * - Other error codes may indicate additional failures.
+ *
+ * @warning Ensure that the thread has been correctly initialized and is in a valid state
+ * before calling this function to avoid undefined behavior. Improper initialization
+ * could lead to issues such as the thread not running as expected.
+ */
+sysret_t sys_thread_startup(rt_thread_t thread)
+{
+ return rt_thread_startup(thread);
+}
+
+/**
+ * @brief Retrieves the identifier of the current thread.
+ *
+ * This system call returns the thread identifier of the currently executing thread. It allows
+ * a thread to obtain its own identifier, which can be useful for various thread management
+ * tasks such as self-identification, logging, or checking the thread's status.
+ *
+ * @return rt_thread_t The identifier of the current thread.
+ * If no thread is currently executing, a null or invalid thread ID
+ * might be returned depending on the system's implementation.
+ *
+ * @note This function is typically used when a thread needs to identify itself, especially
+ * in cases where thread management is performed dynamically or the thread identifier
+ * is required for synchronization or debugging purposes.
+ *
+ * @warning Be aware that in environments where there is no concept of threads or if the
+ * current context is not a thread (e.g., during interrupt handling or early system
+ * initialization), the return value might be invalid.
+ */
+rt_thread_t sys_thread_self(void)
+{
+ return rt_thread_self();
+}
+
+/**
+ * @brief Finds a thread by its name.
+ *
+ * This system call is used to search for a thread based on its name. It returns a reference to the
+ * thread if found, otherwise it returns `RT_NULL`. The name comparison is case-sensitive.
+ *
+ * @param[in] name The name of the thread to search for. This should be a valid string that
+ * uniquely identifies the thread within the system.
+ *
+ * @return rt_thread_t The thread object corresponding to the given name, or `RT_NULL` if no
+ * matching thread was found.
+ *
+ * @note The thread name is typically assigned when the thread is created, and it can be used to
+ * identify threads in the system.
+ *
+ * @warning Ensure that the `name` string is correctly set and unique within the system to avoid
+ * unexpected behavior.
+ *
+ * @see sys_thread_create(), sys_thread_delete()
+ */
+rt_thread_t sys_thread_find(char *name)
+{
+ int len = 0;
+ char *kname = RT_NULL;
+ rt_thread_t thread;
+
+ len = lwp_user_strlen(name);
+ if (len <= 0)
+ {
+ return RT_NULL;
+ }
+
+ kname = (char *)kmem_get(len + 1);
+ if (!kname)
+ {
+ return RT_NULL;
+ }
+
+ if (lwp_get_from_user(kname, (void *)name, len + 1) != (len + 1))
+ {
+ kmem_put(kname);
+ return RT_NULL;
+ }
+
+ thread = rt_thread_find(name);
+
+ kmem_put(kname);
+
+ return thread;
+}
+
+/**
+ * @brief Gets the current system tick count.
+ *
+ * This system call returns the current value of the system tick counter, which is typically incremented
+ * at a fixed interval (e.g., every millisecond or microsecond). The tick count can be used for timing
+ * purposes, such as measuring the elapsed time or triggering time-based events.
+ *
+ * @return rt_tick_t The current value of the system tick counter.
+ *
+ * @note The system tick counter typically wraps around after reaching its maximum value, so the
+ * returned tick value may reset after a certain period of time, depending on the configuration
+ * of the system tick timer.
+ *
+ * @warning Be cautious when using the tick value for time-based calculations, as the counter may
+ * overflow and wrap around. Ensure that the code handling the tick count properly accounts
+ * for potential overflow.
+ *
+ * @see sys_tick_init(), sys_tick_delay()
+ */
+rt_tick_t sys_tick_get(void)
+{
+ return rt_tick_get();
+}
+
+/**
+ * @brief Delays the current thread for a specified number of milliseconds.
+ *
+ * This system call puts the calling thread to sleep for a given number of milliseconds. It is a blocking
+ * call, meaning the thread will not execute any further instructions until the specified delay has
+ * passed. The delay is achieved by the system's timer mechanism.
+ *
+ * @param[in] ms The number of milliseconds to delay. The value must be a positive integer.
+ *
+ * @return sysret_t Returns `0` on success, or a negative error code on failure.
+ *
+ * @note This function is useful for introducing a fixed delay in time-sensitive applications or when
+ * the thread needs to be paused before continuing execution.
+ *
+ * @warning Be cautious when using this function in real-time or time-critical applications, as
+ * excessive delays may affect overall system performance or responsiveness.
+ *
+ * @see sys_thread_delay(), sys_thread_sleep()
+ */
+sysret_t sys_thread_mdelay(rt_int32_t ms)
+{
+ return rt_thread_mdelay(ms);
+}
+
+/**
+ * @brief Retrieves the current value of the error code.
+ *
+ * This function returns the most recent error code set by a system call. The error code is typically set
+ * when a system call fails. This function allows users to retrieve the last error that occurred, helping to
+ * diagnose issues or handle errors in a more controlled manner.
+ *
+ * @return sysret_t The current error code. A value of `0` indicates no error, while a non-zero value
+ * represents the most recent error. The error codes are system-specific and can
+ * represent various failure conditions (e.g., `EINVAL`, `ENOMEM`, `EIO`).
+ *
+ * @note The error code returned is specific to the current thread or process and is typically updated
+ * each time a system call fails. The error code is persistent until it is overwritten by the next
+ * failed system call or explicitly reset.
+ *
+ * @see sys_set_errno(), sys_perror(), sys_strerror()
+ */
+/**
+ * @brief Retrieves the current thread's error code.
+ *
+ * @return sysret_t The current error code.
+ */
+sysret_t sys_get_errno(void)
+{
+ return rt_get_errno();
+}
+
+#ifdef ARCH_MM_MMU
+
+/**
+ * @brief Sets the thread-specific data area.
+ *
+ * This function is used to associate a specific area of memory with the current thread. The area pointed to
+ * by `p` is set as the thread's local storage. Thread-specific data is used to store data that is unique to
+ * each thread, allowing different threads to maintain independent state information.
+ *
+ * @param[in] p A pointer to the memory area that is to be set as the thread's local storage. This area
+ * will be used by the thread to store its specific data. The structure and size of the data
+ * area depend on the implementation and use case.
+ *
+ * @return sysret_t Returns `0` on success. On failure, it returns a negative error code.
+ *
+ * @note This function is typically used to set up thread-specific storage for managing data that should
+ * not be shared between threads. The data area is accessible only by the thread that set it, ensuring
+ * thread safety for the stored information.
+ *
+ * @see sys_get_thread_area(), sys_thread_create(), sys_thread_self()
+ */
+sysret_t sys_set_thread_area(void *p)
+{
+ rt_thread_t thread;
+
+ thread = rt_thread_self();
+ thread->thread_idr = p;
+ arch_set_thread_area(p);
+
+ return 0;
+}
+
+/**
+ * @brief Sets the address at which the thread ID is stored.
+ *
+ * This function sets the address of a variable that will store the thread ID for the calling thread.
+ * The specified address `tidptr` will hold the thread's unique identifier. This can be useful for
+ * managing thread-specific state or for synchronization mechanisms where the thread's ID needs to be
+ * shared or checked by other parts of the system.
+ *
+ * @param[in] tidptr A pointer to an integer where the thread ID will be stored. This value will
+ * hold the calling thread's ID, and it can be accessed to identify the thread
+ * later. The value of the thread ID can be used in various thread management
+ * operations.
+ *
+ * @return sysret_t Returns `0` on success. On failure, returns a negative error code.
+ *
+ * @note This function is typically used in systems that require associating a specific address with the
+ * thread ID, often in real-time or embedded systems where managing and accessing thread IDs is
+ * crucial for scheduling or resource allocation.
+ *
+ * @see sys_get_tid(), sys_thread_self(), sys_thread_create()
+ */
+sysret_t sys_set_tid_address(int *tidptr)
+{
+ rt_thread_t thread;
+
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)tidptr, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+#endif
+ thread = rt_thread_self();
+ thread->clear_child_tid = tidptr;
+ return thread->tid;
+}
+#endif /* ARCH_MM_MMU */
+
+/**
+ * @brief Gets the thread ID of the calling thread.
+ *
+ * This function returns the unique thread identifier (thread ID) for the calling thread. The thread ID
+ * can be used to uniquely identify the thread within the system and is typically used for debugging,
+ * thread management, or scheduling purposes.
+ *
+ * @return sysret_t The thread ID of the calling thread. The value is typically a positive integer
+ * representing the unique ID assigned to the thread. In case of failure, an error code
+ * may be returned.
+ *
+ * @note The thread ID returned by this function is unique within the system, and it may be used to
+ * reference or manipulate the specific thread associated with the ID.
+ *
+ * @see sys_set_tid_address(), sys_thread_self(), sys_thread_create()
+ */
+sysret_t sys_gettid(void)
+{
+ return rt_thread_self()->tid;
+}
+
+/**
+ * @brief Checks the accessibility of a file or directory.
+ *
+ * This function checks whether the calling process has the specified access rights for the given file or directory.
+ * The check is performed based on the provided `mode`, which can indicate whether read, write, or execute permissions
+ * are required.
+ *
+ * @param[in] filename The path to the file or directory whose accessibility is being checked.
+ * @param[in] mode The access mode to check for. This can be a combination of the following:
+ * - `R_OK`: Check for read permission.
+ * - `W_OK`: Check for write permission.
+ * - `X_OK`: Check for execute permission.
+ * - `F_OK`: Check if the file exists.
+ *
+ * @return sysret_t Returns `0` if the specified access is allowed. On failure, returns a negative error code.
+ *
+ * @note This function does not modify the file or directory, it only checks if the specified access rights are granted.
+ *
+ * @see sys_open(), sys_stat(), sys_fstat(), sys_chmod(), sys_chown()
+ */