fork: memory leak detection test.
Change-Id: I9c64f8fdaee15642b3d1d2d7d869927b0bcd6511
This commit is contained in:
committed by
Masamichi Takagi
parent
f2460695c4
commit
299d47abf5
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@ CMakeFiles
|
|||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
Makefile
|
Makefile
|
||||||
!test/*/*/Makefile
|
!test/*/*/Makefile
|
||||||
|
!test/signalonfork+wait/Makefile
|
||||||
!test/*/*/*.cmd
|
!test/*/*/*.cmd
|
||||||
Kbuild
|
Kbuild
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
|
|||||||
10
test/signalonfork+wait/Makefile
Normal file
10
test/signalonfork+wait/Makefile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Makefile COPYRIGHT FUJITSU LIMITED 2019
|
||||||
|
CC?=gcc
|
||||||
|
LDFLAGS=-lpthread
|
||||||
|
CFLAGS=-Wall -O0 -ggdb3
|
||||||
|
|
||||||
|
all: signalonfork_wait
|
||||||
|
signalonfork_wait: signalonfork_wait.o
|
||||||
|
signalonfork_wait.o: signalonfork_wait.c
|
||||||
|
clean:
|
||||||
|
rm -f signalonfork_wait.o signalonfork_wait
|
||||||
36
test/signalonfork+wait/README
Normal file
36
test/signalonfork+wait/README
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
==========
|
||||||
|
How to run
|
||||||
|
==========
|
||||||
|
|
||||||
|
(1) cd <mckernel>
|
||||||
|
(2) patch -p1 < test/signalonfork+wait/error_injection.patch
|
||||||
|
(3) Build McKernel
|
||||||
|
(4) cd <mckernel>/test/signalonfork+wait
|
||||||
|
(5) make
|
||||||
|
(6) edit "$HOME/.mck_test_config"
|
||||||
|
* NUMA nodes should be 0 only
|
||||||
|
(7) sh ./run.sh
|
||||||
|
(8) sh ./run_error_injection.sh
|
||||||
|
|
||||||
|
==========================
|
||||||
|
sample of .mck_test_config
|
||||||
|
==========================
|
||||||
|
|
||||||
|
% cat "$HOME/.mck_test_config"
|
||||||
|
# Config file for McKernel tests
|
||||||
|
: ${MCK_DIR:=/opt/usr/ihk-mckernel}
|
||||||
|
: ${BIN:=$MCK_DIR/bin}
|
||||||
|
: ${SBIN:=$MCK_DIR/sbin}
|
||||||
|
: ${OSTEST:=}
|
||||||
|
: ${LTP:=}
|
||||||
|
: ${BOOTPARAM:=-c 4-15 -m 16G}
|
||||||
|
: ${MCKERNEL_VERSION:=1.5.0}
|
||||||
|
|
||||||
|
============
|
||||||
|
What to test
|
||||||
|
============
|
||||||
|
|
||||||
|
Check for memory leaks when a fork system call and delivery of the signal occur simultaneously.
|
||||||
|
|
||||||
|
--
|
||||||
|
README COPYRIGHT FUJITSU LIMITED 2019
|
||||||
396
test/signalonfork+wait/error_injection.patch
Normal file
396
test/signalonfork+wait/error_injection.patch
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
error_injection.patch COPYRIGHT FUJITSU LIMITED 2019
|
||||||
|
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
|
||||||
|
index 608c435..b5c8518 100644
|
||||||
|
--- a/kernel/CMakeLists.txt
|
||||||
|
+++ b/kernel/CMakeLists.txt
|
||||||
|
@@ -29,6 +29,7 @@ if (${ARCH} STREQUAL "arm64")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(MCKERNEL_SRCS
|
||||||
|
+ sysctrl-signalonfork_wait.c
|
||||||
|
init.c mem.c debug.c mikc.c listeners.c ap.c syscall.c cls.c host.c process.c
|
||||||
|
copy.c waitq.c futex.c timer.c plist.c fileobj.c shmobj.c zeroobj.c
|
||||||
|
procfs.c devobj.c sysfs.c xpmem.c profile.c freeze.c rbtree.c pager.c
|
||||||
|
diff --git a/kernel/include/sysctrl-signalonfork_wait.h b/kernel/include/sysctrl-signalonfork_wait.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..2e4833e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/kernel/include/sysctrl-signalonfork_wait.h
|
||||||
|
@@ -0,0 +1,49 @@
|
||||||
|
+#ifndef __SYSCTRL_SIGNALONFORK_WAIT_H__
|
||||||
|
+#define __SYSCTRL_SIGNALONFORK_WAIT_H__
|
||||||
|
+
|
||||||
|
+enum signalonfork_error {
|
||||||
|
+ signalonfork_error_null = 0,
|
||||||
|
+
|
||||||
|
+ do_fork_release_cpuid_0 = 0x010000,
|
||||||
|
+ do_fork_destroy_thread_0 = 0x010100,
|
||||||
|
+ do_fork_destroy_thread_1 = 0x010101,
|
||||||
|
+ do_fork_destroy_thread_2 = 0x010102,
|
||||||
|
+ do_fork_release_ids_0 = 0x010200,
|
||||||
|
+ do_fork_release_ids_1 = 0x010201,
|
||||||
|
+ do_fork_free_mod_clone_arg_0 = 0x010300,
|
||||||
|
+ do_fork_free_mod_clone_arg_1 = 0x010301,
|
||||||
|
+
|
||||||
|
+ clone_thread_free_thread_0 = 0x020000,
|
||||||
|
+ clone_thread_free_thread_1 = 0x020001,
|
||||||
|
+ clone_thread_free_fp_regs_0 = 0x020100,
|
||||||
|
+ clone_thread_free_fp_regs_1 = 0x020101,
|
||||||
|
+ clone_thread_free_fork_process_proc_0 = 0x020200,
|
||||||
|
+ clone_thread_free_fork_process_proc_1 = 0x020201,
|
||||||
|
+ clone_thread_free_fork_process_asp_0 = 0x020300,
|
||||||
|
+ clone_thread_free_fork_process_vm_0 = 0x020400,
|
||||||
|
+ clone_thread_free_fork_process_cmdline_0 = 0x020500,
|
||||||
|
+ clone_thread_free_fork_process_cmdline_1 = 0x020501,
|
||||||
|
+ clone_thread_free_fork_process_mckfd_0 = 0x020600,
|
||||||
|
+ clone_thread_free_fork_clone_process_0 = 0x020700,
|
||||||
|
+ clone_thread_free_copy_user_ranges_0 = 0x020800,
|
||||||
|
+
|
||||||
|
+ copy_user_ranges_err_rollback_0 = 0x030000,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static inline int __sof_err(enum signalonfork_error err)
|
||||||
|
+{
|
||||||
|
+ extern enum signalonfork_error sof_error;
|
||||||
|
+ return (err == sof_error);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define sof_err(err) ({ \
|
||||||
|
+ int ret = __sof_err(err); \
|
||||||
|
+ if (ret) { \
|
||||||
|
+ kprintf("sof error injection: %s\n", \
|
||||||
|
+ #err); \
|
||||||
|
+ } \
|
||||||
|
+ ret; \
|
||||||
|
+ })
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#endif /*__SYSCTRL_SIGNALONFORK_WAIT_H__*/
|
||||||
|
diff --git a/kernel/init.c b/kernel/init.c
|
||||||
|
index 9ee3b42..ecf2f79 100644
|
||||||
|
--- a/kernel/init.c
|
||||||
|
+++ b/kernel/init.c
|
||||||
|
@@ -330,6 +330,9 @@ static void populate_sysfs(void)
|
||||||
|
numa_sysfs_setup();
|
||||||
|
dynamic_debug_sysfs_setup();
|
||||||
|
//setup_remote_snooping_samples();
|
||||||
|
+
|
||||||
|
+ extern void signalonfork_test_sysfs_setup(void);
|
||||||
|
+ signalonfork_test_sysfs_setup();
|
||||||
|
} /* populate_sysfs() */
|
||||||
|
|
||||||
|
int host_ikc_inited = 0;
|
||||||
|
diff --git a/kernel/process.c b/kernel/process.c
|
||||||
|
index b2d7f34..f607198 100644
|
||||||
|
--- a/kernel/process.c
|
||||||
|
+++ b/kernel/process.c
|
||||||
|
@@ -27,6 +27,7 @@
|
||||||
|
#include <kmalloc.h>
|
||||||
|
#include <cls.h>
|
||||||
|
#include <page.h>
|
||||||
|
+#include <sysctrl-signalonfork_wait.h>
|
||||||
|
#include <cpulocal.h>
|
||||||
|
#include <auxvec.h>
|
||||||
|
#include <hwcap.h>
|
||||||
|
@@ -395,6 +396,9 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
IHK_MC_AP_NOWAIT)) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
+ if (sof_err(clone_thread_free_thread_0)) {
|
||||||
|
+ goto free_thread;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
memset(thread, 0, sizeof(struct thread));
|
||||||
|
INIT_LIST_HEAD(&thread->hash_list);
|
||||||
|
@@ -409,10 +413,17 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
ihk_mc_init_user_process(&thread->ctx, &thread->uctx, ((char *)thread) +
|
||||||
|
KERNEL_STACK_NR_PAGES * PAGE_SIZE, pc, sp);
|
||||||
|
|
||||||
|
+ if (sof_err(clone_thread_free_thread_1)) {
|
||||||
|
+ goto free_thread;
|
||||||
|
+ }
|
||||||
|
/* copy fp_regs from parent */
|
||||||
|
if (save_fp_regs(org)) {
|
||||||
|
goto free_thread;
|
||||||
|
}
|
||||||
|
+ if (sof_err(clone_thread_free_fp_regs_0)) {
|
||||||
|
+ goto free_fp_regs;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (copy_fp_regs(org, thread)) {
|
||||||
|
goto free_fp_regs;
|
||||||
|
}
|
||||||
|
@@ -437,23 +448,47 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
}
|
||||||
|
/* fork() */
|
||||||
|
else {
|
||||||
|
+ if (sof_err(clone_thread_free_fp_regs_1)) {
|
||||||
|
+ goto free_fp_regs;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
proc = kmalloc(sizeof(struct process), IHK_MC_AP_NOWAIT);
|
||||||
|
if(!proc)
|
||||||
|
goto free_fp_regs;
|
||||||
|
+
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_proc_0)) {
|
||||||
|
+ goto free_fork_process_proc;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
memset(proc, '\0', sizeof(struct process));
|
||||||
|
init_process(proc, org->proc);
|
||||||
|
#ifdef PROFILE_ENABLE
|
||||||
|
proc->profile = org->proc->profile;
|
||||||
|
#endif
|
||||||
|
proc->termsig = termsig;
|
||||||
|
+
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_proc_1)) {
|
||||||
|
+ goto free_fork_process_proc;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
asp = create_address_space(cpu_local_var(resource_set), 1);
|
||||||
|
if (!asp) {
|
||||||
|
goto free_fork_process_proc;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_asp_0)) {
|
||||||
|
+ goto free_fork_process_asp;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
proc->vm = kmalloc(sizeof(struct process_vm), IHK_MC_AP_NOWAIT);
|
||||||
|
if (!proc->vm) {
|
||||||
|
goto free_fork_process_asp;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_vm_0)) {
|
||||||
|
+ goto free_fork_process_vm;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
memset(proc->vm, '\0', sizeof(struct process_vm));
|
||||||
|
|
||||||
|
proc->saved_cmdline_len = org->proc->saved_cmdline_len;
|
||||||
|
@@ -462,6 +497,11 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
if (!proc->saved_cmdline) {
|
||||||
|
goto free_fork_process_vm;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_cmdline_0)) {
|
||||||
|
+ goto free_fork_process_cmdline;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
memcpy(proc->saved_cmdline, org->proc->saved_cmdline,
|
||||||
|
proc->saved_cmdline_len);
|
||||||
|
|
||||||
|
@@ -484,6 +524,10 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
/* Copy user-space mappings.
|
||||||
|
* TODO: do this with COW later? */
|
||||||
|
v->on_fork_vm = proc->vm;
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_cmdline_1)) {
|
||||||
|
+ v->on_fork_vm = NULL;
|
||||||
|
+ goto free_fork_process_cmdline;
|
||||||
|
+ }
|
||||||
|
if (copy_user_ranges(proc->vm, org->vm) != 0) {
|
||||||
|
v->on_fork_vm = NULL;
|
||||||
|
goto free_fork_process_cmdline;
|
||||||
|
@@ -492,6 +536,9 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
|
||||||
|
/* Copy mckfd list
|
||||||
|
FIXME: Replace list manipulation with list_add() etc. */
|
||||||
|
+ if (sof_err(clone_thread_free_copy_user_ranges_0)) {
|
||||||
|
+ goto free_fork_process_mckfd;
|
||||||
|
+ }
|
||||||
|
long irqstate = ihk_mc_spinlock_lock(&proc->mckfd_lock);
|
||||||
|
struct mckfd *cur;
|
||||||
|
for (cur = org->proc->mckfd; cur; cur = cur->next) {
|
||||||
|
@@ -517,6 +564,9 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock(&proc->mckfd_lock, irqstate);
|
||||||
|
+ if (sof_err(clone_thread_free_fork_process_mckfd_0)) {
|
||||||
|
+ goto free_fork_process_mckfd;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
thread->vm->vdso_addr = org->vm->vdso_addr;
|
||||||
|
thread->vm->vvar_addr = org->vm->vvar_addr;
|
||||||
|
@@ -536,6 +586,13 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp,
|
||||||
|
/* copy signal handlers (i.e., fork()) */
|
||||||
|
else {
|
||||||
|
dkprintf("fork(): sigcommon\n");
|
||||||
|
+ if (sof_err(clone_thread_free_fork_clone_process_0)) {
|
||||||
|
+ if (clone_flags & CLONE_VM) {
|
||||||
|
+ goto free_clone_process;
|
||||||
|
+ }
|
||||||
|
+ goto free_fork_process_mckfd;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
thread->sigcommon = kmalloc(sizeof(struct sig_common),
|
||||||
|
IHK_MC_AP_NOWAIT);
|
||||||
|
if (!thread->sigcommon) {
|
||||||
|
@@ -849,6 +906,10 @@ static int copy_user_ranges(struct process_vm *vm, struct process_vm *orgvm)
|
||||||
|
// memory_stat_rss_add() is called in child-node, i.e. copy_user_pte()
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (sof_err(copy_user_ranges_err_rollback_0)) {
|
||||||
|
+ goto err_rollback;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
memory_range_write_unlock(orgvm, &irqflags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
diff --git a/kernel/syscall.c b/kernel/syscall.c
|
||||||
|
index 4ed043f..17bec37 100644
|
||||||
|
--- a/kernel/syscall.c
|
||||||
|
+++ b/kernel/syscall.c
|
||||||
|
@@ -29,6 +29,7 @@
|
||||||
|
#include <cpulocal.h>
|
||||||
|
#include <ihk/mm.h>
|
||||||
|
#include <ihk/ikc.h>
|
||||||
|
+#include <sysctrl-signalonfork_wait.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <cls.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
@@ -2737,6 +2738,10 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||||
|
kprintf("do_fork,core not available\n");
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
+ if (sof_err(do_fork_release_cpuid_0)) {
|
||||||
|
+ err = -EFAULT;
|
||||||
|
+ goto release_cpuid;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
new = clone_thread(old, curpc,
|
||||||
|
newsp ? newsp : cursp, clone_flags);
|
||||||
|
@@ -2747,6 +2752,10 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||||
|
}
|
||||||
|
|
||||||
|
newproc = new->proc;
|
||||||
|
+ if (sof_err(do_fork_destroy_thread_0)) {
|
||||||
|
+ err = -EFAULT;
|
||||||
|
+ goto destroy_thread;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
cpu_set(cpuid, &new->vm->address_space->cpu_set,
|
||||||
|
&new->vm->address_space->cpu_set_lock);
|
||||||
|
@@ -2766,8 +2775,13 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||||
|
goto destroy_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
- newproc->tids = kmalloc(sizeof(struct mcexec_tid) *
|
||||||
|
- NR_TIDS, IHK_MC_AP_NOWAIT);
|
||||||
|
+ if (sof_err(do_fork_destroy_thread_1)) {
|
||||||
|
+ newproc->tids = NULL;
|
||||||
|
+ } else {
|
||||||
|
+ newproc->tids = kmalloc(sizeof(struct mcexec_tid) *
|
||||||
|
+ NR_TIDS, IHK_MC_AP_NOWAIT);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (!newproc->tids) {
|
||||||
|
mcs_rwlock_writer_unlock(&newproc->threads_lock, &lock);
|
||||||
|
kfree(tids);
|
||||||
|
@@ -2775,7 +2789,12 @@ unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||||
|
goto destroy_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((err = settid(new, NR_TIDS, tids)) < 0) {
|
||||||
|
+ if (sof_err(do_fork_release_ids_0)) {
|
||||||
|
+ err = -EFAULT;
|
||||||
|
+ } else {
|
||||||
|
+ err = settid(new, NR_TIDS, tids);
|
||||||
|
+ }
|
||||||
|
+ if (err < 0) {
|
||||||
|
mcs_rwlock_writer_unlock(&newproc->threads_lock,
|
||||||
|
&lock);
|
||||||
|
kfree(tids);
|
||||||
|
@@ -2835,7 +2854,11 @@ retry_tid:
|
||||||
|
if(oldproc->ppid_parent->pid != 1)
|
||||||
|
request1.args[0] = clone_flags;
|
||||||
|
}
|
||||||
|
- newproc->pid = do_syscall(&request1, ihk_mc_get_processor_id());
|
||||||
|
+ if (sof_err(do_fork_destroy_thread_2)) {
|
||||||
|
+ newproc->pid = -EFAULT;
|
||||||
|
+ } else {
|
||||||
|
+ newproc->pid = do_syscall(&request1, ihk_mc_get_processor_id());
|
||||||
|
+ }
|
||||||
|
if (newproc->pid < 0) {
|
||||||
|
kprintf("ERROR: forking host process\n");
|
||||||
|
err = newproc->pid;
|
||||||
|
@@ -2900,6 +2923,11 @@ retry_tid:
|
||||||
|
ihk_mc_syscall_ret(new->uctx) = 0;
|
||||||
|
|
||||||
|
new->status = PS_RUNNING;
|
||||||
|
+
|
||||||
|
+ if (sof_err(do_fork_release_ids_1)) {
|
||||||
|
+ err = -EFAULT;
|
||||||
|
+ goto release_ids;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* Only the first do_fork() call creates a thread on a Linux CPU */
|
||||||
|
if (__sync_bool_compare_and_swap(&old->mod_clone, SPAWN_TO_REMOTE, SPAWN_TO_LOCAL)) {
|
||||||
|
@@ -2918,6 +2946,12 @@ retry_tid:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chain_thread(new);
|
||||||
|
+
|
||||||
|
+ if (sof_err(do_fork_free_mod_clone_arg_0)) {
|
||||||
|
+ err = -EFAULT;
|
||||||
|
+ goto free_mod_clone_arg;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (!(clone_flags & CLONE_VM)) {
|
||||||
|
newproc->status = PS_RUNNING;
|
||||||
|
if(clone_flags & CLONE_PARENT){
|
||||||
|
@@ -2960,7 +2994,12 @@ retry_tid:
|
||||||
|
request1.number = __NR_clone;
|
||||||
|
request1.args[0] = 1;
|
||||||
|
request1.args[1] = new->tid;
|
||||||
|
- err = do_syscall(&request1, ihk_mc_get_processor_id());
|
||||||
|
+
|
||||||
|
+ if (sof_err(do_fork_free_mod_clone_arg_1)) {
|
||||||
|
+ err = -EFAULT;
|
||||||
|
+ } else {
|
||||||
|
+ err = do_syscall(&request1, ihk_mc_get_processor_id());
|
||||||
|
+ }
|
||||||
|
if (err) {
|
||||||
|
goto free_mod_clone_arg;
|
||||||
|
}
|
||||||
|
diff --git a/kernel/sysctrl-signalonfork_wait.c b/kernel/sysctrl-signalonfork_wait.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..6995fab
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/kernel/sysctrl-signalonfork_wait.c
|
||||||
|
@@ -0,0 +1,36 @@
|
||||||
|
+#include <sysctrl-signalonfork_wait.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <sysfs.h>
|
||||||
|
+#include <kmsg.h>
|
||||||
|
+
|
||||||
|
+enum signalonfork_error sof_error;
|
||||||
|
+
|
||||||
|
+static ssize_t signalonfork_test_show(struct sysfs_ops *ops,
|
||||||
|
+ void *instance, void *buf, size_t size)
|
||||||
|
+{
|
||||||
|
+ return snprintf(buf, size, "%d\n", sof_error);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t signalonfork_test_store(struct sysfs_ops *ops,
|
||||||
|
+ void *instance, void *buf, size_t size)
|
||||||
|
+{
|
||||||
|
+ sof_error = strtol(buf, NULL, 0);
|
||||||
|
+ return size;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct sysfs_ops signalonfork_test_ops = {
|
||||||
|
+ .show = &signalonfork_test_show,
|
||||||
|
+ .store = &signalonfork_test_store,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void signalonfork_test_sysfs_setup(void)
|
||||||
|
+{
|
||||||
|
+ int error;
|
||||||
|
+
|
||||||
|
+ error = sysfs_createf(&signalonfork_test_ops, NULL, 0666,
|
||||||
|
+ "/sys/kernel/debug/signalonfork_test");
|
||||||
|
+ if (error) {
|
||||||
|
+ kprintf("%s: ERROR: creating signalonfork_test sysfs file",
|
||||||
|
+ __func__);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
78
test/signalonfork+wait/result.log
Normal file
78
test/signalonfork+wait/result.log
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
=========================
|
||||||
|
aarch64(run.sh)
|
||||||
|
=========================
|
||||||
|
% sh run.sh
|
||||||
|
mcstop+release.sh ... done
|
||||||
|
mcreboot.sh -c 12-59 -m 2048M@4,2048M@5,2048M@6,2048M@7 -q 60 ... done
|
||||||
|
@@@ initialize:
|
||||||
|
seed for $RANDOM=13000
|
||||||
|
@@@ run signalonfork_wait: 1..1000
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
|
||||||
|
OK
|
||||||
|
|
||||||
|
=========================
|
||||||
|
aarch64(run_error_injection.sh)
|
||||||
|
=========================
|
||||||
|
% sh run_error_injection.sh
|
||||||
|
mcstop+release.sh ... done
|
||||||
|
mcreboot.sh -c 4-51 -m 4096M ... done
|
||||||
|
@@@ initialize:
|
||||||
|
seed for $RANDOM=3466
|
||||||
|
@@@ run signalonfork_wait(do_fork_release_cpuid_0, 0x010000) wait=1326
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_destroy_thread_0, 0x010100) wait=1201
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_destroy_thread_1, 0x010101) wait=1412
|
||||||
|
./signalonfork_wait: pthread_create fail: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(do_fork_destroy_thread_2, 0x010102) wait=1041
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_release_ids_0, 0x010200) wait=1402
|
||||||
|
./signalonfork_wait: pthread_create fail: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_release_ids_1, 0x010201) wait=1354
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_0, 0x010300) wait=1495
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_1, 0x010301) wait=1020
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_thread_0, 0x020000) wait=1216
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_thread_1, 0x020001) wait=1217
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fp_regs_0, 0x020100) wait=1045
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fp_regs_1, 0x020101) wait=1026
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_0, 0x020200) wait=1412
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_1, 0x020201) wait=1087
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_asp_0, 0x020300) wait=1439
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_vm_0, 0x020400) wait=1273
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_0, 0x020500) wait=1356
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_1, 0x020501) wait=1240
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_mckfd_0, 0x020600) wait=1052
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_clone_process_0, 0x020700) wait=1003
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_copy_user_ranges_0, 0x020800) wait=1465
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(copy_user_ranges_err_rollback_0, 0x030000) wait=1042
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
OK
|
||||||
|
|
||||||
|
--
|
||||||
|
result.log COPYRIGHT FUJITSU LIMITED 2019
|
||||||
78
test/signalonfork+wait/result_apollo.log
Normal file
78
test/signalonfork+wait/result_apollo.log
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
=========================
|
||||||
|
aarch64[apollo] (run.sh)
|
||||||
|
=========================
|
||||||
|
$ sh run.sh
|
||||||
|
mcstop+release.sh ... done
|
||||||
|
mcreboot.sh -c 8-55 -m 4096M -q 60 ... done
|
||||||
|
@@@ initialize:
|
||||||
|
seed for $RANDOM=8501
|
||||||
|
@@@ run signalonfork_wait: 1..1000
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
....................................................................................................
|
||||||
|
|
||||||
|
OK
|
||||||
|
|
||||||
|
=========================
|
||||||
|
aarch64[apollo] (run_error_injection.sh)
|
||||||
|
=========================
|
||||||
|
$ sh run_error_injection.sh
|
||||||
|
mcstop+release.sh ... done
|
||||||
|
mcreboot.sh -c 8-55 -m 4096M -q 60 ... done
|
||||||
|
@@@ initialize:
|
||||||
|
seed for $RANDOM=16838
|
||||||
|
@@@ run signalonfork_wait(do_fork_release_cpuid_0, 0x010000) wait=1492
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_destroy_thread_0, 0x010100) wait=1368
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_destroy_thread_1, 0x010101) wait=1454
|
||||||
|
./signalonfork_wait: pthread_create fail: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(do_fork_destroy_thread_2, 0x010102) wait=1014
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_release_ids_0, 0x010200) wait=1350
|
||||||
|
./signalonfork_wait: pthread_create fail: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_release_ids_1, 0x010201) wait=1056
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_0, 0x010300) wait=1382
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_1, 0x010301) wait=1244
|
||||||
|
./signalonfork_wait: fork: Bad address
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_thread_0, 0x020000) wait=1016
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_thread_1, 0x020001) wait=1455
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fp_regs_0, 0x020100) wait=1252
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fp_regs_1, 0x020101) wait=1481
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_0, 0x020200) wait=1140
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_1, 0x020201) wait=1292
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_asp_0, 0x020300) wait=1355
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_vm_0, 0x020400) wait=1251
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_0, 0x020500) wait=1275
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_1, 0x020501) wait=1451
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_process_mckfd_0, 0x020600) wait=1150
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_fork_clone_process_0, 0x020700) wait=1066
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(clone_thread_free_copy_user_ranges_0, 0x020800) wait=1484
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
@@@ run signalonfork_wait(copy_user_ranges_err_rollback_0, 0x030000) wait=1461
|
||||||
|
./signalonfork_wait: fork: Cannot allocate memory
|
||||||
|
OK
|
||||||
|
|
||||||
|
--
|
||||||
|
result_apollo.log COPYRIGHT FUJITSU LIMITED 2019
|
||||||
52
test/signalonfork+wait/run.sh
Normal file
52
test/signalonfork+wait/run.sh
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# run.sh COPYRIGHT FUJITSU LIMITED 2019
|
||||||
|
test_dir=$(dirname "${BASH_SOURCE[0]}")
|
||||||
|
|
||||||
|
#
|
||||||
|
# read config
|
||||||
|
#
|
||||||
|
. "${test_dir}/../common.sh"
|
||||||
|
|
||||||
|
#
|
||||||
|
# init
|
||||||
|
#
|
||||||
|
echo "@@@ initialize:"
|
||||||
|
seed="$RANDOM"
|
||||||
|
RANDOM=$seed
|
||||||
|
echo "seed for \$RANDOM=$seed"
|
||||||
|
|
||||||
|
meminfo="/sys/devices/virtual/mcos/mcos0/sys/devices/system/node/node0/meminfo"
|
||||||
|
"${MCEXEC}" 0 ./signalonfork_wait -nt 1 -t $((1000*5)) >/dev/null
|
||||||
|
sleep 1
|
||||||
|
exp_free_mem=`cat "$meminfo" | grep MemFree:`
|
||||||
|
|
||||||
|
#
|
||||||
|
# run
|
||||||
|
#
|
||||||
|
nr_loop=1000
|
||||||
|
echo "@@@ run signalonfork_wait: 1..$nr_loop"
|
||||||
|
for i in `seq 1 $nr_loop`
|
||||||
|
do
|
||||||
|
echo -n "."
|
||||||
|
new_line=$(($i % 100))
|
||||||
|
if [ $new_line -eq 0 ]; then
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
msec=$((1000 + $RANDOM % 500))
|
||||||
|
"${MCEXEC}" 0 ./signalonfork_wait -nt 1 -t $msec >/dev/null
|
||||||
|
sleep 1
|
||||||
|
free_mem=`cat "$meminfo" | grep MemFree:`
|
||||||
|
if [ "$exp_free_mem" != "$free_mem" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "NG[$i]: detected memory leak."
|
||||||
|
echo "before:"
|
||||||
|
echo " ${exp_free_mem}"
|
||||||
|
echo "after:"
|
||||||
|
echo " ${free_mem}"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
75
test/signalonfork+wait/run_error_injection.sh
Normal file
75
test/signalonfork+wait/run_error_injection.sh
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# run_error_injection.sh COPYRIGHT FUJITSU LIMITED 2019
|
||||||
|
test_dir=$(dirname "${BASH_SOURCE[0]}")
|
||||||
|
|
||||||
|
#
|
||||||
|
# read config
|
||||||
|
#
|
||||||
|
. "${test_dir}/../common.sh"
|
||||||
|
|
||||||
|
#
|
||||||
|
# init
|
||||||
|
#
|
||||||
|
echo "@@@ initialize:"
|
||||||
|
seed="$RANDOM"
|
||||||
|
RANDOM=$seed
|
||||||
|
echo "seed for \$RANDOM=$seed"
|
||||||
|
|
||||||
|
meminfo="/sys/devices/virtual/mcos/mcos0/sys/devices/system/node/node0/meminfo"
|
||||||
|
"${MCEXEC}" 0 ./signalonfork_wait -nt 1 -t $((1000*5)) >/dev/null
|
||||||
|
sleep 1
|
||||||
|
exp_free_mem=`cat "$meminfo" | grep MemFree:`
|
||||||
|
injection="/sys/devices/virtual/mcos/mcos0/sys/kernel/debug/signalonfork_test"
|
||||||
|
|
||||||
|
#
|
||||||
|
# run
|
||||||
|
#
|
||||||
|
while read label eq val
|
||||||
|
do
|
||||||
|
if [ -z "$label" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
val=`echo "$val" | sed 's|,.*$||g'`
|
||||||
|
|
||||||
|
msec=$((1000 + $RANDOM % 500))
|
||||||
|
echo "$val" > "$injection"
|
||||||
|
echo "@@@ run signalonfork_wait($label, $val) wait=$msec"
|
||||||
|
"${MCEXEC}" 0 ./signalonfork_wait -nt 2 -t $msec > /dev/null
|
||||||
|
sleep 1
|
||||||
|
free_mem=`cat "$meminfo" | grep MemFree:`
|
||||||
|
if [ "$exp_free_mem" != "$free_mem" ]; then
|
||||||
|
echo "NG: detected memory leak."
|
||||||
|
echo "before:"
|
||||||
|
echo " ${exp_free_mem}"
|
||||||
|
echo "after:"
|
||||||
|
echo " ${free_mem}"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
done <<__EOL__
|
||||||
|
do_fork_release_cpuid_0 = 0x010000,
|
||||||
|
do_fork_destroy_thread_0 = 0x010100,
|
||||||
|
do_fork_destroy_thread_1 = 0x010101,
|
||||||
|
do_fork_destroy_thread_2 = 0x010102,
|
||||||
|
do_fork_release_ids_0 = 0x010200,
|
||||||
|
do_fork_release_ids_1 = 0x010201,
|
||||||
|
do_fork_free_mod_clone_arg_0 = 0x010300,
|
||||||
|
do_fork_free_mod_clone_arg_1 = 0x010301,
|
||||||
|
|
||||||
|
clone_thread_free_thread_0 = 0x020000,
|
||||||
|
clone_thread_free_thread_1 = 0x020001,
|
||||||
|
clone_thread_free_fp_regs_0 = 0x020100,
|
||||||
|
clone_thread_free_fp_regs_1 = 0x020101,
|
||||||
|
clone_thread_free_fork_process_proc_0 = 0x020200,
|
||||||
|
clone_thread_free_fork_process_proc_1 = 0x020201,
|
||||||
|
clone_thread_free_fork_process_asp_0 = 0x020300,
|
||||||
|
clone_thread_free_fork_process_vm_0 = 0x020400,
|
||||||
|
clone_thread_free_fork_process_cmdline_0 = 0x020500,
|
||||||
|
clone_thread_free_fork_process_cmdline_1 = 0x020501,
|
||||||
|
clone_thread_free_fork_process_mckfd_0 = 0x020600,
|
||||||
|
clone_thread_free_fork_clone_process_0 = 0x020700,
|
||||||
|
clone_thread_free_copy_user_ranges_0 = 0x020800,
|
||||||
|
|
||||||
|
copy_user_ranges_err_rollback_0 = 0x030000,
|
||||||
|
__EOL__
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
327
test/signalonfork+wait/signalonfork_wait.c
Normal file
327
test/signalonfork+wait/signalonfork_wait.c
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
/* signalonfork_wait.c COPYRIGHT FUJITSU LIMITED 2019 */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <linux/futex.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define MAXNUMTHREADS 256
|
||||||
|
#define DEFAULTTIMETOWAIT 500
|
||||||
|
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
int numthreads = 1;
|
||||||
|
int nosignal;
|
||||||
|
int timetowait = DEFAULTTIMETOWAIT;
|
||||||
|
|
||||||
|
struct timeval timeBeforeFork;
|
||||||
|
struct timeval timeBeforeTest;
|
||||||
|
struct timeval timeAfterTest;
|
||||||
|
|
||||||
|
|
||||||
|
#define LAPTIME_MS(start, stop) \
|
||||||
|
((stop.tv_sec - start.tv_sec) * 1000 + \
|
||||||
|
(stop.tv_usec - start.tv_usec) / 1000)
|
||||||
|
|
||||||
|
struct Thread {
|
||||||
|
int tid;
|
||||||
|
pthread_t pthread;
|
||||||
|
} thread[MAXNUMTHREADS];
|
||||||
|
|
||||||
|
pthread_barrier_t barrier;
|
||||||
|
|
||||||
|
void onError(char *message)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: %s: %m\n", argv[0], message);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *subjectThread(void *);
|
||||||
|
|
||||||
|
static void waitChildren(void)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
int status = 0;
|
||||||
|
pid_t pid = wait(&status);
|
||||||
|
|
||||||
|
if (pid == -1) {
|
||||||
|
const char msg[] = "wait fail\n";
|
||||||
|
|
||||||
|
if (errno == ECHILD) {
|
||||||
|
return;
|
||||||
|
} else if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
write(STDERR_FILENO, msg, sizeof(msg));
|
||||||
|
_exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int signum, siginfo_t *info, void *uctx)
|
||||||
|
{
|
||||||
|
waitChildren();
|
||||||
|
if (signum == SIGTERM) {
|
||||||
|
raise(SIGTERM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createThreads(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pthread_barrier_init(&barrier, NULL, numthreads)) {
|
||||||
|
onError("pthread_barrier_init fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i < numthreads; i++) {
|
||||||
|
int rval;
|
||||||
|
|
||||||
|
thread[i].tid = i;
|
||||||
|
rval = pthread_create(&thread[i].pthread,
|
||||||
|
NULL,
|
||||||
|
subjectThread,
|
||||||
|
&thread[i]);
|
||||||
|
if (rval) {
|
||||||
|
onError("pthread_create fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread[0].tid = 0;
|
||||||
|
thread[0].pthread = pthread_self();
|
||||||
|
subjectThread(&thread[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void joinThreads(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < numthreads; i++) {
|
||||||
|
void *rval;
|
||||||
|
|
||||||
|
if (pthread_join(thread[i].pthread, &rval)) {
|
||||||
|
onError("pthread_join fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Join done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void subjectTask(struct Thread *thread)
|
||||||
|
{
|
||||||
|
pthread_barrier_wait(&barrier);
|
||||||
|
|
||||||
|
gettimeofday(&timeBeforeTest, NULL);
|
||||||
|
printf("[%d] setup: %ld ms\n",
|
||||||
|
thread->tid,
|
||||||
|
LAPTIME_MS(timeBeforeFork,
|
||||||
|
timeBeforeTest));
|
||||||
|
|
||||||
|
printf("[%d] START TEST\n", thread->tid);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
onError("fork");
|
||||||
|
} else if (pid == 0) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%d TEST FAIL OVERRUN\n", thread->tid);
|
||||||
|
|
||||||
|
gettimeofday(&timeAfterTest, NULL);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
;
|
||||||
|
// exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void subjectProcess(void)
|
||||||
|
{
|
||||||
|
printf("[%d] I am a subject.\n", getpid());
|
||||||
|
|
||||||
|
// Subjecttask();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void subjectCleanup(void *arg)
|
||||||
|
{
|
||||||
|
struct Thread *thread = (struct Thread *) arg;
|
||||||
|
|
||||||
|
printf("[%d] cleanup\n", thread->tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *subjectThread(void *arg)
|
||||||
|
{
|
||||||
|
struct Thread *thread = (struct Thread *)arg;
|
||||||
|
struct sigaction act = {
|
||||||
|
.sa_sigaction = signal_handler,
|
||||||
|
.sa_flags = SA_SIGINFO | SA_RESETHAND,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (sigaction(SIGTERM, &act, NULL) == -1) {
|
||||||
|
onError("sigaction fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[%d] I am a %s %d, %lx %lx\n",
|
||||||
|
getpid(), __func__, thread->tid,
|
||||||
|
thread->pthread, pthread_self());
|
||||||
|
|
||||||
|
pthread_cleanup_push(subjectCleanup, arg);
|
||||||
|
|
||||||
|
//sleep(random() % 5 + 1);
|
||||||
|
//printf("[%d:%d] wake up\n", getpid(), thread->tid);
|
||||||
|
|
||||||
|
pthread_barrier_wait(&barrier);
|
||||||
|
|
||||||
|
subjectTask(thread);
|
||||||
|
|
||||||
|
pthread_cleanup_pop(1);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void examinerProcess(pid_t subject)
|
||||||
|
{
|
||||||
|
struct timespec req, rem;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
printf("[%d] I am the examiner for %d.\n", getpid(), subject);
|
||||||
|
|
||||||
|
req.tv_sec = timetowait / 1000;
|
||||||
|
req.tv_nsec = (timetowait % 1000) * 1000000;
|
||||||
|
|
||||||
|
if (nanosleep(&req, &rem) < 0) {
|
||||||
|
fprintf(stderr, "nanosleep is interrupted, but ignore\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kill(subject, SIGTERM) < 0) {
|
||||||
|
printf("TEST FAIL (EXIT ALREADY)\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitpid(subject, &status, 0) < 0) {
|
||||||
|
onError("waitpid fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
printf("The TEST process unexpectedly "
|
||||||
|
"exited with return value %d\n",
|
||||||
|
WEXITSTATUS(status));
|
||||||
|
printf("TEST FAILED\n");
|
||||||
|
if (WEXITSTATUS(status) == 0) {
|
||||||
|
exit(-1);
|
||||||
|
} else {
|
||||||
|
exit(WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
printf("The TEST process is terminated by the signal %d\n",
|
||||||
|
WTERMSIG(status));
|
||||||
|
if (WTERMSIG(status) == SIGTERM) {
|
||||||
|
printf("TEST SUCCEEDED\n");
|
||||||
|
} else {
|
||||||
|
printf("TEST FAILED\n");
|
||||||
|
exit(WTERMSIG(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("TEST SUCCEEDED IF YOU DID NOT SEE 'OVERRUN'\n");
|
||||||
|
// printf("TEST FINISHED\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int _argc, char **_argv)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
argc = _argc;
|
||||||
|
argv = _argv;
|
||||||
|
|
||||||
|
printf("DANGERTEST SIGNALONFORK\n");
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (strcmp("-nt", argv[i]) == 0) {
|
||||||
|
i++;
|
||||||
|
if (i < argc) {
|
||||||
|
numthreads = atoi(argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s: num threads required\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (strcmp("-nosignal", argv[i]) == 0) {
|
||||||
|
nosignal = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp("-t", argv[i]) == 0) {
|
||||||
|
i++;
|
||||||
|
if (i < argc) {
|
||||||
|
timetowait = atoi(argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s: argument error\n"
|
||||||
|
"Usage:\n"
|
||||||
|
"\t-nt <num threads>\n"
|
||||||
|
"\t-nosignal\n"
|
||||||
|
"\t-t <time to wait (msec)>\n",
|
||||||
|
argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numthreads < 1 || numthreads > MAXNUMTHREADS) {
|
||||||
|
fprintf(stderr, "%s: invalid num threads\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("NUMTHREADS: %d\n", numthreads);
|
||||||
|
printf("NOSIGNAL: %d\n", nosignal);
|
||||||
|
printf("TIMETOWAIT: %d msec\n", timetowait);
|
||||||
|
|
||||||
|
// setup();
|
||||||
|
|
||||||
|
gettimeofday(&timeBeforeFork, NULL);
|
||||||
|
|
||||||
|
if (nosignal) {
|
||||||
|
createThreads();
|
||||||
|
joinThreads();
|
||||||
|
} else {
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
onError("fork");
|
||||||
|
} else if (pid == 0) {
|
||||||
|
createThreads();
|
||||||
|
joinThreads();
|
||||||
|
} else {
|
||||||
|
examinerProcess(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user