diff --git a/arch/x86_64/kernel/cpu.c b/arch/x86_64/kernel/cpu.c index a283ad99..172bdf2c 100644 --- a/arch/x86_64/kernel/cpu.c +++ b/arch/x86_64/kernel/cpu.c @@ -847,9 +847,6 @@ void setup_x86_ap(void (*next_func)(void)) } void arch_show_interrupt_context(const void *reg); -void set_signal(int sig, void *regs, struct siginfo *info); -void check_signal(unsigned long, void *, int); -void check_sig_pending(); extern void tlb_flush_handler(int vector); void __show_stack(uintptr_t *sp) { @@ -877,7 +874,7 @@ void interrupt_exit(struct x86_user_context *regs) cpu_enable_interrupt(); check_sig_pending(); check_need_resched(); - check_signal(0, regs, 0); + check_signal(0, regs, -1); } else { check_sig_pending(); diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c index a7fd9e82..bb513000 100644 --- a/arch/x86_64/kernel/syscall.c +++ b/arch/x86_64/kernel/syscall.c @@ -36,8 +36,6 @@ void terminate_mcexec(int, int); extern long do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact); long syscall(int num, ihk_mc_user_context_t *ctx); -void set_signal(int sig, void *regs0, siginfo_t *info); -void check_signal(unsigned long rc, void *regs0, int num); extern unsigned long do_fork(int, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); extern int get_xsave_size(); @@ -261,7 +259,7 @@ SYSCALL_DECLARE(rt_sigreturn) info.si_code = TRAP_TRACE; set_signal(SIGTRAP, regs, &info); check_need_resched(); - check_signal(0, regs, 0); + check_signal(0, regs, -1); } if(ksigsp.fpregs && xsavesize){ @@ -286,7 +284,6 @@ SYSCALL_DECLARE(rt_sigreturn) } extern struct cpu_local_var *clv; -extern unsigned long do_kill(struct thread *thread, int pid, int tid, int sig, struct siginfo *info, int ptracecont); extern void interrupt_syscall(struct thread *, int sig); extern void terminate(int, int); extern int num_processors; @@ -643,11 +640,13 @@ arch_ptrace(long request, int pid, long addr, long data) static int isrestart(int num, unsigned long rc, int sig, int restart) { - if(sig == SIGKILL || sig == SIGSTOP) + if (sig == SIGKILL || sig == SIGSTOP) return 0; - if(num == 0 || rc != -EINTR) + if (num < 0 || rc != -EINTR) return 0; - switch(num){ + if (sig == SIGCHLD) + return 1; + switch (num) { case __NR_pause: case __NR_rt_sigsuspend: case __NR_rt_sigtimedwait: @@ -668,14 +667,12 @@ isrestart(int num, unsigned long rc, int sig, int restart) case __NR_io_getevents: return 0; } - if(sig == SIGCHLD) - return 1; - if(restart) + if (restart) return 1; return 0; } -void +int do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pending *pending, int num) { struct x86_user_context *regs = regs0; @@ -687,6 +684,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi int ptraceflag = 0; struct mcs_rwlock_node_irqsave lock; struct mcs_rwlock_node_irqsave mcs_rw_node; + int restart = 0; for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1); dkprintf("do_signal(): tid=%d, pid=%d, sig=%d\n", thread->tid, proc->pid, sig); @@ -715,7 +713,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi if(k->sa.sa_handler == SIG_IGN){ kfree(pending); mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node); - return; + goto out; } else if(k->sa.sa_handler){ unsigned long *usp; /* user stack */ @@ -765,9 +763,8 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi memcpy(&ksigsp.sigstack, &thread->sigstack, sizeof(stack_t)); ksigsp.sigrc = rc; ksigsp.num = num; - ksigsp.restart = isrestart(num, rc, sig, k->sa.sa_flags & SA_RESTART); - if(num != 0 && rc == -EINTR && sig == SIGCHLD) - ksigsp.restart = 1; + restart = isrestart(num, rc, sig, k->sa.sa_flags & SA_RESTART); + ksigsp.restart = restart; if(xsavesize){ uint64_t xsave_mask = get_xsave_mask(); unsigned int low = (unsigned int)xsave_mask; @@ -780,7 +777,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi kfree(_kfpregs); kprintf("do_signal,no space available\n"); terminate(0, sig); - return; + goto out; } kfpregs = (void *)((((unsigned long)_kfpregs) + 63) & ~63); memset(kfpregs, '\0', xsavesize); @@ -790,7 +787,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi kfree(_kfpregs); kprintf("do_signal,write_process_vm failed\n"); terminate(0, sig); - return; + goto out; } ksigsp.fpregs = (void *)fpregs; kfree(_kfpregs); @@ -802,7 +799,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi mcs_rwlock_writer_unlock(&thread->sigcommon->lock, &mcs_rw_node); kprintf("do_signal,write_process_vm failed\n"); terminate(0, sig); - return; + goto out; } usp = (unsigned long *)sigsp; @@ -832,7 +829,7 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi info.si_code = TRAP_TRACE; set_signal(SIGTRAP, regs, &info); check_need_resched(); - check_signal(0, regs, 0); + check_signal(0, regs, -1); } } else { @@ -940,6 +937,8 @@ do_signal(unsigned long rc, void *regs0, struct thread *thread, struct sig_pendi break; } } +out: + return restart; } static struct sig_pending * @@ -1019,6 +1018,12 @@ void save_syscall_return_value(int num, unsigned long rc) return; } +/** \brief check arrived signals and processing + * + * @param rc return value of syscall + * @param regs0 context + * @param num syscall number (-1: Not called on exiting system call) + */ void check_signal(unsigned long rc, void *regs0, int num) { @@ -1059,7 +1064,9 @@ check_signal(unsigned long rc, void *regs0, int num) goto out; } - do_signal(rc, regs, thread, pending, num); + if (do_signal(rc, regs, thread, pending, num)) { + num = -1; + } } out: @@ -1139,7 +1146,7 @@ check_sig_pending_thread(struct thread *thread) } void -check_sig_pending() +check_sig_pending(void) { struct thread *thread; struct cpu_local_var *v; diff --git a/kernel/include/process.h b/kernel/include/process.h index 45446355..24acf1fb 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -839,6 +839,13 @@ void chain_thread(struct thread *); void proc_init(void); void set_timer(int runq_locked); struct sig_pending *hassigpending(struct thread *thread); +extern int do_signal(unsigned long rc, void *regs0, struct thread *thread, + struct sig_pending *pending, int num); +extern void check_signal(unsigned long rc, void *regs0, int num); +extern unsigned long do_kill(struct thread *thread, int pid, int tid, int sig, + struct siginfo *info, int ptracecont); +extern void set_signal(int sig, void *regs, struct siginfo *info); +extern void check_sig_pending(void); void release_fp_regs(struct thread *proc); void save_fp_regs(struct thread *proc); diff --git a/kernel/mem.c b/kernel/mem.c index 63164230..f6ec0ca8 100644 --- a/kernel/mem.c +++ b/kernel/mem.c @@ -960,8 +960,6 @@ static struct ihk_mc_interrupt_handler query_free_mem_handler = { .priv = NULL, }; -void set_signal(int sig, void *regs, struct siginfo *info); -void check_signal(unsigned long, void *, int); int gencore(struct thread *, void *, struct coretable **, int *); void freecore(struct coretable **); @@ -1221,7 +1219,7 @@ out: if(interrupt_from_user(regs)){ cpu_enable_interrupt(); check_need_resched(); - check_signal(0, regs, 0); + check_signal(0, regs, -1); } set_cputime(interrupt_from_user(regs)? 0: 1); #ifdef PROFILE_ENABLE diff --git a/kernel/process.c b/kernel/process.c index 6e6eb1f4..582631bd 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -82,7 +82,6 @@ extern void lapic_timer_disable(); extern int num_processors; extern ihk_spinlock_t cpuid_head_lock; int ptrace_detach(int pid, int data); -extern unsigned long do_kill(struct thread *, int pid, int tid, int sig, struct siginfo *info, int ptracecont); extern void procfs_create_thread(struct thread *); extern void procfs_delete_thread(struct thread *); diff --git a/kernel/syscall.c b/kernel/syscall.c index 1c726822..97fb3bcc 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -116,10 +116,7 @@ static ihk_spinlock_t tod_data_lock = SPIN_LOCK_UNLOCKED; static unsigned long uti_desc; /* Address of struct uti_desc object in syscall_intercept.c */ static void calculate_time_from_tsc(struct timespec *ts); -void check_signal(unsigned long, void *, int); void save_syscall_return_value(int num, unsigned long rc); -void do_signal(long rc, void *regs, struct thread *thread, struct sig_pending *pending, int num); -extern unsigned long do_kill(struct thread *thread, int pid, int tid, int sig, struct siginfo *info, int ptracecont); extern long alloc_debugreg(struct thread *thread); extern int num_processors; extern unsigned long ihk_mc_get_ns_per_tsc(void); @@ -4204,7 +4201,7 @@ SYSCALL_DECLARE(rt_sigtimedwait) list_del(&pending->list); thread->sigmask.__val[0] = bset; mcs_rwlock_writer_unlock(lock, &mcs_rw_node); - do_signal(-EINTR, NULL, thread, pending, 0); + do_signal(-EINTR, NULL, thread, pending, -1); return -EINTR; } mcs_rwlock_writer_unlock(lock, &mcs_rw_node); @@ -4317,7 +4314,7 @@ do_sigsuspend(struct thread *thread, const sigset_t *set) list_del(&pending->list); mcs_rwlock_writer_unlock(lock, &mcs_rw_node); thread->sigmask.__val[0] = bset; - do_signal(-EINTR, NULL, thread, pending, 0); + do_signal(-EINTR, NULL, thread, pending, -1); break; } return -EINTR; @@ -9549,7 +9546,7 @@ long syscall(int num, ihk_mc_user_context_t *ctx) if(cpu_local_var(current)->proc->status == PS_EXITED && (num != __NR_exit && num != __NR_exit_group)){ save_syscall_return_value(num, -EINVAL); - check_signal(-EINVAL, NULL, 0); + check_signal(-EINVAL, NULL, -1); set_cputime(0); return -EINVAL; } diff --git a/test/issues/1009/C1009.patch b/test/issues/1009/C1009.patch new file mode 100644 index 00000000..05cf8c6b --- /dev/null +++ b/test/issues/1009/C1009.patch @@ -0,0 +1,49 @@ +diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c +index 4b2742b..a3173c9 100644 +--- a/arch/x86_64/kernel/syscall.c ++++ b/arch/x86_64/kernel/syscall.c +@@ -1670,6 +1670,11 @@ long do_arch_prctl(unsigned long code, unsigned long address) + break; + case ARCH_SET_GS: + return -ENOTSUPP; ++ case 999: { ++ struct thread *thread = cpu_local_var(current); ++ thread->proc->dblsig = (int)address; ++ return 0; ++ } + default: + return -EINVAL; + } +diff --git a/kernel/include/process.h b/kernel/include/process.h +index 24acf1f..dd94469 100644 +--- a/kernel/include/process.h ++++ b/kernel/include/process.h +@@ -580,6 +580,8 @@ struct process { + #endif // PROFILE_ENABLE + int nr_processes; /* For partitioned execution */ + int process_rank; /* Rank in partition */ ++ ++ int dblsig; + }; + + /* +diff --git a/kernel/syscall.c b/kernel/syscall.c +index 15d4593..3d03fad 100644 +--- a/kernel/syscall.c ++++ b/kernel/syscall.c +@@ -9632,6 +9632,15 @@ long syscall(int num, ihk_mc_user_context_t *ctx) + + if (!list_empty(&thread->sigpending) || + !list_empty(&thread->sigcommon->sigpending)) { ++ if (!list_empty(&thread->sigcommon->sigpending) && ++ thread->proc->dblsig) { ++ kprintf("have a signal, waiting arrive more signal\n"); ++ while (list_is_singular( ++ &thread->sigcommon->sigpending)) { ++ schedule(); ++ } ++ kprintf("have some signals\n"); ++ } + check_signal(l, NULL, num); + } + diff --git a/test/issues/1009/C1009.sh b/test/issues/1009/C1009.sh new file mode 100644 index 00000000..a00a2fe6 --- /dev/null +++ b/test/issues/1009/C1009.sh @@ -0,0 +1,131 @@ +#!/bin/sh +BOOTPARAM="-c 1-7,17-23,9-15,25-31 -m 10G@0,10G@1" +USELTP=1 +USEOSTEST= + +################################################################################ +BINDIR= +SBINDIR= +OSTESTDIR= +LTPDIR= +LTPBIN= +MCEXEC= +TESTMCK= + +if [ -f $HOME/mck_test_config ]; then + . $HOME/mck_test_config +elif [ -f ../../../mck_test_config.sample ]; then + . ../../../mck_test_config.sample +else + BIN= + SBIN= + OSTEST= + LTP= +fi + +#------------------------------------------------------------------------------- +if [ "x$BIN" = x ]; then + if [ -f ../../../config.h ]; then + str=`grep "^#define BINDIR " ../../../config.h | head -1 | sed 's/^#define BINDIR /BINDIR=/'` + eval $str + fi +else + BINDIR="$BIN" +fi + +if [ "x$SBIN" = x ]; then + if [ -f ../../../Makefile ]; then + str=`grep ^SBINDIR ../../../Makefile | head -1 | sed 's/ //g'` + eval $str + fi +else + SBINDIR="$SBIN" +fi + +if [ ! -x "$BINDIR/mcexec" ]; then + echo no mckernel found $BINDIR >&2 + exit 1 +fi +MCEXEC="$BINDIR/mcexec" + +#------------------------------------------------------------------------------- +if [ "x$USELTP" != x ]; then + if [ "x$LTP" = x ]; then + if [ -f "$HOME/ltp/testcases/bin/fork01" ]; then + LTPDIR="$HOME/ltp" + fi + else + LTPDIR="$LTP" + fi + + if [ ! -x "$LTPDIR/testcases/bin/fork01" ]; then + echo no LTP found $LTPDIR >&2 + exit 1 + fi + LTPBIN="$LTPDIR/testcases/bin" +fi + +#------------------------------------------------------------------------------- +if [ "x$USEOSTEST" != x ]; then + if [ "x$OSTEST" = x ]; then + if [ -f "$HOME/ostest/bin/test_mck" ]; then + OSTESTDIR="$HOME/ostest" + fi + else + OSTESTDIR="$OSTEST" + fi + + if [ ! -x "$OSTESTDIR"/bin/test_mck ]; then + echo no ostest found $OSTESTDIR >&2 + exit 1 + fi + TESTMCK="$OSTESTDIR/bin/test_mck" +fi + +#=============================================================================== +if [ ! -x "$SBINDIR/mcstop+release.sh" ]; then + echo mcstop+release: not found >&2 + exit 1 +fi +echo -n "mcstop+release.sh ... " +sudo "$SBINDIR/mcstop+release.sh" +echo "done" + +if lsmod | grep mcctrl > /dev/null 2>&1; then + echo mckernel shutdown failed >&2 + exit 1 +fi + +if [ ! -x "$SBINDIR/mcreboot.sh" ]; then + echo mcreboot: not found >&2 + exit 1 +fi +echo -n "mcreboot.sh $BOOTPARAM ... " +sudo "$SBINDIR/mcreboot.sh" $BOOTPARAM +echo "done" + +if ! lsmod | grep mcctrl > /dev/null 2>&1; then + echo mckernel boot failed >&2 + exit 1 +fi + +################################################################################ +$MCEXEC ./C1009T01 + +if [ x$LTPDIR = x ]; then + echo no LTP found >&2 + exit 1 +fi + +for i in kill01:02 kill12:03 pause02:04 sigaction01:05 ; do + tp=`echo $i|sed 's/:.*//'` + id=`echo $i|sed 's/.*://'` + $MCEXEC $LTPBIN/$tp 2>&1 | tee $tp.txt + ok=`grep TPASS $tp.txt | wc -l` + ng=`grep TFAIL $tp.txt | wc -l` + if [ $ng = 0 ]; then + echo "*** C1009T$id: $tp OK ($ok)" + else + echo "*** C1009T$id: $tp NG (ok=$ok ng=%ng)" + fi +done diff --git a/test/issues/1009/C1009.txt b/test/issues/1009/C1009.txt new file mode 100644 index 00000000..c77bc7ee --- /dev/null +++ b/test/issues/1009/C1009.txt @@ -0,0 +1,24 @@ +Script started on Mon Sep 10 15:12:28 2018 +bash-4.2$ make test +gcc -g -Wall -o C1009T01 C1009T01.c +sh ./C1009.sh +SIGUSR2 +SIGUSR1 +read A OK +read B OK +*** C1009T01: OK +kill01 1 TPASS : received expected signal 9 +*** C1009T02: kill01 OK (1) +kill12 1 TPASS : Test passed +*** C1009T03: kill12 OK (1) +pause02 1 TPASS : pause was interrupted correctly +*** C1009T04: pause02 OK (1) +sigaction01 1 TPASS : SA_RESETHAND did not cause SA_SIGINFO to be cleared +sigaction01 2 TPASS : SA_RESETHAND was masked when handler executed +sigaction01 3 TPASS : sig has been masked because sa_mask originally contained sig +sigaction01 4 TPASS : siginfo pointer non NULL +*** C1009T05: sigaction01 OK (4) +bash-4.2$ exit +exit + +Script done on Mon Sep 10 15:12:54 2018 diff --git a/test/issues/1009/C1009T01.c b/test/issues/1009/C1009T01.c new file mode 100644 index 00000000..74716ff7 --- /dev/null +++ b/test/issues/1009/C1009T01.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int arch_prctl(int code, unsigned long *addr); + +void +sigusr(int sig) +{ + if (sig == SIGUSR1) { + printf("SIGUSR1\n"); + } + else if (sig == SIGUSR2) { + printf("SIGUSR2\n"); + } + else { + printf("other sig\n"); + } + fflush(stdout); +} + +int +main(int argc, char **argv) +{ + struct sigaction act; + pid_t pid1 = 0; + pid_t pid2 = 0; + pid_t parent; + int pfd[2]; + char ch; + int rc; + unsigned long val; + + memset(&act, '\0', sizeof(act)); + act.sa_handler = sigusr; + act.sa_flags = SA_RESTART; + sigaction(SIGUSR1, &act, NULL); + sigaction(SIGUSR2, &act, NULL); + + pipe(pfd); + + parent = getpid(); + val = 1; + if (arch_prctl(999, (unsigned long *)val) == -1) { + fprintf(stderr, "C1009T01 WARN: no mckernel patch detected.\n"); + exit(1); + } + + if ((pid1 = fork())) { + pid2 = fork(); + } + + if (!pid1 || !pid2) { + int sig; + + close(pfd[0]); + if (pid1) + sig = SIGUSR2; + else + sig = SIGUSR1; + + sleep(1); + kill(parent, sig); + if (pid1) { + sleep(2); + ch = 'B'; + } + else { + sleep(1); + ch = 'A'; + } + write(pfd[1], &ch, 1); + close(pfd[1]); + exit(0); + } + rc = read(pfd[0], &ch, 1); + if (rc != 1) { + printf("C1009T01 NG: read error rc=%d errno=%d\n", rc, errno); + exit(1); + } + if (ch != 'A') { + printf("C1009T01 NG: read BAD DATA ch=%c\n", ch); + exit(1); + } + val = 0; + arch_prctl(999, (unsigned long *)val); + printf("read %c OK\n", ch); + rc = read(pfd[0], &ch, 1); + if (rc != 1) { + printf("C1009T01 NG: read error rc=%d errno=%d\n", rc, errno); + exit(1); + } + if (ch != 'B') { + printf("C1009T01 NG: read BAD DATA ch=%c\n", ch); + exit(1); + } + + printf("read %c OK\n", ch); + printf("*** C1009T01: OK\n"); + exit(0); +} diff --git a/test/issues/1009/Makefile b/test/issues/1009/Makefile new file mode 100644 index 00000000..4453ab75 --- /dev/null +++ b/test/issues/1009/Makefile @@ -0,0 +1,13 @@ +CC = gcc +TARGET = C1009T01 + +all:: $(TARGET) + +C1009T01: C1009T01.c + $(CC) -g -Wall -o $@ $^ + +test:: all + sh ./C1009.sh + +clean:: + rm -f $(TARGET) *.o diff --git a/test/issues/1009/README b/test/issues/1009/README new file mode 100644 index 00000000..548d35da --- /dev/null +++ b/test/issues/1009/README @@ -0,0 +1,27 @@ +【Issue#1009 動作確認】 +□ テスト内容 +1. システムコール処理中にシグナルハンドラを呼び出す複数のシグナルを + 受信し、当該システムコールを再処理するとき、当該システムコールが + 1度しか処理されないことを確認する(指摘現象)。 + 尚、シグナルを同時に発行する状態を再現させるのが困難なため、本 + テストは複数シグナルを待ち合わせるパッチを適用したカーネルで行う。 + McKernel へのパッチファイルは C1009.patch である。 +C1009T01 シグナルを複数受信したとき、システムコールの再処理を1度だけ行う確認 + +2. 変更が他のシグナル処理に影響しないことをLTPを用いて確認する。 +C1009T02 kill01: kill の基本機能の確認 +C1009T03 kill12: kill, wait, signal の組み合わせ確認 +C1009T04 pause02: pause の基本機能の確認 +C1009T05 sigaction01: sigaction の基本機能の確認 + +□ 実行手順 +$ make test + +実行できない場合は、C1009.shの以下の行を適切に書き換えた後に実行。 +BIN= mcexec が存在するパス +SBIN= mcreboot.sh が存在するパス +LTP= LTP が存在するパス + +□ 実行結果 +C1009.txt 参照。 +全ての項目が OK となっていることを確認。