mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-27 19:33:23 +00:00
Reorganize the codebase
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
888853a6de
commit
271a16d492
4
regression/apps/bin/Makefile
Normal file
4
regression/apps/bin/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
ln -sf /busybox/busybox sh
|
1
regression/apps/bin/sh
Symbolic link
1
regression/apps/bin/sh
Symbolic link
@ -0,0 +1 @@
|
||||
/busybox/busybox
|
7
regression/apps/busybox/README.md
Normal file
7
regression/apps/busybox/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
### How to compile this busybox
|
||||
We don't include the source code of busybox here since the source code is really large. The busybox can be compiled with following commands.
|
||||
|
||||
After download the source code of busybox 1.35.0 and unzip, then cd to the directory of busybox
|
||||
1. `make defconfig`. We set all config as default.
|
||||
2. Set static link option in .config: `CONFIG_STATIC=y`. We need a static-linked busybox binary since we does not support dynamic linking now.
|
||||
3. Set standalone shell option in .config: `CONFIG_FEATURE_SH_STANDALONE=y`. The standalone ash will try to call busybox applets instead of search binaries in host system. e.g., when running ls, standalone ash will invoke `busybox ls`.
|
3
regression/apps/busybox/busybox
Executable file
3
regression/apps/busybox/busybox
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6db28e1ed8bdac06ac595b2126cefc10ecf16156bf4c1005950f561aedc0531a
|
||||
size 2701792
|
12
regression/apps/execve/Makefile
Normal file
12
regression/apps/execve/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello.c execve.c
|
||||
@gcc -static hello.c -o hello
|
||||
@gcc -static execve.c -o execve
|
||||
|
||||
clean:
|
||||
@rm hello
|
||||
@rm execve
|
||||
|
||||
run: build
|
||||
@./execve
|
3
regression/apps/execve/execve
Executable file
3
regression/apps/execve/execve
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c7cc90df87ade7ff2cb494e13678aceaf93542883558fda947bd2fc01e2d73a6
|
||||
size 871952
|
15
regression/apps/execve/execve.c
Normal file
15
regression/apps/execve/execve.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
char* argv[] = { "argv1", "argv2", NULL };
|
||||
char* envp[] = { "home=/", "version=1.1", NULL };
|
||||
// The hello will be put at /execve/hello in InitRamfs
|
||||
printf("Execve a new file /execve/hello:\n");
|
||||
// flush the stdout content to ensure the content print to console
|
||||
fflush(stdout);
|
||||
execve("/execve/hello", argv, envp);
|
||||
printf("Should not print\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
3
regression/apps/execve/hello
Executable file
3
regression/apps/execve/hello
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d0152798ba393fb04603ead02083e74de560d9cf51584f5cdca762d0706ebd2d
|
||||
size 871960
|
16
regression/apps/execve/hello.c
Normal file
16
regression/apps/execve/hello.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[], char *envp[]) {
|
||||
printf("Hello world from hello.c(execved in execve.c)!\n");
|
||||
printf("argc = %d\n", argc);
|
||||
for(int i = 0; i < argc; i++) {
|
||||
printf("%s\n", argv[i]);
|
||||
}
|
||||
for(int i = 0 ;; i++) {
|
||||
if (envp[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
printf("%s\n", envp[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
10
regression/apps/fork/Makefile
Normal file
10
regression/apps/fork/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: fork.s
|
||||
@gcc -static -nostdlib fork.s -o fork
|
||||
|
||||
clean:
|
||||
@rm fork
|
||||
|
||||
run: build
|
||||
@./fork
|
3
regression/apps/fork/fork
Executable file
3
regression/apps/fork/fork
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9bc1642390b9dc38ecc058240e529401c38aa8bb9a86bad3615e4bdad505fa8c
|
||||
size 9592
|
69
regression/apps/fork/fork.s
Normal file
69
regression/apps/fork/fork.s
Normal file
@ -0,0 +1,69 @@
|
||||
.global _start
|
||||
|
||||
.section .text
|
||||
_start:
|
||||
call print_hello_world
|
||||
mov $57, %rax # syscall number of fork
|
||||
syscall
|
||||
|
||||
cmp $0, %rax
|
||||
je _child # child process
|
||||
jmp _parent # parent process
|
||||
_parent:
|
||||
call wait_child
|
||||
call get_pid
|
||||
call print_parent_message
|
||||
call exit
|
||||
_child:
|
||||
call get_pid
|
||||
call print_child_message
|
||||
call exit
|
||||
wait_child:
|
||||
mov %rax, %rdi # child process id
|
||||
_loop:
|
||||
mov $61, %rax # syscall number of wait4
|
||||
mov $0, %rsi # exit status address
|
||||
mov $1, %rdx # WNOHANG
|
||||
syscall
|
||||
cmp %rdi, %rax # The return value is the pid of child
|
||||
jne _loop
|
||||
ret
|
||||
exit:
|
||||
mov $60, %rax # syscall number of exit
|
||||
mov $0, %rdi # exit code
|
||||
syscall
|
||||
get_pid:
|
||||
mov $39, %rax
|
||||
syscall
|
||||
ret
|
||||
print_hello_world:
|
||||
mov $message, %rsi # address of message
|
||||
mov $message_end, %rdx
|
||||
sub %rsi, %rdx # calculate message len
|
||||
jmp _print_message
|
||||
print_parent_message:
|
||||
mov $message_parent, %rsi # address of message
|
||||
mov $message_parent_end, %rdx
|
||||
sub %rsi, %rdx # calculate message len
|
||||
jmp _print_message
|
||||
print_child_message:
|
||||
mov $message_child, %rsi # address of message
|
||||
mov $message_child_end, %rdx
|
||||
sub %rsi, %rdx # calculate message len
|
||||
jmp _print_message
|
||||
# never directly call _print_message
|
||||
_print_message:
|
||||
mov $1, %rax # syscall number of write
|
||||
mov $1, %rdi # stdout
|
||||
syscall
|
||||
ret
|
||||
.section .rodata
|
||||
message:
|
||||
.ascii "Hello, world in fork\n"
|
||||
message_end:
|
||||
message_parent:
|
||||
.ascii "Hello world from parent\n"
|
||||
message_parent_end:
|
||||
message_child:
|
||||
.ascii "Hello world from child\n"
|
||||
message_child_end:
|
10
regression/apps/fork_c/Makefile
Normal file
10
regression/apps/fork_c/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: fork.c
|
||||
@gcc -static fork.c -o fork
|
||||
|
||||
clean:
|
||||
@rm fork
|
||||
|
||||
run: build
|
||||
@./fork
|
3
regression/apps/fork_c/fork
Executable file
3
regression/apps/fork_c/fork
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ca7a77a72da160f11670a04a16b623944295b9059399da45f57668f121b00d11
|
||||
size 877152
|
14
regression/apps/fork_c/fork.c
Normal file
14
regression/apps/fork_c/fork.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
printf("before fork\n");
|
||||
fflush(stdout);
|
||||
if(fork() == 0) {
|
||||
printf("after fork: Hello from child\n");
|
||||
} else {
|
||||
printf("after fork: Hello from parent\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
10
regression/apps/hello_c/Makefile
Normal file
10
regression/apps/hello_c/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello.c
|
||||
@gcc -static -mno-sse hello.c -o hello
|
||||
|
||||
clean:
|
||||
@rm hello
|
||||
|
||||
run: build
|
||||
@./hello
|
3
regression/apps/hello_c/hello
Executable file
3
regression/apps/hello_c/hello
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dda5a7d6081cc2252056375d0550731ef2fd24789aa5f17da189a36bf78c588d
|
||||
size 871896
|
6
regression/apps/hello_c/hello.c
Normal file
6
regression/apps/hello_c/hello.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("hello world from hello_c!\n");
|
||||
return 0;
|
||||
}
|
10
regression/apps/hello_pie/Makefile
Normal file
10
regression/apps/hello_pie/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello.c
|
||||
@gcc hello.c -o hello
|
||||
|
||||
clean:
|
||||
@rm hello
|
||||
|
||||
run: build
|
||||
@./hello
|
3
regression/apps/hello_pie/hello
Executable file
3
regression/apps/hello_pie/hello
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:64b67cf4ad247d668833888447ec7f12d37f5f816abd549d5c2c08fecfa4dd09
|
||||
size 16696
|
6
regression/apps/hello_pie/hello.c
Normal file
6
regression/apps/hello_pie/hello.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("hello world from hello_pie!\n");
|
||||
return 0;
|
||||
}
|
10
regression/apps/hello_world/Makefile
Normal file
10
regression/apps/hello_world/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello_world.s
|
||||
@gcc -static -nostdlib hello_world.s -o hello_world
|
||||
|
||||
clean:
|
||||
@rm hello_world
|
||||
|
||||
run: build
|
||||
@./hello_world
|
3
regression/apps/hello_world/hello_world
Executable file
3
regression/apps/hello_world/hello_world
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f56fb5cf05f234578b13c8d73f2d29568f6f513602f1ea0b71a0dbf0cf8f60f8
|
||||
size 9104
|
26
regression/apps/hello_world/hello_world.s
Normal file
26
regression/apps/hello_world/hello_world.s
Normal file
@ -0,0 +1,26 @@
|
||||
.global _start
|
||||
|
||||
.section .text
|
||||
_start:
|
||||
call print_message
|
||||
call print_message
|
||||
call print_message
|
||||
mov $60, %rax # syscall number of exit
|
||||
mov $0, %rdi # exit code
|
||||
syscall
|
||||
get_pid:
|
||||
mov $39, %rax
|
||||
syscall
|
||||
ret
|
||||
print_message:
|
||||
mov $1, %rax # syscall number of write
|
||||
mov $1, %rdi # stdout
|
||||
mov $message, %rsi # address of message
|
||||
mov $message_end, %rdx
|
||||
sub %rsi, %rdx # calculate message len
|
||||
syscall
|
||||
ret
|
||||
.section .rodata
|
||||
message:
|
||||
.ascii "Hello, world\n"
|
||||
message_end:
|
10
regression/apps/pthread/Makefile
Normal file
10
regression/apps/pthread/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: pthread_test.c
|
||||
@gcc -static pthread_test.c -lpthread -o pthread_test
|
||||
|
||||
clean:
|
||||
@rm pthread_test
|
||||
|
||||
run: build
|
||||
@./pthread_test
|
3
regression/apps/pthread/pthread_test
Executable file
3
regression/apps/pthread/pthread_test
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d40bfc16dbf95aba3afa1934fa4efc0147f0a0a12533362a8d95e105d4d2af21
|
||||
size 1693840
|
280
regression/apps/pthread/pthread_test.c
Normal file
280
regression/apps/pthread/pthread_test.c
Normal file
@ -0,0 +1,280 @@
|
||||
// This test file is from occlum pthread test.
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#ifndef SYS_gettid
|
||||
#error "SYS_gettid unavailable on this system"
|
||||
#endif
|
||||
|
||||
#define gettid() ((pid_t)syscall(SYS_gettid))
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
// ============================================================================
|
||||
|
||||
#define THROW_ERROR(fmt, ...) do { \
|
||||
printf("\t\tERROR:" fmt " in func %s at line %d of file %s with errno %d: %s\n", \
|
||||
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, strerror(errno)); \
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
// ============================================================================
|
||||
// Helper macros
|
||||
// ============================================================================
|
||||
|
||||
|
||||
#define NTHREADS (3)
|
||||
#define STACK_SIZE (8 * 1024)
|
||||
|
||||
// ============================================================================
|
||||
// The test case of concurrent counter
|
||||
// ============================================================================
|
||||
|
||||
#define LOCAL_COUNT (1000UL)
|
||||
#define EXPECTED_GLOBAL_COUNT (LOCAL_COUNT * NTHREADS)
|
||||
|
||||
struct thread_arg {
|
||||
int ti;
|
||||
long local_count;
|
||||
volatile unsigned long *global_count;
|
||||
pthread_mutex_t *mutex;
|
||||
};
|
||||
|
||||
static void *thread_func(void *_arg) {
|
||||
struct thread_arg *arg = _arg;
|
||||
for (long i = 0; i < arg->local_count; i++) {
|
||||
pthread_mutex_lock(arg->mutex);
|
||||
(*arg->global_count)++;
|
||||
pthread_mutex_unlock(arg->mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int test_mutex_with_concurrent_counter(void) {
|
||||
/*
|
||||
* Multiple threads are to increase a global counter concurrently
|
||||
*/
|
||||
volatile unsigned long global_count = 0;
|
||||
pthread_t threads[NTHREADS];
|
||||
struct thread_arg thread_args[NTHREADS];
|
||||
/*
|
||||
* Protect the counter with a mutex
|
||||
*/
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
/*
|
||||
* Start the threads
|
||||
*/
|
||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||
struct thread_arg *thread_arg = &thread_args[ti];
|
||||
thread_arg->ti = ti;
|
||||
thread_arg->local_count = LOCAL_COUNT;
|
||||
thread_arg->global_count = &global_count;
|
||||
thread_arg->mutex = &mutex;
|
||||
|
||||
if (pthread_create(&threads[ti], NULL, thread_func, thread_arg) < 0) {
|
||||
printf("ERROR: pthread_create failed (ti = %d)\n", ti);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Wait for the threads to finish
|
||||
*/
|
||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||
if (pthread_join(threads[ti], NULL) < 0) {
|
||||
printf("ERROR: pthread_join failed (ti = %d)\n", ti);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check the correctness of the concurrent counter
|
||||
*/
|
||||
if (global_count != EXPECTED_GLOBAL_COUNT) {
|
||||
printf("ERROR: incorrect global_count (actual = %ld, expected = %ld)\n",
|
||||
global_count, EXPECTED_GLOBAL_COUNT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// The test case of robust mutex
|
||||
// ============================================================================
|
||||
|
||||
struct thread_robust_arg {
|
||||
int ti;
|
||||
volatile int *global_count;
|
||||
pthread_mutex_t *mutex;
|
||||
};
|
||||
|
||||
int ret_err = -1;
|
||||
|
||||
static void *thread_worker(void *_arg) {
|
||||
struct thread_robust_arg *arg = _arg;
|
||||
int err = pthread_mutex_lock(arg->mutex);
|
||||
if (err == EOWNERDEAD) {
|
||||
// The mutex is locked by the thread here, but the state is marked as
|
||||
// inconsistent, the thread should call 'pthread_mutex_consistent' to
|
||||
// make the mutex consistent again.
|
||||
if (pthread_mutex_consistent(arg->mutex) != 0) {
|
||||
printf("ERROR: failed to recover the mutex\n");
|
||||
return &ret_err;
|
||||
}
|
||||
} else if (err != 0) {
|
||||
printf("ERROR: failed to lock the mutex with error: %d\n", err);
|
||||
return &ret_err;
|
||||
}
|
||||
// Mutex is locked
|
||||
(*arg->global_count)++;
|
||||
// Wait for other threads to acquire the lock
|
||||
sleep(1);
|
||||
// Exit without unlocking the mutex, this will makes the mutex in an
|
||||
// inconsistent state.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int test_robust_mutex_with_concurrent_counter(void) {
|
||||
volatile int global_count = 0;
|
||||
pthread_t threads[NTHREADS];
|
||||
struct thread_robust_arg thread_args[NTHREADS];
|
||||
// Init robust mutex
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
|
||||
pthread_mutex_init(&mutex, &attr);
|
||||
// Start the threads
|
||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||
struct thread_robust_arg *thread_arg = &thread_args[ti];
|
||||
thread_arg->ti = ti;
|
||||
thread_arg->global_count = &global_count;
|
||||
thread_arg->mutex = &mutex;
|
||||
|
||||
if (pthread_create(&threads[ti], NULL, thread_worker, thread_arg) < 0) {
|
||||
THROW_ERROR("pthread_create failed (ti = %d)", ti);
|
||||
}
|
||||
}
|
||||
// Wait for the threads to finish
|
||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||
int *ret_val;
|
||||
if (pthread_join(threads[ti], (void **)&ret_val) < 0) {
|
||||
THROW_ERROR("pthread_join failed (ti = %d)", ti);
|
||||
}
|
||||
// printf("Thread %d joined\n", ti);
|
||||
// fflush(stdout);
|
||||
if (ret_val && *ret_val != 0) {
|
||||
THROW_ERROR("run thread failed (ti = %d) with return val: %d", ti, *ret_val);
|
||||
}
|
||||
}
|
||||
// printf("Thread all exited.\n");
|
||||
// fflush(stdout);
|
||||
// Check the result
|
||||
if (global_count != NTHREADS) {
|
||||
THROW_ERROR("incorrect global_count (actual = %d, expected = %d)", global_count,
|
||||
NTHREADS);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// The test case of waiting condition variable
|
||||
// ============================================================================
|
||||
|
||||
#define WAIT_ROUND (10)
|
||||
|
||||
struct thread_cond_arg {
|
||||
int ti;
|
||||
volatile unsigned int *val;
|
||||
volatile int *exit_thread_count;
|
||||
pthread_cond_t *cond_val;
|
||||
pthread_mutex_t *mutex;
|
||||
};
|
||||
|
||||
static void *thread_cond_wait(void *_arg) {
|
||||
struct thread_cond_arg *arg = _arg;
|
||||
printf("Thread #%d: start to wait on condition variable.\n", arg->ti);
|
||||
fflush(stdout);
|
||||
for (unsigned int i = 0; i < WAIT_ROUND; ++i) {
|
||||
int tid = gettid();
|
||||
printf("WAIT ROUND: %d, tid = %d\n", i, tid);
|
||||
fflush(stdout);
|
||||
pthread_mutex_lock(arg->mutex);
|
||||
printf("pthread mutex lock: tid = %d\n", tid);
|
||||
fflush(stdout);
|
||||
while (*(arg->val) == 0) {
|
||||
pthread_cond_wait(arg->cond_val, arg->mutex);
|
||||
printf("pthread cond wait: tid = %d\n", tid);
|
||||
fflush(stdout);
|
||||
}
|
||||
pthread_mutex_unlock(arg->mutex);
|
||||
}
|
||||
(*arg->exit_thread_count)++;
|
||||
printf("Thread #%d: exited.\n", arg->ti);
|
||||
fflush(stdout);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int test_mutex_with_cond_wait(void) {
|
||||
volatile unsigned int val = 0;
|
||||
volatile int exit_thread_count = 0;
|
||||
pthread_t threads[NTHREADS];
|
||||
struct thread_cond_arg thread_args[NTHREADS];
|
||||
pthread_cond_t cond_val = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
/*
|
||||
* Start the threads waiting on the condition variable
|
||||
*/
|
||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||
struct thread_cond_arg *thread_arg = &thread_args[ti];
|
||||
thread_arg->ti = ti;
|
||||
thread_arg->val = &val;
|
||||
thread_arg->exit_thread_count = &exit_thread_count;
|
||||
thread_arg->cond_val = &cond_val;
|
||||
thread_arg->mutex = &mutex;
|
||||
|
||||
if (pthread_create(&threads[ti], NULL, thread_cond_wait, thread_arg) < 0) {
|
||||
printf("ERROR: pthread_create failed (ti = %d)\n", ti);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Unblock all threads currently waiting on the condition variable
|
||||
*/
|
||||
while (exit_thread_count < NTHREADS) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
val = 1;
|
||||
pthread_cond_broadcast(&cond_val);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
val = 0;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
/*
|
||||
* Wait for the threads to finish
|
||||
*/
|
||||
for (int ti = 0; ti < NTHREADS; ti++) {
|
||||
if (pthread_join(threads[ti], NULL) < 0) {
|
||||
printf("ERROR: pthread_join failed (ti = %d)\n", ti);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_mutex_with_concurrent_counter();
|
||||
test_robust_mutex_with_concurrent_counter();
|
||||
// test_mutex_with_cond_wait();
|
||||
return 0;
|
||||
}
|
16
regression/apps/scripts/run_tests.sh
Executable file
16
regression/apps/scripts/run_tests.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=/scripts
|
||||
cd ${SCRIPT_DIR}/..
|
||||
|
||||
echo "Running tests......"
|
||||
tests="hello_world/hello_world fork/fork execve/execve fork_c/fork signal_c/signal_test pthread/pthread_test hello_pie/hello"
|
||||
|
||||
for testcase in ${tests}
|
||||
do
|
||||
echo "Running test ${testcase}......"
|
||||
${testcase}
|
||||
done
|
||||
echo "All tests passed"
|
37
regression/apps/scripts/test_cmd.sh
Executable file
37
regression/apps/scripts/test_cmd.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
SCRIPT_DIR=/scripts
|
||||
cd ${SCRIPT_DIR}
|
||||
|
||||
touch hello.txt
|
||||
mv hello.txt hello_world.txt
|
||||
rm hello_world.txt
|
||||
|
||||
awk '{print $2}' test_cmd.sh
|
||||
cp test_cmd.sh test_cmd_backup.sh
|
||||
cat test_cmd_backup.sh
|
||||
rm test_cmd_backup.sh
|
||||
|
||||
ln -s test_cmd.sh tesk_cmd_soft_link
|
||||
readlink -f tesk_cmd_soft_link
|
||||
tail -n 1 tesk_cmd_soft_link
|
||||
rm tesk_cmd_soft_link
|
||||
|
||||
ln test_cmd.sh tesk_cmd_hard_link
|
||||
tail -n 1 tesk_cmd_hard_link
|
||||
unlink tesk_cmd_hard_link
|
||||
|
||||
sed 3q test_cmd.sh
|
||||
|
||||
find . -name "*test_cmd*"
|
||||
|
||||
mkdir foo
|
||||
rmdir foo
|
||||
|
||||
echo "Hello world from jinux" > hello.txt
|
||||
rm hello.txt
|
||||
|
||||
cd ..
|
7
regression/apps/signal_c/Makefile
Normal file
7
regression/apps/signal_c/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
.PHONY: build clean run
|
||||
build: signal_test.c
|
||||
@gcc -static signal_test.c -o signal_test
|
||||
clean:
|
||||
@rm signal_test
|
||||
run: build
|
||||
@./signal_test
|
3
regression/apps/signal_c/signal_test
Executable file
3
regression/apps/signal_c/signal_test
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:25894b343f222eea5074a83e16a7140868a992a66e7bc8e363fabf2c23e19451
|
||||
size 882520
|
284
regression/apps/signal_c/signal_test.c
Normal file
284
regression/apps/signal_c/signal_test.c
Normal file
@ -0,0 +1,284 @@
|
||||
// This test file is from occlum, to test whether we implement signal correctly.
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <ucontext.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <spawn.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
// ============================================================================
|
||||
|
||||
#define THROW_ERROR(fmt, ...) do { \
|
||||
printf("\t\tERROR:" fmt " in func %s at line %d of file %s with errno %d: %s\n", \
|
||||
##__VA_ARGS__, __func__, __LINE__, __FILE__, errno, strerror(errno)); \
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Test sigprocmask
|
||||
// ============================================================================
|
||||
|
||||
#define sigcmpset(a, b) memcmp((a), (b), 8)
|
||||
|
||||
int test_sigprocmask() {
|
||||
int ret;
|
||||
sigset_t new, old;
|
||||
sigset_t expected_old;
|
||||
|
||||
// Check sigmask == []
|
||||
if ((ret = sigprocmask(0, NULL, &old)) < 0) {
|
||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||
}
|
||||
sigemptyset(&expected_old);
|
||||
if (sigcmpset(&old, &expected_old) != 0) {
|
||||
THROW_ERROR("unexpected old sigset");
|
||||
}
|
||||
|
||||
// SIG_BLOCK: [] --> [SIGSEGV]
|
||||
sigemptyset(&new);
|
||||
sigaddset(&new, SIGSEGV);
|
||||
if ((ret = sigprocmask(SIG_BLOCK, &new, &old)) < 0) {
|
||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||
}
|
||||
sigemptyset(&expected_old);
|
||||
if (sigcmpset(&old, &expected_old) != 0) {
|
||||
THROW_ERROR("unexpected old sigset");
|
||||
}
|
||||
|
||||
// SIG_SETMASK: [SIGSEGV] --> [SIGIO]
|
||||
sigemptyset(&new);
|
||||
sigaddset(&new, SIGIO);
|
||||
if ((ret = sigprocmask(SIG_SETMASK, &new, &old)) < 0) {
|
||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||
}
|
||||
sigemptyset(&expected_old);
|
||||
sigaddset(&expected_old, SIGSEGV);
|
||||
if (sigcmpset(&old, &expected_old) != 0) {
|
||||
THROW_ERROR("unexpected old sigset");
|
||||
}
|
||||
|
||||
// SIG_UNBLOCK: [SIGIO] -> []
|
||||
if ((ret = sigprocmask(SIG_UNBLOCK, &new, &old)) < 0) {
|
||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||
}
|
||||
sigemptyset(&expected_old);
|
||||
sigaddset(&expected_old, SIGIO);
|
||||
if (sigcmpset(&old, &expected_old) != 0) {
|
||||
THROW_ERROR("unexpected old sigset");
|
||||
}
|
||||
|
||||
// Check sigmask == []
|
||||
if ((ret = sigprocmask(0, NULL, &old)) < 0) {
|
||||
THROW_ERROR("sigprocmask failed unexpectedly");
|
||||
}
|
||||
sigemptyset(&expected_old);
|
||||
if (sigcmpset(&old, &expected_old) != 0) {
|
||||
THROW_ERROR("unexpected old sigset");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test raise syscall and user-registered signal handlers
|
||||
// ============================================================================
|
||||
|
||||
#define MAX_RECURSION_LEVEL 3
|
||||
|
||||
static void handle_sigio(int num, siginfo_t *info, void *context) {
|
||||
static volatile int recursion_level = 0;
|
||||
printf("Hello from SIGIO signal handler (recursion_level = %d)!\n", recursion_level);
|
||||
fflush(stdout);
|
||||
|
||||
recursion_level++;
|
||||
if (recursion_level <= MAX_RECURSION_LEVEL) {
|
||||
raise(SIGIO);
|
||||
}
|
||||
recursion_level--;
|
||||
}
|
||||
|
||||
int test_raise() {
|
||||
struct sigaction new_action, old_action;
|
||||
memset(&new_action, 0, sizeof(struct sigaction));
|
||||
memset(&old_action, 0, sizeof(struct sigaction));
|
||||
new_action.sa_sigaction = handle_sigio;
|
||||
new_action.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||
if (sigaction(SIGIO, &new_action, &old_action) < 0) {
|
||||
THROW_ERROR("registering new signal handler failed");
|
||||
}
|
||||
if (old_action.sa_handler != SIG_DFL) {
|
||||
THROW_ERROR("unexpected old sig handler");
|
||||
}
|
||||
|
||||
raise(SIGIO);
|
||||
|
||||
if (sigaction(SIGIO, &old_action, NULL) < 0) {
|
||||
THROW_ERROR("restoring old signal handler failed");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test catching and handling hardware exception
|
||||
// ============================================================================
|
||||
|
||||
static void handle_sigfpe(int num, siginfo_t *info, void *_context) {
|
||||
printf("SIGFPE Caught\n");
|
||||
fflush(stdout);
|
||||
assert(num == SIGFPE);
|
||||
assert(info->si_signo == SIGFPE);
|
||||
ucontext_t *ucontext = _context;
|
||||
mcontext_t *mcontext = &ucontext->uc_mcontext;
|
||||
// The faulty instruction should be `idiv %esi` (f7 fe)
|
||||
mcontext->gregs[REG_RIP] += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: this function is fragile in the sense that compiler may not always
|
||||
// emit the instruction pattern that triggers divide-by-zero as we expect.
|
||||
// TODO: rewrite this in assembly
|
||||
int div_maybe_zero(int x, int y) {
|
||||
return x / y;
|
||||
}
|
||||
|
||||
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
|
||||
|
||||
int test_handle_sigfpe() {
|
||||
// Set up a signal handler that handles divide-by-zero exception
|
||||
struct sigaction new_action, old_action;
|
||||
memset(&new_action, 0, sizeof(struct sigaction));
|
||||
memset(&old_action, 0, sizeof(struct sigaction));
|
||||
new_action.sa_sigaction = handle_sigfpe;
|
||||
new_action.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGFPE, &new_action, &old_action) < 0) {
|
||||
THROW_ERROR("registering new signal handler failed");
|
||||
}
|
||||
if (old_action.sa_handler != SIG_DFL) {
|
||||
THROW_ERROR("unexpected old sig handler");
|
||||
}
|
||||
|
||||
char x[512] __attribute__((aligned(16))) = {};
|
||||
char y[512] __attribute__((aligned(16))) = {};
|
||||
|
||||
// Trigger divide-by-zero exception
|
||||
int a = 1;
|
||||
int b = 0;
|
||||
// Use volatile to prevent compiler optimization
|
||||
volatile int c;
|
||||
fxsave(x);
|
||||
c = div_maybe_zero(a, b);
|
||||
fxsave(y);
|
||||
|
||||
// jinux does not save and restore fpregs now, so we emit this check.
|
||||
// if (memcmp(x, y, 512) != 0) {
|
||||
// THROW_ERROR("floating point registers are modified");
|
||||
// }
|
||||
|
||||
printf("Signal handler successfully jumped over the divide-by-zero instruction\n");
|
||||
fflush(stdout);
|
||||
|
||||
if (sigaction(SIGFPE, &old_action, NULL) < 0) {
|
||||
THROW_ERROR("restoring old signal handler failed");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: rewrite this in assembly
|
||||
int read_maybe_null(int *p) {
|
||||
return *p;
|
||||
}
|
||||
|
||||
static void handle_sigsegv(int num, siginfo_t *info, void *_context) {
|
||||
printf("SIGSEGV Caught\n");
|
||||
fflush(stdout);
|
||||
|
||||
assert(num == SIGSEGV);
|
||||
assert(info->si_signo == SIGSEGV);
|
||||
|
||||
ucontext_t *ucontext = _context;
|
||||
mcontext_t *mcontext = &ucontext->uc_mcontext;
|
||||
// TODO: how long is the instruction?
|
||||
// The faulty instruction should be `idiv %esi` (f7 fe)
|
||||
mcontext->gregs[REG_RIP] += 2;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int test_handle_sigsegv() {
|
||||
// Set up a signal handler that handles divide-by-zero exception
|
||||
struct sigaction new_action, old_action;
|
||||
memset(&new_action, 0, sizeof(struct sigaction));
|
||||
memset(&old_action, 0, sizeof(struct sigaction));
|
||||
new_action.sa_sigaction = handle_sigsegv;
|
||||
new_action.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGSEGV, &new_action, &old_action) < 0) {
|
||||
THROW_ERROR("registering new signal handler failed");
|
||||
}
|
||||
if (old_action.sa_handler != SIG_DFL) {
|
||||
THROW_ERROR("unexpected old sig handler");
|
||||
}
|
||||
|
||||
int *addr = NULL;
|
||||
volatile int val = read_maybe_null(addr);
|
||||
(void)val; // to suppress "unused variables" warning
|
||||
|
||||
printf("Signal handler successfully jumped over a null-dereferencing instruction\n");
|
||||
fflush(stdout);
|
||||
|
||||
if (sigaction(SIGSEGV, &old_action, NULL) < 0) {
|
||||
THROW_ERROR("restoring old signal handler failed");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test SIGCHLD signal
|
||||
// ============================================================================
|
||||
int sigchld = 0;
|
||||
|
||||
void proc_exit() {
|
||||
sigchld = 1;
|
||||
}
|
||||
|
||||
int test_sigchld() {
|
||||
signal(SIGCHLD, proc_exit);
|
||||
printf("Run a parent process has pid = %d\n", getpid());
|
||||
fflush(stdout);
|
||||
int pid = fork();
|
||||
if(pid == 0) {
|
||||
// child process
|
||||
printf("create a new proces successfully (pid = %d)\n", getpid());
|
||||
fflush(stdout);
|
||||
} else {
|
||||
// parent process
|
||||
wait(NULL);
|
||||
printf("sigchld = %d\n", sigchld);
|
||||
fflush(stdout);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_sigprocmask();
|
||||
test_raise();
|
||||
test_handle_sigfpe();
|
||||
test_handle_sigsegv();
|
||||
test_sigchld();
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user