sync smart & dfs (#8672)

Signed-off-by: xqyjlj <xqyjlj@126.com>
Signed-off-by: Shell <smokewood@qq.com>
Co-authored-by: xqyjlj <xqyjlj@126.com>
This commit is contained in:
Shell
2024-03-28 23:42:56 +08:00
committed by GitHub
co-authored by xqyjlj
parent 40e26f4909
commit 83e95bdff4
131 changed files with 14954 additions and 6478 deletions
+2 -19
View File
@@ -8,7 +8,7 @@ menuconfig RT_USING_LWP
if RT_USING_LWP
config LWP_DEBUG
bool "Enable debugging features of LwP"
default n
default y
config RT_LWP_MAX_NR
int "The max number of light-weight process"
@@ -51,24 +51,6 @@ if RT_USING_LWP
default y
endif
config LWP_UNIX98_PTY
bool "The unix98 PTY support"
default n
if LWP_UNIX98_PTY
config LWP_PTY_INPUT_BFSZ
int "The unix98 PTY input buffer size"
default 1024
config LWP_PTY_PTS_SIZE
int "The unix98 PTY device max num"
default 3
config LWP_PTY_USING_DEBUG
bool "The unix98 PTY debug output"
default n
endif
menuconfig RT_USING_LDSO
bool "LDSO: dynamic load shared objects"
depends on RT_USING_DFS_V2
@@ -85,5 +67,6 @@ if RT_USING_LWP
default n
endif
source "$RTT_DIR/components/lwp/terminal/Kconfig"
endif
+6 -5
View File
@@ -22,11 +22,6 @@ if arch == 'risc-v':
if cpu in rv64:
cpu = 'rv64'
if GetDepend('LWP_UNIX98_PTY'):
# print("LWP_UNIX98_PTY")
src += Glob('unix98pty/*.c')
CPPPATH += ['unix98pty/']
if platform in platform_file.keys(): # support platforms
if arch in support_arch.keys() and cpu in support_arch[arch]:
asm_path = 'arch/' + arch + '/' + cpu + '/*_' + platform_file[platform]
@@ -40,6 +35,12 @@ if platform in platform_file.keys(): # support platforms
CPPPATH = [cwd]
CPPPATH += [cwd + '/arch/' + arch + '/' + cpu]
# Terminal I/O Subsystem
termios_path = ['./terminal/', './terminal/freebsd/']
for item in termios_path:
src += Glob(item + '*.c')
CPPPATH += ['./terminal/']
group = DefineGroup('lwP', src, depend = ['RT_USING_SMART'], CPPPATH = CPPPATH)
Return('group')
@@ -8,6 +8,7 @@
* 2021-05-18 Jesven first version
* 2023-07-16 Shell Move part of the codes to C from asm in signal handling
* 2023-10-16 Shell Support a new backtrace framework
* 2023-08-03 Shell Support of syscall restart (SA_RESTART)
*/
#include <armv8.h>
@@ -123,6 +124,7 @@ int arch_set_thread_context(void (*exit)(void), void *new_thread_stack,
#define ALGIN_BYTES (16)
/* the layout is part of ABI, dont change it */
struct signal_ucontext
{
rt_int64_t sigreturn;
@@ -130,11 +132,62 @@ struct signal_ucontext
siginfo_t si;
rt_align(16)
rt_align(ALGIN_BYTES)
struct rt_hw_exp_stack frame;
};
void *arch_signal_ucontext_restore(rt_base_t user_sp)
RT_STATIC_ASSERT(abi_offset_compatible, offsetof(struct signal_ucontext, si) == UCTX_ABI_OFFSET_TO_SI);
void *arch_signal_ucontext_get_frame(struct signal_ucontext *uctx)
{
return &uctx->frame;
}
/* internal used only */
void arch_syscall_prepare_signal(rt_base_t rc, struct rt_hw_exp_stack *exp_frame)
{
long x0 = exp_frame->x0;
exp_frame->x0 = rc;
exp_frame->x7 = x0;
return ;
}
void arch_syscall_restart(void *sp, void *ksp);
void arch_syscall_set_errno(void *eframe, int expected, int code)
{
struct rt_hw_exp_stack *exp_frame = eframe;
if (exp_frame->x0 == -expected)
exp_frame->x0 = -code;
return ;
}
void arch_signal_check_erestart(void *eframe, void *ksp)
{
struct rt_hw_exp_stack *exp_frame = eframe;
long rc = exp_frame->x0;
long sys_id = exp_frame->x8;
(void)sys_id;
if (rc == -ERESTART)
{
LOG_D("%s(rc=%ld,sys_id=%ld,pid=%d)", __func__, rc, sys_id, lwp_self()->pid);
LOG_D("%s: restart rc = %ld", lwp_get_syscall_name(sys_id), rc);
exp_frame->x0 = exp_frame->x7;
arch_syscall_restart(eframe, ksp);
}
return ;
}
static void arch_signal_post_action(struct signal_ucontext *new_sp, rt_base_t kernel_sp)
{
arch_signal_check_erestart(&new_sp->frame, (void *)kernel_sp);
return ;
}
void *arch_signal_ucontext_restore(rt_base_t user_sp, rt_base_t kernel_sp)
{
struct signal_ucontext *new_sp;
new_sp = (void *)user_sp;
@@ -142,6 +195,7 @@ void *arch_signal_ucontext_restore(rt_base_t user_sp)
if (lwp_user_accessable(new_sp, sizeof(*new_sp)))
{
lwp_thread_signal_mask(rt_thread_self(), LWP_SIG_MASK_CMD_SET_MASK, &new_sp->save_sigmask, RT_NULL);
arch_signal_post_action(new_sp, kernel_sp);
}
else
{
@@ -157,7 +211,7 @@ void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo,
lwp_sigset_t *save_sig_mask)
{
struct signal_ucontext *new_sp;
new_sp = (void *)(user_sp - sizeof(struct signal_ucontext));
new_sp = (void *)((user_sp - sizeof(struct signal_ucontext)) & ~0xf);
if (lwp_user_accessable(new_sp, sizeof(*new_sp)))
{
@@ -11,8 +11,7 @@
#ifndef LWP_ARCH_H__
#define LWP_ARCH_H__
#include <lwp.h>
#include <lwp_arch_comm.h>
#include <rtconfig.h>
#ifdef ARCH_MM_MMU
@@ -26,6 +25,13 @@
#define USER_VADDR_START 0x00200000UL
#define USER_LOAD_VADDR USER_VADDR_START
#define UCTX_ABI_OFFSET_TO_SI 16
#ifndef __ASSEMBLY__
#include <lwp.h>
#include <lwp_arch_comm.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -34,7 +40,7 @@ unsigned long rt_hw_ffz(unsigned long x);
rt_inline void icache_invalid_all(void)
{
asm volatile ("ic ialluis\n\tisb sy":::"memory");
__asm__ volatile ("ic ialluis\n\tisb sy":::"memory");
}
/**
@@ -57,11 +63,14 @@ void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo,
* @param user_sp sp of user
* @return void*
*/
void *arch_signal_ucontext_restore(rt_base_t user_sp);
void *arch_signal_ucontext_restore(rt_base_t user_sp, rt_base_t kernel_sp);
void arch_syscall_restart(void *sp, void *ksp);
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLY__ */
#endif
#endif /* ARCH_MM_MMU */
#endif /*LWP_ARCH_H__*/
+67 -3
View File
@@ -7,6 +7,7 @@
* Date Author Notes
* 2021-05-18 Jesven first version
* 2023-07-16 Shell Move part of the codes to C from asm in signal handling
* 2023-08-03 Shell Support of syscall restart (SA_RESTART)
*/
#ifndef __ASSEMBLY__
@@ -17,6 +18,7 @@
#include "asm-generic.h"
#include "asm-fpu.h"
#include "armv8.h"
#include "lwp_arch.h"
/*********************
* SPSR BIT *
@@ -155,6 +157,14 @@ START_POINT_END(SVC_Handler)
.global arch_syscall_exit
arch_syscall_exit:
/**
* @brief back up former x0 which is required to restart syscall, then setup
* syscall return value in stack frame
*/
mov x1, sp
bl arch_syscall_prepare_signal
msr daifset, #3
ldp x2, x3, [sp], #0x10 /* SPSR and ELR. */
@@ -177,7 +187,10 @@ arch_syscall_exit:
ldp x12, x13, [sp], #0x10
ldp x10, x11, [sp], #0x10
ldp x8, x9, [sp], #0x10
add sp, sp, #0x40
ldp x6, x7, [sp], #0x10
ldp x4, x5, [sp], #0x10
ldp x2, x3, [sp], #0x10
ldp x0, x1, [sp], #0x10
RESTORE_FPU sp
/* the sp is reset to the outer most level, irq and fiq are disabled */
@@ -383,10 +396,53 @@ lwp_check_debug_quit:
ldp x29, x30, [sp], #0x10
ret
.global arch_syscall_restart
arch_syscall_restart:
msr daifset, 3
mov sp, x1
/* drop exception frame in user stack */
msr sp_el0, x0
/* restore previous exception frame */
msr spsel, #0
ldp x2, x3, [sp], #0x10
msr elr_el1, x2
msr spsr_el1, x3
ldp x29, x30, [sp], #0x10
ldp x28, x29, [sp], #0x10
msr fpcr, x28
msr fpsr, x29
ldp x28, x29, [sp], #0x10
ldp x26, x27, [sp], #0x10
ldp x24, x25, [sp], #0x10
ldp x22, x23, [sp], #0x10
ldp x20, x21, [sp], #0x10
ldp x18, x19, [sp], #0x10
ldp x16, x17, [sp], #0x10
ldp x14, x15, [sp], #0x10
ldp x12, x13, [sp], #0x10
ldp x10, x11, [sp], #0x10
ldp x8, x9, [sp], #0x10
ldp x6, x7, [sp], #0x10
ldp x4, x5, [sp], #0x10
ldp x2, x3, [sp], #0x10
ldp x0, x1, [sp], #0x10
RESTORE_FPU sp
msr spsel, #1
b vector_exception
arch_signal_quit:
/* drop current exception frame */
add sp, sp, #CONTEXT_SIZE
mov x1, sp
mrs x0, sp_el0
bl arch_signal_ucontext_restore
add x0, x0, #-CONTEXT_SIZE
@@ -456,6 +512,11 @@ arch_thread_signal_enter:
/* arch_signal_ucontext_save(user_sp, psiginfo, exp_frame, save_sig_mask); */
bl arch_signal_ucontext_save
mov x22, x0
/* get and saved pointer to uframe */
bl arch_signal_ucontext_get_frame
mov x2, x0
mov x0, x22
dc cvau, x0
dsb sy
@@ -483,12 +544,15 @@ arch_thread_signal_enter:
/** set the return address to the sigreturn */
mov x30, x0
cbnz x21, 1f
mov x21, x30
1:
/** set the entry address of signal handler */
msr elr_el1, x21
/* siginfo is above the return address */
add x2, x30, 16
add x1, x2, #CONTEXT_SIZE
add x1, x30, UCTX_ABI_OFFSET_TO_SI
/* uframe is saved in x2 */
mov x0, x19
/**
@@ -192,6 +192,12 @@ void *arch_signal_ucontext_save(rt_base_t lr, siginfo_t *psiginfo,
return new_sp;
}
void arch_syscall_set_errno(void *eframe, int expected, int code)
{
/* NO support */
return ;
}
#ifdef LWP_ENABLE_ASID
#define MAX_ASID_BITS 8
#define MAX_ASID (1 << MAX_ASID_BITS)
+1 -1
View File
@@ -35,7 +35,7 @@ rt_inline unsigned long rt_hw_ffz(unsigned long x)
rt_inline void icache_invalid_all(void)
{
asm volatile ("mcr p15, 0, r0, c7, c5, 0\ndsb\nisb":::"memory");//iciallu
__asm__ volatile ("mcr p15, 0, r0, c7, c5, 0\ndsb\nisb":::"memory");//iciallu
}
unsigned int arch_get_asid(struct rt_lwp *lwp);
@@ -242,6 +242,7 @@ int arch_set_thread_context(void (*exit)(void), void *new_thread_stack,
* | |
* +------------------------+ --> thread sp
*/
return 0;
}
#define ALGIN_BYTES (16)
@@ -317,6 +318,12 @@ void *arch_signal_ucontext_save(int signo, siginfo_t *psiginfo,
return new_sp;
}
void arch_syscall_set_errno(void *eframe, int expected, int code)
{
/* NO support */
return ;
}
/**
* void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
*/
+3 -3
View File
@@ -28,9 +28,9 @@
#define FUTEX_CLOCK_REALTIME 256
#define FUTEX_WAITERS 0x80000000
#define FUTEX_OWNER_DIED 0x40000000
#define FUTEX_TID_MASK 0x3fffffff
#define FUTEX_WAITERS 0x80000000
#define FUTEX_OWNER_DIED 0x40000000
#define FUTEX_TID_MASK 0x3fffffff
struct robust_list
{
+170 -98
View File
@@ -12,6 +12,8 @@
* 2023-02-20 wangxiaoyao inv icache before new app startup
* 2023-02-20 wangxiaoyao fix bug on foreground app switch
* 2023-10-16 Shell Support a new backtrace framework
* 2023-11-17 xqyjlj add process group and session support
* 2023-11-30 Shell add lwp_startup()
*/
#define DBG_TAG "lwp"
@@ -39,7 +41,7 @@
#include "lwp_arch_comm.h"
#include "lwp_signal.h"
#include "lwp_dbg.h"
#include "console.h"
#include <terminal/terminal.h>
#ifdef ARCH_MM_MMU
#include <lwp_user_mm.h>
@@ -59,16 +61,31 @@ static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
#ifdef DFS_USING_WORKDIR
extern char working_directory[];
#endif
static struct termios stdin_termios, old_stdin_termios;
int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]);
struct termios *get_old_termios(void)
/**
* @brief The default console is only a backup device with lowest priority.
* It's always recommended to scratch the console from the boot arguments.
* And dont forget to register the device with a higher priority.
*/
static rt_err_t lwp_default_console_setup(void)
{
return &old_stdin_termios;
rt_device_t bakdev = rt_device_find("ttyS0");
rt_err_t rc;
if (bakdev)
{
lwp_console_register_backend(bakdev, LWP_CONSOLE_LOWEST_PRIOR);
rc = RT_EOK;
}
else
{
rc = -RT_EINVAL;
}
return rc;
}
int lwp_component_init(void)
static int lwp_component_init(void)
{
int rc;
if ((rc = lwp_tid_init()) != RT_EOK)
@@ -83,10 +100,99 @@ int lwp_component_init(void)
{
LOG_E("%s: rt_channel_component_init failed", __func__);
}
else if ((rc = lwp_futex_init()) != RT_EOK)
{
LOG_E("%s: lwp_futex_init() failed", __func__);
}
else if ((rc = lwp_default_console_setup()) != RT_EOK)
{
LOG_E("%s: lwp_default_console_setup() failed", __func__);
}
return rc;
}
INIT_COMPONENT_EXPORT(lwp_component_init);
rt_weak int lwp_startup_debug_request(void)
{
return 0;
}
#define LATENCY_TIMES (3)
#define LATENCY_IN_MSEC (128)
#define LWP_CONSOLE_PATH "CONSOLE=/dev/console"
const char *init_search_path[] = {
"/sbin/init",
"/bin/init",
};
/**
* Startup process 0 and do the essential works
* This is the "Hello World" point of RT-Smart
*/
static int lwp_startup(void)
{
int error;
const char *init_path;
char *argv[] = {0, "&"};
char *envp[] = {LWP_CONSOLE_PATH, 0};
#ifdef LWP_DEBUG
int command;
int countdown = LATENCY_TIMES;
while (countdown)
{
command = lwp_startup_debug_request();
if (command)
{
return 0;
}
rt_kprintf("Press any key to stop init process startup ... %d\n", countdown);
countdown -= 1;
rt_thread_mdelay(LATENCY_IN_MSEC);
}
rt_kprintf("Starting init ...\n");
#endif
for (size_t i = 0; i < sizeof(init_search_path)/sizeof(init_search_path[0]); i++)
{
struct stat s;
init_path = init_search_path[i];
error = stat(init_path, &s);
if (error == 0)
{
argv[0] = (void *)init_path;
error = lwp_execve((void *)init_path, 0, sizeof(argv)/sizeof(argv[0]), argv, envp);
if (error < 0)
{
LOG_E("%s: failed to startup process 0 (init)\n"
"Switching to legacy mode...", __func__);
}
else if (error != 1)
{
LOG_E("%s: pid 1 is already allocated", __func__);
error = -EBUSY;
}
else
{
rt_lwp_t p = lwp_from_pid_locked(1);
p->sig_protected = 0;
error = 0;
}
break;
}
}
if (error)
{
LOG_E("%s: init program not found\n"
"Switching to legacy mode...", __func__);
}
return error;
}
INIT_APP_EXPORT(lwp_startup);
void lwp_setcwd(char *buf)
{
struct rt_lwp *lwp = RT_NULL;
@@ -100,11 +206,11 @@ void lwp_setcwd(char *buf)
lwp = (struct rt_lwp *)rt_thread_self()->lwp;
if (lwp)
{
rt_strncpy(lwp->working_directory, buf, DFS_PATH_MAX);
rt_strncpy(lwp->working_directory, buf, DFS_PATH_MAX - 1);
}
else
{
rt_strncpy(working_directory, buf, DFS_PATH_MAX);
rt_strncpy(working_directory, buf, DFS_PATH_MAX - 1);
}
return ;
@@ -114,8 +220,13 @@ char *lwp_getcwd(void)
{
char *dir_buf = RT_NULL;
struct rt_lwp *lwp = RT_NULL;
rt_thread_t thread = rt_thread_self();
if (thread)
{
lwp = (struct rt_lwp *)thread->lwp;
}
lwp = (struct rt_lwp *)rt_thread_self()->lwp;
if (lwp)
{
if(lwp->working_directory[0] != '/')
@@ -1077,25 +1188,35 @@ void lwp_cleanup(struct rt_thread *tid)
return;
}
static void lwp_copy_stdio_fdt(struct rt_lwp *lwp)
static void lwp_execve_setup_stdio(struct rt_lwp *lwp)
{
struct dfs_file *d;
struct dfs_fdtable *lwp_fdt;
struct dfs_file *cons_file;
int cons_fd;
lwp_fdt = &lwp->fdt;
/* open console */
cons_fd = open("/dev/console", O_RDWR);
if (cons_fd < 0)
{
LOG_E("%s: Cannot open console tty", __func__);
return ;
}
LOG_D("%s: open console as fd %d", __func__, cons_fd);
/* init 4 fds */
lwp_fdt->fds = rt_calloc(4, sizeof(void *));
if (lwp_fdt->fds)
{
cons_file = fd_get(cons_fd);
lwp_fdt->maxfd = 4;
d = fd_get(0);
fdt_fd_associate_file(lwp_fdt, 0, d);
d = fd_get(1);
fdt_fd_associate_file(lwp_fdt, 1, d);
d = fd_get(2);
fdt_fd_associate_file(lwp_fdt, 2, d);
fdt_fd_associate_file(lwp_fdt, 0, cons_file);
fdt_fd_associate_file(lwp_fdt, 1, cons_file);
fdt_fd_associate_file(lwp_fdt, 2, cons_file);
}
close(cons_fd);
return;
}
@@ -1197,11 +1318,8 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
int result;
struct rt_lwp *lwp;
char *thread_name;
char *argv_last = argv[argc - 1];
int bg = 0;
struct process_aux *aux;
int tid = 0;
int ret;
if (filename == RT_NULL)
{
@@ -1213,7 +1331,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
return -EACCES;
}
lwp = lwp_create(LWP_CREATE_FLAG_ALLOC_PID);
lwp = lwp_create(LWP_CREATE_FLAG_ALLOC_PID | LWP_CREATE_FLAG_NOTRACE_EXEC);
if (lwp == RT_NULL)
{
@@ -1236,12 +1354,6 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
}
#endif
if (argv_last[0] == '&' && argv_last[1] == '\0')
{
argc--;
bg = 1;
}
if ((aux = lwp_argscopy(lwp, argc, argv, envp)) == RT_NULL)
{
lwp_tid_put(tid);
@@ -1263,7 +1375,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
rt_thread_t thread = RT_NULL;
rt_uint32_t priority = 25, tick = 200;
lwp_copy_stdio_fdt(lwp);
lwp_execve_setup_stdio(lwp);
/* obtain the base name */
thread_name = strrchr(filename, '/');
@@ -1284,88 +1396,46 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
if (thread != RT_NULL)
{
struct rt_lwp *self_lwp;
rt_session_t session;
rt_processgroup_t group;
thread->tid = tid;
lwp_tid_set_thread(tid, thread);
LOG_D("lwp kernel => (0x%08x, 0x%08x)\n", (rt_size_t)thread->stack_addr,
(rt_size_t)thread->stack_addr + thread->stack_size);
self_lwp = lwp_self();
/* when create init, self_lwp == null */
if (self_lwp == RT_NULL && lwp_to_pid(lwp) != 1)
{
self_lwp = lwp_from_pid_and_lock(1);
}
if (self_lwp)
{
//lwp->tgroup_leader = &thread; //add thread group leader for lwp
lwp->__pgrp = tid;
lwp->session = self_lwp->session;
/* lwp add to children link */
lwp_children_register(self_lwp, lwp);
}
else
session = RT_NULL;
group = RT_NULL;
group = lwp_pgrp_create(lwp);
if (group)
{
//lwp->tgroup_leader = &thread; //add thread group leader for lwp
lwp->__pgrp = tid;
}
if (!bg)
{
if (lwp->session == -1)
lwp_pgrp_insert(group, lwp);
if (self_lwp == RT_NULL)
{
struct tty_struct *tty = RT_NULL;
struct rt_lwp *old_lwp;
tty = (struct tty_struct *)console_tty_get();
old_lwp = tty->foreground;
if (old_lwp)
{
rt_mutex_take(&tty->lock, RT_WAITING_FOREVER);
ret = tty_push(&tty->head, old_lwp);
rt_mutex_release(&tty->lock);
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;
lwp->tty->foreground = lwp;
tcgetattr(1, &stdin_termios);
old_stdin_termios = stdin_termios;
stdin_termios.c_lflag |= ICANON | ECHO | ECHOCTL;
tcsetattr(1, 0, &stdin_termios);
session = lwp_session_create(lwp);
lwp_session_insert(session, group);
}
else
{
if (self_lwp != RT_NULL)
{
rt_mutex_take(&self_lwp->tty->lock, RT_WAITING_FOREVER);
ret = tty_push(&self_lwp->tty->head, self_lwp);
rt_mutex_release(&self_lwp->tty->lock);
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;
lwp->tty->foreground = lwp;
}
else
{
lwp->tty = RT_NULL;
}
session = lwp_session_find(lwp_sid_get_byprocess(self_lwp));
lwp_session_insert(session, group);
}
}
else
{
lwp->background = RT_TRUE;
}
thread->lwp = lwp;
#ifndef ARCH_MM_MMU
struct lwp_app_head *app_head = (struct lwp_app_head*)lwp->text_entry;
@@ -1381,6 +1451,8 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
#endif /* not defined ARCH_MM_MMU */
rt_list_insert_after(&lwp->t_grp, &thread->sibling);
lwp->did_exec = RT_TRUE;
if (debug && rt_dbg_ops)
{
lwp->debug = debug;
@@ -1482,30 +1554,30 @@ rt_err_t lwp_backtrace_frame(rt_thread_t uthread, struct rt_hw_backtrace_frame *
char **argv;
rt_lwp_t lwp;
if (uthread->lwp)
if (uthread && uthread->lwp && rt_scheduler_is_available())
{
lwp = uthread->lwp;
argv = lwp_get_command_line_args(lwp);
if (argv)
{
LOG_RAW("please use: addr2line -e %s -a -f", argv[0]);
rt_kprintf("please use: addr2line -e %s -a -f", argv[0]);
lwp_free_command_line_args(argv);
}
else
{
LOG_RAW("please use: addr2line -e %s -a -f", lwp->cmd);
rt_kprintf("please use: addr2line -e %s -a -f", lwp->cmd);
}
while (nesting < RT_BACKTRACE_LEVEL_MAX_NR)
{
LOG_RAW(" 0x%lx", frame->pc);
rt_kprintf(" 0x%lx", frame->pc);
if (rt_hw_backtrace_frame_unwind(uthread, frame))
{
break;
}
nesting++;
}
LOG_RAW("\n");
rt_kprintf("\n");
rc = RT_EOK;
}
return rc;
+138 -21
View File
@@ -9,6 +9,9 @@
* 2019-10-12 Jesven Add MMU and userspace support
* 2020-10-08 Bernard Architecture and code cleanup
* 2021-08-26 linzhenxing add lwp_setcwd\lwp_getcwd
* 2023-11-17 xqyjlj add process group and session support
* 2023-12-02 Shell Add macro to create lwp status and
* fix dead lock problem on pgrp
*/
/*
@@ -48,10 +51,6 @@
#include <locale.h>
#endif /* RT_USING_MUSLLIBC */
#ifdef RT_USING_TTY
struct tty_struct;
#endif /* RT_USING_TTY */
#ifdef __cplusplus
extern "C" {
#endif
@@ -76,12 +75,48 @@ struct rt_lwp_notify
rt_slist_t list_node;
};
struct lwp_tty;
#ifdef RT_USING_MUSLLIBC
#define LWP_CREATE_STAT(exit_code) (((exit_code) & 0xff) << 8)
#define LWP_COREDUMP_FLAG 0x80
#define LWP_CREATE_STAT_EXIT(exit_code) (((exit_code)&0xff) << 8)
#define LWP_CREATE_STAT_SIGNALED(signo, coredump) (((signo) & 0x7f) | (coredump ? LWP_COREDUMP_FLAG : 0))
#define LWP_CREATE_STAT_STOPPED(signo) (LWP_CREATE_STAT_EXIT(signo) | 0x7f)
#define LWP_CREATE_STAT_CONTINUED (0xffff)
#else
#error "No compatible lwp set status provided for this libc"
#endif
typedef struct rt_lwp *rt_lwp_t;
typedef struct rt_session *rt_session_t;
typedef struct rt_processgroup *rt_processgroup_t;
struct rt_session {
struct rt_object object;
rt_lwp_t leader;
rt_list_t processgroup;
pid_t sid;
pid_t foreground_pgid;
struct rt_mutex mutex;
struct lwp_tty *ctty;
};
struct rt_processgroup {
struct rt_object object;
rt_lwp_t leader;
rt_list_t process;
rt_list_t pgrp_list_node;
pid_t pgid;
pid_t sid;
struct rt_session *session;
struct rt_mutex mutex;
rt_atomic_t ref;
/* flags on process group */
unsigned int is_orphaned:1;
};
struct rt_lwp
{
#ifdef ARCH_MM_MMU
@@ -100,14 +135,21 @@ struct rt_lwp
uint8_t lwp_type;
uint8_t reserv[3];
struct rt_lwp *parent;
struct rt_lwp *first_child;
struct rt_lwp *sibling;
/* flags */
unsigned int terminated:1;
unsigned int background:1;
unsigned int term_ctrlterm:1; /* have control terminal? */
unsigned int did_exec:1; /* Whether exec has been performed */
unsigned int jobctl_stopped:1; /* job control: current proc is stopped */
unsigned int wait_reap_stp:1; /* job control: has wait event for parent */
unsigned int sig_protected:1; /* signal: protected proc cannot be killed or stopped */
rt_list_t wait_list;
rt_bool_t terminated;
rt_bool_t background;
int lwp_ret;
struct rt_lwp *parent; /* parent process */
struct rt_lwp *first_child; /* first child process */
struct rt_lwp *sibling; /* sibling(child) process */
struct rt_wqueue waitpid_waiters;
lwp_status_t lwp_status;
void *text_entry;
uint32_t text_size;
@@ -118,15 +160,16 @@ struct rt_lwp
void *args;
uint32_t args_length;
pid_t pid;
pid_t __pgrp; /*Accessed via process_group()*/
pid_t tty_old_pgrp;
pid_t session;
rt_list_t t_grp;
rt_list_t timer; /* POSIX timer object binding to a process */
pid_t sid; /* session ID */
pid_t pgid; /* process group ID */
struct rt_processgroup *pgrp;
rt_list_t pgrp_node; /* process group node */
rt_list_t t_grp; /* thread group */
rt_list_t timer; /* POSIX timer object binding to a process */
int leader; /* boolean value for session group_leader*/
struct dfs_fdtable fdt;
char cmd[RT_NAME_MAX];
char *exe_file; /* process file path */
/* POSIX signal */
struct lwp_signal signal;
@@ -135,7 +178,7 @@ struct rt_lwp
struct rt_mutex object_mutex;
struct rt_user_context user_ctx;
struct rt_wqueue wait_queue; /*for console */
struct rt_wqueue wait_queue; /* for console */
struct tty_struct *tty; /* NULL if no tty */
struct lwp_avl_struct *address_search_head; /* for addressed object fast search */
@@ -152,8 +195,9 @@ struct rt_lwp
uint64_t generation;
unsigned int asid;
#endif
struct rusage rt_rusage;
};
typedef struct rt_lwp *rt_lwp_t;
struct rt_lwp *lwp_self(void);
rt_err_t lwp_children_register(struct rt_lwp *parent, struct rt_lwp *child);
@@ -182,7 +226,7 @@ void lwp_tid_put(int tid);
* @return rt_thread_t
*/
rt_thread_t lwp_tid_get_thread_and_inc_ref(int tid);
rt_thread_t lwp_tid_get_thread_raw(int tid);
/**
* @brief Decrease a reference count
*
@@ -216,6 +260,78 @@ rt_err_t lwp_futex_init(void);
rt_err_t lwp_futex(struct rt_lwp *lwp, int *uaddr, int op, int val,
const struct timespec *timeout, int *uaddr2, int val3);
/* processgroup api */
rt_inline pid_t lwp_pgid_get_bypgrp(rt_processgroup_t group)
{
return group ? group->pgid : 0;
}
rt_inline pid_t lwp_pgid_get_byprocess(rt_lwp_t process)
{
return process ? process->pgid : 0;
}
rt_processgroup_t lwp_pgrp_find(pid_t pgid);
void lwp_pgrp_dec_ref(rt_processgroup_t pgrp);
rt_processgroup_t lwp_pgrp_find_and_inc_ref(pid_t pgid);
rt_processgroup_t lwp_pgrp_create(rt_lwp_t leader);
int lwp_pgrp_delete(rt_processgroup_t group);
/**
* Note: all the pgrp with process operation must be called in the context where
* process lock is taken. This is protect us from a possible dead lock condition
*
* The order is mandatory in the case:
* PGRP_LOCK(pgrp);
* LWP_LOCK(p);
* ... bussiness logic
* LWP_UNLOCK(p);
* PGRP_UNLOCK(pgrp);
*/
int lwp_pgrp_insert(rt_processgroup_t group, rt_lwp_t process);
int lwp_pgrp_remove(rt_processgroup_t group, rt_lwp_t process);
int lwp_pgrp_move(rt_processgroup_t group, rt_lwp_t process);
int lwp_pgrp_update_children_info(rt_processgroup_t group, pid_t sid, pid_t pgid);
/* session api */
rt_inline pid_t lwp_sid_get_bysession(rt_session_t session)
{
return session ? session->sid : 0;
}
rt_inline pid_t lwp_sid_get_bypgrp(rt_processgroup_t group)
{
return group ? group->sid : 0;
}
rt_inline pid_t lwp_sid_get_byprocess(rt_lwp_t process)
{
return process ? process->sid : 0;
}
rt_session_t lwp_session_find(pid_t sid);
rt_session_t lwp_session_create(struct rt_lwp *leader);
int lwp_session_delete(rt_session_t session);
/**
* Note: all the session operation must be called in the context where
* process lock is taken. This is protect us from a possible dead lock condition
*
* The order is mandatory in the case:
* PGRP_LOCK(pgrp);
* LWP_LOCK(p);
* ... bussiness logic
* LWP_UNLOCK(p);
* PGRP_UNLOCK(pgrp);
*/
int lwp_session_insert(rt_session_t session, rt_processgroup_t group);
int lwp_session_remove(rt_session_t session, rt_processgroup_t group);
int lwp_session_move(rt_session_t session, rt_processgroup_t group);
int lwp_session_update_children_info(rt_session_t session, pid_t sid);
int lwp_session_set_foreground(rt_session_t session, pid_t pgid);
/* complete the job control related bussiness on process exit */
void lwp_jobctrl_on_exit(struct rt_lwp *lwp);
#ifdef __cplusplus
}
@@ -301,6 +417,7 @@ int dbg_step_type(void);
void dbg_attach_req(void *pc);
int dbg_check_suspend(void);
void rt_hw_set_process_id(int pid);
void lwp_futex_exit_robust_list(rt_thread_t thread);
/* backtrace service */
rt_err_t lwp_backtrace_frame(rt_thread_t uthread, struct rt_hw_backtrace_frame *frame);
+4
View File
@@ -61,6 +61,10 @@ rt_noreturn void arch_thread_signal_enter(int signo, siginfo_t *psiginfo,
void *exp_frame, void *entry_uaddr,
lwp_sigset_t *save_sig_mask);
void arch_signal_check_erestart(void *eframe, void *ksp);
void arch_syscall_set_errno(void *eframe, int expected, int code);
int arch_backtrace_uthread(rt_thread_t thread);
#endif /* __LWP_ARCH_COMM__ */
+1
View File
@@ -797,6 +797,7 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
/* copy file name to process name */
rt_strncpy(lwp->cmd, filename, RT_NAME_MAX);
lwp->exe_file = dfs_normalize_path(NULL, filename); // malloc
ret = elf_file_load(&load_info);
if (ret != RT_EOK)
+15 -14
View File
@@ -475,6 +475,11 @@ static long _futex_wake(rt_futex_t futex, struct rt_lwp *lwp, int number,
{
number--;
woken_cnt++;
is_empty = RT_FALSE;
}
else
{
is_empty = RT_TRUE;
}
_futex_unlock(lwp, op_flags);
}
@@ -512,23 +517,16 @@ static long _futex_requeue(rt_futex_t futex1, rt_futex_t futex2,
*/
while (nr_wake && !is_empty)
{
rt_sched_lock_level_t slvl;
rt_sched_lock(&slvl);
is_empty = rt_list_isempty(&(futex1->waiting_thread));
if (!is_empty)
if (rt_susp_list_dequeue(&futex1->waiting_thread, RT_EOK))
{
thread = RT_THREAD_LIST_NODE_ENTRY(futex1->waiting_thread.next);
/* remove from waiting list */
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
thread->error = RT_EOK;
/* resume the suspended thread */
rt_thread_resume(thread);
nr_wake--;
woken_cnt++;
is_empty = RT_FALSE;
}
else
{
is_empty = RT_TRUE;
}
rt_sched_unlock(slvl);
}
rtn = woken_cnt;
@@ -542,7 +540,10 @@ static long _futex_requeue(rt_futex_t futex1, rt_futex_t futex2,
{
rt_sched_lock_level_t slvl;
rt_sched_lock(&slvl);
/* moving from one susp list to another */
is_empty = rt_list_isempty(&(futex1->waiting_thread));
if (!is_empty)
{
thread = RT_THREAD_LIST_NODE_ENTRY(futex1->waiting_thread.next);
@@ -914,7 +915,7 @@ void lwp_futex_exit_robust_list(rt_thread_t thread)
rc = _fetch_robust_entry(&next_entry, &entry->next, &next_pi);
if (entry != pending)
{
if (_handle_futex_death((void *)entry + futex_offset, thread, pi,
if (_handle_futex_death((int *)((size_t)entry + futex_offset), thread, pi,
RT_FALSE))
return;
}
+56 -13
View File
@@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2023-07-25 Shell first version
* 2023-11-25 Shell Add pgrp, session lock API
*/
#define DBG_TAG "lwp.internal"
@@ -15,7 +16,7 @@
#include <stdlib.h>
#include "lwp_internal.h"
static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t interruptable)
static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, int flags)
{
LWP_DEF_RETURN_CODE(rc);
int retry;
@@ -45,15 +46,15 @@ static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t i
do {
retry = 0;
if (interruptable)
if (flags & LWP_MTX_FLAGS_INTR)
rc = rt_mutex_take_interruptible(mtx, effect_timeout);
else
rc = rt_mutex_take(mtx, effect_timeout);
rc = rt_mutex_take_killable(mtx, effect_timeout);
#ifdef LWP_DEBUG
if (rc == RT_EOK)
{
if (rt_mutex_get_hold(mtx) > 1)
if (!(flags & LWP_MTX_FALGS_NESTED) && rt_mutex_get_hold(mtx) > 1)
{
LOG_W("Already hold the lock");
rt_backtrace();
@@ -88,6 +89,7 @@ static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t i
}
else
{
rc = -RT_EINVAL;
LOG_W("%s: mtx should not be NULL", __func__);
RT_ASSERT(0);
}
@@ -95,10 +97,10 @@ static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t i
LWP_RETURN(rc);
}
rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t interruptable)
rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, int flags)
{
LWP_DEF_RETURN_CODE(rc);
rc = _mutex_take_safe(mtx, timeout, interruptable);
rc = _mutex_take_safe(mtx, timeout, flags);
LWP_RETURN(rc);
}
@@ -116,18 +118,17 @@ rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx)
LWP_RETURN(rc);
}
rt_err_t lwp_critical_enter(struct rt_lwp *lwp)
rt_err_t lwp_critical_enter(struct rt_lwp *lwp, int flags)
{
rt_err_t rc;
rc = lwp_mutex_take_safe(&lwp->lwp_lock, RT_WAITING_FOREVER, 0);
do {
rc = lwp_mutex_take_safe(&lwp->lwp_lock, RT_WAITING_FOREVER, flags);
} while (rc != RT_EOK && !(flags & LWP_MTX_FLAGS_INTR) && rc == -RT_EINTR);
/* if current process is force killed */
if (rc != RT_EOK)
if (rc != RT_EOK && rc != -RT_EINTR)
{
if (rc == -RT_EINTR && lwp_self() != RT_NULL)
sys_exit(EXIT_SUCCESS);
else
LOG_I("%s: unexpected return code = %ld", __func__, rc);
LOG_I("%s: unexpected return code = %ld", __func__, rc);
}
return rc;
@@ -137,3 +138,45 @@ rt_err_t lwp_critical_exit(struct rt_lwp *lwp)
{
return lwp_mutex_release_safe(&lwp->lwp_lock);
}
rt_err_t lwp_pgrp_critical_enter(struct rt_processgroup *pgrp, int flags)
{
rt_err_t rc;
do {
rc = lwp_mutex_take_safe(&pgrp->mutex, RT_WAITING_FOREVER, flags);
} while (rc != RT_EOK && !(flags & LWP_MTX_FLAGS_INTR) && rc == -RT_EINTR);
/* if current process is force killed */
if (rc != RT_EOK && rc != -RT_EINTR)
{
LOG_I("%s: unexpected return code = %ld", __func__, rc);
}
return rc;
}
rt_err_t lwp_pgrp_critical_exit(struct rt_processgroup *pgrp)
{
return lwp_mutex_release_safe(&pgrp->mutex);
}
rt_err_t lwp_sess_critical_enter(struct rt_session *sess, int flags)
{
rt_err_t rc;
do {
rc = lwp_mutex_take_safe(&sess->mutex, RT_WAITING_FOREVER, flags);
} while (rc != RT_EOK && !(flags & LWP_MTX_FLAGS_INTR) && rc == -RT_EINTR);
/* if current process is force killed */
if (rc != RT_EOK && rc != -RT_EINTR)
{
LOG_I("%s: unexpected return code = %ld", __func__, rc);
}
return rc;
}
rt_err_t lwp_sess_critical_exit(struct rt_session *sess)
{
return lwp_mutex_release_safe(&sess->mutex);
}
+102 -9
View File
@@ -6,21 +6,32 @@
* Change Logs:
* Date Author Notes
* 2023-07-25 Shell first version
* 2023-11-25 Shell Add pgrp, session lock API
*/
#ifndef __LWP_INTERNAL_H__
#define __LWP_INTERNAL_H__
#include "lwp.h"
#include "lwp_arch.h"
#include "lwp_user_mm.h"
#include "lwp_mm.h"
#include <rtthread.h>
#include "libc_musl.h"
struct rt_lwp;
rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t interruptable);
#define LWP_MTX_FLAGS_INTR 0x1 /* interruptible waiting */
#define LWP_MTX_FALGS_NESTED 0x2 /* allow nested */
rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, int flags);
rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx);
rt_inline rt_bool_t lwp_in_user_space(const char *addr)
{
return (addr >= (char *)USER_VADDR_START && addr < (char *)USER_VADDR_TOP);
}
#ifdef RT_USING_SMP
#define LOCAL_IRQ_MASK() rt_hw_local_irq_disable()
#define LOCAL_IRQ_UNMASK(level) rt_hw_local_irq_enable(level)
@@ -30,16 +41,34 @@ rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx);
#endif
#ifndef LWP_USING_CPUS_LOCK
rt_err_t lwp_critical_enter(struct rt_lwp *lwp);
rt_err_t lwp_sess_critical_enter(struct rt_session *sess, int flags);
rt_err_t lwp_sess_critical_exit(struct rt_session *sess);
rt_err_t lwp_pgrp_critical_enter(struct rt_processgroup *pgrp, int flags);
rt_err_t lwp_pgrp_critical_exit(struct rt_processgroup *pgrp);
rt_err_t lwp_critical_enter(struct rt_lwp *lwp, int flags);
rt_err_t lwp_critical_exit(struct rt_lwp *lwp);
#define LWP_LOCK(lwp) \
do { \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_critical_enter(lwp) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
#define LWP_ASSERT_LOCKED(proc) RT_ASSERT(rt_mutex_get_owner(&(proc)->lwp_lock) == rt_thread_self())
#define PGRP_ASSERT_LOCKED(pgrp) RT_ASSERT(rt_mutex_get_owner(&(pgrp)->mutex) == rt_thread_self())
#define LWP_LOCK(lwp) \
do \
{ \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_critical_enter(lwp, 0) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define LWP_LOCK_NESTED(lwp) \
do \
{ \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_critical_enter(lwp, LWP_MTX_FALGS_NESTED) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define LWP_UNLOCK(lwp) \
@@ -50,10 +79,72 @@ rt_err_t lwp_critical_exit(struct rt_lwp *lwp);
} \
} while (0)
#define PGRP_LOCK(pgrp) \
do \
{ \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_pgrp_critical_enter(pgrp, 0) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define PGRP_LOCK_NESTED(pgrp) \
do \
{ \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_pgrp_critical_enter(pgrp, LWP_MTX_FALGS_NESTED) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define PGRP_UNLOCK(pgrp) \
do \
{ \
if (lwp_pgrp_critical_exit(pgrp) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define SESS_LOCK(sess) \
do \
{ \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_sess_critical_enter(sess, 0) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define SESS_LOCK_NESTED(sess) \
do \
{ \
RT_DEBUG_SCHEDULER_AVAILABLE(1); \
if (lwp_sess_critical_enter(sess, LWP_MTX_FALGS_NESTED) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#define SESS_UNLOCK(sess) \
do \
{ \
if (lwp_sess_critical_exit(sess) != RT_EOK) \
{ \
RT_ASSERT(0); \
} \
} while (0)
#else
#define LWP_LOCK(lwp) rt_base_t level = rt_hw_interrupt_disable()
#define LWP_UNLOCK(lwp) rt_hw_interrupt_enable(level)
#define PGRP_LOCK(pgrp) rt_base_t level = rt_hw_interrupt_disable()
#define PGRP_UNLOCK(pgrp) rt_hw_interrupt_enable(level)
#define SESS_LOCK(sess) rt_base_t level = rt_hw_interrupt_disable()
#define SESS_UNLOCK(sess) rt_hw_interrupt_enable(level)
#endif /* LWP_USING_CPUS_LOCK */
@@ -95,4 +186,6 @@ rt_err_t lwp_critical_exit(struct rt_lwp *lwp);
#define LWP_RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;}
#endif /* LWP_DEBUG */
int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]);
#endif /* __LWP_INTERNAL_H__ */
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#define DBG_TAG "lwp.tty"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include <terminal/terminal.h>
#include "lwp_internal.h"
static void jobctrl_set_pgrp_orphaned(struct rt_processgroup *pgrp)
{
rt_lwp_t proc, nx_proc;
PGRP_LOCK(pgrp);
pgrp->is_orphaned = 1;
rt_list_for_each_entry(proc, &pgrp->process, pgrp_node)
{
LWP_LOCK(proc);
if (proc->jobctl_stopped)
{
LWP_UNLOCK(proc);
rt_list_for_each_entry_safe(proc, nx_proc, &pgrp->process, pgrp_node)
{
LWP_LOCK(proc);
lwp_signal_kill(proc, SIGHUP, SI_KERNEL, 0);
lwp_signal_kill(proc, SIGCONT, SI_KERNEL, 0);
LWP_UNLOCK(proc);
}
}
LWP_UNLOCK(proc);
}
PGRP_UNLOCK(pgrp);
}
void lwp_jobctrl_on_exit(struct rt_lwp *lwp)
{
rt_processgroup_t pgrp;
rt_session_t session;
lwp_tty_t tp;
pgrp = lwp->pgrp;
RT_ASSERT(pgrp);
session = pgrp->session;
RT_ASSERT(session);
/**
* as a session leader, we have to mark tty as freed. So others can race to
* take it before we actually close and released that tty
*/
SESS_LOCK(session);
if (session->sid == lwp->pid)
{
tp = session->ctty;
session->leader = 0;
/* signal to foreground group that modem is disconnected */
if (tp)
{
tty_lock(tp);
if (tp->t_session == session)
lwp_tty_signal_pgrp(tp, SIGHUP);
tty_unlock(tp);
}
/* revoke tty vnode ? */
rt_list_for_each_entry(pgrp, &session->processgroup, pgrp_list_node)
{
jobctrl_set_pgrp_orphaned(pgrp);
}
}
SESS_UNLOCK(session);
/* release tty */
/* allow tty stolen? */
}
File diff suppressed because it is too large Load Diff
+498 -210
View File
File diff suppressed because it is too large Load Diff
+31 -7
View File
@@ -11,14 +11,14 @@
#ifndef LWP_PID_H__
#define LWP_PID_H__
#include "lwp.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LWP_CREATE_FLAG_NONE 0x0000
#define LWP_CREATE_FLAG_ALLOC_PID 0x0001 /* allocate pid on lwp object create */
#define LWP_CREATE_FLAG_NONE 0x0000
#define LWP_CREATE_FLAG_ALLOC_PID 0x0001 /* allocate pid on lwp object create */
#define LWP_CREATE_FLAG_INIT_USPACE 0x0002 /* do user space initialization */
#define LWP_CREATE_FLAG_NOTRACE_EXEC 0x0004 /* not trace if execve() after fork() */
struct rt_lwp;
@@ -46,6 +46,7 @@ void lwp_free(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_raw_locked(pid_t pid);
struct rt_lwp* lwp_from_pid_locked(pid_t pid);
pid_t lwp_to_pid(struct rt_lwp* lwp);
@@ -54,7 +55,29 @@ char* lwp_pid2name(int32_t pid);
int lwp_getpid(void);
pid_t lwp_waitpid(const pid_t pid, int *status, int options);
struct rusage
{
struct timeval ru_utime;
struct timeval ru_stime;
long ru_maxrss;
long ru_ixrss;
long ru_idrss;
long ru_isrss;
long ru_minflt;
long ru_majflt;
long ru_nswap;
long ru_inblock;
long ru_oublock;
long ru_msgsnd;
long ru_msgrcv;
long ru_nsignals;
long ru_nvcsw;
long ru_nivcsw;
long reserved[16];
};
pid_t lwp_waitpid(const pid_t pid, int *status, int options, struct rusage *ru);
rt_err_t lwp_waitpid_kick(struct rt_lwp *parent, struct rt_lwp *self_lwp);
pid_t waitpid(pid_t pid, int *status, int options);
long list_process(void);
@@ -85,8 +108,9 @@ rt_inline void lwp_from_pid_release_lock(struct rt_lwp *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);
typedef rt_base_t lwp_status_t;
void lwp_thread_exit(rt_thread_t thread, int status);
void lwp_exit(struct rt_lwp *lwp, lwp_status_t status);
#ifdef __cplusplus
}
-459
View File
@@ -1,459 +0,0 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021/01/02 bernard the first version
* 2022/12/18 bernard fix the _m_lock to tid in user land.
*/
#include "lwp_internal.h"
#include <rtthread.h>
#ifdef ARCH_MM_MMU
#include <lwp_user_mm.h>
#endif
#include <sys/time.h>
#include <syscall_generic.h>
#define PMUTEX_NORMAL 0 /* Unable to recursion */
#define PMUTEX_RECURSIVE 1 /* Can be recursion */
#define PMUTEX_ERRORCHECK 2 /* This type of mutex provides error checking */
struct rt_pmutex
{
union
{
rt_mutex_t kmutex;
rt_sem_t ksem; /* use sem to emulate the mutex without recursive */
} lock;
struct lwp_avl_struct node;
struct rt_object *custom_obj;
rt_uint8_t type; /* pmutex type */
};
/*
* userspace mutex definitions in musl
*/
struct rt_umutex
{
union
{
int __i[6];
volatile int __vi[6];
volatile void *volatile __p[6];
} __u;
};
#define _m_type __u.__i[0]
#define _m_lock __u.__vi[1]
#define _m_waiters __u.__vi[2]
#define _m_prev __u.__p[3]
#define _m_next __u.__p[4]
#define _m_count __u.__i[5]
static struct rt_mutex _pmutex_lock;
static int pmutex_system_init(void)
{
rt_mutex_init(&_pmutex_lock, "pmtxLock", RT_IPC_FLAG_FIFO);
return 0;
}
INIT_PREV_EXPORT(pmutex_system_init);
static rt_err_t pmutex_destory(void *data)
{
rt_err_t ret = -1;
struct rt_pmutex *pmutex = (struct rt_pmutex *)data;
if (pmutex)
{
lwp_mutex_take_safe(&_pmutex_lock, RT_WAITING_FOREVER, 0);
/* remove pmutex from pmutext avl */
lwp_avl_remove(&pmutex->node, (struct lwp_avl_struct **)pmutex->node.data);
lwp_mutex_release_safe(&_pmutex_lock);
if (pmutex->type == PMUTEX_NORMAL)
{
rt_sem_delete(pmutex->lock.ksem);
}
else
{
rt_mutex_delete(pmutex->lock.kmutex);
}
/* release object */
rt_free(pmutex);
ret = 0;
}
return ret;
}
static struct rt_pmutex* pmutex_create(void *umutex, struct rt_lwp *lwp)
{
struct rt_pmutex *pmutex = RT_NULL;
struct rt_object *obj = RT_NULL;
rt_ubase_t type;
if (!lwp)
{
return RT_NULL;
}
long *p = (long *)umutex;
/* umutex[0] bit[0-1] saved mutex type */
type = *p & 3;
if (type != PMUTEX_NORMAL && type != PMUTEX_RECURSIVE && type != PMUTEX_ERRORCHECK)
{
return RT_NULL;
}
pmutex = (struct rt_pmutex *)rt_malloc(sizeof(struct rt_pmutex));
if (!pmutex)
{
return RT_NULL;
}
if (type == PMUTEX_NORMAL)
{
pmutex->lock.ksem = rt_sem_create("pmutex", 1, RT_IPC_FLAG_PRIO);
if (!pmutex->lock.ksem)
{
rt_free(pmutex);
return RT_NULL;
}
}
else
{
pmutex->lock.kmutex = rt_mutex_create("pmutex", RT_IPC_FLAG_PRIO);
if (!pmutex->lock.kmutex)
{
rt_free(pmutex);
return RT_NULL;
}
}
obj = rt_custom_object_create("pmutex", (void *)pmutex, pmutex_destory);
if (!obj)
{
if (pmutex->type == PMUTEX_NORMAL)
{
rt_sem_delete(pmutex->lock.ksem);
}
else
{
rt_mutex_delete(pmutex->lock.kmutex);
}
rt_free(pmutex);
return RT_NULL;
}
pmutex->node.avl_key = (avl_key_t)umutex;
pmutex->node.data = &lwp->address_search_head;
pmutex->custom_obj = obj;
pmutex->type = type;
/* insert into pmutex head */
lwp_avl_insert(&pmutex->node, &lwp->address_search_head);
return pmutex;
}
static struct rt_pmutex* pmutex_get(void *umutex, struct rt_lwp *lwp)
{
struct rt_pmutex *pmutex = RT_NULL;
struct lwp_avl_struct *node = RT_NULL;
node = lwp_avl_find((avl_key_t)umutex, lwp->address_search_head);
if (!node)
{
return RT_NULL;
}
pmutex = rt_container_of(node, struct rt_pmutex, node);
return pmutex;
}
static int _pthread_mutex_init(void *umutex)
{
struct rt_lwp *lwp = RT_NULL;
struct rt_pmutex *pmutex = RT_NULL;
rt_err_t lock_ret = 0;
/* umutex union is 6 x (void *) */
if (!lwp_user_accessable(umutex, sizeof(void *) * 6))
{
rt_set_errno(EINVAL);
return -EINVAL;
}
lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
if (lock_ret != RT_EOK)
{
rt_set_errno(EAGAIN);
return -EAGAIN;
}
lwp = lwp_self();
pmutex = pmutex_get(umutex, lwp);
if (pmutex == RT_NULL)
{
/* create a pmutex according to this umutex */
pmutex = pmutex_create(umutex, lwp);
if (pmutex == RT_NULL)
{
rt_mutex_release(&_pmutex_lock);
rt_set_errno(ENOMEM);
return -ENOMEM;
}
if (lwp_user_object_add(lwp, pmutex->custom_obj) != 0)
{
rt_custom_object_destroy(pmutex->custom_obj);
rt_set_errno(ENOMEM);
return -ENOMEM;
}
}
else
{
lwp_mutex_take_safe(&_pmutex_lock, RT_WAITING_FOREVER, 1);
if (pmutex->type == PMUTEX_NORMAL)
{
pmutex->lock.ksem->value = 1;
}
else
{
pmutex->lock.kmutex->owner = RT_NULL;
pmutex->lock.kmutex->priority = 0xFF;
pmutex->lock.kmutex->hold = 0;
pmutex->lock.kmutex->ceiling_priority = 0xFF;
}
lwp_mutex_release_safe(&_pmutex_lock);
}
rt_mutex_release(&_pmutex_lock);
return 0;
}
static int _pthread_mutex_lock_timeout(void *umutex, struct timespec *timeout)
{
struct rt_lwp *lwp = RT_NULL;
struct rt_pmutex *pmutex = RT_NULL;
struct rt_umutex *umutex_p = (struct rt_umutex*)umutex;
rt_err_t lock_ret = 0;
rt_int32_t time = RT_WAITING_FOREVER;
if (!lwp_user_accessable((void *)umutex, sizeof(struct rt_umutex)))
{
rt_set_errno(EINVAL);
return -EINVAL;
}
if (timeout)
{
if (!lwp_user_accessable((void *)timeout, sizeof(struct timespec)))
{
rt_set_errno(EINVAL);
return -EINVAL;
}
time = rt_timespec_to_tick(timeout);
}
lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
if (lock_ret != RT_EOK)
{
rt_set_errno(EINTR);
return -EINTR;
}
lwp = lwp_self();
pmutex = pmutex_get(umutex, lwp);
if (pmutex == RT_NULL)
{
rt_mutex_release(&_pmutex_lock);
rt_set_errno(EINVAL);
return -ENOMEM; /* umutex not recored in kernel */
}
rt_mutex_release(&_pmutex_lock);
switch (pmutex->type)
{
case PMUTEX_NORMAL:
lock_ret = rt_sem_take_interruptible(pmutex->lock.ksem, time);
break;
case PMUTEX_RECURSIVE:
lock_ret = rt_mutex_take_interruptible(pmutex->lock.kmutex, time);
if (lock_ret == RT_EOK)
{
umutex_p->_m_lock = rt_thread_self()->tid;
}
break;
case PMUTEX_ERRORCHECK:
lock_ret = lwp_mutex_take_safe(&_pmutex_lock, RT_WAITING_FOREVER, 1);
if (lock_ret != RT_EOK)
{
return -EINTR;
}
if (pmutex->lock.kmutex->owner == rt_thread_self())
{
lwp_mutex_release_safe(&_pmutex_lock);
return -EDEADLK;
}
lwp_mutex_release_safe(&_pmutex_lock);
lock_ret = rt_mutex_take_interruptible(pmutex->lock.kmutex, time);
if (lock_ret == RT_EOK)
{
umutex_p->_m_lock = rt_thread_self()->tid;
}
break;
default: /* unknown type */
return -EINVAL;
}
if (lock_ret != RT_EOK)
{
if (lock_ret == -RT_ETIMEOUT)
{
if (time == 0) /* timeout is 0, means try lock failed */
{
rt_set_errno(EBUSY);
return -EBUSY;
}
else
{
rt_set_errno(ETIMEDOUT);
return -ETIMEDOUT;
}
}
else if (lock_ret == -RT_EINTR)
{
rt_set_errno(EINTR);
return -EINTR;
}
else
{
rt_set_errno(EAGAIN);
return -EAGAIN;
}
}
return 0;
}
static int _pthread_mutex_unlock(void *umutex)
{
rt_err_t lock_ret = 0;
struct rt_lwp *lwp = RT_NULL;
struct rt_pmutex *pmutex = RT_NULL;
struct rt_umutex *umutex_p = (struct rt_umutex*)umutex;
lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
if (lock_ret != RT_EOK)
{
rt_set_errno(EAGAIN);
return -EAGAIN;
}
lwp = lwp_self();
pmutex = pmutex_get(umutex, lwp);
if (pmutex == RT_NULL)
{
rt_mutex_release(&_pmutex_lock);
rt_set_errno(EPERM);
return -EPERM;//unlock static mutex of unlock state
}
rt_mutex_release(&_pmutex_lock);
switch (pmutex->type)
{
case PMUTEX_NORMAL:
if(pmutex->lock.ksem->value >=1)
{
rt_set_errno(EPERM);
return -EPERM;//unlock dynamic mutex of unlock state
}
else
{
lock_ret = rt_sem_release(pmutex->lock.ksem);
}
break;
case PMUTEX_RECURSIVE:
case PMUTEX_ERRORCHECK:
lock_ret = rt_mutex_release(pmutex->lock.kmutex);
if ((lock_ret == RT_EOK) && pmutex->lock.kmutex->owner == NULL)
{
umutex_p->_m_lock = 0;
}
break;
default: /* unknown type */
return -EINVAL;
}
if (lock_ret != RT_EOK)
{
rt_set_errno(EPERM);
return -EPERM;
}
return 0;
}
static int _pthread_mutex_destroy(void *umutex)
{
struct rt_lwp *lwp = RT_NULL;
struct rt_pmutex *pmutex = RT_NULL;
rt_err_t lock_ret = 0;
lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
if (lock_ret != RT_EOK)
{
rt_set_errno(EAGAIN);
return -EAGAIN;
}
lwp = lwp_self();
pmutex = pmutex_get(umutex, lwp);
if (pmutex == RT_NULL)
{
rt_mutex_release(&_pmutex_lock);
rt_set_errno(EINVAL);
return -EINVAL;
}
lwp_user_object_delete(lwp, pmutex->custom_obj);
rt_mutex_release(&_pmutex_lock);
return 0;
}
sysret_t sys_pmutex(void *umutex, int op, void *arg)
{
int ret = -EINVAL;
switch (op)
{
case PMUTEX_INIT:
ret = _pthread_mutex_init(umutex);
break;
case PMUTEX_LOCK:
ret = _pthread_mutex_lock_timeout(umutex, (struct timespec*)arg);
if (ret == -ENOMEM)
{
/* lock not init, try init it and lock again. */
ret = _pthread_mutex_init(umutex);
if (ret == 0)
{
ret = _pthread_mutex_lock_timeout(umutex, (struct timespec*)arg);
}
}
break;
case PMUTEX_UNLOCK:
ret = _pthread_mutex_unlock(umutex);
break;
case PMUTEX_DESTROY:
ret = _pthread_mutex_destroy(umutex);
break;
default:
rt_set_errno(EINVAL);
break;
}
return ret;
}
+432
View File
@@ -0,0 +1,432 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-17 xqyjlj the first version
* 2023-11-29 Shell Add direct reference of sess for group
*/
#include "lwp.h"
#include "lwp_internal.h"
#include "lwp_syscall.h"
#include "terminal/terminal.h"
#define DBG_TAG "lwp.session"
#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
rt_session_t lwp_session_find(pid_t sid)
{
rt_base_t level;
rt_session_t session = RT_NULL;
rt_list_t *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
information = rt_object_get_information(RT_Object_Class_Session);
/* parameter check */
if ((sid < 0) || (information == RT_NULL))
{
return RT_NULL;
}
if (sid == 0)
{
sid = lwp_getpid();
}
/* enter critical */
level = rt_spin_lock_irqsave(&(information->spinlock));
/* try to find session */
rt_list_for_each(node, &(information->object_list))
{
session = (rt_session_t)rt_list_entry(node, struct rt_object, list);
if (session->sid == sid)
{
rt_spin_unlock_irqrestore(&(information->spinlock), level);
return session;
}
}
rt_spin_unlock_irqrestore(&(information->spinlock), level);
return RT_NULL;
}
rt_session_t lwp_session_create(rt_lwp_t leader)
{
rt_session_t session = RT_NULL;
/* parameter check */
if (leader == RT_NULL)
{
return RT_NULL;
}
session = rt_malloc(sizeof(struct rt_session));
if (session != RT_NULL)
{
rt_object_init(&(session->object), RT_Object_Class_Session, "session");
rt_list_init(&(session->processgroup));
rt_mutex_init(&(session->mutex), "session", RT_IPC_FLAG_PRIO);
session->leader = leader;
session->sid = leader->pid;
lwp_pgrp_update_children_info(leader->pgrp, session->sid, leader->pgid);
session->foreground_pgid = session->sid;
session->ctty = RT_NULL;
}
return session;
}
int lwp_session_delete(rt_session_t session)
{
int retry = 1;
lwp_tty_t ctty;
/* parameter check */
if (session == RT_NULL)
{
return -EINVAL;
}
/* clear children sid */
lwp_session_update_children_info(session, 0);
while (retry)
{
retry = 0;
ctty = session->ctty;
SESS_LOCK_NESTED(session);
if (session->ctty == ctty)
{
if (ctty)
{
SESS_UNLOCK(session);
/**
* Note: it's safe to release the session lock now. Even if someone
* race to acquire the tty, it's safe under protection of tty_lock()
* and the check inside
*/
tty_lock(ctty);
tty_rel_sess(ctty, session);
session->ctty = RT_NULL;
}
else
{
SESS_UNLOCK(session);
}
}
else
{
SESS_UNLOCK(session);
retry = 1;
}
}
rt_object_detach(&(session->object));
rt_mutex_detach(&(session->mutex));
rt_free(session);
return 0;
}
int lwp_session_insert(rt_session_t session, rt_processgroup_t group)
{
/* parameter check */
if (session == RT_NULL || group == RT_NULL)
{
return -EINVAL;
}
SESS_LOCK_NESTED(session);
PGRP_LOCK_NESTED(group);
group->sid = session->sid;
group->session = session;
lwp_pgrp_update_children_info(group, session->sid, group->pgid);
rt_list_insert_after(&(session->processgroup), &(group->pgrp_list_node));
PGRP_UNLOCK(group);
SESS_UNLOCK(session);
return 0;
}
int lwp_session_remove(rt_session_t session, rt_processgroup_t group)
{
rt_bool_t is_empty = RT_FALSE;
/* parameter check */
if (session == RT_NULL || group == RT_NULL)
{
return -EINVAL;
}
SESS_LOCK_NESTED(session);
PGRP_LOCK_NESTED(group);
rt_list_remove(&(group->pgrp_list_node));
/* clear children sid */
lwp_pgrp_update_children_info(group, 0, group->pgid);
group->sid = 0;
group->session = RT_NULL;
PGRP_UNLOCK(group);
is_empty = rt_list_isempty(&(session->processgroup));
SESS_UNLOCK(session);
if (is_empty)
{
lwp_session_delete(session);
return 1;
}
return 0;
}
int lwp_session_move(rt_session_t session, rt_processgroup_t group)
{
rt_session_t prev_session;
/* parameter check */
if (session == RT_NULL || group == RT_NULL)
{
return -EINVAL;
}
if (lwp_sid_get_bysession(session) == lwp_sid_get_bypgrp(group))
{
return 0;
}
SESS_LOCK(session);
prev_session = group->session;
if (prev_session)
{
SESS_LOCK(prev_session);
lwp_session_remove(prev_session, group);
SESS_UNLOCK(prev_session);
}
lwp_session_insert(session, group);
SESS_UNLOCK(session);
return 0;
}
int lwp_session_update_children_info(rt_session_t session, pid_t sid)
{
rt_list_t *node = RT_NULL;
rt_processgroup_t group = RT_NULL;
if (session == RT_NULL)
{
return -EINVAL;
}
SESS_LOCK_NESTED(session);
rt_list_for_each(node, &(session->processgroup))
{
group = (rt_processgroup_t)rt_list_entry(node, struct rt_processgroup, pgrp_list_node);
PGRP_LOCK_NESTED(group);
if (sid != -1)
{
group->sid = sid;
group->session = session;
lwp_pgrp_update_children_info(group, sid, group->pgid);
}
PGRP_UNLOCK(group);
}
SESS_UNLOCK(session);
return 0;
}
int lwp_session_set_foreground(rt_session_t session, pid_t pgid)
{
rt_processgroup_t group = RT_NULL;
rt_list_t *node = RT_NULL;
rt_bool_t is_contains = RT_FALSE;
/* parameter check */
if (session == RT_NULL || pgid <= 0)
{
return -EINVAL;
}
SESS_LOCK(session);
rt_list_for_each(node, &(session->processgroup))
{
group = (rt_processgroup_t)rt_list_entry(node, struct rt_processgroup, pgrp_list_node);
PGRP_LOCK(group);
if (group->pgid == pgid)
{
is_contains = RT_TRUE;
}
PGRP_UNLOCK(group);
}
if (is_contains)
{
session->foreground_pgid = pgid;
// TODO: maybe notify tty
}
SESS_UNLOCK(session);
return is_contains ? 0 : -EINVAL;
}
/**
* setsid() creates a new session if the calling process is not a process group leader.
* The calling process is the leader of the new session (i.e., its session ID is made the same as its process ID).
* The calling process also becomes the process group leader of a new process group in the session
* (i.e., its process group ID is made the same as its process ID).
*/
sysret_t sys_setsid(void)
{
rt_lwp_t process;
pid_t pid;
rt_processgroup_t group;
rt_session_t session;
sysret_t err = 0;
process = lwp_self();
pid = lwp_to_pid(process);
/**
* if the calling process is already a process group leader.
*/
if (lwp_pgrp_find(pid))
{
err = -EPERM;
goto exit;
}
group = lwp_pgrp_create(process);
if (group)
{
lwp_pgrp_move(group, process);
session = lwp_session_create(process);
if (session)
{
lwp_session_move(session, group);
}
else
{
lwp_pgrp_delete(group);
}
err = lwp_sid_get_bysession(session);
}
else
{
err = -ENOMEM;
}
exit:
return err;
}
/**
* getsid() returns the session ID of the process with process ID pid.
* If pid is 0, getsid() returns the session ID of the calling process.
*/
sysret_t sys_getsid(pid_t pid)
{
rt_lwp_t process, self_process;
pid_t sid;
lwp_pid_lock_take();
process = lwp_from_pid_locked(pid);
lwp_pid_lock_release();
if (process == RT_NULL)
{
return -ESRCH;
}
self_process = lwp_self();
sid = lwp_sid_get_byprocess(process);
if (sid != lwp_sid_get_byprocess(self_process))
{
/**
* A process with process ID pid exists, but it is not in the same session as the calling process,
* and the implementation considers this an error.
*
* Note: Linux does not return EPERM.
*/
return -EPERM;
}
return sid;
}
#ifdef RT_USING_FINSH
#include "finsh.h"
long list_session(void)
{
int count = 0, index;
rt_session_t *sessions;
rt_session_t session;
rt_thread_t thread;
char name[RT_NAME_MAX];
rt_kprintf("SID leader process\n");
rt_kprintf("---- ----------------\n");
count = rt_object_get_length(RT_Object_Class_Session);
if (count > 0)
{
/* get pointers */
sessions = (rt_session_t *)rt_calloc(count, sizeof(rt_session_t));
if (sessions)
{
index = rt_object_get_pointers(RT_Object_Class_Session, (rt_object_t *)sessions, count);
if (index > 0)
{
for (index = 0; index < count; index++)
{
struct rt_session se;
session = sessions[index];
SESS_LOCK(session);
rt_memcpy(&se, session, sizeof(struct rt_session));
SESS_UNLOCK(session);
if (se.leader && se.leader)
{
thread = rt_list_entry(se.leader->t_grp.prev, struct rt_thread, sibling);
rt_strncpy(name, thread->parent.name, RT_NAME_MAX);
}
else
{
rt_strncpy(name, "nil", RT_NAME_MAX);
}
rt_kprintf("%4d %-*.*s\n", se.sid, RT_NAME_MAX, RT_NAME_MAX, name);
}
}
rt_free(sessions);
}
}
return 0;
}
MSH_CMD_EXPORT(list_session, list session);
#endif
-27
View File
@@ -1,27 +0,0 @@
#include <rthw.h>
#include <rtthread.h>
#include "lwp.h"
//#include "lwp_tid.h"
#include "lwp_pid.h"
int setsid(void)
{
int err = -EPERM;
struct rt_thread *current_thread = rt_thread_self();
struct rt_lwp *current_lwp = (struct rt_lwp *)rt_thread_self()->lwp;
if (current_lwp->session == current_thread->tid)
{
return err;
}
current_lwp->session = current_thread->tid;
current_lwp->__pgrp = current_thread->tid;
current_lwp->leader = 1;
current_lwp->tty = RT_NULL;
current_lwp->tty_old_pgrp = 0;
err = current_lwp->session;
return err;
}
File diff suppressed because it is too large Load Diff
+68 -15
View File
@@ -7,6 +7,7 @@
* Date Author Notes
* 2020-02-23 Jesven first version.
* 2023-07-06 Shell update the generation, pending and delivery API
* 2023-11-22 Shell support for job control signal
*/
#ifndef __LWP_SIGNAL_H__
@@ -17,23 +18,33 @@
#include <rtthread.h>
#include <sys/signal.h>
struct timespec;
struct itimerspec;
#ifdef __cplusplus
extern "C" {
#endif
#define _USIGNAL_SIGMASK(signo) (1u << ((signo)-1))
#define LWP_SIG_IGNORE_SET (_USIGNAL_SIGMASK(SIGCHLD) | _USIGNAL_SIGMASK(SIGURG))
#define LWP_SIG_ACT_DFL ((lwp_sighandler_t)0)
#define LWP_SIG_ACT_IGN ((lwp_sighandler_t)1)
#define LWP_SIG_USER_SA_FLAGS \
(SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \
#define LWP_SIG_NO_IGN_SET \
(_USIGNAL_SIGMASK(SIGCONT) | _USIGNAL_SIGMASK(SIGSTOP) | \
_USIGNAL_SIGMASK(SIGKILL))
#define LWP_SIG_IGNORE_SET \
(_USIGNAL_SIGMASK(SIGCHLD) | _USIGNAL_SIGMASK(SIGURG) | \
_USIGNAL_SIGMASK(SIGWINCH) /* from 4.3 BSD, not POSIX.1 */)
#define LWP_SIG_JOBCTL_SET \
(_USIGNAL_SIGMASK(SIGCONT) | _USIGNAL_SIGMASK(SIGSTOP) | \
_USIGNAL_SIGMASK(SIGTSTP) | _USIGNAL_SIGMASK(SIGTTIN) | \
_USIGNAL_SIGMASK(SIGTTOU))
#define LWP_SIG_STOP_SET \
(_USIGNAL_SIGMASK(SIGSTOP) | _USIGNAL_SIGMASK(SIGTSTP) | \
_USIGNAL_SIGMASK(SIGTTIN) | _USIGNAL_SIGMASK(SIGTTOU))
#define LWP_SIG_ACT_DFL ((lwp_sighandler_t)0)
#define LWP_SIG_ACT_IGN ((lwp_sighandler_t)1)
#define LWP_SIG_USER_SA_FLAGS \
(SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \
SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS)
#define LWP_SIG_INVALID_TIMER ((timer_t)-1)
typedef enum {
typedef enum
{
LWP_SIG_MASK_CMD_BLOCK,
LWP_SIG_MASK_CMD_UNBLOCK,
LWP_SIG_MASK_CMD_SET_MASK,
@@ -43,7 +54,8 @@ typedef enum {
/**
* LwP implementation of POSIX signal
*/
struct lwp_signal {
struct lwp_signal
{
timer_t real_timer;
struct lwp_sigqueue sig_queue;
rt_thread_t sig_dispatch_thr[_LWP_NSIG];
@@ -55,9 +67,12 @@ struct lwp_signal {
lwp_sigset_t sig_action_onstack;
lwp_sigset_t sig_action_restart;
lwp_sigset_t sig_action_siginfo;
lwp_sigset_t sig_action_nocldstop;
lwp_sigset_t sig_action_nocldwait;
};
struct rt_lwp;
struct rt_processgroup;
#ifndef ARCH_MM_MMU
void lwp_sighandler_set(int sig, lwp_sighandler_t func);
@@ -93,12 +108,14 @@ rt_inline void lwp_thread_signal_detach(struct lwp_thread_signal *tsig)
* @param signo the signal number
* @param code as in siginfo
* @param value as in siginfo
* @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as successful
* @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as
* successful
*
* @note the *signal_kill have the same definition of a successful return as
* kill() in IEEE Std 1003.1-2017
*/
rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code, long value);
rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code,
lwp_siginfo_ext_t value);
/**
* @brief set or examine the signal action of signo
@@ -119,9 +136,11 @@ rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo,
* @param signo the signal number
* @param code as in siginfo
* @param value as in siginfo
* @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as successful
* @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as
* successful
*/
rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, long value);
rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code,
lwp_siginfo_ext_t value);
/**
* @brief set signal mask of target thread
@@ -136,7 +155,8 @@ rt_err_t lwp_thread_signal_mask(rt_thread_t thread, lwp_sig_mask_cmd_t how,
const lwp_sigset_t *sigset, lwp_sigset_t *oset);
/**
* @brief Catch signal if exists and no return, otherwise return with no side effect
* @brief Catch signal if exists and no return, otherwise return with no
* side effect
*
* @param exp_frame the exception frame on kernel stack
*/
@@ -172,10 +192,43 @@ rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
*/
void lwp_thread_signal_pending(rt_thread_t thread, lwp_sigset_t *sigset);
/**
* @brief send a signal to the process group
*
* @param pgrp target process group
* @param signo the signal number
* @param code as in siginfo
* @param value as in siginfo
* @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as
* successful
*/
rt_err_t lwp_pgrp_signal_kill(struct rt_processgroup *pgrp, long signo,
long code, lwp_siginfo_ext_t value);
rt_inline int lwp_sigismember(lwp_sigset_t *set, int _sig)
{
unsigned long sig = _sig - 1;
if (_LWP_NSIG_WORDS == 1)
{
return 1 & (set->sig[0] >> sig);
}
else
{
return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
}
}
struct itimerspec;
rt_bool_t lwp_sigisign(struct rt_lwp *lwp, int _sig);
rt_err_t lwp_signal_setitimer(struct rt_lwp *lwp, int which,
const struct itimerspec *restrict new,
struct itimerspec *restrict old);
rt_bool_t lwp_signal_restart_syscall(struct rt_lwp *lwp, int error_code);
#ifdef __cplusplus
}
#endif
+20 -1
View File
@@ -113,7 +113,7 @@ struct musl_ifreq
{
union
{
#define IFNAMSIZ 16
#define IFNAMSIZ 16
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
union
@@ -133,4 +133,23 @@ struct musl_ifreq
} ifr_ifru;
};
struct musl_rtentry
{
unsigned long int rt_pad1;
struct musl_sockaddr rt_dst;
struct musl_sockaddr rt_gateway;
struct musl_sockaddr rt_genmask;
unsigned short int rt_flags;
short int rt_pad2;
unsigned long int rt_pad3;
unsigned char rt_tos;
unsigned char rt_class;
short int rt_pad4[sizeof(long)/2-1];
short int rt_metric;
char *rt_dev;
unsigned long int rt_mtu;
unsigned long int rt_window;
unsigned short int rt_irtt;
};
#endif /* __LWP_SYS_SOCKET_H__ */
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -108,10 +108,15 @@ sysret_t sys_log(const char* log, int size);
#ifdef ARCH_MM_MMU
sysret_t sys_futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3);
sysret_t sys_pmutex(void *umutex, int op, void *arg);
sysret_t sys_cacheflush(void *addr, int len, int cache);
#endif /* ARCH_MM_MMU */
sysret_t sys_setsid(void);
sysret_t sys_getsid(pid_t pid);
sysret_t sys_setpgid(pid_t pid, pid_t pgid);
sysret_t sys_getpgid(pid_t pid);
#ifdef __cplusplus
}
#endif
+15 -6
View File
@@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2021-01-15 shaojinchun first version
* 2023-11-16 xqyjlj Fix the case where tid is 0
*/
#define DBG_TAG "lwp.tid"
@@ -126,20 +127,28 @@ void lwp_tid_put(int tid)
lwp_mutex_release_safe(&tid_lock);
}
rt_thread_t lwp_tid_get_thread_and_inc_ref(int tid)
rt_thread_t lwp_tid_get_thread_raw(int tid)
{
struct lwp_avl_struct *p;
rt_thread_t thread = RT_NULL;
lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
p = lwp_avl_find(tid, lwp_tid_root);
if (p)
{
thread = (rt_thread_t)p->data;
if (thread != RT_NULL)
{
thread->tid_ref_count += 1;
}
}
return thread;
}
rt_thread_t lwp_tid_get_thread_and_inc_ref(int tid)
{
rt_thread_t thread = RT_NULL;
lwp_mutex_take_safe(&tid_lock, RT_WAITING_FOREVER, 0);
thread = tid ? lwp_tid_get_thread_raw(tid) : rt_thread_self();
if (thread != RT_NULL)
{
thread->tid_ref_count += 1;
}
lwp_mutex_release_safe(&tid_lock);
return thread;
+21 -14
View File
@@ -23,10 +23,7 @@
#ifdef ARCH_MM_MMU
#include <lwp.h>
#include <lwp_arch.h>
#include <lwp_mm.h>
#include <lwp_user_mm.h>
#include "lwp_internal.h"
#include <mm_aspace.h>
#include <mm_fault.h>
@@ -161,10 +158,10 @@ void lwp_aspace_switch(struct rt_thread *thread)
void lwp_unmap_user_space(struct rt_lwp *lwp)
{
arch_user_space_free(lwp);
if (lwp->aspace)
arch_user_space_free(lwp);
}
static void *_lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size,
int text)
{
@@ -566,6 +563,14 @@ int lwp_munmap(struct rt_lwp *lwp, void *addr, size_t length)
return lwp_errno_to_posix(ret);
}
void *lwp_mremap(struct rt_lwp *lwp, void *old_address, size_t old_size,
size_t new_size, int flags, void *new_address)
{
RT_ASSERT(lwp);
return rt_aspace_mremap_range(lwp->aspace, old_address, old_size, new_size, flags, new_address);
}
size_t lwp_get_from_user(void *dst, void *src, size_t size)
{
struct rt_lwp *lwp = RT_NULL;
@@ -621,11 +626,6 @@ size_t lwp_put_to_user(void *dst, void *src, size_t size)
return lwp_data_put(lwp, dst, src, size);
}
rt_inline rt_bool_t _in_user_space(const char *addr)
{
return (addr >= (char *)USER_VADDR_START && addr < (char *)USER_VADDR_TOP);
}
rt_inline rt_bool_t _can_unaligned_access(const char *addr)
{
return rt_kmem_v2p((char *)addr) - PV_OFFSET == addr;
@@ -636,9 +636,9 @@ void *lwp_memcpy(void * __restrict dst, const void * __restrict src, size_t size
void *rc = dst;
long len;
if (_in_user_space(dst))
if (lwp_in_user_space(dst))
{
if (!_in_user_space(src))
if (!lwp_in_user_space(src))
{
len = lwp_put_to_user(dst, (void *)src, size);
if (!len)
@@ -654,7 +654,7 @@ void *lwp_memcpy(void * __restrict dst, const void * __restrict src, size_t size
}
else
{
if (_in_user_space(src))
if (lwp_in_user_space(src))
{
len = lwp_get_from_user(dst, (void *)src, size);
if (!len)
@@ -979,6 +979,13 @@ size_t lwp_user_strlen(const char *s)
return lwp_user_strlen_ext(lwp, s);
}
size_t lwp_strlen(struct rt_lwp *lwp, const char *s)
{
if (lwp_in_user_space(s))
return lwp_user_strlen_ext(lwp, s);
else
return strlen(s);
}
char** lwp_get_command_line_args(struct rt_lwp *lwp)
{
+4
View File
@@ -56,6 +56,9 @@ void* lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot, int fla
*/
int lwp_munmap(struct rt_lwp *lwp, void *addr, size_t length);
void *lwp_mremap(struct rt_lwp *lwp, void *old_address, size_t old_size,
size_t new_size, int flags, void *new_address);
/**
* @brief Test if address from user is accessible address by user
*
@@ -163,6 +166,7 @@ rt_base_t lwp_brk(void *addr);
size_t lwp_user_strlen(const char *s);
size_t lwp_user_strlen_ext(struct rt_lwp *lwp, const char *s);
size_t lwp_strlen(struct rt_lwp *lwp, const char *s);
int lwp_fork_aspace(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp);
+13
View File
@@ -0,0 +1,13 @@
menuconfig LWP_USING_TERMINAL
bool "Terminal I/O Subsystem"
depends on RT_USING_SMART
default y
if LWP_USING_TERMINAL
config LWP_PTY_MAX_PARIS_LIMIT
int "Max number of pty devices registered at the same time"
default 64
help
This upper limit is set to protect kernel memory from draining
out by the application if it keeps allocating pty devices.
endif
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Portions of this software were developed under sponsorship from Snow
* B.V., the Netherlands.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS_TTYDISC_H_
#define _SYS_TTYDISC_H_
#ifndef __LWP_TERMINAL_H__
#error "can only be included through <terminal.h>"
#endif /* !__LWP_TERMINAL_H__ */
#include <rtdef.h>
struct rt_wqueue;
struct rt_thread;
struct lwp_tty;
struct uio;
/* Top half routines. */
void ttydisc_open(struct lwp_tty *tp);
void ttydisc_close(struct lwp_tty *tp);
int ttydisc_read(struct lwp_tty *tp, struct uio *uio, int ioflag);
int ttydisc_write(struct lwp_tty *tp, struct uio *uio, int ioflag);
void ttydisc_optimize(struct lwp_tty *tp);
/* Bottom half routines. */
void ttydisc_modem(struct lwp_tty *tp, int open);
#define ttydisc_can_bypass(tp) ((tp)->t_flags & TF_BYPASS)
int ttydisc_rint(struct lwp_tty *tp, char c, int flags);
size_t ttydisc_rint_simple(struct lwp_tty *tp, const void *buf, size_t len);
size_t ttydisc_rint_bypass(struct lwp_tty *tp, const void *buf, size_t len);
void ttydisc_rint_done(struct lwp_tty *tp);
size_t ttydisc_rint_poll(struct lwp_tty *tp);
size_t ttydisc_getc(struct lwp_tty *tp, void *buf, size_t len);
int ttydisc_getc_uio(struct lwp_tty *tp, struct uio *uio);
size_t ttydisc_getc_poll(struct lwp_tty *tp);
/* Error codes for ttydisc_rint(). */
#define TRE_FRAMING 0x01
#define TRE_PARITY 0x02
#define TRE_OVERRUN 0x04
#define TRE_BREAK 0x08
#endif /* !_SYS_TTYDISC_H_ */
+180
View File
@@ -0,0 +1,180 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#include "bsd_porting.h"
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Portions of this software were developed under sponsorship from Snow
* B.V., the Netherlands.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS_TTYQUEUE_H_
#define _SYS_TTYQUEUE_H_
#ifndef __LWP_TERMINAL_H__
#error "can only be included through <teminal.h>"
#endif /* !__LWP_TERMINAL_H__ */
struct lwp_tty;
struct ttyinq_block;
struct ttyoutq_block;
struct uio;
/* Data input queue. */
struct ttyinq
{
struct ttyinq_block *ti_firstblock;
struct ttyinq_block *ti_startblock;
struct ttyinq_block *ti_reprintblock;
struct ttyinq_block *ti_lastblock;
unsigned int ti_begin;
unsigned int ti_linestart;
unsigned int ti_reprint;
unsigned int ti_end;
unsigned int ti_nblocks;
unsigned int ti_quota;
};
#define TTYINQ_DATASIZE 128
/* Data output queue. */
struct ttyoutq
{
struct ttyoutq_block *to_firstblock;
struct ttyoutq_block *to_lastblock;
unsigned int to_begin;
unsigned int to_end;
unsigned int to_nblocks;
unsigned int to_quota;
};
#define TTYOUTQ_DATASIZE (256 - sizeof(struct ttyoutq_block *))
/* Input queue handling routines. */
int ttyinq_setsize(struct ttyinq *ti, struct lwp_tty *tp, size_t len);
void ttyinq_free(struct ttyinq *ti);
int ttyinq_read_uio(struct ttyinq *ti, struct lwp_tty *tp, struct uio *uio,
size_t readlen, size_t flushlen);
size_t ttyinq_write(struct ttyinq *ti, const void *buf, size_t len, int quote);
int ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t len,
int quote);
void ttyinq_canonicalize(struct ttyinq *ti);
size_t ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen,
char *lastc);
void ttyinq_flush(struct ttyinq *ti);
int ttyinq_peekchar(struct ttyinq *ti, char *c, int *quote);
void ttyinq_unputchar(struct ttyinq *ti);
void ttyinq_reprintpos_set(struct ttyinq *ti);
void ttyinq_reprintpos_reset(struct ttyinq *ti);
rt_inline size_t ttyinq_getsize(struct ttyinq *ti)
{
return (ti->ti_nblocks * TTYINQ_DATASIZE);
}
rt_inline size_t ttyinq_getallocatedsize(struct ttyinq *ti)
{
return (ti->ti_quota * TTYINQ_DATASIZE);
}
rt_inline size_t ttyinq_bytesleft(struct ttyinq *ti)
{
size_t len;
/* Make sure the usage never exceeds the length. */
len = ti->ti_nblocks * TTYINQ_DATASIZE;
MPASS(len >= ti->ti_end);
return (len - ti->ti_end);
}
rt_inline size_t ttyinq_bytescanonicalized(struct ttyinq *ti)
{
MPASS(ti->ti_begin <= ti->ti_linestart);
return (ti->ti_linestart - ti->ti_begin);
}
rt_inline size_t ttyinq_bytesline(struct ttyinq *ti)
{
MPASS(ti->ti_linestart <= ti->ti_end);
return (ti->ti_end - ti->ti_linestart);
}
/* Input buffer iteration. */
typedef void ttyinq_line_iterator_t(void *data, char c, int flags);
void ttyinq_line_iterate_from_linestart(struct ttyinq *ti,
ttyinq_line_iterator_t *iterator,
void *data);
void ttyinq_line_iterate_from_reprintpos(struct ttyinq *ti,
ttyinq_line_iterator_t *iterator,
void *data);
/* Output queue handling routines. */
void ttyoutq_flush(struct ttyoutq *to);
int ttyoutq_setsize(struct ttyoutq *to, struct lwp_tty *tp, size_t len);
void ttyoutq_free(struct ttyoutq *to);
size_t ttyoutq_read(struct ttyoutq *to, void *buf, size_t len);
int ttyoutq_read_uio(struct ttyoutq *to, struct lwp_tty *tp, struct uio *uio);
size_t ttyoutq_write(struct ttyoutq *to, const void *buf, size_t len);
int ttyoutq_write_nofrag(struct ttyoutq *to, const void *buf, size_t len);
rt_inline size_t ttyoutq_getsize(struct ttyoutq *to)
{
return (to->to_nblocks * TTYOUTQ_DATASIZE);
}
rt_inline size_t ttyoutq_getallocatedsize(struct ttyoutq *to)
{
return (to->to_quota * TTYOUTQ_DATASIZE);
}
rt_inline size_t ttyoutq_bytesleft(struct ttyoutq *to)
{
size_t len;
/* Make sure the usage never exceeds the length. */
len = to->to_nblocks * TTYOUTQ_DATASIZE;
MPASS(len >= to->to_end);
return (len - to->to_end);
}
rt_inline size_t ttyoutq_bytesused(struct ttyoutq *to)
{
return (to->to_end - to->to_begin);
}
#endif /* !_SYS_TTYQUEUE_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+370
View File
@@ -0,0 +1,370 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#include "../bsd_porting.h"
#include "../terminal.h"
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Portions of this software were developed under sponsorship from Snow
* B.V., the Netherlands.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* TTY output queue buffering.
*
* The previous design of the TTY layer offered the so-called clists.
* These clists were used for both the input queues and the output
* queue. We don't use certain features on the output side, like quoting
* bits for parity marking and such. This mechanism is similar to the
* old clists, but only contains the features we need to buffer the
* output.
*/
struct ttyoutq_block
{
struct ttyoutq_block *tob_next;
char tob_data[TTYOUTQ_DATASIZE];
};
static uma_zone_t ttyoutq_zone;
#define TTYOUTQ_INSERT_TAIL(to, tob) \
do \
{ \
if (to->to_end == 0) \
{ \
tob->tob_next = to->to_firstblock; \
to->to_firstblock = tob; \
} \
else \
{ \
tob->tob_next = to->to_lastblock->tob_next; \
to->to_lastblock->tob_next = tob; \
} \
to->to_nblocks++; \
} while (0)
#define TTYOUTQ_REMOVE_HEAD(to) \
do \
{ \
to->to_firstblock = to->to_firstblock->tob_next; \
to->to_nblocks--; \
} while (0)
#define TTYOUTQ_RECYCLE(to, tob) \
do \
{ \
if (to->to_quota <= to->to_nblocks) \
uma_zfree(ttyoutq_zone, tob); \
else \
TTYOUTQ_INSERT_TAIL(to, tob); \
} while (0)
void ttyoutq_flush(struct ttyoutq *to)
{
to->to_begin = 0;
to->to_end = 0;
}
int ttyoutq_setsize(struct ttyoutq *to, struct lwp_tty *tp, size_t size)
{
struct ttyoutq_block *tob;
to->to_quota = howmany(size, TTYOUTQ_DATASIZE);
while (to->to_quota > to->to_nblocks)
{
/*
* List is getting bigger.
* Add new blocks to the tail of the list.
*
* We must unlock the TTY temporarily, because we need
* to allocate memory. This won't be a problem, because
* in the worst case, another thread ends up here, which
* may cause us to allocate too many blocks, but this
* will be caught by the loop below.
*/
tty_unlock(tp);
tob = uma_zalloc(ttyoutq_zone, M_WAITOK);
tty_lock(tp);
if (tty_gone(tp))
{
uma_zfree(ttyoutq_zone, tob);
return -ENXIO;
}
TTYOUTQ_INSERT_TAIL(to, tob);
}
return 0;
}
void ttyoutq_free(struct ttyoutq *to)
{
struct ttyoutq_block *tob;
ttyoutq_flush(to);
to->to_quota = 0;
while ((tob = to->to_firstblock) != NULL)
{
TTYOUTQ_REMOVE_HEAD(to);
uma_zfree(ttyoutq_zone, tob);
}
MPASS(to->to_nblocks == 0);
}
size_t ttyoutq_read(struct ttyoutq *to, void *buf, size_t len)
{
char *cbuf = buf;
while (len > 0)
{
struct ttyoutq_block *tob;
size_t cbegin, cend, clen;
/* See if there still is data. */
if (to->to_begin == to->to_end)
break;
tob = to->to_firstblock;
if (tob == NULL)
break;
/*
* The end address should be the lowest of these three:
* - The write pointer
* - The blocksize - we can't read beyond the block
* - The end address if we could perform the full read
*/
cbegin = to->to_begin;
cend = MIN(MIN(to->to_end, to->to_begin + len), TTYOUTQ_DATASIZE);
clen = cend - cbegin;
/* Copy the data out of the buffers. */
memcpy(cbuf, tob->tob_data + cbegin, clen);
cbuf += clen;
len -= clen;
if (cend == to->to_end)
{
/* Read the complete queue. */
to->to_begin = 0;
to->to_end = 0;
}
else if (cend == TTYOUTQ_DATASIZE)
{
/* Read the block until the end. */
TTYOUTQ_REMOVE_HEAD(to);
to->to_begin = 0;
to->to_end -= TTYOUTQ_DATASIZE;
TTYOUTQ_RECYCLE(to, tob);
}
else
{
/* Read the block partially. */
to->to_begin += clen;
}
}
return cbuf - (char *)buf;
}
/*
* An optimized version of ttyoutq_read() which can be used in pseudo
* TTY drivers to directly copy data from the outq to userspace, instead
* of buffering it.
*
* We can only copy data directly if we need to read the entire block
* back to the user, because we temporarily remove the block from the
* queue. Otherwise we need to copy it to a temporary buffer first, to
* make sure data remains in the correct order.
*/
int ttyoutq_read_uio(struct ttyoutq *to, struct lwp_tty *tp, struct uio *uio)
{
while (uio->uio_resid > 0)
{
int error;
struct ttyoutq_block *tob;
size_t cbegin, cend, clen;
/* See if there still is data. */
if (to->to_begin == to->to_end)
return 0;
tob = to->to_firstblock;
if (tob == NULL)
return 0;
/*
* The end address should be the lowest of these three:
* - The write pointer
* - The blocksize - we can't read beyond the block
* - The end address if we could perform the full read
*/
cbegin = to->to_begin;
cend = MIN(MIN(to->to_end, to->to_begin + uio->uio_resid),
TTYOUTQ_DATASIZE);
clen = cend - cbegin;
/*
* We can prevent buffering in some cases:
* - We need to read the block until the end.
* - We don't need to read the block until the end, but
* there is no data beyond it, which allows us to move
* the write pointer to a new block.
*/
if (cend == TTYOUTQ_DATASIZE || cend == to->to_end)
{
/*
* Fast path: zero copy. Remove the first block,
* so we can unlock the TTY temporarily.
*/
TTYOUTQ_REMOVE_HEAD(to);
to->to_begin = 0;
if (to->to_end <= TTYOUTQ_DATASIZE)
to->to_end = 0;
else
to->to_end -= TTYOUTQ_DATASIZE;
/* Temporary unlock and copy the data to userspace. */
tty_unlock(tp);
error = uiomove(tob->tob_data + cbegin, clen, uio);
tty_lock(tp);
/* Block can now be readded to the list. */
TTYOUTQ_RECYCLE(to, tob);
}
else
{
char ob[TTYOUTQ_DATASIZE - 1];
/*
* Slow path: store data in a temporary buffer.
*/
memcpy(ob, tob->tob_data + cbegin, clen);
to->to_begin += clen;
MPASS(to->to_begin < TTYOUTQ_DATASIZE);
/* Temporary unlock and copy the data to userspace. */
tty_unlock(tp);
error = uiomove(ob, clen, uio);
tty_lock(tp);
}
if (error != 0)
return error;
}
return 0;
}
size_t ttyoutq_write(struct ttyoutq *to, const void *buf, size_t nbytes)
{
const char *cbuf = buf;
struct ttyoutq_block *tob;
unsigned int boff;
size_t l;
while (nbytes > 0)
{
boff = to->to_end % TTYOUTQ_DATASIZE;
if (to->to_end == 0)
{
/* First time we're being used or drained. */
MPASS(to->to_begin == 0);
tob = to->to_firstblock;
if (tob == NULL)
{
/* Queue has no blocks. */
break;
}
to->to_lastblock = tob;
}
else if (boff == 0)
{
/* We reached the end of this block on last write. */
tob = to->to_lastblock->tob_next;
if (tob == NULL)
{
/* We've reached the watermark. */
break;
}
to->to_lastblock = tob;
}
else
{
tob = to->to_lastblock;
}
/* Don't copy more than was requested. */
l = MIN(nbytes, TTYOUTQ_DATASIZE - boff);
MPASS(l > 0);
memcpy(tob->tob_data + boff, cbuf, l);
cbuf += l;
nbytes -= l;
to->to_end += l;
}
return (cbuf - (const char *)buf);
}
int ttyoutq_write_nofrag(struct ttyoutq *to, const void *buf, size_t nbytes)
{
size_t ret __unused;
if (ttyoutq_bytesleft(to) < nbytes)
return -1;
/* We should always be able to write it back. */
ret = ttyoutq_write(to, buf, nbytes);
MPASS(ret == nbytes);
return 0;
}
static int ttyoutq_startup(void)
{
ttyoutq_zone = uma_zcreate("ttyoutq", sizeof(struct ttyoutq_block), NULL,
NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
return 0;
}
INIT_PREV_EXPORT(ttyoutq_startup);
#if 0
SYSINIT(ttyoutq, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyoutq_startup, NULL);
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+415
View File
@@ -0,0 +1,415 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#ifndef __LWP_TERMINAL_H__
#define __LWP_TERMINAL_H__
#include "bsd_ttyqueue.h"
#include "bsd_ttydisc.h"
#ifdef USING_BSD_HOOK
#include "bsd_ttyhook.h"
#endif
#include <lwp.h>
#include <rtdef.h>
/* include kernel header for termios base definitions */
#include <termios.h>
/* for _POSIX_VDISABLE */
#include <unistd.h>
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Portions of this software were developed under sponsorship from Snow
* B.V., the Netherlands.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
struct lwp_tty;
/*
* Driver routines that are called from the line discipline to adjust
* hardware parameters and such.
*/
typedef int tsw_open_t(struct lwp_tty *tp);
typedef void tsw_close_t(struct lwp_tty *tp);
typedef void tsw_outwakeup_t(struct lwp_tty *tp);
typedef void tsw_inwakeup_t(struct lwp_tty *tp);
typedef int tsw_ioctl_t(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data,
struct rt_thread *td);
typedef int tsw_cioctl_t(struct lwp_tty *tp, int unit, rt_ubase_t cmd, rt_caddr_t data,
struct rt_thread *td);
typedef int tsw_param_t(struct lwp_tty *tp, struct termios *t);
typedef int tsw_modem_t(struct lwp_tty *tp, int sigon, int sigoff);
typedef int tsw_mmap_t(struct lwp_tty *tp, vm_ooffset_t offset,
vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr);
typedef void tsw_pktnotify_t(struct lwp_tty *tp, char event);
typedef void tsw_free_t(void *softc);
typedef rt_bool_t tsw_busy_t(struct lwp_tty *tp);
struct lwp_ttydevsw
{
unsigned int tsw_flags; /* Default TTY flags. */
tsw_open_t *tsw_open; /* Device opening. */
tsw_close_t *tsw_close; /* Device closure. */
tsw_outwakeup_t *tsw_outwakeup; /* Output available. */
tsw_inwakeup_t *tsw_inwakeup; /* Input can be stored again. */
tsw_ioctl_t *tsw_ioctl; /* ioctl() hooks. */
tsw_cioctl_t *tsw_cioctl; /* ioctl() on control devices. */
tsw_param_t *tsw_param; /* TIOCSETA device parameter setting. */
tsw_modem_t *tsw_modem; /* Modem sigon/sigoff. */
tsw_mmap_t *tsw_mmap; /* mmap() hooks. */
tsw_pktnotify_t *tsw_pktnotify; /* TIOCPKT events. */
tsw_free_t *tsw_free; /* Destructor. */
tsw_busy_t *tsw_busy; /* Draining output. */
void *tsw_spare[3]; /* For future use. */
};
typedef struct lwp_ttydevsw *lwp_ttydevsw_t;
struct lwp_tty
{
struct rt_device parent; /* inherit from Class:RT_Device */
struct rt_mutex *t_mtx; /* TTY lock. */
struct rt_mutex t_mtxobj; /* Per-TTY lock (when not borrowing). */
rt_list_t t_list; /* (l) TTY list entry. */
int t_drainwait; /* (t) TIOCDRAIN timeout seconds. */
unsigned int t_flags; /* (t) Terminal option flags. */
/* Keep flags in sync with db_show_tty and pstat(8). */
#define TF_NOPREFIX 0x00001 /* Don't prepend "tty" to device name. */
#define TF_INITLOCK 0x00002 /* Create init/lock state devices. */
#define TF_CALLOUT 0x00004 /* Create "cua" devices. */
#define TF_OPENED_IN 0x00008 /* "tty" node is in use. */
#define TF_OPENED_OUT 0x00010 /* "cua" node is in use. */
#define TF_OPENED_CONS 0x00020 /* Device in use as console. */
#define TF_OPENED (TF_OPENED_IN | TF_OPENED_OUT | TF_OPENED_CONS)
#define TF_GONE 0x00040 /* Device node is gone. */
#define TF_OPENCLOSE 0x00080 /* Device is in open()/close(). */
#define TF_ASYNC 0x00100 /* Asynchronous I/O enabled. */
#define TF_LITERAL 0x00200 /* Accept the next character literally. */
#define TF_HIWAT_IN 0x00400 /* We've reached the input watermark. */
#define TF_HIWAT_OUT 0x00800 /* We've reached the output watermark. */
#define TF_HIWAT (TF_HIWAT_IN | TF_HIWAT_OUT)
#define TF_STOPPED 0x01000 /* Output flow control - stopped. */
#define TF_EXCLUDE 0x02000 /* Exclusive access. */
#define TF_BYPASS 0x04000 /* Optimized input path. */
#define TF_ZOMBIE 0x08000 /* Modem disconnect received. */
#define TF_HOOK 0x10000 /* TTY has hook attached. */
#define TF_BUSY_IN 0x20000 /* Process busy in read() -- not supported. */
#define TF_BUSY_OUT 0x40000 /* Process busy in write(). */
#define TF_BUSY (TF_BUSY_IN | TF_BUSY_OUT)
unsigned int t_revokecnt; /* (t) revoke() count. */
/* Buffering mechanisms. */
struct ttyinq t_inq; /* (t) Input queue. */
size_t t_inlow; /* (t) Input low watermark. */
struct ttyoutq t_outq; /* (t) Output queue. */
size_t t_outlow; /* (t) Output low watermark. */
/* Sleeping mechanisms. */
struct rt_condvar t_inwait; /* (t) Input wait queue. */
struct rt_condvar t_outwait; /* (t) Output wait queue. */
struct rt_condvar t_outserwait; /* (t) Serial output wait queue. */
struct rt_condvar t_bgwait; /* (t) Background wait queue. */
struct rt_condvar t_dcdwait; /* (t) Carrier Detect wait queue. */
struct rt_wqueue t_inpoll; /* (t) Input poll queue. */
struct rt_wqueue t_outpoll; /* (t) Output poll queue. */
#ifdef USING_BSD_AIO
struct sigio *t_sigio; /* (t) Asynchronous I/O. */
#endif
struct termios t_termios; /* (t) I/O processing flags. */
struct winsize t_winsize; /* (t) Window size. */
unsigned int t_column; /* (t) Current cursor position. */
unsigned int t_writepos; /* (t) Where input was interrupted. */
int t_compatflags; /* (t) COMPAT_43TTY flags. */
/* Init/lock-state devices. */
struct termios t_termios_init_in; /* tty%s.init. */
struct termios t_termios_lock_in; /* tty%s.lock. */
#ifdef USING_BSD_INIT_LOCK_DEVICE
struct termios t_termios_init_out; /* cua%s.init. */
struct termios t_termios_lock_out; /* cua%s.lock. */
#endif /* USING_BSD_INIT_LOCK_DEVICE */
struct lwp_ttydevsw *t_devsw; /* (c) Driver hooks. */
#ifdef USING_BSD_HOOK
struct lwp_ttyhook *t_hook; /* (t) Capture/inject hook. */
#endif
/* Process signal delivery. */
struct rt_processgroup *t_pgrp; /* (t) Foreground process group. */
struct rt_session *t_session; /* (t) Associated session. */
unsigned int t_sessioncnt; /* (t) Backpointing sessions. */
void *t_devswsoftc; /* (c) Soft config, for drivers. */
#ifdef USING_BSD_HOOK
void *t_hooksoftc; /* (t) Soft config, for hooks. */
#endif
#ifdef USING_BSD_CHAR_DEVICE
struct cdev *t_dev; /* (c) Primary character device. */
#endif /* USING_BSD_CHAR_DEVICE */
#ifdef USING_BSD_SIGINFO
size_t t_prbufsz; /* (t) SIGINFO buffer size. */
char t_prbuf[]; /* (t) SIGINFO buffer. */
#endif /* USING_BSD_SIGINFO */
};
typedef struct lwp_tty *lwp_tty_t;
/* Allocation and deallocation. */
void tty_rel_pgrp(struct lwp_tty *tp, struct rt_processgroup *pgrp);
void tty_rel_sess(struct lwp_tty *tp, struct rt_session *sess);
void tty_rel_gone(struct lwp_tty *tp);
/* tty locking mechanism */
#define tty_getlock(tp) ((tp)->t_mtx)
#define tty_lock(tp) rt_mutex_take(tty_getlock(tp), RT_WAITING_FOREVER);
#define tty_unlock(tp) rt_mutex_release(tty_getlock(tp))
#define tty_lock_owned(tp) \
(rt_mutex_get_owner(tty_getlock(tp)) == rt_thread_self())
#define tty_lock_notrecused(tp) (rt_mutex_get_hold(tty_getlock(tp)) == 1)
#define tty_assert_locked(tp) RT_ASSERT(tty_lock_owned(tp))
#define tty_lock_assert(tp, option) \
(((option) == (MA_OWNED | MA_NOTRECURSED)) \
? (tty_lock_owned(tp) && tty_lock_notrecused(tp)) \
: rt_assert_handler("Operation not allowed", __func__, __LINE__))
/* System messages. */
int tty_checkoutq(struct lwp_tty *tp);
int tty_putchar(struct lwp_tty *tp, char c);
int tty_putstrn(struct lwp_tty *tp, const char *p, size_t n);
int tty_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, void *data, int fflag,
struct rt_thread *td);
int tty_ioctl_compat(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data, int fflag,
struct rt_thread *td);
void tty_set_winsize(struct lwp_tty *tp, const struct winsize *wsz);
void tty_init_console(struct lwp_tty *tp, speed_t speed);
void tty_flush(struct lwp_tty *tp, int flags);
void tty_hiwat_in_block(struct lwp_tty *tp);
void tty_hiwat_in_unblock(struct lwp_tty *tp);
dev_t tty_udev(struct lwp_tty *tp);
/* tesing on tty */
#define tty_opened(tp) ((tp)->t_flags & TF_OPENED)
#define tty_gone(tp) ((tp)->t_flags & TF_GONE)
#define tty_softc(tp) ((tp)->t_devswsoftc)
#define tty_devname(tp) ((tp)->parent.parent.name)
/**
* @brief TTY registeration on device subsystem
*
* @warning It's the duty of the caller to ensure that the name is not
* identical to any existed registered devices.
*
* @param terminal the target tty device
* @param name name of the device (must be exclusive)
* @return rt_err_t RT_EOK on success
*/
rt_err_t lwp_tty_register(lwp_tty_t terminal, const char *name);
/**
* @brief TTY allocation and deallocation. TTY devices can be deallocated when
* the driver doesn't use it anymore, when the TTY isn't a session's
* controlling TTY and when the device node isn't opened through devfs.
*
* @param handle device handle of tty
* @param softc device configuration binding on tty
* @param prefix device name prefix
* @param cutom_mtx the lock provided to protect tty
* @return lwp_tty_t NULL on failure
*/
lwp_tty_t lwp_tty_create_ext(lwp_ttydevsw_t handle, void *softc,
rt_mutex_t custom_mtx);
/**
* @brief Handful version of lwp_tty_create_ext
*
* @param softc device configuration binding on tty
* @param cutom_mtx the lock provided to protect tty
* @param prefix device name prefix
* @return lwp_tty_t NULL on failure
*/
lwp_tty_t lwp_tty_create(lwp_ttydevsw_t handle, void *softc);
void lwp_tty_delete(lwp_tty_t tp);
void lwp_tty_signal_sessleader(struct lwp_tty *tp, int sig);
void lwp_tty_signal_pgrp(struct lwp_tty *tp, int sig);
/**
* @brief Create a new pseudo-terminal multiplexer
*
* @param root_path path of root mount point of ptyfs
* @return rt_device_t new device object if succeed, otherwise NULL
*/
rt_err_t lwp_ptmx_init(rt_device_t ptmx_device, const char *root_path);
#define LWP_CONSOLE_LOWEST_PRIOR 0
#define LWP_CONSOLE_HIGHEST_PRIO INT_MAX
/**
* @brief Register an alternative backend tty device as console
*/
rt_err_t lwp_console_register_backend(struct rt_device *bakdev, int prio);
rt_inline int ttydevsw_open(struct lwp_tty *tp)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_open(tp));
}
rt_inline void ttydevsw_close(struct lwp_tty *tp)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_devsw->tsw_close(tp);
}
rt_inline void ttydevsw_outwakeup(struct lwp_tty *tp)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
/* Prevent spurious wakeups. */
if (ttydisc_getc_poll(tp) == 0)
return;
tp->t_devsw->tsw_outwakeup(tp);
}
rt_inline void ttydevsw_inwakeup(struct lwp_tty *tp)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
/* Prevent spurious wakeups. */
if (tp->t_flags & TF_HIWAT_IN)
return;
tp->t_devsw->tsw_inwakeup(tp);
}
rt_inline int ttydevsw_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data,
struct rt_thread *td)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_ioctl(tp, cmd, data, td));
}
rt_inline int ttydevsw_cioctl(struct lwp_tty *tp, int unit, rt_ubase_t cmd,
rt_caddr_t data, struct rt_thread *td)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_cioctl(tp, unit, cmd, data, td));
}
rt_inline int ttydevsw_param(struct lwp_tty *tp, struct termios *t)
{
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_param(tp, t));
}
rt_inline int ttydevsw_modem(struct lwp_tty *tp, int sigon, int sigoff)
{
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_modem(tp, sigon, sigoff));
}
rt_inline int ttydevsw_mmap(struct lwp_tty *tp, vm_ooffset_t offset,
vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
{
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_mmap(tp, offset, paddr, nprot, memattr));
}
rt_inline void ttydevsw_pktnotify(struct lwp_tty *tp, char event)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
tp->t_devsw->tsw_pktnotify(tp, event);
}
rt_inline void ttydevsw_free(struct lwp_tty *tp)
{
MPASS(tty_gone(tp));
tp->t_devsw->tsw_free(tty_softc(tp));
}
rt_inline rt_bool_t ttydevsw_busy(struct lwp_tty *tp)
{
tty_assert_locked(tp);
MPASS(!tty_gone(tp));
return (tp->t_devsw->tsw_busy(tp));
}
rt_inline size_t ttydisc_read_poll(struct lwp_tty *tp)
{
tty_assert_locked(tp);
return ttyinq_bytescanonicalized(&tp->t_inq);
}
rt_inline size_t ttydisc_write_poll(struct lwp_tty *tp)
{
tty_assert_locked(tp);
return ttyoutq_bytesleft(&tp->t_outq);
}
#endif /* __LWP_TERMINAL_H__ */
+136
View File
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#ifndef __TTY_CONFIG_H__
#define __TTY_CONFIG_H__
/* default buffer size of tty siginfo */
#define LWP_TTY_PRBUF_SIZE 256
/*
* System wide defaults for terminal state.
*/
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ttydefaults.h 8.4 (Berkeley) 1/21/94
*/
/*
* Defaults on "first" open.
*/
#define TTYDEF_IFLAG (BRKINT | ICRNL | IMAXBEL | IXON | IXANY | IUTF8)
#define TTYDEF_OFLAG (OPOST | ONLCR)
#define TTYDEF_LFLAG_NOECHO (ICANON | ISIG | IEXTEN)
#define TTYDEF_LFLAG_ECHO \
(TTYDEF_LFLAG_NOECHO | ECHO | ECHOE | ECHOKE | ECHOCTL)
#define TTYDEF_LFLAG TTYDEF_LFLAG_ECHO
#define TTYDEF_CFLAG (CREAD | CS8 | HUPCL)
#define TTYDEF_SPEED (B9600)
/*
* Control Character Defaults
*/
/*
* XXX: A lot of code uses lowercase characters, but control-character
* conversion is actually only valid when applied to uppercase
* characters. We just treat lowercase characters as if they were
* inserted as uppercase.
*/
#define _CONTROL(c) \
((c) >= 'a' && (c) <= 'z' ? ((c) - 'a' + 1) : (((c) - 'A' + 1) & 0x7f))
#define CEOF _CONTROL('D')
#define CEOL 0xff /* XXX avoid _POSIX_VDISABLE */
#define CERASE 0x7f
#define CERASE2 _CONTROL('H')
#define CINTR _CONTROL('C')
#define CSTATUS _CONTROL('T')
#define CKILL _CONTROL('U')
#define CMIN 1
#define CQUIT _CONTROL('\\')
#define CSUSP _CONTROL('Z')
#define CTIME 0
#define CDSUSP _CONTROL('Y')
#define CSTART _CONTROL('Q')
#define CSTOP _CONTROL('S')
#define CLNEXT _CONTROL('V')
#define CDISCARD _CONTROL('O')
#define CWERASE _CONTROL('W')
#define CREPRINT _CONTROL('R')
#define CEOT CEOF
/* compat */
#define CBRK CEOL
#define CRPRNT CREPRINT
#define CFLUSH CDISCARD
/* PROTECTED INCLUSION ENDS HERE */
#endif /* !__TTY_CONFIG_H__ */
/*
* #define TTY_CONF_INCLUDE_CCHARS to include an array of default control
* characters.
*/
#ifdef TTY_CONF_INCLUDE_CCHARS
#include <rtdef.h>
#include <termios.h>
#include <unistd.h>
static const cc_t tty_ctrl_charset[NCCS] = {
[VINTR] = CINTR,
[VQUIT] = CQUIT,
[VERASE] = CERASE,
[VKILL] = CKILL,
[VEOF] = CEOF,
[VSTART] = CSTART,
[VSTOP] = CSTOP,
[VSUSP] = CSUSP,
[VREPRINT] = CREPRINT,
[VDISCARD] = CDISCARD,
[VWERASE] = CWERASE,
[VLNEXT] = CLNEXT,
[VMIN] = CMIN
#undef _CONTROL
};
#undef TTY_CONF_INCLUDE_CCHARS
#endif /* __TTY_CONFIG_H__ */
+128
View File
@@ -0,0 +1,128 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-12-11 Shell init ver.
*/
#define DBG_TAG "lwp.tty"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include "tty_config.h"
#include "tty_internal.h"
#include "bsd_porting.h"
#include "terminal.h"
#include <fcntl.h>
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops cons_rtdev_ops;
#endif
struct backend_entry
{
rt_list_t bakend_list_node;
int prio;
rt_device_t bakdev;
};
static rt_list_t _bakend_list;
static void _bent_enqueue(struct backend_entry *bent)
{
struct backend_entry *idx;
rt_bool_t inserted = RT_FALSE;
rt_list_for_each_entry(idx, &_bakend_list, bakend_list_node)
{
if (idx->prio < bent->prio)
{
rt_list_insert_before(&idx->bakend_list_node, &bent->bakend_list_node);
inserted = RT_TRUE;
break;
}
}
if (!inserted)
rt_list_insert_after(&_bakend_list, &bent->bakend_list_node);
return ;
}
rt_err_t lwp_console_register_backend(struct rt_device *bakdev, int prio)
{
rt_err_t ret = RT_EOK;
struct backend_entry *bent;
bent = rt_malloc(sizeof(struct backend_entry));
if (bent)
{
rt_list_init(&bent->bakend_list_node);
bent->prio = prio;
bent->bakdev = bakdev;
_bent_enqueue(bent);
}
else
{
ret = -RT_ENOMEM;
}
return ret;
}
static struct rt_device _cons_rtdev;
static int fops_open(struct dfs_file *file)
{
return -EINVAL;
}
static struct dfs_file_ops _cons_fops = {
.open = fops_open,
};
static rt_err_t _cons_readlink(struct rt_device *dev, char *buf, int len)
{
int rc = -EIO;
struct backend_entry *bent;
if (!rt_list_isempty(&_bakend_list))
{
bent = rt_list_first_entry(&_bakend_list, struct backend_entry, bakend_list_node);
if (bent)
{
RT_ASSERT(bent->bakdev);
strncpy(buf, bent->bakdev->parent.name, MIN(len, RT_NAME_MAX));
LOG_D("%s: backend device %s", __func__, buf);
rc = 0;
}
}
if (rc != 0)
{
LOG_W("%s: No backend device", __func__);
}
return rc;
}
static int _cons_init(void)
{
rt_err_t rc;
rt_list_init(&_bakend_list);
/* setup system level device */
_cons_rtdev.type = RT_Device_Class_Char;
_cons_rtdev.ops = &cons_rtdev_ops;
rc = rt_device_register(&_cons_rtdev, "console", RT_DEVICE_FLAG_DYNAMIC);
if (rc == RT_EOK)
{
_cons_rtdev.readlink = &_cons_readlink;
_cons_rtdev.fops = &_cons_fops;
}
return rc;
}
INIT_DEVICE_EXPORT(_cons_init);
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-30 Shell init ver.
*/
#define DBG_TAG "lwp.ctty"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define TTY_CONF_INCLUDE_CCHARS
#include "tty_config.h"
#include "tty_internal.h"
#include "terminal.h"
static int fops_open(struct dfs_file *file)
{
return -EINVAL;
}
static rt_err_t ctty_readlink(struct rt_device *dev, char *buf, int len)
{
int rc = -ENXIO;
lwp_tty_t tp;
rt_session_t sess;
rt_processgroup_t pgrp;
rt_lwp_t lwp;
lwp = lwp_self();
if (lwp)
{
pgrp = lwp->pgrp;
if (pgrp)
{
sess = pgrp->session;
if (sess)
{
tp = sess->ctty;
if (tp)
{
tty_lock(tp);
if (lwp->pgrp == pgrp && pgrp->session == sess && sess->ctty == tp)
{
rt_strncpy(buf, tp->parent.parent.name, len);
rc = RT_EOK;
}
tty_unlock(tp);
}
}
}
}
return rc;
}
static struct dfs_file_ops ctty_file_ops = {
.open = fops_open,
};
/* character device for tty */
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops tty_dev_ops = {
/* IO directly through device is not allowed */
};
#else
#error Must enable RT_USING_DEVICE_OPS in Kconfig
#endif
rt_inline void device_setup(rt_device_t ctty)
{
ctty->type = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
ctty->ops = &tty_dev_ops;
#else
#error Must enable RT_USING_DEVICE_OPS in Kconfig
#endif
}
/* register device to DFS */
static int lwp_ctty_register(rt_device_t ctty)
{
rt_err_t rc = -RT_ENOMEM;
const char *tty_name = "tty";
device_setup(ctty);
rc = rt_device_register(ctty, tty_name, RT_DEVICE_FLAG_DYNAMIC);
if (rc == RT_EOK)
{
ctty->readlink = &ctty_readlink;
ctty->fops = &ctty_file_ops;
}
return rc;
}
static struct rt_device ctty;
static int lwp_ctty_init(void)
{
return lwp_ctty_register(&ctty);
}
INIT_DEVICE_EXPORT(lwp_ctty_init);
+456
View File
@@ -0,0 +1,456 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#define DBG_TAG "lwp.tty"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define TTY_CONF_INCLUDE_CCHARS
#include "tty_config.h"
#include "tty_internal.h"
#include "terminal.h"
/* configure option: timeout of tty drain wait */
static int tty_drainwait = 5 * 60;
#define TTY_NAME_PREFIX "tty"
static char *alloc_device_name(const char *name)
{
char *tty_dev_name;
long name_buf_len = (sizeof(TTY_NAME_PREFIX) - 1) /* raw prefix */
+ rt_strlen(name) /* custom name */
+ 1; /* tailing \0 */
tty_dev_name = rt_malloc(name_buf_len);
if (tty_dev_name)
sprintf(tty_dev_name, "%s%s", TTY_NAME_PREFIX, name);
return tty_dev_name;
}
/* character device for tty */
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops tty_dev_ops = {
/* IO directly through device is not allowed */
};
#else
#error Must enable RT_USING_DEVICE_OPS in Kconfig
#endif
static int tty_fops_open(struct dfs_file *file)
{
int rc;
lwp_tty_t tp;
rt_device_t device;
int devtype = 0; /* unused */
if (file->vnode && file->vnode->data)
{
if (file->vnode->ref_count != 1)
{
rc = 0;
}
else
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
rc = bsd_ttydev_methods.d_open(tp, file->flags, devtype,
rt_thread_self());
}
}
else
{
rc = -EINVAL;
}
return rc;
}
static int tty_fops_close(struct dfs_file *file)
{
int rc;
lwp_tty_t tp;
rt_device_t device;
int fflags = FFLAGS(file->flags);
int devtype = 0; /* unused */
if (file->vnode && file->vnode->data)
{
if (file->vnode->ref_count != 1)
{
rc = 0;
}
else
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
rc = bsd_ttydev_methods.d_close(tp, fflags, devtype, rt_thread_self());
}
}
else
{
rc = -EINVAL;
}
return rc;
}
static int tty_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
{
int rc;
lwp_tty_t tp;
rt_device_t device;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
rc = lwp_tty_ioctl_adapter(tp, cmd, file->flags, arg, rt_thread_self());
}
else
{
rc = -EINVAL;
}
return rc;
}
static ssize_t tty_fops_read(struct dfs_file *file, void *buf, size_t count,
off_t *pos)
{
ssize_t rc = 0;
int error;
struct uio uio;
struct iovec iov;
rt_device_t device;
struct lwp_tty *tp;
int ioflags;
int oflags = file->flags;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
/* setup ioflags */
ioflags = 0;
if (oflags & O_NONBLOCK)
ioflags |= IO_NDELAY;
/* setup uio parameters */
iov.iov_base = (void *)buf;
iov.iov_len = count;
uio.uio_offset = file->fpos;
uio.uio_resid = count;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_rw = UIO_READ;
rc = count;
error = bsd_ttydev_methods.d_read(tp, &uio, ioflags);
rc -= uio.uio_resid;
if (error)
{
LOG_D("%s: failed to write %d bytes of data. error code %d",
__func__, uio.uio_resid, error);
rc = error;
}
/* reset file context */
file->fpos = uio.uio_offset;
}
if (rc)
LOG_D("%s(len=%d, buf=%c \"%d\")", __func__, rc, *((char *)buf),
*((char *)buf));
return rc;
}
static ssize_t tty_fops_write(struct dfs_file *file, const void *buf,
size_t count, off_t *pos)
{
ssize_t rc = 0;
int error;
struct uio uio;
struct iovec iov;
rt_device_t device;
struct lwp_tty *tp;
int ioflags;
int oflags = file->flags;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
/* setup ioflags */
ioflags = 0;
if (oflags & O_NONBLOCK)
ioflags |= IO_NDELAY;
/* setup uio parameters */
iov.iov_base = (void *)buf;
iov.iov_len = count;
uio.uio_offset = file->fpos;
uio.uio_resid = count;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_rw = UIO_WRITE;
rc = count;
error = bsd_ttydev_methods.d_write(tp, &uio, ioflags);
if (error)
{
rc = error;
LOG_D("%s: failed to write %d bytes of data. error code %d",
__func__, uio.uio_resid, error);
}
else
{
rc -= uio.uio_resid;
}
/* reset file context */
file->fpos = uio.uio_offset;
}
return rc;
}
static int tty_fops_flush(struct dfs_file *file)
{
return -EINVAL;
}
static off_t tty_fops_lseek(struct dfs_file *file, off_t offset, int wherece)
{
return -EINVAL;
}
static int tty_fops_truncate(struct dfs_file *file, off_t offset)
{
/**
* regarding to POSIX.1, TRUNC is not supported for tty device.
* return 0 always to make filesystem happy
*/
return 0;
}
static int tty_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
{
int rc;
rt_device_t device;
struct lwp_tty *tp;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
rc = bsd_ttydev_methods.d_poll(tp, req, rt_thread_self());
}
else
{
rc = -1;
}
return rc;
}
static int tty_fops_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
{
return -EINVAL;
}
static int tty_fops_lock(struct dfs_file *file, struct file_lock *flock)
{
return -EINVAL;
}
static int tty_fops_flock(struct dfs_file *file, int operation, struct file_lock *flock)
{
return -EINVAL;
}
static struct dfs_file_ops tty_file_ops = {
.open = tty_fops_open,
.close = tty_fops_close,
.ioctl = tty_fops_ioctl,
.read = tty_fops_read,
.write = tty_fops_write,
.flush = tty_fops_flush,
.lseek = tty_fops_lseek,
.truncate = tty_fops_truncate,
.poll = tty_fops_poll,
.mmap = tty_fops_mmap,
.lock = tty_fops_lock,
.flock = tty_fops_flock,
};
rt_inline void device_setup(lwp_tty_t terminal)
{
terminal->parent.type = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
terminal->parent.ops = &tty_dev_ops;
#else
#error Must enable RT_USING_DEVICE_OPS in Kconfig
#endif
}
/* register TTY device */
rt_err_t lwp_tty_register(lwp_tty_t terminal, const char *name)
{
rt_err_t rc = -RT_ENOMEM;
const char *tty_name;
char *alloc_name;
if (terminal->t_devsw->tsw_flags & TF_NOPREFIX)
{
alloc_name = RT_NULL;
tty_name = name;
}
else
{
alloc_name = alloc_device_name(name);
tty_name = alloc_name;
}
if (tty_name)
{
device_setup(terminal);
rc = rt_device_register(&terminal->parent, tty_name, 0);
if (rc == RT_EOK)
{
terminal->parent.fops = &tty_file_ops;
LOG_D("%s() /dev/%s device registered", __func__, tty_name);
}
rt_free(alloc_name);
}
return rc;
}
static void tty_init_termios(lwp_tty_t tp)
{
struct termios *t = &tp->t_termios_init_in;
t->c_cflag = TTYDEF_CFLAG;
t->c_iflag = TTYDEF_IFLAG;
t->c_lflag = TTYDEF_LFLAG;
t->c_oflag = TTYDEF_OFLAG;
t->__c_ispeed = TTYDEF_SPEED;
t->__c_ospeed = TTYDEF_SPEED;
memcpy(&t->c_cc, tty_ctrl_charset,
sizeof(tty_ctrl_charset) / sizeof(tty_ctrl_charset[0]));
#ifdef USING_BSD_INIT_LOCK_DEVICE
tp->t_termios_init_out = *t;
#endif /* USING_BSD_INIT_LOCK_DEVICE */
}
lwp_tty_t lwp_tty_create_ext(lwp_ttydevsw_t handle, void *softc,
rt_mutex_t custom_mtx)
{
lwp_tty_t tp;
tp = rt_calloc(1, sizeof(struct lwp_tty)
#ifdef USING_BSD_SIGINFO
+ LWP_TTY_PRBUF_SIZE
#endif
);
if (!tp)
return tp;
bsd_devsw_init(handle);
#ifdef USING_BSD_SIGINFO
tp->t_prbufsz = LWP_TTY_PRBUF_SIZE;
#endif
tp->t_devsw = handle;
tp->t_devswsoftc = softc;
tp->t_flags = handle->tsw_flags;
tp->t_drainwait = tty_drainwait;
tty_init_termios(tp);
cv_init(&tp->t_inwait, "ttyin");
cv_init(&tp->t_outwait, "ttyout");
cv_init(&tp->t_outserwait, "ttyosr");
cv_init(&tp->t_bgwait, "ttybg");
cv_init(&tp->t_dcdwait, "ttydcd");
rt_wqueue_init(&tp->t_inpoll);
rt_wqueue_init(&tp->t_outpoll);
/* Allow drivers to use a custom mutex to lock the TTY. */
if (custom_mtx != NULL)
{
tp->t_mtx = custom_mtx;
}
else
{
tp->t_mtx = &tp->t_mtxobj;
rt_mutex_init(&tp->t_mtxobj, "ttydev", RT_IPC_FLAG_PRIO);
}
#ifdef USING_BSD_POLL
knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx);
knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx);
#endif
return tp;
}
lwp_tty_t lwp_tty_create(lwp_ttydevsw_t handle, void *softc)
{
return lwp_tty_create_ext(handle, softc, NULL);
}
void lwp_tty_delete(lwp_tty_t tp)
{
/*
* ttyydev_leave() usually frees the i/o queues earlier, but it is
* not always called between queue allocation and here. The queues
* may be allocated by ioctls on a pty control device without the
* corresponding pty slave device ever being open, or after it is
* closed.
*/
ttyinq_free(&tp->t_inq);
ttyoutq_free(&tp->t_outq);
rt_wqueue_wakeup_all(&tp->t_inpoll, (void *)POLLHUP);
rt_wqueue_wakeup_all(&tp->t_outpoll, (void *)POLLHUP);
#ifdef USING_BSD_POLL
knlist_destroy(&tp->t_inpoll.si_note);
knlist_destroy(&tp->t_outpoll.si_note);
#endif
cv_destroy(&tp->t_inwait);
cv_destroy(&tp->t_outwait);
cv_destroy(&tp->t_bgwait);
cv_destroy(&tp->t_dcdwait);
cv_destroy(&tp->t_outserwait);
if (tp->t_mtx == &tp->t_mtxobj)
rt_mutex_detach(&tp->t_mtxobj);
ttydevsw_free(tp);
rt_device_unregister(&tp->parent);
rt_free(tp);
}
/*
* Report on state of foreground process group.
*/
void tty_info(struct lwp_tty *tp)
{
/* TODO */
return;
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-11-13 Shell init ver.
*/
#ifndef __LWP_TTY_INTERNAL_H__
#define __LWP_TTY_INTERNAL_H__
#include "lwp.h"
#include "terminal.h"
extern struct cdevsw bsd_ttydev_methods;
extern struct bsd_fileops bsd_ptsdev_methods;
/* bsd devsw porting */
void bsd_devsw_init(struct lwp_ttydevsw *tsw);
/**
* Do not assert RTS or DTR automatically. If CNO_RTSDTR is set then the RTS and
* DTR lines will not be asserted when the device is opened. As a result, this
* flag is only useful on initial-state devices.
*
* Note: this feature is not using on smart system, so this flag is always 0.
*/
#define CNO_RTSDTR 0
/* Waking up readers/writers. */
int tty_wait(struct lwp_tty *tp, struct rt_condvar *cv);
int tty_wait_background(struct lwp_tty *tp, struct rt_thread *td, int sig);
int tty_timedwait(struct lwp_tty *tp, struct rt_condvar *cv, rt_tick_t timeout);
void tty_wakeup(struct lwp_tty *tp, int flags);
void tty_info(struct lwp_tty *tp);
void pts_set_lock(lwp_tty_t pts, rt_bool_t is_lock);
rt_bool_t pts_is_locked(lwp_tty_t pts);
int pts_get_pktmode(lwp_tty_t pts);
int pts_alloc(int fflags, struct rt_thread *td, struct dfs_file *ptm_file);
int lwp_tty_ioctl_adapter(lwp_tty_t tp, int cmd, int oflags, void *args, rt_thread_t td);
int lwp_tty_set_ctrl_proc(lwp_tty_t tp, rt_thread_t td);
int lwp_tty_assign_foreground(lwp_tty_t tp, rt_thread_t td, int pgid);
int lwp_tty_bg_stop(struct lwp_tty *tp, struct rt_condvar *cv);
rt_inline rt_bool_t is_sess_leader(rt_lwp_t p)
{
/**
* Note: a pgrp leader is never lose its group, so once it's
* true then it's always true
*/
return p->pid == p->sid;
}
rt_inline int tty_is_ctty(struct lwp_tty *tp, struct rt_lwp *p)
{
tty_assert_locked(tp);
return p->pgrp->session == tp->t_session && p->term_ctrlterm;
}
#endif /* __LWP_TTY_INTERNAL_H__ */
+350
View File
@@ -0,0 +1,350 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-12-07 Shell init ver.
*/
#define DBG_TAG "lwp.tty"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include "tty_config.h"
#include "tty_internal.h"
#include "bsd_porting.h"
#include "terminal.h"
#include <fcntl.h>
static struct dfs_file_ops ptm_fops;
static int ptm_fops_open(struct dfs_file *file)
{
int rc;
rt_uint32_t oflags = file->flags;
rt_thread_t cur_thr = rt_thread_self();
/* we don't check refcnt because each open will create a new device */
if (file->vnode && file->vnode->data)
{
/**
* Filter out illegal flags
*/
if ((oflags & ~(O_RDWR | O_NOCTTY | O_CLOEXEC | O_LARGEFILE)) == 0)
{
rc = pts_alloc(FFLAGS(oflags & O_ACCMODE), cur_thr, file);
/* detached operation from devfs */
if (rc == 0)
file->vnode->fops = &ptm_fops;
}
else
{
rc = -EINVAL;
}
}
else
{
rc = -EINVAL;
}
return rc;
}
static int ptm_fops_close(struct dfs_file *file)
{
int rc;
lwp_tty_t tp;
rt_device_t device;
if (file->vnode && file->vnode->data)
{
if (file->vnode->ref_count != 1)
{
rc = 0;
}
else
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
rc = bsd_ptsdev_methods.fo_close(tp, rt_thread_self());
}
}
else
{
rc = -EINVAL;
}
return rc;
}
static ssize_t ptm_fops_read(struct dfs_file *file, void *buf, size_t count,
off_t *pos)
{
ssize_t rc = 0;
int error;
struct uio uio;
struct iovec iov;
rt_device_t device;
struct lwp_tty *tp;
int oflags = file->flags;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
/* setup uio parameters */
iov.iov_base = (void *)buf;
iov.iov_len = count;
uio.uio_offset = file->fpos;
uio.uio_resid = count;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_rw = UIO_READ;
rc = count;
error =
bsd_ptsdev_methods.fo_read(tp, &uio, 0, oflags, rt_thread_self());
rc -= uio.uio_resid;
if (error)
{
rc = error;
}
/* reset file context */
file->fpos = uio.uio_offset;
}
return rc;
}
static ssize_t ptm_fops_write(struct dfs_file *file, const void *buf,
size_t count, off_t *pos)
{
ssize_t rc = 0;
int error;
struct uio uio;
struct iovec iov;
rt_device_t device;
struct lwp_tty *tp;
int oflags = file->flags;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
/* setup uio parameters */
iov.iov_base = (void *)buf;
iov.iov_len = count;
uio.uio_offset = file->fpos;
uio.uio_resid = count;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_rw = UIO_WRITE;
rc = count;
error =
bsd_ptsdev_methods.fo_write(tp, &uio, 0, oflags, rt_thread_self());
if (error)
{
rc = error;
}
else
{
rc -= uio.uio_resid;
}
/* reset file context */
file->fpos = uio.uio_offset;
}
return rc;
}
static int ptm_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
{
int rc;
lwp_tty_t tp;
rt_device_t device;
rt_ubase_t cmd_normal = (unsigned int)cmd;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
switch (cmd_normal)
{
case TIOCSPTLCK:
{
int is_lock;
if (lwp_get_from_user(&is_lock, arg, sizeof(int)) != sizeof(int))
return -EFAULT;
pts_set_lock(tp, is_lock);
rc = 0;
}
break;
case TIOCGPTLCK:
{
int is_lock = pts_is_locked(tp);
if (lwp_put_to_user(arg, &is_lock, sizeof(int)) != sizeof(int))
return -EFAULT;
rc = 0;
}
break;
case TIOCGPKT:
{
int pktmode = pts_get_pktmode(tp);
if (lwp_put_to_user(arg, &pktmode, sizeof(int)) != sizeof(int))
return -EFAULT;
rc = 0;
}
break;
default:
rc = bsd_ptsdev_methods.fo_ioctl(
tp, cmd_normal, arg, 0, FFLAGS(file->flags), rt_thread_self());
break;
}
}
else
{
rc = -EINVAL;
}
return rc;
}
static int ptm_fops_flush(struct dfs_file *file)
{
return -EINVAL;
}
static off_t ptm_fops_lseek(struct dfs_file *file, off_t offset, int wherece)
{
return -EINVAL;
}
static int ptm_fops_truncate(struct dfs_file *file, off_t offset)
{
return -EINVAL;
}
static int ptm_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
{
int rc;
rt_device_t device;
struct lwp_tty *tp;
if (file->vnode && file->vnode->data)
{
device = (rt_device_t)file->vnode->data;
tp = rt_container_of(device, struct lwp_tty, parent);
rc = bsd_ptsdev_methods.fo_poll(tp, req, 0, rt_thread_self());
}
else
{
rc = -1;
}
return rc;
}
static int ptm_fops_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
{
return -EINVAL;
}
static int ptm_fops_lock(struct dfs_file *file, struct file_lock *flock)
{
return -EINVAL;
}
static int ptm_fops_flock(struct dfs_file *file, int operation, struct file_lock *flock)
{
return -EINVAL;
}
static struct dfs_file_ops ptm_fops = {
.open = ptm_fops_open,
.close = ptm_fops_close,
.ioctl = ptm_fops_ioctl,
.read = ptm_fops_read,
.write = ptm_fops_write,
.flush = ptm_fops_flush,
.lseek = ptm_fops_lseek,
.truncate = ptm_fops_truncate,
.poll = ptm_fops_poll,
.mmap = ptm_fops_mmap,
.lock = ptm_fops_lock,
.flock = ptm_fops_flock,
};
rt_err_t lwp_ptmx_init(rt_device_t ptmx_device, const char *root_path)
{
char *device_name;
int root_len;
const char *dev_rel_path;
rt_err_t rc;
root_len = strlen(root_path);
dev_rel_path = "/ptmx";
device_name = rt_malloc(root_len + sizeof("/ptmx"));
if (device_name)
{
/* Register device */
sprintf(device_name, "%s%s", root_path, dev_rel_path);
rt_device_register(ptmx_device, device_name, 0);
/* Setup fops */
ptmx_device->fops = &ptm_fops;
rt_free(device_name);
rc = RT_EOK;
}
else
{
rc = -RT_ENOMEM;
}
return rc;
}
/* system level ptmx */
static struct rt_device sysptmx;
static struct dfs_file_ops sysptmx_file_ops;
static rt_err_t sysptmx_readlink(struct rt_device *dev, char *buf, int len)
{
int rc = 0;
/* TODO: support multi-root ? */
strncpy(buf, "pts/ptmx", len);
return rc;
}
static int _sys_ptmx_init(void)
{
rt_err_t rc;
rt_device_t sysptmx_rtdev = &sysptmx;
/* setup system level device */
sysptmx_rtdev->type = RT_Device_Class_Char;
sysptmx_rtdev->ops = RT_NULL;
rc = rt_device_register(sysptmx_rtdev, "ptmx", RT_DEVICE_FLAG_DYNAMIC);
if (rc == RT_EOK)
{
sysptmx_rtdev->readlink = &sysptmx_readlink;
sysptmx_rtdev->fops = &sysptmx_file_ops;
}
return rc;
}
INIT_DEVICE_EXPORT(_sys_ptmx_init);