[smart] fixup of lwp recycling and mm varea (#8206)
Signed-off-by: shell <wangxiaoyao@rt-thread.com> Signed-off-by: Shell <smokewood@qq.com> Co-authored-by: xqyjlj <xqyjlj@126.com>
This commit is contained in:
parent
1b6f0e88a3
commit
c2036e769a
|
@ -295,6 +295,10 @@ void fdt_fd_release(struct dfs_fdtable *fdt, int fd)
|
||||||
if (file && file->ref_count == 1)
|
if (file && file->ref_count == 1)
|
||||||
{
|
{
|
||||||
rt_mutex_detach(&file->pos_lock);
|
rt_mutex_detach(&file->pos_lock);
|
||||||
|
if (file->mmap_context)
|
||||||
|
{
|
||||||
|
rt_free(file->mmap_context);
|
||||||
|
}
|
||||||
rt_free(file);
|
rt_free(file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#define PMUTEX_DESTROY 3
|
#define PMUTEX_DESTROY 3
|
||||||
|
|
||||||
/* for sys/mman.h */
|
/* for sys/mman.h */
|
||||||
#define MAP_FAILED ((void *)-1)
|
|
||||||
|
|
||||||
#define MAP_SHARED 0x01
|
#define MAP_SHARED 0x01
|
||||||
#define MAP_PRIVATE 0x02
|
#define MAP_PRIVATE 0x02
|
||||||
|
|
|
@ -1157,6 +1157,10 @@ rt_err_t lwp_children_register(struct rt_lwp *parent, struct rt_lwp *child)
|
||||||
LWP_UNLOCK(parent);
|
LWP_UNLOCK(parent);
|
||||||
|
|
||||||
LOG_D("%s(parent=%p, child=%p)", __func__, parent, child);
|
LOG_D("%s(parent=%p, child=%p)", __func__, parent, child);
|
||||||
|
/* parent holds reference to child */
|
||||||
|
lwp_ref_inc(parent);
|
||||||
|
/* child holds reference to parent */
|
||||||
|
lwp_ref_inc(child);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1178,6 +1182,8 @@ rt_err_t lwp_children_unregister(struct rt_lwp *parent, struct rt_lwp *child)
|
||||||
LWP_UNLOCK(parent);
|
LWP_UNLOCK(parent);
|
||||||
|
|
||||||
LOG_D("%s(parent=%p, child=%p)", __func__, parent, child);
|
LOG_D("%s(parent=%p, child=%p)", __func__, parent, child);
|
||||||
|
lwp_ref_dec(child);
|
||||||
|
lwp_ref_dec(parent);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1195,7 +1201,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||||
|
|
||||||
if (filename == RT_NULL)
|
if (filename == RT_NULL)
|
||||||
{
|
{
|
||||||
return -RT_ERROR;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access(filename, X_OK) != 0)
|
if (access(filename, X_OK) != 0)
|
||||||
|
@ -1208,7 +1214,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||||
if (lwp == RT_NULL)
|
if (lwp == RT_NULL)
|
||||||
{
|
{
|
||||||
dbg_log(DBG_ERROR, "lwp struct out of memory!\n");
|
dbg_log(DBG_ERROR, "lwp struct out of memory!\n");
|
||||||
return -RT_ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
LOG_D("lwp malloc : %p, size: %d!", lwp, sizeof(struct rt_lwp));
|
LOG_D("lwp malloc : %p, size: %d!", lwp, sizeof(struct rt_lwp));
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,6 @@ char *lwp_getcwd(void);
|
||||||
void lwp_request_thread_exit(rt_thread_t thread_to_exit);
|
void lwp_request_thread_exit(rt_thread_t thread_to_exit);
|
||||||
int lwp_check_exit_request(void);
|
int lwp_check_exit_request(void);
|
||||||
void lwp_terminate(struct rt_lwp *lwp);
|
void lwp_terminate(struct rt_lwp *lwp);
|
||||||
void lwp_wait_subthread_exit(void);
|
|
||||||
|
|
||||||
int lwp_tid_init(void);
|
int lwp_tid_init(void);
|
||||||
int lwp_tid_get(void);
|
int lwp_tid_get(void);
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
* 2023-07-27 shell Move the detach of children process on parent exit to lwp_terminate.
|
* 2023-07-27 shell Move the detach of children process on parent exit to lwp_terminate.
|
||||||
* Make lwp_from_pid locked by caller to avoid possible use-after-free
|
* Make lwp_from_pid locked by caller to avoid possible use-after-free
|
||||||
* error
|
* error
|
||||||
|
* 2023-10-27 shell Format codes of sys_exit(). Fix the data racing where lock is missed
|
||||||
|
* Add reference on pid/tid, so the resource is not freed while using.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rthw.h>
|
#include <rthw.h>
|
||||||
|
@ -149,6 +151,8 @@ void lwp_pid_put(struct rt_lwp *lwp)
|
||||||
|
|
||||||
/* reset pid field */
|
/* reset pid field */
|
||||||
lwp->pid = 0;
|
lwp->pid = 0;
|
||||||
|
/* clear reference */
|
||||||
|
lwp_ref_dec(lwp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lwp_pid_set_lwp_locked(pid_t pid, struct rt_lwp *lwp)
|
static void lwp_pid_set_lwp_locked(pid_t pid, struct rt_lwp *lwp)
|
||||||
|
@ -159,6 +163,7 @@ static void lwp_pid_set_lwp_locked(pid_t pid, struct rt_lwp *lwp)
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
p->data = lwp;
|
p->data = lwp;
|
||||||
|
lwp_ref_inc(lwp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,8 +398,9 @@ void lwp_free(struct rt_lwp* lwp)
|
||||||
* - lwp (RW. there is no other writer/reader compete with lwp_free, since
|
* - lwp (RW. there is no other writer/reader compete with lwp_free, since
|
||||||
* all the reference is clear)
|
* all the reference is clear)
|
||||||
*/
|
*/
|
||||||
LOG_D("lwp free: %p\n", lwp);
|
LOG_D("lwp free: %p", lwp);
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
|
||||||
if (lwp->args != RT_NULL)
|
if (lwp->args != RT_NULL)
|
||||||
{
|
{
|
||||||
|
@ -407,18 +413,8 @@ void lwp_free(struct rt_lwp* lwp)
|
||||||
lwp->args = RT_NULL;
|
lwp->args = RT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lwp->fdt.fds != RT_NULL)
|
|
||||||
{
|
|
||||||
/* auto clean fds */
|
|
||||||
__exit_files(lwp);
|
|
||||||
rt_free(lwp->fdt.fds);
|
|
||||||
lwp->fdt.fds = RT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lwp_user_object_clear(lwp);
|
lwp_user_object_clear(lwp);
|
||||||
lwp_user_object_lock_destroy(lwp);
|
lwp_user_object_lock_destroy(lwp);
|
||||||
RT_ASSERT(lwp->lwp_lock.owner == RT_NULL);
|
|
||||||
rt_mutex_detach(&lwp->lwp_lock);
|
|
||||||
|
|
||||||
/* free data section */
|
/* free data section */
|
||||||
if (lwp->data_entry != RT_NULL)
|
if (lwp->data_entry != RT_NULL)
|
||||||
|
@ -453,27 +449,134 @@ void lwp_free(struct rt_lwp* lwp)
|
||||||
lwp_unmap_user_space(lwp);
|
lwp_unmap_user_space(lwp);
|
||||||
#endif
|
#endif
|
||||||
timer_list_free(&lwp->timer);
|
timer_list_free(&lwp->timer);
|
||||||
/* for children */
|
|
||||||
while (lwp->first_child)
|
|
||||||
{
|
|
||||||
struct rt_lwp *child;
|
|
||||||
|
|
||||||
child = lwp->first_child;
|
LWP_UNLOCK(lwp);
|
||||||
lwp->first_child = child->sibling;
|
RT_ASSERT(lwp->lwp_lock.owner == RT_NULL);
|
||||||
if (child->terminated)
|
rt_mutex_detach(&lwp->lwp_lock);
|
||||||
{
|
|
||||||
lwp_pid_put(child);
|
/**
|
||||||
rt_free(child);
|
* pid must have release before enter lwp_free()
|
||||||
}
|
* otherwise this is a data racing
|
||||||
else
|
*/
|
||||||
{
|
RT_ASSERT(lwp->pid == 0);
|
||||||
/** Note: safe since the slist node is release */
|
rt_free(lwp);
|
||||||
child->sibling = RT_NULL;
|
}
|
||||||
/* Note: this may cause an orphan lwp */
|
|
||||||
child->parent = RT_NULL;
|
rt_inline rt_noreturn
|
||||||
}
|
void _thread_exit(rt_lwp_t lwp, rt_thread_t thread)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Note: the tid tree always hold a reference to thread, hence the tid must
|
||||||
|
* be release before cleanup of thread
|
||||||
|
*/
|
||||||
|
lwp_tid_put(thread->tid);
|
||||||
|
thread->tid = 0;
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
rt_list_remove(&thread->sibling);
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
|
rt_thread_delete(thread);
|
||||||
|
rt_schedule();
|
||||||
|
while (1) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_inline void _clear_child_tid(rt_thread_t thread)
|
||||||
|
{
|
||||||
|
if (thread->clear_child_tid)
|
||||||
|
{
|
||||||
|
int t = 0;
|
||||||
|
int *clear_child_tid = thread->clear_child_tid;
|
||||||
|
|
||||||
|
thread->clear_child_tid = RT_NULL;
|
||||||
|
lwp_put_to_user(clear_child_tid, &t, sizeof t);
|
||||||
|
sys_futex(clear_child_tid, FUTEX_WAKE | FUTEX_PRIVATE, 1, RT_NULL, RT_NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lwp_exit(rt_lwp_t lwp, rt_base_t status)
|
||||||
|
{
|
||||||
|
rt_thread_t thread;
|
||||||
|
|
||||||
|
if (!lwp)
|
||||||
|
{
|
||||||
|
LOG_W("%s: lwp should not be null", __func__);
|
||||||
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread = rt_thread_self();
|
||||||
|
RT_ASSERT((struct rt_lwp *)thread->lwp == lwp);
|
||||||
|
LOG_D("process(lwp.pid=%d) exit", lwp->pid);
|
||||||
|
|
||||||
|
#ifdef ARCH_MM_MMU
|
||||||
|
_clear_child_tid(thread);
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
/**
|
||||||
|
* Brief: only one thread should calls exit_group(),
|
||||||
|
* but we can not ensured that during run-time
|
||||||
|
*/
|
||||||
|
lwp->lwp_ret = LWP_CREATE_STAT(status);
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
|
lwp_terminate(lwp);
|
||||||
|
#else
|
||||||
|
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||||
|
if (main_thread == tid)
|
||||||
|
{
|
||||||
|
rt_thread_t sub_thread;
|
||||||
|
rt_list_t *list;
|
||||||
|
|
||||||
|
lwp_terminate(lwp);
|
||||||
|
|
||||||
|
/* delete all subthread */
|
||||||
|
while ((list = tid->sibling.prev) != &lwp->t_grp)
|
||||||
|
{
|
||||||
|
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||||
|
rt_list_remove(&sub_thread->sibling);
|
||||||
|
rt_thread_delete(sub_thread);
|
||||||
|
}
|
||||||
|
lwp->lwp_ret = value;
|
||||||
|
}
|
||||||
|
#endif /* ARCH_MM_MMU */
|
||||||
|
|
||||||
|
_thread_exit(lwp, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lwp_thread_exit(rt_thread_t thread, rt_base_t status)
|
||||||
|
{
|
||||||
|
rt_thread_t header_thr;
|
||||||
|
struct rt_lwp *lwp;
|
||||||
|
|
||||||
|
LOG_D("%s", __func__);
|
||||||
|
|
||||||
|
RT_ASSERT(thread == rt_thread_self());
|
||||||
|
lwp = (struct rt_lwp *)thread->lwp;
|
||||||
|
RT_ASSERT(lwp != RT_NULL);
|
||||||
|
|
||||||
|
#ifdef ARCH_MM_MMU
|
||||||
|
_clear_child_tid(thread);
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
header_thr = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||||
|
if (header_thr == thread && thread->sibling.prev == &lwp->t_grp)
|
||||||
|
{
|
||||||
|
lwp->lwp_ret = LWP_CREATE_STAT(status);
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
|
lwp_terminate(lwp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
}
|
||||||
|
#endif /* ARCH_MM_MMU */
|
||||||
|
|
||||||
|
_thread_exit(lwp, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _pop_tty(rt_lwp_t lwp)
|
||||||
|
{
|
||||||
if (!lwp->background)
|
if (!lwp->background)
|
||||||
{
|
{
|
||||||
struct termios *old_stdin_termios = get_old_termios();
|
struct termios *old_stdin_termios = get_old_termios();
|
||||||
|
@ -497,36 +600,11 @@ void lwp_free(struct rt_lwp* lwp)
|
||||||
}
|
}
|
||||||
rt_mutex_release(&lwp->tty->lock);
|
rt_mutex_release(&lwp->tty->lock);
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
lwp->tty = RT_NULL;
|
lwp->tty = RT_NULL;
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for parent */
|
|
||||||
if (lwp->parent)
|
|
||||||
{
|
|
||||||
struct rt_thread *thread;
|
|
||||||
if (!rt_list_isempty(&lwp->wait_list))
|
|
||||||
{
|
|
||||||
thread = rt_list_entry(lwp->wait_list.next, struct rt_thread, tlist);
|
|
||||||
thread->error = RT_EOK;
|
|
||||||
thread->msg_ret = (void*)(rt_size_t)lwp->lwp_ret;
|
|
||||||
rt_thread_resume(thread);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
struct rt_lwp **it = &lwp->parent->first_child;
|
|
||||||
|
|
||||||
while (*it != lwp)
|
|
||||||
{
|
|
||||||
it = &(*it)->sibling;
|
|
||||||
}
|
|
||||||
*it = lwp->sibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lwp_pid_put(lwp);
|
|
||||||
rt_free(lwp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @note the reference is not for synchronization, but for the release of resource. the synchronization is done through lwp & pid lock */
|
/** @note the reference is not for synchronization, but for the release of resource. the synchronization is done through lwp & pid lock */
|
||||||
|
@ -689,13 +767,29 @@ static sysret_t _lwp_wait_and_recycle(struct rt_lwp *child, rt_thread_t cur_thr,
|
||||||
rt_list_insert_before(&child->wait_list, &(cur_thr->tlist));
|
rt_list_insert_before(&child->wait_list, &(cur_thr->tlist));
|
||||||
LWP_UNLOCK(child);
|
LWP_UNLOCK(child);
|
||||||
|
|
||||||
|
rt_set_errno(RT_EINTR);
|
||||||
rt_exit_critical();
|
rt_exit_critical();
|
||||||
rt_schedule();
|
rt_schedule();
|
||||||
|
|
||||||
if (child->terminated)
|
/**
|
||||||
error = child->pid;
|
* Since parent is holding a reference to children this lock will
|
||||||
|
* not be freed before parent dereference to it.
|
||||||
|
*/
|
||||||
|
LWP_LOCK(child);
|
||||||
|
|
||||||
|
error = rt_get_errno();
|
||||||
|
if (error == RT_EINTR)
|
||||||
|
{
|
||||||
|
error = -EINTR;
|
||||||
|
}
|
||||||
|
else if (error != RT_EOK)
|
||||||
|
{
|
||||||
|
LOG_W("%s: unexpected error code %ld", __func__, error);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
error = -RT_EINTR;
|
{
|
||||||
|
error = child->pid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rt_exit_critical();
|
rt_exit_critical();
|
||||||
|
@ -705,18 +799,18 @@ static sysret_t _lwp_wait_and_recycle(struct rt_lwp *child, rt_thread_t cur_thr,
|
||||||
|
|
||||||
lwp_stat = child->lwp_ret;
|
lwp_stat = child->lwp_ret;
|
||||||
terminated = child->terminated;
|
terminated = child->terminated;
|
||||||
if (!terminated)
|
LWP_UNLOCK(child);
|
||||||
LWP_UNLOCK(child);
|
|
||||||
|
|
||||||
if (error > 0)
|
if (error > 0)
|
||||||
{
|
{
|
||||||
if (terminated)
|
if (terminated)
|
||||||
{
|
{
|
||||||
|
LOG_D("func %s: child detached", __func__);
|
||||||
/** Reap the child process if it's exited */
|
/** Reap the child process if it's exited */
|
||||||
lwp_children_unregister(self_lwp, child);
|
|
||||||
child->parent = RT_NULL;
|
|
||||||
lwp_pid_put(child);
|
lwp_pid_put(child);
|
||||||
|
lwp_children_unregister(self_lwp, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
lwp_data_put(self_lwp, status, &lwp_stat, sizeof(*status));
|
lwp_data_put(self_lwp, status, &lwp_stat, sizeof(*status));
|
||||||
}
|
}
|
||||||
|
@ -880,16 +974,15 @@ long list_process(void)
|
||||||
|
|
||||||
thread = threads[index];
|
thread = threads[index];
|
||||||
|
|
||||||
/** FIXME: take the rt_thread_t lock */
|
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||||
level = rt_hw_interrupt_disable();
|
|
||||||
if ((rt_object_get_type(&thread->parent) & ~RT_Object_Class_Static) != RT_Object_Class_Thread)
|
if ((rt_object_get_type(&thread->parent) & ~RT_Object_Class_Static) != RT_Object_Class_Thread)
|
||||||
{
|
{
|
||||||
rt_hw_interrupt_enable(level);
|
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_memcpy(&th, thread, sizeof(struct rt_thread));
|
rt_memcpy(&th, thread, sizeof(struct rt_thread));
|
||||||
rt_hw_interrupt_enable(level);
|
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||||
|
|
||||||
if (th.lwp == RT_NULL)
|
if (th.lwp == RT_NULL)
|
||||||
{
|
{
|
||||||
|
@ -989,8 +1082,7 @@ static int found_thread(struct rt_lwp* lwp, rt_thread_t thread)
|
||||||
rt_base_t level;
|
rt_base_t level;
|
||||||
rt_list_t *list;
|
rt_list_t *list;
|
||||||
|
|
||||||
/** FIXME: take the rt_thread_t lock */
|
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||||
level = rt_hw_interrupt_disable();
|
|
||||||
list = lwp->t_grp.next;
|
list = lwp->t_grp.next;
|
||||||
while (list != &lwp->t_grp)
|
while (list != &lwp->t_grp)
|
||||||
{
|
{
|
||||||
|
@ -1004,7 +1096,7 @@ static int found_thread(struct rt_lwp* lwp, rt_thread_t thread)
|
||||||
}
|
}
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
rt_hw_interrupt_enable(level);
|
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,8 +1114,7 @@ void lwp_request_thread_exit(rt_thread_t thread_to_exit)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: take the rt_thread_t lock */
|
level = rt_spin_lock_irqsave(&thread_to_exit->spinlock);
|
||||||
level = rt_hw_interrupt_disable();
|
|
||||||
|
|
||||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||||
if (thread_to_exit == main_thread)
|
if (thread_to_exit == main_thread)
|
||||||
|
@ -1063,14 +1154,15 @@ void lwp_request_thread_exit(rt_thread_t thread_to_exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
rt_hw_interrupt_enable(level);
|
rt_spin_unlock_irqrestore(&thread_to_exit->spinlock, level);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _wait_sibling_exit(rt_lwp_t lwp, rt_thread_t curr_thread);
|
||||||
|
static void _resr_cleanup(struct rt_lwp *lwp);
|
||||||
|
|
||||||
void lwp_terminate(struct rt_lwp *lwp)
|
void lwp_terminate(struct rt_lwp *lwp)
|
||||||
{
|
{
|
||||||
rt_list_t *list;
|
|
||||||
|
|
||||||
if (!lwp)
|
if (!lwp)
|
||||||
{
|
{
|
||||||
/* kernel thread not support */
|
/* kernel thread not support */
|
||||||
|
@ -1085,46 +1177,50 @@ void lwp_terminate(struct rt_lwp *lwp)
|
||||||
{
|
{
|
||||||
/* stop the receiving of signals */
|
/* stop the receiving of signals */
|
||||||
lwp->terminated = RT_TRUE;
|
lwp->terminated = RT_TRUE;
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
/* broadcast exit request for sibling threads */
|
_wait_sibling_exit(lwp, rt_thread_self());
|
||||||
for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
|
_resr_cleanup(lwp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _wait_sibling_exit(rt_lwp_t lwp, rt_thread_t curr_thread)
|
||||||
|
{
|
||||||
|
rt_base_t level;
|
||||||
|
rt_list_t *list;
|
||||||
|
rt_thread_t thread;
|
||||||
|
|
||||||
|
/* broadcast exit request for sibling threads */
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
|
||||||
|
{
|
||||||
|
thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||||
|
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||||
|
if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
|
||||||
{
|
{
|
||||||
rt_thread_t thread;
|
thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
|
||||||
|
}
|
||||||
|
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||||
|
|
||||||
thread = rt_list_entry(list, struct rt_thread, sibling);
|
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||||
if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
|
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
|
||||||
{
|
{
|
||||||
thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
|
thread->error = RT_EINTR;
|
||||||
}
|
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||||
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
|
|
||||||
{
|
rt_hw_dsb();
|
||||||
thread->error = RT_EINTR;
|
rt_thread_wakeup(thread);
|
||||||
rt_hw_dsb();
|
}
|
||||||
rt_thread_wakeup(thread);
|
else
|
||||||
}
|
{
|
||||||
|
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LWP_UNLOCK(lwp);
|
LWP_UNLOCK(lwp);
|
||||||
}
|
|
||||||
|
|
||||||
void lwp_wait_subthread_exit(void)
|
|
||||||
{
|
|
||||||
struct rt_lwp *lwp;
|
|
||||||
rt_thread_t thread;
|
|
||||||
rt_thread_t main_thread;
|
|
||||||
|
|
||||||
lwp = lwp_self();
|
|
||||||
if (!lwp)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread = rt_thread_self();
|
|
||||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
|
||||||
if (thread != main_thread)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -1138,7 +1234,7 @@ void lwp_wait_subthread_exit(void)
|
||||||
* - sibling list of lwp (RW. It will clear all siblings finally)
|
* - sibling list of lwp (RW. It will clear all siblings finally)
|
||||||
*/
|
*/
|
||||||
LWP_LOCK(lwp);
|
LWP_LOCK(lwp);
|
||||||
subthread_is_terminated = (int)(thread->sibling.prev == &lwp->t_grp);
|
subthread_is_terminated = (int)(curr_thread->sibling.prev == &lwp->t_grp);
|
||||||
if (!subthread_is_terminated)
|
if (!subthread_is_terminated)
|
||||||
{
|
{
|
||||||
rt_thread_t sub_thread;
|
rt_thread_t sub_thread;
|
||||||
|
@ -1146,7 +1242,7 @@ void lwp_wait_subthread_exit(void)
|
||||||
int all_subthread_in_init = 1;
|
int all_subthread_in_init = 1;
|
||||||
|
|
||||||
/* check all subthread is in init state */
|
/* check all subthread is in init state */
|
||||||
for (list = thread->sibling.prev; list != &lwp->t_grp; list = list->prev)
|
for (list = curr_thread->sibling.prev; list != &lwp->t_grp; list = list->prev)
|
||||||
{
|
{
|
||||||
|
|
||||||
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||||
|
@ -1159,7 +1255,7 @@ void lwp_wait_subthread_exit(void)
|
||||||
if (all_subthread_in_init)
|
if (all_subthread_in_init)
|
||||||
{
|
{
|
||||||
/* delete all subthread */
|
/* delete all subthread */
|
||||||
while ((list = thread->sibling.prev) != &lwp->t_grp)
|
while ((list = curr_thread->sibling.prev) != &lwp->t_grp)
|
||||||
{
|
{
|
||||||
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||||
rt_list_remove(&sub_thread->sibling);
|
rt_list_remove(&sub_thread->sibling);
|
||||||
|
@ -1187,13 +1283,104 @@ void lwp_wait_subthread_exit(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _resr_cleanup(struct rt_lwp *lwp)
|
||||||
|
{
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
lwp_signal_detach(&lwp->signal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Detach children from lwp
|
||||||
|
*
|
||||||
|
* @note Critical Section
|
||||||
|
* - the lwp (RW. Release lwp)
|
||||||
|
* - the pid resource manager (RW. Release the pid)
|
||||||
|
*/
|
||||||
|
while (lwp->first_child)
|
||||||
|
{
|
||||||
|
struct rt_lwp *child;
|
||||||
|
|
||||||
|
child = lwp->first_child;
|
||||||
|
lwp->first_child = child->sibling;
|
||||||
|
|
||||||
|
/** @note safe since the slist node is release */
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
LWP_LOCK(child);
|
||||||
|
child->sibling = RT_NULL;
|
||||||
|
/* info: this may cause an orphan lwp */
|
||||||
|
child->parent = RT_NULL;
|
||||||
|
LWP_UNLOCK(child);
|
||||||
|
lwp_ref_dec(child);
|
||||||
|
lwp_ref_dec(lwp);
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
}
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
|
_pop_tty(lwp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wakeup parent if it's waiting for this lwp, otherwise a signal
|
||||||
|
* will be sent to parent
|
||||||
|
*
|
||||||
|
* @note Critical Section
|
||||||
|
* - the parent lwp (RW.)
|
||||||
|
*/
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
if (lwp->parent)
|
||||||
|
{
|
||||||
|
struct rt_thread *thread;
|
||||||
|
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
if (!rt_list_isempty(&lwp->wait_list))
|
||||||
|
{
|
||||||
|
thread = rt_list_entry(lwp->wait_list.next, struct rt_thread, tlist);
|
||||||
|
thread->error = RT_EOK;
|
||||||
|
thread->msg_ret = (void*)(rt_size_t)lwp->lwp_ret;
|
||||||
|
rt_thread_resume(thread);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* children cannot detach itself and must wait for parent to take care of it */
|
||||||
|
lwp_signal_kill(lwp->parent, SIGCHLD, CLD_EXITED, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
|
/* INFO: orphan hasn't parents to do the reap of pid */
|
||||||
|
lwp_pid_put(lwp);
|
||||||
|
}
|
||||||
|
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
if (lwp->fdt.fds != RT_NULL)
|
||||||
|
{
|
||||||
|
struct dfs_file **fds;
|
||||||
|
|
||||||
|
/* auto clean fds */
|
||||||
|
__exit_files(lwp);
|
||||||
|
fds = lwp->fdt.fds;
|
||||||
|
lwp->fdt.fds = RT_NULL;
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
|
||||||
|
rt_free(fds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int _lwp_setaffinity(pid_t pid, int cpu)
|
static int _lwp_setaffinity(pid_t pid, int cpu)
|
||||||
{
|
{
|
||||||
struct rt_lwp *lwp;
|
struct rt_lwp *lwp;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
lwp_pid_lock_take();
|
lwp_pid_lock_take();
|
||||||
lwp = lwp_from_pid_locked(pid);
|
if(pid == 0)
|
||||||
|
lwp = lwp_self();
|
||||||
|
else
|
||||||
|
lwp = lwp_from_pid_locked(pid);
|
||||||
if (lwp)
|
if (lwp)
|
||||||
{
|
{
|
||||||
#ifdef RT_USING_SMP
|
#ifdef RT_USING_SMP
|
||||||
|
|
|
@ -85,6 +85,9 @@ rt_inline void lwp_from_pid_release_lock(struct rt_lwp *lwp)
|
||||||
lwp_ref_dec(lwp);
|
lwp_ref_dec(lwp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lwp_thread_exit(rt_thread_t thread, rt_base_t status);
|
||||||
|
void lwp_exit(struct rt_lwp *lwp, rt_base_t status);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -298,12 +298,12 @@ static int _pthread_mutex_lock_timeout(void *umutex, struct timespec *timeout)
|
||||||
lwp_mutex_release_safe(&_pmutex_lock);
|
lwp_mutex_release_safe(&_pmutex_lock);
|
||||||
return -EDEADLK;
|
return -EDEADLK;
|
||||||
}
|
}
|
||||||
|
lwp_mutex_release_safe(&_pmutex_lock);
|
||||||
lock_ret = rt_mutex_take_interruptible(pmutex->lock.kmutex, time);
|
lock_ret = rt_mutex_take_interruptible(pmutex->lock.kmutex, time);
|
||||||
if (lock_ret == RT_EOK)
|
if (lock_ret == RT_EOK)
|
||||||
{
|
{
|
||||||
umutex_p->_m_lock = rt_thread_self()->tid;
|
umutex_p->_m_lock = rt_thread_self()->tid;
|
||||||
}
|
}
|
||||||
lwp_mutex_release_safe(&_pmutex_lock);
|
|
||||||
break;
|
break;
|
||||||
default: /* unknown type */
|
default: /* unknown type */
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -764,7 +764,6 @@ rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo,
|
||||||
rt_list_t *thread_list;
|
rt_list_t *thread_list;
|
||||||
rt_err_t ret = RT_EOK;
|
rt_err_t ret = RT_EOK;
|
||||||
|
|
||||||
|
|
||||||
if (lwp)
|
if (lwp)
|
||||||
{
|
{
|
||||||
/** acquire READ access to lwp */
|
/** acquire READ access to lwp */
|
||||||
|
|
|
@ -328,104 +328,35 @@ static void _crt_thread_entry(void *parameter)
|
||||||
/* exit group */
|
/* exit group */
|
||||||
sysret_t sys_exit_group(int value)
|
sysret_t sys_exit_group(int value)
|
||||||
{
|
{
|
||||||
rt_thread_t tid, main_thread;
|
sysret_t rc = 0;
|
||||||
struct rt_lwp *lwp;
|
struct rt_lwp *lwp = lwp_self();
|
||||||
|
|
||||||
tid = rt_thread_self();
|
if (lwp)
|
||||||
lwp = (struct rt_lwp *)tid->lwp;
|
lwp_exit(lwp, value);
|
||||||
LOG_D("process(%p) exit.", lwp);
|
else
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
if (tid->clear_child_tid)
|
|
||||||
{
|
{
|
||||||
int t = 0;
|
LOG_E("Can't find matching process of current thread");
|
||||||
int *clear_child_tid = tid->clear_child_tid;
|
rc = -EINVAL;
|
||||||
|
|
||||||
tid->clear_child_tid = RT_NULL;
|
|
||||||
lwp_put_to_user(clear_child_tid, &t, sizeof t);
|
|
||||||
sys_futex(clear_child_tid, FUTEX_WAKE | FUTEX_PRIVATE, 1, RT_NULL, RT_NULL, 0);
|
|
||||||
}
|
}
|
||||||
lwp_terminate(lwp);
|
|
||||||
|
|
||||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
return rc;
|
||||||
if (main_thread == tid)
|
|
||||||
{
|
|
||||||
lwp_wait_subthread_exit();
|
|
||||||
lwp->lwp_ret = LWP_CREATE_STAT(value);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
|
||||||
if (main_thread == tid)
|
|
||||||
{
|
|
||||||
rt_thread_t sub_thread;
|
|
||||||
rt_list_t *list;
|
|
||||||
|
|
||||||
lwp_terminate(lwp);
|
|
||||||
|
|
||||||
/* delete all subthread */
|
|
||||||
while ((list = tid->sibling.prev) != &lwp->t_grp)
|
|
||||||
{
|
|
||||||
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
|
||||||
rt_list_remove(&sub_thread->sibling);
|
|
||||||
rt_thread_delete(sub_thread);
|
|
||||||
}
|
|
||||||
lwp->lwp_ret = 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_schedule();
|
|
||||||
|
|
||||||
/* never reach here */
|
|
||||||
RT_ASSERT(0);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* thread exit */
|
/* thread exit */
|
||||||
void sys_exit(int status)
|
sysret_t sys_exit(int status)
|
||||||
{
|
{
|
||||||
rt_thread_t tid, main_thread;
|
sysret_t rc = 0;
|
||||||
struct rt_lwp *lwp;
|
rt_thread_t tid;
|
||||||
|
|
||||||
LOG_D("thread exit");
|
|
||||||
|
|
||||||
tid = rt_thread_self();
|
tid = rt_thread_self();
|
||||||
lwp = (struct rt_lwp *)tid->lwp;
|
if (tid && tid->lwp)
|
||||||
|
lwp_thread_exit(tid, status);
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
if (tid->clear_child_tid)
|
|
||||||
{
|
{
|
||||||
int t = 0;
|
LOG_E("Can't find matching process of current thread");
|
||||||
int *clear_child_tid = tid->clear_child_tid;
|
rc = -EINVAL;
|
||||||
|
|
||||||
tid->clear_child_tid = RT_NULL;
|
|
||||||
lwp_put_to_user(clear_child_tid, &t, sizeof t);
|
|
||||||
sys_futex(clear_child_tid, FUTEX_WAKE, 1, RT_NULL, RT_NULL, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
return rc;
|
||||||
if (main_thread == tid && tid->sibling.prev == &lwp->t_grp)
|
|
||||||
{
|
|
||||||
lwp_terminate(lwp);
|
|
||||||
lwp_wait_subthread_exit();
|
|
||||||
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_schedule();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* syscall: "read" ret: "ssize_t" args: "int" "void *" "size_t" */
|
/* syscall: "read" ret: "ssize_t" args: "int" "void *" "size_t" */
|
||||||
|
@ -1174,18 +1105,28 @@ sysret_t sys_getpid(void)
|
||||||
/* syscall: "getpriority" ret: "int" args: "int" "id_t" */
|
/* syscall: "getpriority" ret: "int" args: "int" "id_t" */
|
||||||
sysret_t sys_getpriority(int which, id_t who)
|
sysret_t sys_getpriority(int which, id_t who)
|
||||||
{
|
{
|
||||||
|
long prio = 0xff;
|
||||||
|
|
||||||
if (which == PRIO_PROCESS)
|
if (which == PRIO_PROCESS)
|
||||||
{
|
{
|
||||||
rt_thread_t tid;
|
struct rt_lwp *lwp = RT_NULL;
|
||||||
|
|
||||||
tid = rt_thread_self();
|
lwp_pid_lock_take();
|
||||||
if (who == (id_t)(rt_size_t)tid || who == 0xff)
|
if(who == 0)
|
||||||
|
lwp = lwp_self();
|
||||||
|
else
|
||||||
|
lwp = lwp_from_pid_locked(who);
|
||||||
|
|
||||||
|
if (lwp)
|
||||||
{
|
{
|
||||||
return tid->current_priority;
|
rt_thread_t thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||||
|
prio = thread->current_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lwp_pid_lock_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0xff;
|
return prio;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* syscall: "setpriority" ret: "int" args: "int" "id_t" "int" */
|
/* syscall: "setpriority" ret: "int" args: "int" "id_t" "int" */
|
||||||
|
@ -1193,14 +1134,30 @@ sysret_t sys_setpriority(int which, id_t who, int prio)
|
||||||
{
|
{
|
||||||
if (which == PRIO_PROCESS)
|
if (which == PRIO_PROCESS)
|
||||||
{
|
{
|
||||||
rt_thread_t tid;
|
struct rt_lwp *lwp = RT_NULL;
|
||||||
|
|
||||||
tid = rt_thread_self();
|
lwp_pid_lock_take();
|
||||||
if ((who == (id_t)(rt_size_t)tid || who == 0xff) && (prio >= 0 && prio < RT_THREAD_PRIORITY_MAX))
|
if(who == 0)
|
||||||
|
lwp = lwp_self();
|
||||||
|
else
|
||||||
|
lwp = lwp_from_pid_locked(who);
|
||||||
|
|
||||||
|
if (lwp && prio >= 0 && prio < RT_THREAD_PRIORITY_MAX)
|
||||||
{
|
{
|
||||||
rt_thread_control(tid, RT_THREAD_CTRL_CHANGE_PRIORITY, &prio);
|
rt_list_t *list;
|
||||||
|
rt_thread_t thread;
|
||||||
|
for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
|
||||||
|
{
|
||||||
|
thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||||
|
rt_thread_control(thread, RT_THREAD_CTRL_CHANGE_PRIORITY, &prio);
|
||||||
|
}
|
||||||
|
lwp_pid_lock_release();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2790,6 +2747,7 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
|
||||||
* Since no other threads can access the lwp field, it't uneccessary to
|
* Since no other threads can access the lwp field, it't uneccessary to
|
||||||
* take a lock here
|
* take a lock here
|
||||||
*/
|
*/
|
||||||
|
RT_ASSERT(rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling) == thread);
|
||||||
|
|
||||||
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);
|
strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX);
|
||||||
|
@ -5560,7 +5518,6 @@ sysret_t sys_sched_getscheduler(int tid, int *policy, void *param)
|
||||||
struct sched_param *sched_param = RT_NULL;
|
struct sched_param *sched_param = RT_NULL;
|
||||||
rt_thread_t thread = RT_NULL;
|
rt_thread_t thread = RT_NULL;
|
||||||
|
|
||||||
|
|
||||||
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
|
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
|
||||||
{
|
{
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
|
@ -48,7 +48,7 @@ typedef uint32_t id_t; /* may contain pid, uid or gid */
|
||||||
const char *lwp_get_syscall_name(rt_uint32_t number);
|
const char *lwp_get_syscall_name(rt_uint32_t number);
|
||||||
const void *lwp_get_sys_api(rt_uint32_t number);
|
const void *lwp_get_sys_api(rt_uint32_t number);
|
||||||
|
|
||||||
void sys_exit(int value);
|
sysret_t sys_exit(int value);
|
||||||
sysret_t sys_exit_group(int status);
|
sysret_t sys_exit_group(int status);
|
||||||
ssize_t sys_read(int fd, void *buf, size_t nbyte);
|
ssize_t sys_read(int fd, void *buf, size_t nbyte);
|
||||||
ssize_t sys_write(int fd, const void *buf, size_t nbyte);
|
ssize_t sys_write(int fd, const void *buf, size_t nbyte);
|
||||||
|
|
|
@ -109,11 +109,67 @@ rt_err_t rt_aspace_anon_ref_dec(rt_mem_obj_t aobj)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rt_varea_pgmgr_insert(rt_varea_t varea, void *page_addr)
|
||||||
|
{
|
||||||
|
/* each mapping of page frame in the varea is binding with a reference */
|
||||||
|
rt_page_ref_inc(page_addr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private unmapping of address space
|
||||||
|
*/
|
||||||
|
static void _pgmgr_pop_all(rt_varea_t varea)
|
||||||
|
{
|
||||||
|
rt_aspace_t aspace = varea->aspace;
|
||||||
|
char *iter = varea->start;
|
||||||
|
char *end_addr = iter + varea->size;
|
||||||
|
|
||||||
|
RT_ASSERT(iter < end_addr);
|
||||||
|
RT_ASSERT(!((long)iter & ARCH_PAGE_MASK));
|
||||||
|
RT_ASSERT(!((long)end_addr & ARCH_PAGE_MASK));
|
||||||
|
|
||||||
|
for (; iter != end_addr; iter += ARCH_PAGE_SIZE)
|
||||||
|
{
|
||||||
|
void *page_pa = rt_hw_mmu_v2p(aspace, iter);
|
||||||
|
char *page_va = rt_kmem_p2v(page_pa);
|
||||||
|
if (page_pa != ARCH_MAP_FAILED && page_va)
|
||||||
|
{
|
||||||
|
rt_hw_mmu_unmap(aspace, iter, ARCH_PAGE_SIZE);
|
||||||
|
rt_pages_free(page_va, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _pgmgr_pop_range(rt_varea_t varea, void *rm_start, void *rm_end)
|
||||||
|
{
|
||||||
|
void *page_va;
|
||||||
|
|
||||||
|
RT_ASSERT(!((rt_ubase_t)rm_start & ARCH_PAGE_MASK));
|
||||||
|
RT_ASSERT(!((rt_ubase_t)rm_end & ARCH_PAGE_MASK));
|
||||||
|
while (rm_start != rm_end)
|
||||||
|
{
|
||||||
|
page_va = rt_hw_mmu_v2p(varea->aspace, rm_start);
|
||||||
|
|
||||||
|
if (page_va != ARCH_MAP_FAILED)
|
||||||
|
{
|
||||||
|
page_va -= PV_OFFSET;
|
||||||
|
LOG_D("%s: free page %p", __func__, page_va);
|
||||||
|
rt_varea_unmap_page(varea, rm_start);
|
||||||
|
rt_pages_free(page_va, 0);
|
||||||
|
}
|
||||||
|
rm_start += ARCH_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char *_anon_get_name(rt_varea_t varea)
|
static const char *_anon_get_name(rt_varea_t varea)
|
||||||
{
|
{
|
||||||
return varea->aspace == _anon_obj_get_backup(varea->mem_obj) ? "anonymous" : "reference";
|
return varea->aspace == _anon_obj_get_backup(varea->mem_obj) ? "anonymous" : "reference";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration handler on varea re-construction
|
||||||
|
*/
|
||||||
|
|
||||||
static void _anon_varea_open(struct rt_varea *varea)
|
static void _anon_varea_open(struct rt_varea *varea)
|
||||||
{
|
{
|
||||||
rt_aspace_anon_ref_inc(varea->mem_obj);
|
rt_aspace_anon_ref_inc(varea->mem_obj);
|
||||||
|
@ -127,7 +183,9 @@ static void _anon_varea_open(struct rt_varea *varea)
|
||||||
static void _anon_varea_close(struct rt_varea *varea)
|
static void _anon_varea_close(struct rt_varea *varea)
|
||||||
{
|
{
|
||||||
rt_aspace_anon_ref_dec(varea->mem_obj);
|
rt_aspace_anon_ref_dec(varea->mem_obj);
|
||||||
rt_mm_dummy_mapper.on_varea_close(varea);
|
|
||||||
|
/* unmap and dereference page frames in the varea region */
|
||||||
|
_pgmgr_pop_all(varea);
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t _anon_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
|
static rt_err_t _anon_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
|
||||||
|
@ -137,21 +195,45 @@ static rt_err_t _anon_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_s
|
||||||
|
|
||||||
static rt_err_t _anon_varea_shrink(rt_varea_t varea, void *new_start, rt_size_t size)
|
static rt_err_t _anon_varea_shrink(rt_varea_t varea, void *new_start, rt_size_t size)
|
||||||
{
|
{
|
||||||
return rt_mm_dummy_mapper.on_varea_shrink(varea, new_start, size);
|
char *varea_start = varea->start;
|
||||||
|
void *rm_start;
|
||||||
|
void *rm_end;
|
||||||
|
|
||||||
|
if (varea_start == (char *)new_start)
|
||||||
|
{
|
||||||
|
rm_start = varea_start + size;
|
||||||
|
rm_end = varea_start + varea->size;
|
||||||
|
}
|
||||||
|
else /* if (varea_start < (char *)new_start) */
|
||||||
|
{
|
||||||
|
RT_ASSERT(varea_start < (char *)new_start);
|
||||||
|
rm_start = varea_start;
|
||||||
|
rm_end = new_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pgmgr_pop_range(varea, rm_start, rm_end);
|
||||||
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t _anon_varea_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
|
static rt_err_t _anon_varea_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
|
||||||
{
|
{
|
||||||
|
/* remove the resource in the unmap region, and do nothing for the subset */
|
||||||
|
_pgmgr_pop_range(existed, unmap_start, (char *)unmap_start + unmap_len);
|
||||||
|
|
||||||
_anon_varea_open(subset);
|
_anon_varea_open(subset);
|
||||||
return rt_mm_dummy_mapper.on_varea_split(existed, unmap_start, unmap_len, subset);
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t _anon_varea_merge(struct rt_varea *merge_to, struct rt_varea *merge_from)
|
static rt_err_t _anon_varea_merge(struct rt_varea *merge_to, struct rt_varea *merge_from)
|
||||||
{
|
{
|
||||||
_anon_varea_close(merge_from);
|
/* do nothing for the varea merge */
|
||||||
return rt_mm_dummy_mapper.on_varea_merge(merge_to, merge_from);
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private mapping of address space
|
||||||
|
*/
|
||||||
|
|
||||||
rt_inline void _map_page_in_varea(rt_aspace_t asapce, rt_varea_t varea,
|
rt_inline void _map_page_in_varea(rt_aspace_t asapce, rt_varea_t varea,
|
||||||
struct rt_aspace_fault_msg *msg, char *fault_addr)
|
struct rt_aspace_fault_msg *msg, char *fault_addr)
|
||||||
{
|
{
|
||||||
|
@ -168,6 +250,7 @@ rt_inline void _map_page_in_varea(rt_aspace_t asapce, rt_varea_t varea,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* page frame inquiry or allocation in backup address space */
|
||||||
static void *_get_page_from_backup(rt_aspace_t backup, rt_base_t offset_in_mobj)
|
static void *_get_page_from_backup(rt_aspace_t backup, rt_base_t offset_in_mobj)
|
||||||
{
|
{
|
||||||
void *frame_pa;
|
void *frame_pa;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#define DBG_TAG "mm.object"
|
#define DBG_TAG "mm.object"
|
||||||
#define DBG_LVL DBG_INFO
|
#define DBG_LVL DBG_INFO
|
||||||
#include "rtdbg.h"
|
#include <rtdbg.h>
|
||||||
|
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
|
|
||||||
|
@ -31,31 +31,6 @@ static const char *get_name(rt_varea_t varea)
|
||||||
return "dummy-mapper";
|
return "dummy-mapper";
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_varea_pgmgr_insert(rt_varea_t varea, void *page_addr)
|
|
||||||
{
|
|
||||||
/* each mapping of page frame in the varea is binding with a reference */
|
|
||||||
rt_page_ref_inc(page_addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* resource recycling of page frames */
|
|
||||||
void rt_varea_pgmgr_pop_all(rt_varea_t varea)
|
|
||||||
{
|
|
||||||
rt_aspace_t aspace = varea->aspace;
|
|
||||||
char *end_addr = varea->start + varea->size;
|
|
||||||
RT_ASSERT(!((long)end_addr & ARCH_PAGE_MASK));
|
|
||||||
|
|
||||||
for (char *iter = varea->start; iter != end_addr; iter += ARCH_PAGE_SIZE)
|
|
||||||
{
|
|
||||||
void *page_pa = rt_hw_mmu_v2p(aspace, iter);
|
|
||||||
char *page_va = rt_kmem_p2v(page_pa);
|
|
||||||
if (page_pa != ARCH_MAP_FAILED && page_va)
|
|
||||||
{
|
|
||||||
rt_hw_mmu_unmap(aspace, iter, ARCH_PAGE_SIZE);
|
|
||||||
rt_pages_free(page_va, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_page_fault(struct rt_varea *varea, struct rt_aspace_fault_msg *msg)
|
static void on_page_fault(struct rt_varea *varea, struct rt_aspace_fault_msg *msg)
|
||||||
{
|
{
|
||||||
void *page;
|
void *page;
|
||||||
|
@ -79,8 +54,6 @@ static void on_varea_open(struct rt_varea *varea)
|
||||||
|
|
||||||
static void on_varea_close(struct rt_varea *varea)
|
static void on_varea_close(struct rt_varea *varea)
|
||||||
{
|
{
|
||||||
/* unmap and dereference page frames in the varea region */
|
|
||||||
rt_varea_pgmgr_pop_all(varea);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t on_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
|
static rt_err_t on_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
|
||||||
|
@ -88,60 +61,18 @@ static rt_err_t on_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _remove_pages(rt_varea_t varea, void *rm_start, void *rm_end)
|
|
||||||
{
|
|
||||||
void *page_va;
|
|
||||||
|
|
||||||
RT_ASSERT(!((rt_ubase_t)rm_start & ARCH_PAGE_MASK));
|
|
||||||
RT_ASSERT(!((rt_ubase_t)rm_end & ARCH_PAGE_MASK));
|
|
||||||
while (rm_start != rm_end)
|
|
||||||
{
|
|
||||||
page_va = rt_hw_mmu_v2p(varea->aspace, rm_start);
|
|
||||||
|
|
||||||
if (page_va != ARCH_MAP_FAILED)
|
|
||||||
{
|
|
||||||
page_va -= PV_OFFSET;
|
|
||||||
LOG_D("%s: free page %p", __func__, page_va);
|
|
||||||
rt_varea_unmap_page(varea, rm_start);
|
|
||||||
rt_pages_free(page_va, 0);
|
|
||||||
}
|
|
||||||
rm_start += ARCH_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static rt_err_t on_varea_shrink(rt_varea_t varea, void *new_start, rt_size_t size)
|
static rt_err_t on_varea_shrink(rt_varea_t varea, void *new_start, rt_size_t size)
|
||||||
{
|
{
|
||||||
char *varea_start = varea->start;
|
|
||||||
void *rm_start;
|
|
||||||
void *rm_end;
|
|
||||||
|
|
||||||
if (varea_start == (char *)new_start)
|
|
||||||
{
|
|
||||||
rm_start = varea_start + size;
|
|
||||||
rm_end = varea_start + varea->size;
|
|
||||||
}
|
|
||||||
else /* if (varea_start < (char *)new_start) */
|
|
||||||
{
|
|
||||||
RT_ASSERT(varea_start < (char *)new_start);
|
|
||||||
rm_start = varea_start;
|
|
||||||
rm_end = new_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
_remove_pages(varea, rm_start, rm_end);
|
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t on_varea_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
|
static rt_err_t on_varea_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
|
||||||
{
|
{
|
||||||
/* remove the resource in the unmap region, and do nothing for the subset */
|
|
||||||
_remove_pages(existed, unmap_start, (char *)unmap_start + unmap_len);
|
|
||||||
|
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t on_varea_merge(struct rt_varea *merge_to, struct rt_varea *merge_from)
|
static rt_err_t on_varea_merge(struct rt_varea *merge_to, struct rt_varea *merge_from)
|
||||||
{
|
{
|
||||||
/* do nothing for the migration */
|
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -863,8 +863,7 @@ int rt_page_install(rt_region_t region)
|
||||||
{
|
{
|
||||||
int err = -RT_EINVAL;
|
int err = -RT_EINVAL;
|
||||||
if (region.end != region.start && !(region.start & ARCH_PAGE_MASK) &&
|
if (region.end != region.start && !(region.start & ARCH_PAGE_MASK) &&
|
||||||
!(region.end & ARCH_PAGE_MASK) &&
|
!(region.end & ARCH_PAGE_MASK))
|
||||||
!((region.end - region.start) & shadow_mask))
|
|
||||||
{
|
{
|
||||||
void *head = addr_to_page(page_start, (void *)region.start);
|
void *head = addr_to_page(page_start, (void *)region.start);
|
||||||
void *tail = addr_to_page(page_start, (void *)region.end);
|
void *tail = addr_to_page(page_start, (void *)region.end);
|
||||||
|
|
|
@ -105,8 +105,6 @@ void _aspace_bst_insert(struct rt_aspace *aspace, struct rt_varea *varea);
|
||||||
*/
|
*/
|
||||||
void _aspace_bst_remove(struct rt_aspace *aspace, struct rt_varea *varea);
|
void _aspace_bst_remove(struct rt_aspace *aspace, struct rt_varea *varea);
|
||||||
|
|
||||||
void rt_varea_pgmgr_pop_all(rt_varea_t varea);
|
|
||||||
|
|
||||||
int rt_varea_fix_private_locked(rt_varea_t ex_varea, void *pa,
|
int rt_varea_fix_private_locked(rt_varea_t ex_varea, void *pa,
|
||||||
struct rt_aspace_fault_msg *msg,
|
struct rt_aspace_fault_msg *msg,
|
||||||
rt_bool_t dont_copy);
|
rt_bool_t dont_copy);
|
||||||
|
|
|
@ -67,7 +67,7 @@ static void test_user_map_varea(void)
|
||||||
uassert_true(varea->start != 0);
|
uassert_true(varea->start != 0);
|
||||||
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
|
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
|
||||||
|
|
||||||
uassert_true(!lwp_ref_dec(lwp));
|
uassert_true(!(lwp_ref_dec(lwp) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_user_map_varea_ext(void)
|
static void test_user_map_varea_ext(void)
|
||||||
|
@ -91,7 +91,7 @@ static void test_user_map_varea_ext(void)
|
||||||
uassert_true(varea->start != 0);
|
uassert_true(varea->start != 0);
|
||||||
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
|
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
|
||||||
|
|
||||||
uassert_true(!lwp_ref_dec(lwp));
|
uassert_true(!(lwp_ref_dec(lwp) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void user_map_varea_tc(void)
|
static void user_map_varea_tc(void)
|
||||||
|
|
|
@ -12,9 +12,9 @@ bsp_path = Dir('#').abspath
|
||||||
|
|
||||||
if not os.path.exists(bsp_path + "/link.lds"):
|
if not os.path.exists(bsp_path + "/link.lds"):
|
||||||
Env['LINKFLAGS'] = Env['LINKFLAGS'].replace('link.lds', cwd + "/link.lds")
|
Env['LINKFLAGS'] = Env['LINKFLAGS'].replace('link.lds', cwd + "/link.lds")
|
||||||
# fix the linker with crtx.o
|
|
||||||
Preprocessing("link.lds.S", ".lds", CPPPATH=[bsp_path])
|
Preprocessing("link.lds.S", ".lds", CPPPATH=[bsp_path])
|
||||||
|
|
||||||
|
# fix the linker with crtx.o
|
||||||
Env['LINKFLAGS'] += ' -nostartfiles'
|
Env['LINKFLAGS'] += ' -nostartfiles'
|
||||||
|
|
||||||
# add common code files
|
# add common code files
|
||||||
|
|
|
@ -373,6 +373,8 @@ void rt_hw_trap_exception(struct rt_hw_exp_stack *regs)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RT_USING_LWP
|
#ifdef RT_USING_LWP
|
||||||
|
/* restore normal execution environment */
|
||||||
|
__asm__ volatile("msr daifclr, 0x3\ndmb ishst\nisb\n");
|
||||||
_check_fault(regs, 0, "user fault");
|
_check_fault(regs, 0, "user fault");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue