diff --git a/components/drivers/tty/console.c b/components/drivers/tty/console.c index e5ca9dc153d783d3db1a208f50620817fb26baff..dc8e8257dd54230ed6e526db8a3960099681e570 100644 --- a/components/drivers/tty/console.c +++ b/components/drivers/tty/console.c @@ -295,7 +295,14 @@ rt_err_t console_register(const char *name, struct rt_device *iodev) console->type = TTY_DRIVER_TYPE_CONSOLE; console->subtype = SERIAL_TYPE_NORMAL; console->driver = iodev; + console->head = rt_calloc(1, sizeof(struct tty_node)); + if (!console->head) + { + return -RT_ENOMEM; + } + tty_initstack(console->head); + rt_spin_lock_init(&console->spinlock); console->pgrp = -1; console->session = -1; console->foreground = RT_NULL; diff --git a/components/drivers/tty/include/tty.h b/components/drivers/tty/include/tty.h index 681c472808cc301d15ceccb73fb193f2cecf4816..ff2e88ee5ffe89308ec994e77727b4409894d3df 100644 --- a/components/drivers/tty/include/tty.h +++ b/components/drivers/tty/include/tty.h @@ -23,6 +23,15 @@ #define current lwp_self() #define __DISABLED_CHAR '\0' +struct tty_node +{ + struct rt_lwp *lwp; + struct tty_node *next; +}; + +void tty_initstack(struct tty_node *node); +int tty_push(struct tty_node **head, struct rt_lwp *lwp); +struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp); /* * When a break, frame error, or parity error happens, these codes are * stuffed into the flags buffer. @@ -139,11 +148,15 @@ struct tty_struct struct winsize winsize; struct termios init_termios; - struct rt_mutex mutex; - +#ifdef RT_USING_SMP + struct rt_spinlock spinlock; +#else + rt_spinlock_t spinlock; +#endif pid_t pgrp; pid_t session; struct rt_lwp *foreground; + struct tty_node *head; struct tty_ldisc *ldisc; void *disc_data; diff --git a/components/drivers/tty/n_tty.c b/components/drivers/tty/n_tty.c index 4a2652d61899352281f7ad0de7e8f1ed79b8357c..5fe2e83761646ffa8041fc39e0ab4a313a72dcff 100644 --- a/components/drivers/tty/n_tty.c +++ b/components/drivers/tty/n_tty.c @@ -534,6 +534,8 @@ static void __isig(int sig, struct tty_struct *tty) { if (sig == SIGTSTP) { + struct rt_lwp *old_lwp; + rt_memcpy(&old_termios, &(tty->init_termios), sizeof(struct termios)); tty->init_termios = *new_termios; ld = tty->ldisc; @@ -545,7 +547,8 @@ static void __isig(int sig, struct tty_struct *tty) } } tty_sigaddset(&lwp->signal_mask, SIGTTOU); - tty->foreground = RT_NULL; + old_lwp = tty_pop(&tty->head, RT_NULL); + tty->foreground = old_lwp; } else { diff --git a/components/drivers/tty/pty.c b/components/drivers/tty/pty.c index 7233c1756616fdb7a84c035170f6c6024d4357ee..40b2c0f5524e751e1eee26cf56060ff575c737ed 100644 --- a/components/drivers/tty/pty.c +++ b/components/drivers/tty/pty.c @@ -341,7 +341,14 @@ static int ptmx_register(void) ptm_drv->type = TTY_DRIVER_TYPE_PTY; ptm_drv->subtype = PTY_TYPE_MASTER; + ptm_drv->head = rt_calloc(1, sizeof(struct tty_node)); + if (!ptm_drv->head) + { + return -RT_ENOMEM; + } + tty_initstack(ptm_drv->head); + rt_spin_lock_init(&ptm_drv->spinlock); ptm_drv->pgrp = -1; ptm_drv->session = -1; ptm_drv->foreground = RT_NULL; diff --git a/components/drivers/tty/tty.c b/components/drivers/tty/tty.c index cf718b4770eefb68961b19d1cacc2ca6fb5f8105..94d560d5ad6cdeadb0f9937cdf929e0b83de5dee 100644 --- a/components/drivers/tty/tty.c +++ b/components/drivers/tty/tty.c @@ -38,6 +38,93 @@ struct termios tty_std_termios = { /* for the benefit of tty drivers */ .__c_ospeed = 38400 }; +void tty_initstack(struct tty_node *node) +{ + node->lwp = RT_NULL; + node->next = node; +} + +static struct tty_node tty_node_cache = { RT_NULL, RT_NULL }; + +static struct tty_node *_tty_node_alloc(void) +{ + struct tty_node *node = tty_node_cache.next; + + if (node == RT_NULL) + { + node = rt_calloc(1, sizeof(struct tty_node)); + } + else + { + tty_node_cache.next = node->next; + } + + return node; +} + +static void _tty_node_free(struct tty_node *node) +{ + node->next = tty_node_cache.next; + tty_node_cache.next = node; +} + +int tty_push(struct tty_node **head, struct rt_lwp *lwp) +{ + struct tty_node *node = _tty_node_alloc(); + + if (!node) + { + return -1; + } + + node->lwp = lwp; + node->next = *head; + *head = node; + + return 0; +} + +struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp) +{ + struct tty_node *node; + struct rt_lwp *lwp = RT_NULL; + + if (!head || !*head) + { + return RT_NULL; + } + + node = *head; + + if (target_lwp != RT_NULL && node->lwp != target_lwp) + { + struct tty_node *prev = RT_NULL; + + while (node != RT_NULL && node->lwp != target_lwp) + { + prev = node; + node = node->next; + } + + if (node != RT_NULL) + { + /* prev is impossible equ RT_NULL */ + prev->next = node->next; + lwp = target_lwp; + _tty_node_free(node); + } + } + else + { + lwp = (*head)->lwp; + *head = (*head)->next; + node->lwp = RT_NULL; + _tty_node_free(node); + } + + return lwp; +} + rt_inline int tty_sigismember(lwp_sigset_t *set, int _sig) { unsigned long sig = _sig - 1; diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index a14782d11071a12f3e07a225a6d02ab1e68f25b1..99d5f5bed366dfd24a1d4618344c5f08d8d190ce 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -1008,6 +1008,7 @@ void lwp_cleanup(struct rt_thread *tid) { rt_base_t level; struct rt_lwp *lwp; + struct tty_node *tty_head = RT_NULL; if (tid == NULL) { @@ -1022,8 +1023,18 @@ void lwp_cleanup(struct rt_thread *tid) lwp_tid_put(tid->tid); rt_list_remove(&tid->sibling); rt_hw_interrupt_enable(level); - lwp_ref_dec(lwp); - + if (lwp->tty != RT_NULL) + { + tty_head = lwp->tty->head; + } + if (!lwp_ref_dec(lwp)) + { + if (tty_head) + { + tty_pop(&tty_head, lwp); + } + } + return; } @@ -1097,6 +1108,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) int bg = 0; struct process_aux *aux; int tid = 0; + int ret; if (filename == RT_NULL) { @@ -1201,7 +1213,20 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) if (lwp->session == -1) { struct tty_struct *tty = RT_NULL; + struct rt_lwp *old_lwp; tty = (struct tty_struct *)console_tty_get(); + old_lwp = tty->foreground; + rt_spin_lock(&tty->spinlock); + ret = tty_push(&tty->head, old_lwp); + rt_spin_unlock(&tty->spinlock); + if (ret < 0) + { + lwp_tid_put(tid); + lwp_ref_dec(lwp); + LOG_E("malloc fail!\n"); + return -ENOMEM; + } + lwp->tty = tty; lwp->tty->pgrp = lwp->__pgrp; lwp->tty->session = lwp->session; @@ -1215,6 +1240,17 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) { if (self_lwp != RT_NULL) { + rt_spin_lock(&self_lwp->tty->spinlock); + ret = tty_push(&self_lwp->tty->head, self_lwp); + rt_spin_unlock(&self_lwp->tty->spinlock); + if (ret < 0) + { + lwp_tid_put(tid); + lwp_ref_dec(lwp); + LOG_E("malloc fail!\n"); + return -ENOMEM; + } + lwp->tty = self_lwp->tty; lwp->tty->pgrp = lwp->__pgrp; lwp->tty->session = lwp->session; diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index 4f212035ccf60e1dcf4861681a5cac3050775218..2e18a57f39fbd1bc93a80428dc4f41adf3929e79 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -438,6 +438,8 @@ void lwp_free(struct rt_lwp* lwp) { struct termios *old_stdin_termios = get_old_termios(); struct rt_lwp *self_lwp = (struct rt_lwp *)lwp_self(); + struct rt_lwp *old_lwp = NULL; + if (lwp->session == -1) { tcsetattr(1, 0, old_stdin_termios); @@ -445,9 +447,12 @@ void lwp_free(struct rt_lwp* lwp) level = rt_hw_interrupt_disable(); if (lwp->tty != RT_NULL) { + rt_spin_lock(&lwp->tty->spinlock); + old_lwp = tty_pop(&lwp->tty->head, RT_NULL); + rt_spin_unlock(&lwp->tty->spinlock); if (lwp->tty->foreground == lwp) { - lwp->tty->foreground = self_lwp; + lwp->tty->foreground = old_lwp; lwp->tty = RT_NULL; } } @@ -481,16 +486,18 @@ void lwp_free(struct rt_lwp* lwp) } } -void lwp_ref_inc(struct rt_lwp *lwp) +int lwp_ref_inc(struct rt_lwp *lwp) { rt_base_t level; level = rt_hw_interrupt_disable(); lwp->ref++; rt_hw_interrupt_enable(level); + + return 0; } -void lwp_ref_dec(struct rt_lwp *lwp) +int lwp_ref_dec(struct rt_lwp *lwp) { rt_base_t level; int ref = -1; @@ -518,7 +525,11 @@ void lwp_ref_dec(struct rt_lwp *lwp) #endif /* RT_LWP_USING_SHM */ #endif /* not defined ARCH_MM_MMU */ lwp_free(lwp); + + return 0; } + + return -1; } struct rt_lwp* lwp_from_pid(pid_t pid) diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h index d20254693dbe8cf06145a0c41315ab3e83fd0396..901c6f80b8d079a68aefd096a3249523e6a74bc5 100644 --- a/components/lwp/lwp_pid.h +++ b/components/lwp/lwp_pid.h @@ -22,8 +22,8 @@ struct lwp_avl_struct *lwp_get_pid_ary(void); struct rt_lwp* lwp_new(void); void lwp_free(struct rt_lwp* lwp); -void lwp_ref_inc(struct rt_lwp *lwp); -void lwp_ref_dec(struct rt_lwp *lwp); +int lwp_ref_inc(struct rt_lwp *lwp); +int lwp_ref_dec(struct rt_lwp *lwp); struct rt_lwp* lwp_from_pid(pid_t pid); pid_t lwp_to_pid(struct rt_lwp* lwp); diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index f0ade6e4216f6e7efe32f423ab840444173d1d52..9d2ce4e35af6d1fd4a469ffdfc8b288b5d354d6a 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -1725,6 +1725,19 @@ int _sys_fork(void) level = rt_hw_interrupt_disable(); if (lwp->tty != RT_NULL) { + int ret; + struct rt_lwp *old_lwp; + + old_lwp = lwp->tty->foreground; + rt_spin_lock(&lwp->tty->spinlock); + ret = tty_push(&lwp->tty->head, old_lwp); + rt_spin_unlock(&lwp->tty->spinlock); + if (ret < 0) + { + LOG_E("malloc fail!\n"); + goto fail; + } + lwp->tty->foreground = lwp; } rt_hw_interrupt_enable(level);