From nobody Mon Oct 6 17:09:03 2025 Received: from m16.mail.126.com (m16.mail.126.com [220.197.31.7]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8701417578 for ; Fri, 18 Jul 2025 06:07:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752818874; cv=none; b=Tu6F3iFb1wKH2OyKJBQ/5wdKFRDJcT01hOyUUAVwqwiMsSk5iJjAQ3LojZpidX56J53PAnsIUyivk9fMax96rN+BbNtnJKxPxbjTKG5qpff5hp1Vj2wkAHzJGETgg/cFcQ0Rx47egPs3dCSZSt1JOs+K9yhwx1EgAtkr9FBUq30= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752818874; c=relaxed/simple; bh=WKsmDsvHkM2YdV1l30cRnyx2nzQrtcCoU4uj/sOTtTY=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=ZyMAUJ6jDUMdCmgGZEb+7NmDBmGZB0U5WYrAtuUZKYtPCQe/Et+GbzhnrNFD5BVZQt2fRNMgZj4Eb90JUVkJnLRx4BHhY6BSsY2kIwnS+cxKhJ5DN8PiuZ2HL3FvxEJ2RzZe1UDKuryCkoTzeqphkevrhY/4k/MLvsr3idKEBug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=126.com; spf=pass smtp.mailfrom=126.com; dkim=pass (1024-bit key) header.d=126.com header.i=@126.com header.b=YfpUArpo; arc=none smtp.client-ip=220.197.31.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=126.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=126.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=126.com header.i=@126.com header.b="YfpUArpo" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=126.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=nH Kf+W5xu8MvnmiXQoE9yWAqzLLh/eEVPFSkiS4AmYk=; b=YfpUArpoofsGNZtGCX TBaKTu2BS/+50xY8fCNppyQdL3rC7PsLJriUPd4pR71JqsFOIvoVxx4bNzgNWsei 8ITmXX/dUaviMkmZwG+ZrW96EnyNb5UxCgA5/F+E1tAd6dhL6B73NQsOhiHUzUjb DZKtRfm8W2D9Tj8aug/Zv/AJA= Received: from localhost.localdomain (unknown []) by gzga-smtp-mtada-g0-1 (Coremail) with SMTP id _____wD3pzWP5HlopgiRAQ--.35541S2; Fri, 18 Jul 2025 14:07:12 +0800 (CST) From: XingxingQiao To: linux-kernel@vger.kernel.org, joel.granados@kernel.org, bsegall@google.com, brauner@kernel.org, wei.liu@kernel.org, peterz@infradead.org Cc: XingxingQiao Subject: [RFC] rt_ipc: a new IPC mechanism called rt_ipc (real-time IPC) Date: Fri, 18 Jul 2025 14:06:34 +0800 Message-ID: <20250718060634.469032-1-mnlife@126.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: _____wD3pzWP5HlopgiRAQ--.35541S2 X-Coremail-Antispam: 1Uf129KBjvAXoWfKw1DKFWDKF18Gw47Jw18Xwb_yoWrArW5Ko W3GF47Cr1xJFnFqFWrGrZ7JrW3XrWDKrW8Gws5tFs7ZF1Ivan8Wayjka13Z3W5ury0vr45 A3y0qw1fXa1IqFn3n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjTRFAp1UUUUU X-CM-SenderInfo: ppqoxwbh6rjloofrz/1tbi5AeO9mh5tlmEOQACsa Content-Type: text/plain; charset="utf-8" This patch set proposes a new IPC mechanism for the Linux kernel called rt_= ipc (real-time IPC). This is refers to this paper: https://www.usenix.org/legacy/publications/li= brary/proceedings/sf94/full_papers/ford.pdf Similar in concept to Android Binder or Linux local sockets, rt_ipc is desi= gned with a 'migrating thread model' to achieve significant real-time performanc= e advantages. Motivation The primary motivation behind rt_ipc is to provide a high-performance, real-time IPC mechanism that addresses the limitations of traditional IPC m= ethods, particularly concerning latency and priority management. This is achieved by implementing an IPC mechanism based on the migrating thread model, where a single thread abstraction moves between tasks during an RPC, with the server code being passively executed. The value rt_ipc provides can be elaborated along these axes: 1. Accelerated Communication Performance: Traditional IPC mechanisms, particularly those based on the 'static thread = model', involve two distinct threads (client and server) and necessitate multiple thread-to-thread context switches, synchronization, and rescheduling. This process introduces overhead, including scheduler delays due to wait and wake-up operations. In contrast, rt_ipc leverages a migrating thread model where the entire RPC operation is performed by a single thread that tempora= rily transitions into the server task. This design eliminates the need for synch= ronization, rescheduling, or a full context switch, significantly reducing communicatio= n latency. Preliminary benchmarks demonstrate a notable performance improvement: for 1,000,000 server-client data exchanges, rt_ipc completes in approximate= ly 1.055 seconds, whereas traditional Linux local sockets require 3.35 seconds. 2. Optimized Context Management: The migrating thread model in rt_ipc avoids the overhead of a complete proc= ess context switch. Instead, only a partial context switch is performed where the kernel switches the address space and a subset of CPU registers, such as the user stack pointer, without switching threads or priorities, and without involving the scheduler. This approach simplifies kernel code a= nd improves RPC performance. 3. Prevention of Priority Inversion: proxy-exec can solve the scheduling priority inversion problem: https://git= hub.com/johnstultz-work/linux-dev/ But rt_ipc provides different solutions: In systems utilizing a static thread model, when a high-priority client ini= tiates an RPC, control is transferred to a separate server thread, which may have its own independent scheduling parameters and attributes. This can lead to classic = problems such as starvation and priority inversion, where a high-priority client is forced to contend with lower-priority server threads. rt_ipc addresses this= by allowing the server's function to directly inherit the client process's att= ributes. By having the client's thread migrate and execute the server's code, the client's own computational resources (including its priority and schedu= ling attributes) are utilized to provide services to itself. This inherent mechanism within the migrating thread model effectively mitigates the priority inversion pro= blem. Signed-off-by: XingxingQiao --- arch/x86/entry/syscalls/syscall_64.tbl | 3 + arch/x86/include/asm/rt_ipc.h | 78 ++++++ arch/x86/kernel/Makefile | 2 + arch/x86/kernel/rt_ipc.c | 361 +++++++++++++++++++++++++ arch/x86/kernel/signal.c | 41 +-- include/linux/rt_ipc.h | 11 + include/linux/sched.h | 7 +- init/Kconfig | 4 + init/init_task.c | 4 + ipc/Makefile | 1 + ipc/rt_ipc.c | 141 ++++++++++ kernel/exit.c | 4 +- kernel/fork.c | 7 +- kernel/sched/core.c | 36 +++ tools/rt_ipc_userspace/Makefile | 13 + tools/rt_ipc_userspace/rt_ipc_action.c | 162 +++++++++++ tools/rt_ipc_userspace/rt_ipc_action.h | 56 ++++ tools/rt_ipc_userspace/rt_ipc_client.c | 89 ++++++ tools/rt_ipc_userspace/rt_ipc_server.c | 64 +++++ 19 files changed, 1062 insertions(+), 22 deletions(-) create mode 100644 arch/x86/include/asm/rt_ipc.h create mode 100644 arch/x86/kernel/rt_ipc.c create mode 100644 include/linux/rt_ipc.h create mode 100644 ipc/rt_ipc.c create mode 100644 tools/rt_ipc_userspace/Makefile create mode 100755 tools/rt_ipc_userspace/rt_ipc_action.c create mode 100755 tools/rt_ipc_userspace/rt_ipc_action.h create mode 100755 tools/rt_ipc_userspace/rt_ipc_client.c create mode 100755 tools/rt_ipc_userspace/rt_ipc_server.c diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscal= ls/syscall_64.tbl index cfb5ca41e30d..1b8b98df9a03 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -391,6 +391,9 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common rt_ipc_register sys_rt_ipc_register +469 common rt_ipc_invoke sys_rt_ipc_invoke +470 common rt_ipc_return sys_rt_ipc_return =20 # # Due to a historical design error, certain syscalls are numbered differen= tly diff --git a/arch/x86/include/asm/rt_ipc.h b/arch/x86/include/asm/rt_ipc.h new file mode 100644 index 000000000000..c3dbae8eba4c --- /dev/null +++ b/arch/x86/include/asm/rt_ipc.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_X86_RT_IPC_H +#define _ASM_X86_RT_IPC_H + +#include +#include +#include + +#define RT_IPC_ACTIVATION_THREAD_NUM 8 + +typedef struct rt_ipc_info { + size_t write_size; /* bytes to write */ + size_t write_consumed; /* bytes consumed by driver */ + uintptr_t write_buffer; + size_t read_size; /* bytes to read */ + size_t read_consumed; /* bytes consumed by driver */ + uintptr_t read_buffer; +} rt_ipc_info_t; + +struct rt_ipc_action { + void (*entry)(unsigned cmd, rt_ipc_info_t *info); + void (*restorer)(void); + int flags; +}; + +struct rt_ipc_migrate_context { + struct task_struct *group_leader; + struct files_struct *files; + struct fs_struct *fs; + struct sighand_struct *sighand; + struct signal_struct *signal; + struct pid *thread_pid; + pid_t pid; + pid_t tgid; + struct rseq *rseq; + u32 rseq_sig; + unsigned long rseq_event_mask; + struct mm_struct *mm; + struct mm_struct *active_mm; + struct nsproxy *nsproxy; + unsigned long min_flt; + unsigned long maj_flt; + unsigned long fsbase; +}; + +struct rt_ipc_context { + struct pt_regs regs; + unsigned long trap_nr; + unsigned long error_code; + unsigned long gs; + unsigned long fs; + unsigned long cr2; +}; + +struct rt_ipc_activation { + struct list_head activation_link; + + size_t stack; + struct rt_ipc_info __user *info; + struct rt_ipc_action *act; + struct task_struct *s; + struct task_struct *c; + + struct rt_ipc_migrate_context context; + struct rt_ipc_context server_ctx; + struct rt_ipc_context client_ctx; +}; + +struct rt_ipc_frame { + void __user *pretcode; + struct rt_ipc_info info; +}; + +int rt_ipc_config_activation(struct task_struct *task); +int rt_ipc_migrate_thread(struct rt_ipc_activation *activation, unsigned i= nt cmd, struct rt_ipc_info *info); + +extern void rt_ipc_context_switch(struct task_struct *next); +#endif /* _ASM_X86_RT_IPC_H */ \ No newline at end of file diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 0d2a6d953be9..77d401993aeb 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -166,3 +166,5 @@ ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_MMCONF_FAM10H) +=3D mmconf-fam10h_64.o obj-y +=3D vsmp_64.o endif + +obj-$(CONFIG_RT_IPC) +=3D rt_ipc.o diff --git a/arch/x86/kernel/rt_ipc.c b/arch/x86/kernel/rt_ipc.c new file mode 100644 index 000000000000..cb24ad603b15 --- /dev/null +++ b/arch/x86/kernel/rt_ipc.c @@ -0,0 +1,361 @@ +#define pr_fmt(fmt) "[%s:%d] " fmt, __func__, __LINE__ + +#include "linux/sched.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool rt_ipc_dbg =3D false; +core_param(rt_ipc_dbg, rt_ipc_dbg, bool, 0644); + +#define WARN1(fmt, args...) ({ \ + WARN(rt_ipc_dbg, fmt, ##args); \ +}) + +#define pr_info1(fmt, args...) { \ +if (rt_ipc_dbg) \ + pr_info(fmt, ##args); \ +} + +static void pr_context(struct pt_regs *regs) +{ + pr_info1("di : %016lx si : %016lx bp : %016lx sp : %016lx\n", regs->di, r= egs->si, regs->bp, regs->sp); + pr_info1("bx : %016lx dx : %016lx cx : %016lx ax : %016lx\n", regs->bx, r= egs->dx, regs->cx, regs->ax); + pr_info1("r8 : %016lx r9 : %016lx r10: %016lx r11: %016lx\n", regs->r8, r= egs->r9, regs->r10, regs->r11); + pr_info1("r12: %016lx r13: %016lx r14: %016lx r15: %016lx\n", regs->r12, = regs->r13, regs->r14, regs->r15); + pr_info1("trap_nr: %016lx error_code: %016lx ip: %016lx flag: %016lx\n", + current->thread.trap_nr, current->thread.error_code, regs->ip, regs->fla= gs); + pr_info1("cs: %016x ss: %016x cr2: %016lx cr3: %016lx\n", regs->cs, regs-= >ss, current->thread.cr2, __read_cr3()); +} + +/* + * If regs->ss will cause an IRET fault, change it. Otherwise leave it + * alone. Using this generally makes no sense unless + * user_64bit_mode(regs) would return true. + */ +static void force_valid_ss(struct pt_regs *regs) +{ + u32 ar; + asm volatile ("lar %[old_ss], %[ar]\n\t" + "jz 1f\n\t" /* If invalid: */ + "xorl %[ar], %[ar]\n\t" /* set ar =3D 0 */ + "1:" + : [ar] "=3Dr" (ar) + : [old_ss] "rm" ((u16)regs->ss)); + + /* + * For a valid 64-bit user context, we need DPL 3, type + * read-write data or read-write exp-down data, and S and P + * set. We can't use VERW because VERW doesn't check the + * P bit. + */ + ar &=3D AR_DPL_MASK | AR_S | AR_P | AR_TYPE_MASK; + if (ar !=3D (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA) && + ar !=3D (AR_DPL3 | AR_S | AR_P | AR_TYPE_RWDATA_EXPDOWN)) + regs->ss =3D __USER_DS; +} + +static int x64_setup_rt_ipc_frame(struct rt_ipc_activation *activation, st= ruct pt_regs *regs, unsigned int cmd, struct rt_ipc_info *info) +{ + struct rt_ipc_frame __user *frame; + void __user *fp =3D NULL; + + frame =3D get_sigframe(NULL, regs, sizeof(struct rt_ipc_frame), &fp); + + if (!user_access_begin(frame, sizeof(*frame))) { + pr_err("%s:%d handler: 0x%lx\n", __func__, __LINE__, (unsigned long)fram= e); + return -EFAULT; + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + unsafe_put_user(activation->act->restorer, &frame->pretcode, Efault); + user_access_end(); + + if (copy_to_user(&frame->info, info , sizeof(struct rt_ipc_info))) + return -EFAULT; + + pr_info1("&frame->info: %llx", (u64)(&frame->info)); + /* TODO: process frame->info */ + + regs->di =3D cmd; + regs->ax =3D 0; + + regs->si =3D (unsigned long)&frame->info; + + regs->ip =3D (unsigned long)activation->act->entry; + + regs->sp =3D (unsigned long)frame; + + regs->cs =3D __USER_CS; + + if (unlikely(regs->ss !=3D __USER_DS)) + force_valid_ss(regs); + + return 0; + +Efault: + user_access_end(); + return -EFAULT; +} + +static void save_context(struct rt_ipc_context *ctx, struct pt_regs *regs) +{ + ctx->regs =3D *regs; + ctx->trap_nr =3D current->thread.trap_nr; + ctx->error_code =3D current->thread.error_code; + ctx->gs =3D 0; + ctx->fs =3D 0; + ctx->cr2 =3D current->thread.cr2; + /* TODO: fpstate save restore */ +} + +static void restore_context(struct rt_ipc_context *ctx, struct pt_regs *re= gs) +{ + current->restart_block.fn =3D do_no_restart_syscall; + + ctx->regs.flags =3D (regs->flags & ~FIX_EFLAGS) | (ctx->regs.flags & FIX_= EFLAGS); + + *regs =3D ctx->regs; + + regs->cs |=3D 0x03; + regs->ss |=3D 0x03; + regs->orig_ax =3D -1; +} + +int rt_ipc_config_activation(struct task_struct *task) +{ + struct pt_regs *regs =3D task_pt_regs(task); + struct rt_ipc_activation *activation; + + list_for_each_entry(activation, &task->rt_ipc_activation_free, activation= _link) { + save_context(&activation->server_ctx, regs); + + pr_info("activation pid: %d stack: %016lx\n", activation->s->pid, activa= tion->stack); + } + + pr_context(regs); + + WARN1("%s:%d\n", __func__, __LINE__); + pr_info("%s:%d pid: %d\n", __func__, __LINE__, current->pid); + + return 0; +} + +static void save_task_context(struct task_struct *p, struct rt_ipc_activat= ion *act) +{ + act->context.files =3D p->files; + act->context.fs =3D p->fs; + act->context.sighand =3D p->sighand; + act->context.signal =3D p->signal; + act->context.thread_pid =3D p->thread_pid; + act->context.pid =3D p->pid; + act->context.tgid =3D p->tgid; + act->context.rseq =3D p->rseq; + act->context.rseq_sig =3D p->rseq_sig; + act->context.rseq_event_mask =3D p->rseq_event_mask; + act->context.mm =3D p->mm; + act->context.active_mm =3D p->active_mm; + act->context.nsproxy =3D p->nsproxy; + act->context.min_flt =3D p->min_flt; + act->context.maj_flt =3D p->maj_flt; + act->context.fsbase =3D p->thread.fsbase; + act->context.group_leader =3D p->group_leader; +} + +#define CONFIG_SWITCH_THREAD_GROUP 1 + +static void migrate_thread(struct task_struct *c, struct task_struct *s, s= truct rt_ipc_activation *act) +{ + save_task_context(c, act); + + atomic_inc(&s->files->count); + c->files =3D s->files; + + c->fs->users++; + c->fs =3D s->fs; + + c->rseq =3D s->rseq; + c->rseq_sig =3D s->rseq_sig; + c->rseq_event_mask =3D s->rseq_event_mask; + + atomic_inc(&s->mm->mm_users); + c->mm =3D s->mm; + c->active_mm =3D s->mm; + + c->nsproxy =3D s->nsproxy; + + c->min_flt =3D s->min_flt; + c->maj_flt =3D s->maj_flt; + + /* fsbase register for glibc tls, thread local storage */ + c->thread.fsbase =3D s->thread.fsbase; + if (static_cpu_has(X86_FEATURE_FSGSBASE)) { + wrfsbase(c->thread.fsbase); + } +} + +static void restore_thread_from_upcall(struct task_struct *c, struct task_= struct *s, struct rt_ipc_activation *act) +{ + struct rt_ipc_migrate_context *ctx =3D &act->context; + + c->files =3D ctx->files; + atomic_dec(&s->files->count); + + c->fs =3D ctx->fs; + s->fs->users--; + + c->rseq =3D ctx->rseq; + c->rseq_sig =3D ctx->rseq_sig; + c->rseq_event_mask =3D ctx->rseq_event_mask; + + c->mm =3D ctx->mm; + c->active_mm =3D ctx->active_mm; + atomic_dec(&s->mm->mm_users); + + c->nsproxy =3D ctx->nsproxy; + + c->min_flt =3D ctx->min_flt; + c->maj_flt =3D ctx->maj_flt; + + c->thread.fsbase =3D ctx->fsbase; + if (static_cpu_has(X86_FEATURE_FSGSBASE)) { + wrfsbase(c->thread.fsbase); + } +} + +static void upcall_setup(struct rt_ipc_activation *activation, unsigned in= t cmd, struct rt_ipc_info *info) +{ + struct pt_regs *regs =3D current_pt_regs(); + unsigned long flags; + spinlock_t *lock =3D &activation->s->sighand->siglock; + pr_info1("c->fsbase: %016lx s->fsbase: %016lx\n", activation->c->thread.f= sbase, activation->s->thread.fsbase); + pr_context(regs); + pr_info1("pt_regs: %px\n", regs); + WARN1("%s:%d s->mm->mm_users: %d READ_ONCE(c->__state): %d READ_ONCE(s->_= _state): %d\n", + __func__, __LINE__, atomic_read(&activation->s->mm->mm_users), READ_ONCE= (activation->c->__state), READ_ONCE(activation->s->__state)); + + save_context(&activation->client_ctx, regs); + + spin_lock_irqsave(lock, flags); + + migrate_thread(activation->c, activation->s, activation); + + rt_ipc_context_switch(activation->c); + spin_unlock_irqrestore(lock, flags); + + restore_context(&activation->server_ctx, regs); + + regs->sp =3D activation->stack; + + if (x64_setup_rt_ipc_frame(activation, regs, cmd, info) < 0) { + pr_err("setup rt ipc frame failed\n"); + goto out; + } + + pr_context(regs); + + pr_info1("c->fsbase: %016lx s->fsbase: %016lx\n", activation->c->thread.f= sbase, activation->s->thread.fsbase); + WARN1("%s:%d\n", __func__, __LINE__); + pr_info1("%s:%d handler: %016lx %016lx\n", __func__, __LINE__, (size_t)ac= tivation->act->entry, (size_t)activation->act->restorer); + + return; + +out: + signal_fault(regs, activation, "rt_ipc_migrate_thread"); +} + +int rt_ipc_migrate_thread(struct rt_ipc_activation *activation, unsigned i= nt cmd, struct rt_ipc_info *info) +{ + activation->c =3D current; + + upcall_setup(activation, cmd, info); + + list_add(&activation->activation_link, ¤t->rt_ipc_activation_in_use= ); + + return 0; +} + +static void clear_activation_info(struct rt_ipc_activation *activation) +{ + activation->c =3D NULL; +} + +static int rt_ipc_return(struct pt_regs *regs, struct rt_ipc_info *info) +{ + unsigned long flags; + spinlock_t *sighand_lock; + spinlock_t *rt_ipc_lock; + + struct rt_ipc_activation *activation =3D + list_first_entry_or_null(¤t->rt_ipc_activation_in_use, struct rt_i= pc_activation, activation_link); + if (!activation) { + pr_err("invaild activation\n"); + return -EFAULT; + } + + sighand_lock =3D &activation->s->sighand->siglock; + rt_ipc_lock =3D &activation->s->group_leader->rt_ipc_lock; + + spin_lock_irqsave(sighand_lock, flags); + + restore_thread_from_upcall(activation->c, activation->s, activation); + rt_ipc_context_switch(activation->c); + + spin_unlock_irqrestore(sighand_lock, flags); + + restore_context(&activation->client_ctx, regs); + + spin_lock_irqsave(rt_ipc_lock, flags); + clear_activation_info(activation); + list_move(&activation->activation_link, &activation->s->group_leader->rt_= ipc_activation_free); + spin_unlock_irqrestore(rt_ipc_lock, flags); + + pr_info1("READ_ONCE(c->__state): %d READ_ONCE(s->__state): %d current: %d= \n", + READ_ONCE(current->__state), READ_ONCE(activation->s->__state), READ_ONC= E(current->__state)); + WARN1("%s:%d\n", __func__, __LINE__); + pr_info1("c->fsbase: %016lx s->fsbase: %016lx\n", current->thread.fsbase,= activation->s->thread.fsbase); + pr_context(regs); + + if (copy_to_user(activation->info, info , sizeof(struct rt_ipc_info))) { + pr_err("activation->info: %lx info: %lx", (size_t)activation->info, (siz= e_t)info); + return -EFAULT; + } + return 0; +} + +SYSCALL_DEFINE0(rt_ipc_return) +{ + struct pt_regs *regs =3D current_pt_regs(); + struct rt_ipc_frame __user *frame; + struct rt_ipc_info info; + + frame =3D (struct rt_ipc_frame __user *)(regs->sp - sizeof(long)); + if (!access_ok(frame, sizeof(*frame))) + goto badframe; + + pr_info1("&frame->info: %lx regs->si: %lx", (size_t)(&frame->info), regs-= >si); + + if (copy_from_user(&info, &frame->info, sizeof(info))) { + goto badframe; + } + /* TODO: process frame->info */ + + if (rt_ipc_return(regs, &info) < 0) { + goto badframe; + } + + regs->ax =3D 0; + + return regs->ax; + +badframe: + signal_fault(regs, frame, "rt_ipc_return"); + return 0; +} diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 2404233336ab..788be933768f 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -94,8 +94,8 @@ void __user * get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size, void __user **fpstate) { - struct k_sigaction *ka =3D &ksig->ka; - int ia32_frame =3D is_ia32_frame(ksig); + struct k_sigaction *ka; + int ia32_frame =3D ksig ? is_ia32_frame(ksig) : 0; /* Default to using normal stack */ bool nested_altstack =3D on_sig_stack(regs->sp); bool entering_altstack =3D false; @@ -108,25 +108,28 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *re= gs, size_t frame_size, if (!ia32_frame) sp -=3D 128; =20 - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - /* - * This checks nested_altstack via sas_ss_flags(). Sensible - * programs use SS_AUTODISARM, which disables that check, and - * programs that don't use SS_AUTODISARM get compatible. - */ - if (sas_ss_flags(sp) =3D=3D 0) { - sp =3D current->sas_ss_sp + current->sas_ss_size; + if (ksig) { + ka =3D &ksig->ka; + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + /* + * This checks nested_altstack via sas_ss_flags(). Sensible + * programs use SS_AUTODISARM, which disables that check, and + * programs that don't use SS_AUTODISARM get compatible. + */ + if (sas_ss_flags(sp) =3D=3D 0) { + sp =3D current->sas_ss_sp + current->sas_ss_size; + entering_altstack =3D true; + } + } else if (ia32_frame && + !nested_altstack && + regs->ss !=3D __USER_DS && + !(ka->sa.sa_flags & SA_RESTORER) && + ka->sa.sa_restorer) { + /* This is the legacy signal stack switching. */ + sp =3D (unsigned long) ka->sa.sa_restorer; entering_altstack =3D true; } - } else if (ia32_frame && - !nested_altstack && - regs->ss !=3D __USER_DS && - !(ka->sa.sa_flags & SA_RESTORER) && - ka->sa.sa_restorer) { - /* This is the legacy signal stack switching. */ - sp =3D (unsigned long) ka->sa.sa_restorer; - entering_altstack =3D true; } =20 sp =3D fpu__alloc_mathframe(sp, ia32_frame, &buf_fx, &math_size); diff --git a/include/linux/rt_ipc.h b/include/linux/rt_ipc.h new file mode 100644 index 000000000000..6089ec12515d --- /dev/null +++ b/include/linux/rt_ipc.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_RT_IPC_H__ +#define __LINUX_RT_IPC_H__ + +#ifdef CONFIG_RT_IPC +#include + +void rt_ipc_deregister(struct task_struct *tsk); +#endif + +#endif /* __LINUX_RT_IPC_H__ */ \ No newline at end of file diff --git a/include/linux/sched.h b/include/linux/sched.h index aa9c5be7a632..c44ac36d756d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -47,6 +47,7 @@ #include #include #include +#include =20 /* task_struct member predeclarations (sorted alphabetically): */ struct audit_context; @@ -1625,7 +1626,11 @@ struct task_struct { #ifdef CONFIG_RETHOOK struct llist_head rethooks; #endif - +#ifdef CONFIG_RT_IPC + struct list_head rt_ipc_activation_free; + struct list_head rt_ipc_activation_in_use; + spinlock_t rt_ipc_lock; +#endif #ifdef CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH /* * If L1D flush is supported on mm context switch diff --git a/init/Kconfig b/init/Kconfig index 666783eb50ab..6a4f5be7d934 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -437,6 +437,10 @@ config SYSVIPC_COMPAT def_bool y depends on COMPAT && SYSVIPC =20 +config RT_IPC + bool "Migrating thread model" + def_bool n + config POSIX_MQUEUE bool "POSIX Message Queues" depends on NET diff --git a/init/init_task.c b/init/init_task.c index e557f622bd90..0ff488738cef 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -143,6 +143,10 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES)= =3D { .timer_slack_ns =3D 50000, /* 50 usec default slack */ .thread_pid =3D &init_struct_pid, .thread_node =3D LIST_HEAD_INIT(init_signals.thread_head), +#ifdef CONFIG_RT_IPC + .rt_ipc_activation_in_use =3D LIST_HEAD_INIT(init_task.rt_ipc_activation_= in_use), + .rt_ipc_activation_free =3D LIST_HEAD_INIT(init_task.rt_ipc_activation_fr= ee), +#endif #ifdef CONFIG_AUDIT .loginuid =3D INVALID_UID, .sessionid =3D AUDIT_SID_UNSET, diff --git a/ipc/Makefile b/ipc/Makefile index c2558c430f51..460b45d579a3 100644 --- a/ipc/Makefile +++ b/ipc/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_POSIX_MQUEUE) +=3D mqueue.o msgutil.o obj-$(CONFIG_IPC_NS) +=3D namespace.o obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) +=3D mq_sysctl.o =20 +obj-$(CONFIG_RT_IPC) +=3D rt_ipc.o diff --git a/ipc/rt_ipc.c b/ipc/rt_ipc.c new file mode 100644 index 000000000000..0d61e33dc7c8 --- /dev/null +++ b/ipc/rt_ipc.c @@ -0,0 +1,141 @@ +#define pr_fmt(fmt) "[%s:%d] " fmt, __func__, __LINE__ + +#include +#include +#include +#include + +static __maybe_unused __cacheline_aligned_in_smp DEFINE_SPINLOCK(rt_ipc_lo= ck); + +void rt_ipc_deregister(struct task_struct *tsk) +{ + struct rt_ipc_activation *activation, *tmp; + struct rt_ipc_action *act =3D NULL; + + list_for_each_entry_safe(activation, tmp, &tsk->rt_ipc_activation_free, a= ctivation_link) { + act =3D activation->act; + list_del_init(&activation->activation_link); + kfree(activation); + } + + if (act) + kfree(act); + + pr_debug("task: %s tsk->pid: %d\n", tsk->comm, tsk->pid); +} + +SYSCALL_DEFINE1(rt_ipc_register, const struct rt_ipc_action __user *, act) +{ + struct rt_ipc_action *kact; + struct rt_ipc_activation *activation; + struct task_struct *p; + spinlock_t *rt_ipc_lock, *sighand_lock; + int ret; + + if (!act) { + ret =3D -EINVAL; + goto out; + } + + kact =3D kmalloc(sizeof(*kact), GFP_KERNEL); + if (!kact) { + ret =3D -ENOMEM; + goto out; + } + + if (copy_from_user(kact, act, sizeof(*act))) { + ret =3D -EFAULT; + goto out_free_act; + } + + rt_ipc_lock =3D ¤t->group_leader->rt_ipc_lock; + sighand_lock =3D ¤t->group_leader->sighand->siglock; + + spin_lock_init(¤t->group_leader->rt_ipc_lock); + + spin_lock_irq(sighand_lock); + + for_each_thread(current, p) { + activation =3D kzalloc(sizeof(*activation), GFP_KERNEL); + BUG_ON(activation =3D=3D NULL); + + activation->stack =3D round_down(task_pt_regs(p)->sp, 128) - 8; + activation->s =3D p; + activation->act =3D kact; + + spin_lock_irq(rt_ipc_lock); + list_add_tail(&activation->activation_link, ¤t->group_leader->rt_i= pc_activation_free); + spin_unlock_irq(rt_ipc_lock); + } + + spin_unlock_irq(sighand_lock); + + ret =3D rt_ipc_config_activation(current->group_leader); + if (ret < 0) { + // TODO: activation free + goto out_free_act; + } + + return ret; + +out_free_act: + kfree(act); +out: + return ret; +} + +static struct rt_ipc_activation *get_available_activation(struct task_stru= ct *task) +{ + struct rt_ipc_activation *activation, *tmp; + + list_for_each_entry_safe(activation, tmp, &task->rt_ipc_activation_free, = activation_link) { + list_del_init(&activation->activation_link); + return activation; + } + + return NULL; +} + +SYSCALL_DEFINE3(rt_ipc_invoke, pid_t, pid, unsigned int __user, cmd, size_= t __user *, args) +{ + struct rt_ipc_activation *activation; + spinlock_t *lock; + struct task_struct *p; + unsigned long flags; + int errno =3D -EINVAL; + struct rt_ipc_info info; + + if (copy_from_user(&info, args, sizeof(info))) { + return -EFAULT; + } + + if (pid < 0) + return errno; + + rcu_read_lock(); + p =3D pid_task(find_vpid(pid), PIDTYPE_PID); + rcu_read_unlock(); + + if (!p) + return -ESRCH; + + lock =3D &p->group_leader->rt_ipc_lock; + + spin_lock_irqsave(lock, flags); + + activation =3D get_available_activation(p->group_leader); + if (!activation) { + spin_unlock_irqrestore(lock, flags); + return errno; + } + + spin_unlock_irqrestore(lock, flags); + + activation->info =3D (void *)args; + + pr_debug("stack: %016lx pid: %d\n", activation->stack, current->pid); + + errno =3D rt_ipc_migrate_thread(activation, cmd, &info); + + return errno; +} \ No newline at end of file diff --git a/kernel/exit.c b/kernel/exit.c index bb184a67ac73..4f5fe3e50b35 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -963,7 +963,9 @@ void __noreturn do_exit(long code) exit_task_namespaces(tsk); exit_task_work(tsk); exit_thread(tsk); - +#ifdef CONFIG_RT_IPC + rt_ipc_deregister(tsk); +#endif sched_autogroup_exit_task(tsk); cgroup_exit(tsk); =20 diff --git a/kernel/fork.c b/kernel/fork.c index 1ee8eb11f38b..09c407394337 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -122,6 +122,8 @@ =20 #include =20 +#include + /* * Minimum number of threads to boot the kernel */ @@ -2418,7 +2420,10 @@ __latent_entropy struct task_struct *copy_process( user_events_fork(p, clone_flags); =20 copy_oom_score_adj(clone_flags, p); - +#ifdef CONFIG_RT_IPC + INIT_LIST_HEAD(&p->rt_ipc_activation_in_use); + INIT_LIST_HEAD(&p->rt_ipc_activation_free); +#endif return p; =20 bad_fork_core_free: diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 81c6df746df1..7835bfc1f93c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5400,6 +5400,42 @@ context_switch(struct rq *rq, struct task_struct *pr= ev, return finish_task_switch(prev); } =20 +#ifdef CONFIG_RT_IPC +void rt_ipc_context_switch(struct task_struct *next) +{ + struct task_struct *prev; + unsigned long flags; + struct rq *rq; + int cpu; + + cpu =3D smp_processor_id(); + rq =3D cpu_rq(cpu); + prev =3D rq->curr; + + raw_spin_rq_lock_irqsave(rq, flags); + + membarrier_switch_mm(rq, prev->active_mm, next->mm); + /* + * sys_membarrier() requires an smp_mb() between setting + * rq->curr / membarrier_switch_mm() and returning to userspace. + * + * The below provides this either through switch_mm(), or in + * case 'prev->active_mm =3D=3D next->mm' through + * finish_task_switch()'s mmdrop(). + */ + switch_mm_irqs_off(prev->active_mm, next->mm, next); + lru_gen_use_mm(next->mm); + + /* switch_mm_cid() requires the memory barriers above. */ + // switch_mm_cid(rq, prev, next); + + __switch_to(prev, next); + barrier(); + + raw_spin_rq_unlock_irqrestore(rq, flags); +} +#endif + /* * nr_running and nr_context_switches: * diff --git a/tools/rt_ipc_userspace/Makefile b/tools/rt_ipc_userspace/Makef= ile new file mode 100644 index 000000000000..2e0656bb1e3f --- /dev/null +++ b/tools/rt_ipc_userspace/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 + +CFLAGS =3D -Wall -Wextra -g -I. +PROGS :=3D rt_ipc_server rt_ipc_client + +all: $(PROGS) +%: %.c + $(CC) $(CFLAGS) rt_ipc_action.c -o $@ $^ + +clean: + $(RM) $(PROGS) + +.PHONY: all clean diff --git a/tools/rt_ipc_userspace/rt_ipc_action.c b/tools/rt_ipc_userspac= e/rt_ipc_action.c new file mode 100755 index 000000000000..ea1217408a9b --- /dev/null +++ b/tools/rt_ipc_userspace/rt_ipc_action.c @@ -0,0 +1,162 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_ipc_action.h" + +#define RT_IPC_RESTORER 0x04000000 + +#define LP_SIZE "8" +# define CFI_STRINGIFY(Name) CFI_STRINGIFY2 (Name) +# define CFI_STRINGIFY2(Name) #Name +# define attribute_hidden __attribute__ ((visibility ("hidden"))) + +/* Align a value by rounding down to closest size. + e.g. Using size of 4096, we get this behavior: + {4095, 4096, 4097} =3D {0, 4096, 4096}. */ +#define ALIGN_DOWN(base, size) ((base) & -((__typeof__ (base)) (size))) + +/* Align a value by rounding up to closest size. + e.g. Using size of 4096, we get this behavior: + {4095, 4096, 4097} =3D {4096, 4096, 8192}. + + Note: The size argument has side effects (expanded multiple times). */ +#define ALIGN_UP(base, size) ALIGN_DOWN ((base) + (size) - 1, (size)) + +#define UCHAR_WIDTH 8 +//#define ULONG_WIDTH 64 +#define __NSIG_WORDS (ALIGN_UP ((_NSIG - 1), ULONG_WIDTH) / ULONG_WIDTH) +#define __NSIG_BYTES (__NSIG_WORDS * (ULONG_WIDTH / UCHAR_WIDTH)) + +#define STUB(act, sigsetsize) (sigsetsize) + +#ifdef RT_IPC_RESTORER +#define HAS_RT_IPC_RESTORER 1 +#endif + +extern void restore_rt (void) asm ("__restore_rt") attribute_hidden; + +#define SET_RT_IPC_RESTORER(kact, act) \ + (kact)->flags =3D (act)->flags | RT_IPC_RESTORER; \ + (kact)->rt_ipc_restorer =3D &restore_rt + +#define do_cfa_expr \ + " .byte 0x0f\n" /* DW_CFA_def_cfa_expression */ \ + " .uleb128 2f-1f\n" /* length */ \ + "1: .byte 0x77\n" /* DW_OP_breg7 */ \ + " .byte 0x06\n" /* DW_OP_deref */ \ + "2:" + +#define do_expr(regno, offset) \ + " .byte 0x10\n" /* DW_CFA_expression */ \ + " .uleb128 " CFI_STRINGIFY (regno) "\n" \ + " .uleb128 2f-1f\n" /* length */ \ + "1: .byte 0x77\n" /* DW_OP_breg7 */ \ + "2:" + +#define RESTORE(name, syscall) RESTORE2 (name, syscall) +# define RESTORE2(name, syscall) \ +asm \ + ( \ + /* `nop' for debuggers assuming `call' should not disalign the code. *= / \ + " nop\n" \ + ".align 16\n" \ + ".LSTART_" #name ":\n" \ + " .type __" #name ",@function\n" \ + "__" #name ":\n" \ + " movq $" #syscall ", %rax\n" \ + " syscall\n" \ + ".LEND_" #name ":\n" \ + ".section .eh_frame,\"a\",@progbits\n" \ + ".LSTARTFRAME_" #name ":\n" \ + " .long .LENDCIE_" #name "-.LSTARTCIE_" #name "\n" \ + ".LSTARTCIE_" #name ":\n" \ + " .long 0\n" /* CIE ID */ \ + " .byte 1\n" /* Version number */ \ + " .string \"zRS\"\n" /* NUL-terminated augmentation string */ \ + " .uleb128 1\n" /* Code alignment factor */ \ + " .sleb128 -8\n" /* Data alignment factor */ \ + " .uleb128 16\n" /* Return address register column (rip) */ \ + /* Augmentation value length */ \ + " .uleb128 .LENDAUGMNT_" #name "-.LSTARTAUGMNT_" #name "\n" \ + ".LSTARTAUGMNT_" #name ":\n" \ + " .byte 0x1b\n" /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ \ + ".LENDAUGMNT_" #name ":\n" \ + " .align " LP_SIZE "\n" \ + ".LENDCIE_" #name ":\n" \ + " .long .LENDFDE_" #name "-.LSTARTFDE_" #name "\n" /* FDE len */ \ + ".LSTARTFDE_" #name ":\n" \ + " .long .LSTARTFDE_" #name "-.LSTARTFRAME_" #name "\n" /* CIE */ \ + /* `LSTART_' is subtracted 1 as debuggers assume a `call' here. */ \ + " .long (.LSTART_" #name "-1)-.\n" /* PC-relative start addr. */ \ + " .long .LEND_" #name "-(.LSTART_" #name "-1)\n" \ + " .uleb128 0\n" /* FDE augmentation length */ \ + do_cfa_expr \ + do_expr (8 /* r8 */, oR8) \ + do_expr (9 /* r9 */, oR9) \ + do_expr (10 /* r10 */, oR10) \ + do_expr (11 /* r11 */, oR11) \ + do_expr (12 /* r12 */, oR12) \ + do_expr (13 /* r13 */, oR13) \ + do_expr (14 /* r14 */, oR14) \ + do_expr (15 /* r15 */, oR15) \ + do_expr (5 /* rdi */, oRDI) \ + do_expr (4 /* rsi */, oRSI) \ + do_expr (6 /* rbp */, oRBP) \ + do_expr (3 /* rbx */, oRBX) \ + do_expr (1 /* rdx */, oRDX) \ + do_expr (0 /* rax */, oRAX) \ + do_expr (2 /* rcx */, oRCX) \ + do_expr (7 /* rsp */, oRSP) \ + do_expr (16 /* rip */, oRIP) \ + /* libgcc-4.1.1 has only `DWARF_FRAME_REGISTERS =3D=3D 17'. */ \ + /* do_expr (49 |* rflags *|, oEFL) */ \ + /* `cs'/`ds'/`fs' are unaligned and a different size. */ \ + /* gas: Error: register save offset not a multiple of 8 */ \ + " .align " LP_SIZE "\n" \ + ".LENDFDE_" #name ":\n" \ + " .previous\n" \ + ); +/* The return code for realtime-signals. */ +RESTORE (restore_rt, __NR_rt_ipc_return) + +void *test(void __maybe_unused *data) +{ + while (1) { + //printf("[%s:%d] pid: %d tid: %d ppid: %d\n", __func__, __LINE__,= getpid(), gettid(), getppid()); + sleep(INT_MAX); + } + return NULL; +} + +int rt_ipc_action(const struct rt_ipc_action *act) +{ + int result; + struct rt_ipc_action kact; + pthread_t ptrd; + + if (!act) { + return -EINVAL; + } + + kact.activation =3D act->activation; + + SET_RT_IPC_RESTORER (&kact, act); + + for (int i =3D 0; i < RT_IPC_ACTIVATION_THREAD_NUM; ++i) { + int res =3D pthread_create(&ptrd, NULL, test, NULL); + assert(res =3D=3D 0); + } + + //pr_info("pid: %d activation: %p rt_ipc_restorer: %p\n", getpid(), ka= ct.activation, kact.rt_ipc_restorer); + + result =3D syscall(SYS_rt_ipc_register, act ? &kact : NULL); + return result; +} diff --git a/tools/rt_ipc_userspace/rt_ipc_action.h b/tools/rt_ipc_userspac= e/rt_ipc_action.h new file mode 100755 index 000000000000..ce1d11eb8530 --- /dev/null +++ b/tools/rt_ipc_userspace/rt_ipc_action.h @@ -0,0 +1,56 @@ +#ifndef __RT_IPC_ACTION_H +#define __RT_IPC_ACTION_H +#include + +#define RT_IPC_ACTIVATION_THREAD_NUM 8 +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +typedef struct rt_ipcinfo { + size_t write_size; + size_t write_buffer; + size_t read_size; + size_t read_buffer; +} rt_ipcinfo_t; + +struct rt_ipc_action { + void (*activation)(unsigned cmd, rt_ipcinfo_t *info); + void (*rt_ipc_restorer)(void); + int flags; +}; + +#define __NR_rt_ipc_register 468 +#define __NR_rt_ipc_invoke 469 +#define __NR_rt_ipc_return 470 + +#define SYS_rt_ipc_register __NR_rt_ipc_register +#define SYS_rt_ipc_invoke __NR_rt_ipc_invoke +#define SYS_rt_ipc_return __NR_rt_ipc_return + +#define NONE "\033[m" +#define RED "\033[0;32;31m" +#define LIGHT_RED "\033[1;31m" +#define GREEN "\033[0;32;32m" +#define LIGHT_GREEN "\033[1;32m" +#define BLUE "\033[0;32;34m" +#define LIGHT_BLUE "\033[1;34m" +#define DARY_GRAY "\033[1;30m" +#define CYAN "\033[0;36m" +#define LIGHT_CYAN "\033[1;36m" +#define PURPLE "\033[0;35m" +#define LIGHT_PURPLE "\033[1;35m" +#define BROWN "\033[0;33m" +#define YELLOW "\033[1;33m" +#define LIGHT_GRAY "\033[0;37m" +#define WHITE "\033[1;37m" + +#if 0 +#define pr_info(fmt, ...) printf("[%s:%d]: " fmt, __func__, __LINE__, ##__= VA_ARGS__) +#define pr_err(fmt, ...) printf(RED"[%s:%d]: " fmt NONE, __func__, __LINE_= _, ##__VA_ARGS__) +#else +#define pr_info(fmt, ...) printf(fmt, ##__VA_ARGS__) +#define pr_err(fmt, ...) printf(RED fmt NONE, ##__VA_ARGS__) +#endif + +int rt_ipc_action(const struct rt_ipc_action *act); + +#endif /* __RT_IPC_ACTION_H */ diff --git a/tools/rt_ipc_userspace/rt_ipc_client.c b/tools/rt_ipc_userspac= e/rt_ipc_client.c new file mode 100755 index 000000000000..c0af767a9829 --- /dev/null +++ b/tools/rt_ipc_userspace/rt_ipc_client.c @@ -0,0 +1,89 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_ipc_action.h" + +#define PAGE_SIZE (1 << 12) + +#define STACK_SIZE (PAGE_SIZE << 1) + +/* +int syscall(SYS_rt_sigqueueinfo, pid_t tgid, int sig, siginfo_t *info); +int syscall(SYS_rt_tgsigqueueinfo, pid_t tgid, pid_t tid, int sig, siginfo= _t *info); +*/ + +#define handle_error_en(en, msg) \ + do { errno =3D en; perror(msg); exit(EXIT_FAILURE); } while= (0) + +static volatile unsigned long long cnt; + +static void *thread_entry(void *args) +{ + struct rt_ipcinfo info; + unsigned int cmd =3D 0x5a5a; + int ret; + info.write_size =3D 1234; + + while (cnt++ !=3D 100000) { + ret =3D syscall(SYS_rt_ipc_invoke, *(int *)args, cmd, &info); + if (ret < 0) + printf("exit from migrating %d\n", gettid()); + //sleep(1); + } + printf("rt_ipc client: %ld\n", info.write_size); + //sleep(0); + return NULL; +} + +int find_pid_by_name(const char *process_name) { + char command[256]; + snprintf(command, sizeof(command), "pgrep %s", process_name); + + FILE *fp =3D popen(command, "r"); + if (fp =3D=3D NULL) { + perror("Error opening pipe"); + return -1; + } + + int pid; + if (fscanf(fp, "%d", &pid) =3D=3D 1) { + pclose(fp); + return pid; + } else { + pclose(fp); + return -1; // Process not found + } +} + +int main(int argc, char **argv) +{ + pid_t pid; + struct timeval t1, t2; + + pid =3D find_pid_by_name("server_rt_ipc"); + if (pid < 0) { + return pid; + } + + printf("client pid %d send syscall SYS_rt_ipc_migrating to server pid:= %d\n", getpid(), pid); + + gettimeofday(&t1, NULL); + + thread_entry(&pid); + + gettimeofday(&t2, NULL); + + __time_t sec =3D t2.tv_sec - t1.tv_sec; + __suseconds_t usec =3D sec * 1000000 + t2.tv_usec - t1.tv_usec; + + printf("time usage sec: %lds usec: %ldus pid %d\n", sec, usec, getpid(= )); + + return 0; +} diff --git a/tools/rt_ipc_userspace/rt_ipc_server.c b/tools/rt_ipc_userspac= e/rt_ipc_server.c new file mode 100755 index 000000000000..c0b75269ea9e --- /dev/null +++ b/tools/rt_ipc_userspace/rt_ipc_server.c @@ -0,0 +1,64 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "rt_ipc_action.h" + +void entry(unsigned cmd, rt_ipcinfo_t *info); + +int main(void) +{ + struct rt_ipc_action act; + + act.activation =3D entry; + int ret =3D rt_ipc_action(&act); + + if (ret < 0) { + pr_err("fatal: rt ipc action error\n"); + return -EINVAL; + } + + pr_info("pid: %d entry: %p\n", getpid(), entry); + + while(1) + { + sleep(INT_MAX); + pr_info("wait for the signal\n"); + } + + return 0; +} + +volatile int g_test; +#define CONFIG_FILE_OP 0 + +static volatile unsigned long long cnt; + +void entry(unsigned int cmd, rt_ipcinfo_t *info) +{ + g_test =3D gettid(); +#if CONFIG_FILE_OP + FILE *f =3D fopen("/tmp/123.txt", "w+"); + if (f =3D=3D NULL) { + pr_info("fopen failed with error: %d\n", errno); + return; + } + char buf[100]; + int a =3D 0; + int b =3D 1; + a =3D b; + b =3D a; + g_test =3D getpid(); + + snprintf(buf, 100, "receive cmd %x pid: %d g_test; %d\n", cmd, getpid(= ), g_test); + fwrite(buf, strlen(buf) + 1, 1, f); + fclose(f); +#endif + info->write_size =3D cnt; + if (++cnt % 10000 =3D=3D 0) + pr_info("message from client: pid: %d cmd: %08x cnt: %lld, info->w= rite_size: %ld\n", g_test, cmd, cnt, info->write_size); + //sleep(5); +} --=20 2.43.0