summaryrefslogtreecommitdiff
path: root/components/lwp/lwp_syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp/lwp_syscall.c')
-rw-r--r--components/lwp/lwp_syscall.c220
1 files changed, 136 insertions, 84 deletions
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index daa4e00480..775781afda 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -12,6 +12,7 @@
* 2021-02-20 lizhirui fix some warnings
* 2023-03-13 WangXiaoyao Format & fix syscall return value
* 2023-07-06 Shell adapt the signal API, and clone, fork to new implementation of lwp signal
+ * 2023-07-27 Shell Move tid_put() from lwp_free() to sys_exit()
*/
#define _GNU_SOURCE
@@ -20,11 +21,12 @@
#include <rtthread.h>
#include <rthw.h>
#include <board.h>
-#include <mm_aspace.h>
+
+#include <console.h>
#include <string.h>
#include <stdint.h>
-#define DBG_TAG "SYSCALL"
+#define DBG_TAG "lwp.syscall"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
@@ -33,6 +35,7 @@
#include "libc_musl.h"
#include "lwp_internal.h"
#ifdef ARCH_MM_MMU
+#include <mm_aspace.h>
#include <lwp_user_mm.h>
#include <lwp_arch.h>
#endif
@@ -325,16 +328,13 @@ static void _crt_thread_entry(void *parameter)
/* exit group */
sysret_t sys_exit_group(int value)
{
- rt_base_t level;
rt_thread_t tid, main_thread;
struct rt_lwp *lwp;
- LOG_D("process exit");
-
tid = rt_thread_self();
lwp = (struct rt_lwp *)tid->lwp;
+ LOG_D("process(%p) exit.", lwp);
- level = rt_hw_interrupt_disable();
#ifdef ARCH_MM_MMU
if (tid->clear_child_tid)
{
@@ -351,7 +351,7 @@ sysret_t sys_exit_group(int value)
if (main_thread == tid)
{
lwp_wait_subthread_exit();
- lwp->lwp_ret = value;
+ lwp->lwp_ret = LWP_CREATE_STAT(value);
}
#else
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
@@ -373,18 +373,24 @@ sysret_t sys_exit_group(int value)
}
#endif /* ARCH_MM_MMU */
+ /**
+ * Note: the tid tree always hold a reference to thread, hence the tid must
+ * be release before cleanup of thread
+ */
+ lwp_tid_put(tid->tid);
+ tid->tid = 0;
+ rt_list_remove(&tid->sibling);
rt_thread_delete(tid);
- rt_hw_interrupt_enable(level);
rt_schedule();
/* never reach here */
+ RT_ASSERT(0);
return 0;
}
/* thread exit */
void sys_exit(int status)
{
- rt_base_t level;
rt_thread_t tid, main_thread;
struct rt_lwp *lwp;
@@ -393,8 +399,6 @@ void sys_exit(int status)
tid = rt_thread_self();
lwp = (struct rt_lwp *)tid->lwp;
- level = rt_hw_interrupt_disable();
-
#ifdef ARCH_MM_MMU
if (tid->clear_child_tid)
{
@@ -411,12 +415,14 @@ void sys_exit(int status)
{
lwp_terminate(lwp);
lwp_wait_subthread_exit();
- lwp->lwp_ret = status;
+ lwp->lwp_ret = LWP_CREATE_STAT(status);
}
#endif /* ARCH_MM_MMU */
+ lwp_tid_put(tid->tid);
+ tid->tid = 0;
+ rt_list_remove(&tid->sibling);
rt_thread_delete(tid);
- rt_hw_interrupt_enable(level);
rt_schedule();
return;
@@ -1079,23 +1085,32 @@ sysret_t sys_kill(int pid, int signo)
{
rt_err_t kret;
sysret_t sysret;
- rt_base_t level;
struct rt_lwp *lwp;
/* handling the semantics of sys_kill */
if (pid > 0)
{
- /* TODO: lock the lwp strcut */
- level = rt_hw_interrupt_disable();
- lwp = lwp_from_pid(pid);
-
- /* lwp_signal_kill() can handle NULL lwp */
+ /**
+ * Brief: Match the pid and send signal to the lwp if found
+ * Note: Critical Section
+ * - pid tree (READ. since the lwp is fetch from the pid tree, it must stay there)
+ */
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_locked(pid);
if (lwp)
+ {
+ lwp_ref_inc(lwp);
+ lwp_pid_lock_release();
+
kret = lwp_signal_kill(lwp, signo, SI_USER, 0);
+ lwp_ref_dec(lwp);
+ kret = 0;
+ }
else
+ {
+ lwp_pid_lock_release();
kret = -RT_ENOENT;
-
- rt_hw_interrupt_enable(level);
+ }
}
else if (pid == 0)
{
@@ -1807,7 +1822,6 @@ sysret_t sys_timer_getoverrun(timer_t timerid)
rt_thread_t sys_thread_create(void *arg[])
{
- rt_base_t level = 0;
void *user_stack = 0;
struct rt_lwp *lwp = 0;
rt_thread_t thread = RT_NULL;
@@ -1887,9 +1901,9 @@ rt_thread_t sys_thread_create(void *arg[])
rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
}
- level = rt_hw_interrupt_disable();
+ LWP_LOCK(lwp);
rt_list_insert_after(&lwp->t_grp, &thread->sibling);
- rt_hw_interrupt_enable(level);
+ LWP_UNLOCK(lwp);
return thread;
@@ -1903,11 +1917,9 @@ fail:
}
#ifdef ARCH_MM_MMU
-#include "lwp_clone.h"
long _sys_clone(void *arg[])
{
- rt_base_t level = 0;
struct rt_lwp *lwp = 0;
rt_thread_t thread = RT_NULL;
rt_thread_t self = RT_NULL;
@@ -2001,9 +2013,9 @@ long _sys_clone(void *arg[])
rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
}
- level = rt_hw_interrupt_disable();
+ LWP_LOCK(lwp);
rt_list_insert_after(&lwp->t_grp, &thread->sibling);
- rt_hw_interrupt_enable(level);
+ LWP_UNLOCK(lwp);
/* copy origin stack */
lwp_memcpy(thread->stack_addr, self->stack_addr, thread->stack_size);
@@ -2016,6 +2028,10 @@ long _sys_clone(void *arg[])
return (long)tid;
fail:
lwp_tid_put(tid);
+ if (thread)
+ {
+ rt_thread_delete(thread);
+ }
if (lwp)
{
lwp_ref_dec(lwp);
@@ -2091,7 +2107,6 @@ static int lwp_copy_files(struct rt_lwp *dst, struct rt_lwp *src)
sysret_t _sys_fork(void)
{
- rt_base_t level;
int tid = 0;
sysret_t falival = 0;
struct rt_lwp *lwp = RT_NULL;
@@ -2166,34 +2181,27 @@ sysret_t _sys_fork(void)
thread->lwp = (void *)lwp;
thread->tid = tid;
- level = rt_hw_interrupt_disable();
-
+ LWP_LOCK(self_lwp);
/* add thread to lwp process */
rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+ LWP_UNLOCK(self_lwp);
- /* lwp add to children link */
- lwp->sibling = self_lwp->first_child;
- self_lwp->first_child = lwp;
- lwp->parent = self_lwp;
-
- rt_hw_interrupt_enable(level);
+ lwp_children_register(self_lwp, lwp);
- /* copy origin stack */
+ /* 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);
- level = rt_hw_interrupt_disable();
user_stack = arch_get_user_sp();
- rt_hw_interrupt_enable(level);
-
arch_set_thread_context(arch_fork_exit,
(void *)((char *)thread->stack_addr + thread->stack_size),
user_stack, &thread->sp);
+
/* new thread never reach there */
- level = rt_hw_interrupt_disable();
+ LWP_LOCK(lwp);
if (lwp->tty != RT_NULL)
{
int ret;
@@ -2212,7 +2220,8 @@ sysret_t _sys_fork(void)
lwp->tty->foreground = lwp;
}
- rt_hw_interrupt_enable(level);
+ LWP_UNLOCK(lwp);
+
rt_thread_startup(thread);
return lwp_to_pid(lwp);
fail:
@@ -2222,6 +2231,10 @@ fail:
{
lwp_tid_put(tid);
}
+ if (thread)
+ {
+ rt_thread_delete(thread);
+ }
if (lwp)
{
lwp_ref_dec(lwp);
@@ -2576,7 +2589,6 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
char *p;
struct rt_lwp *new_lwp = NULL;
struct rt_lwp *lwp;
- rt_base_t level;
int uni_thread;
rt_thread_t thread;
struct process_aux *aux;
@@ -2591,7 +2603,8 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
lwp = lwp_self();
thread = rt_thread_self();
uni_thread = 1;
- level = rt_hw_interrupt_disable();
+
+ LWP_LOCK(lwp);
if (lwp->t_grp.prev != &thread->sibling)
{
uni_thread = 0;
@@ -2600,7 +2613,8 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
{
uni_thread = 0;
}
- rt_hw_interrupt_enable(level);
+ LWP_UNLOCK(lwp);
+
if (!uni_thread)
{
SET_ERRNO(EINVAL);
@@ -2771,10 +2785,14 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
}
}
- /* load ok, now set thread name and swap the data of lwp and new_lwp */
- level = rt_hw_interrupt_disable();
+ /**
+ * 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_strncpy(thread->parent.name, run_name + last_backslash, RT_NAME_MAX);
+ strncpy(thread->parent.name, run_name + last_backslash, RT_NAME_MAX);
+ strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX);
rt_pages_free(page, 0);
@@ -2797,12 +2815,10 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
lwp_signal_detach(&lwp->signal);
lwp_signal_init(&lwp->signal);
- /* to do: clsoe files with flag CLOEXEC */
+ /* to do: clsoe files with flag CLOEXEC, recy sub-thread */
lwp_aspace_switch(thread);
- rt_hw_interrupt_enable(level);
-
lwp_ref_dec(new_lwp);
arch_start_umode(lwp->args,
lwp->text_entry,
@@ -4067,14 +4083,19 @@ sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct
sysret_t sys_tkill(int tid, int sig)
{
#ifdef ARCH_MM_MMU
- rt_base_t level;
rt_thread_t thread;
- int ret;
+ sysret_t ret;
- level = rt_hw_interrupt_disable();
- thread = lwp_tid_get_thread(tid);
+ /**
+ * Brief: Match a tid and do the kill
+ *
+ * Note: Critical Section
+ * - the thread (READ. may be released at the meantime; protected by locked)
+ */
+ thread = lwp_tid_get_thread_and_inc_ref(tid);
ret = lwp_thread_signal_kill(thread, sig, SI_USER, 0);
- rt_hw_interrupt_enable(level);
+ lwp_tid_dec_ref(thread);
+
return ret;
#else
return lwp_thread_kill((rt_thread_t)tid, sig);
@@ -4182,7 +4203,7 @@ sysret_t sys_waitpid(int32_t pid, int *status, int options)
}
else
{
- ret = waitpid(pid, status, options);
+ ret = lwp_waitpid(pid, status, options);
}
#else
if (!lwp_user_accessable((void *)status, sizeof(int)))
@@ -5271,11 +5292,13 @@ sysret_t sys_setaffinity(pid_t pid, size_t size, void *set)
return -1;
}
-sysret_t sys_getaffinity(pid_t pid, size_t size, void *set)
+sysret_t sys_getaffinity(const pid_t pid, size_t size, void *set)
{
#ifdef ARCH_MM_MMU
+ DEF_RETURN_CODE(rc);
cpu_set_t mask;
struct rt_lwp *lwp;
+ rt_bool_t need_release = RT_FALSE;
if (size <= 0 || size > sizeof(cpu_set_t))
{
@@ -5286,33 +5309,47 @@ sysret_t sys_getaffinity(pid_t pid, size_t size, void *set)
return -EFAULT;
}
- if (pid == 0) lwp = lwp_self();
- else lwp = lwp_from_pid(pid);
- if (!lwp)
+ if (pid == 0)
{
- return -ESRCH;
+ lwp = lwp_self();
}
-
-#ifdef RT_USING_SMP
- if (lwp->bind_cpu == RT_CPUS_NR) /* not bind */
+ else
{
- CPU_ZERO_S(size, &mask);
+ need_release = RT_TRUE;
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_locked(pid);
}
- else /* set bind cpu */
+
+ if (!lwp)
{
- /* TODO: only single-core bindings are now supported of rt-smart */
- CPU_SET_S(lwp->bind_cpu, size, &mask);
+ rc = -ESRCH;
}
-#else
- CPU_SET_S(0, size, &mask);
-#endif
-
- if (lwp_put_to_user(set, &mask, size) != size)
+ else
{
- return -1;
+ #ifdef RT_USING_SMP
+ if (lwp->bind_cpu == RT_CPUS_NR) /* not bind */
+ {
+ CPU_ZERO_S(size, &mask);
+ }
+ else /* set bind cpu */
+ {
+ /* TODO: only single-core bindings are now supported of rt-smart */
+ CPU_SET_S(lwp->bind_cpu, size, &mask);
+ }
+ #else
+ CPU_SET_S(0, size, &mask);
+ #endif
+
+ if (lwp_put_to_user(set, &mask, size) != size)
+ rc = -EFAULT;
+ else
+ rc = 0;
}
- return 0;
+ if (need_release)
+ lwp_pid_lock_release();
+
+ RETURN(rc);
#else
return -1;
#endif
@@ -5369,6 +5406,7 @@ sysret_t sys_sched_setparam(pid_t pid, void *param)
struct sched_param *sched_param = RT_NULL;
struct rt_lwp *lwp = NULL;
rt_thread_t main_thread;
+ rt_bool_t need_release = RT_FALSE;
int ret = -1;
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
@@ -5390,15 +5428,21 @@ sysret_t sys_sched_setparam(pid_t pid, void *param)
if (pid > 0)
{
- lwp = lwp_from_pid(pid);
+ need_release = RT_TRUE;
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_locked(pid);
}
else if (pid == 0)
{
lwp = lwp_self();
}
+
if (lwp)
{
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (need_release)
+ lwp_pid_lock_release();
+
ret = rt_thread_control(main_thread, RT_THREAD_CTRL_CHANGE_PRIORITY, (void *)&sched_param->sched_priority);
}
@@ -5413,12 +5457,13 @@ sysret_t sys_sched_yield(void)
return 0;
}
-sysret_t sys_sched_getparam(pid_t pid, void *param)
+sysret_t sys_sched_getparam(const pid_t pid, void *param)
{
struct sched_param *sched_param = RT_NULL;
struct rt_lwp *lwp = NULL;
rt_thread_t main_thread;
int ret = -1;
+ rt_bool_t need_release = RT_FALSE;
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
{
@@ -5433,15 +5478,21 @@ sysret_t sys_sched_getparam(pid_t pid, void *param)
if (pid > 0)
{
- lwp = lwp_from_pid(pid);
+ need_release = RT_TRUE;
+ lwp_pid_lock_take();
+ lwp = lwp_from_pid_locked(pid);
}
else if (pid == 0)
{
lwp = lwp_self();
}
+
if (lwp)
{
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (need_release)
+ lwp_pid_lock_release();
+
sched_param->sched_priority = main_thread->current_priority;
ret = 0;
}
@@ -5474,12 +5525,10 @@ sysret_t sys_sched_get_priority_min(int policy)
sysret_t sys_sched_setscheduler(int tid, int policy, void *param)
{
- int ret = 0;
+ sysret_t ret;
struct sched_param *sched_param = RT_NULL;
rt_thread_t thread = RT_NULL;
- thread = lwp_tid_get_thread(tid);
-
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
{
return -EFAULT;
@@ -5497,7 +5546,9 @@ sysret_t sys_sched_setscheduler(int tid, int policy, void *param)
return -EINVAL;
}
+ thread = lwp_tid_get_thread_and_inc_ref(tid);
ret = rt_thread_control(thread, RT_THREAD_CTRL_CHANGE_PRIORITY, (void *)&sched_param->sched_priority);
+ lwp_tid_dec_ref(thread);
kmem_put(sched_param);
@@ -5509,7 +5560,6 @@ sysret_t sys_sched_getscheduler(int tid, int *policy, void *param)
struct sched_param *sched_param = RT_NULL;
rt_thread_t thread = RT_NULL;
- thread = lwp_tid_get_thread(tid);
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
{
@@ -5528,7 +5578,9 @@ sysret_t sys_sched_getscheduler(int tid, int *policy, void *param)
return -EINVAL;
}
+ thread = lwp_tid_get_thread_and_inc_ref(tid);
sched_param->sched_priority = thread->current_priority;
+ lwp_tid_dec_ref(thread);
lwp_put_to_user((void *)param, sched_param, sizeof(struct sched_param));
kmem_put(sched_param);