mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-21 18:57:16 +08:00
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:
+2
-19
@@ -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
|
||||
|
||||
|
||||
@@ -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__*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
+458
-88
File diff suppressed because it is too large
Load Diff
+68
-15
@@ -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
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
+382
-375
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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_ */
|
||||
@@ -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
@@ -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
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user