diff --git a/LibOS/shim/src/shim_async.c b/LibOS/shim/src/shim_async.c index a7444295..785aea9a 100644 --- a/LibOS/shim/src/shim_async.c +++ b/LibOS/shim/src/shim_async.c @@ -59,8 +59,6 @@ int install_async_event (PAL_HANDLE object, unsigned long time, unsigned long install_time = DkSystemTimeQuery(); - debug("install async event at %llu\n", install_time); - event->callback = callback; event->arg = arg; event->caller = get_cur_tid(); @@ -79,16 +77,58 @@ int install_async_event (PAL_HANDLE object, unsigned long time, prev = &tmp->list; } + /* + * man page of alarm system call : + * DESCRIPTION + * alarm() arranges for a SIGALRM signal to be delivered to the + * calling process in seconds seconds. + * If seconds is zero, any pending alarm is canceled. + * In any event any previously set alarm() is canceled. + */ + if (!list_empty(&async_list)) { + tmp = list_entry((&async_list)->prev, struct async_event, list); + /* + * any previously set alarm() is canceled. + * There should be exactly only one timer pending + */ + list_del(&tmp->list); + free(tmp); + } else + tmp = NULL; + INIT_LIST_HEAD(&event->list); - list_add(&event->list, prev); - + if (!time) // If seconds is zero, any pending alarm is canceled. + free(event); + else + list_add_tail(&event->list, &async_list); + unlock(async_helper_lock); if (atomic_read(&async_helper_state) == HELPER_NOTALIVE) create_async_helper(); - set_event(&async_helper_event, 1); - return 0; + DkEventSet(async_helper_event); + + /* + * man page of alarm system call : + * RETURN VALUE + * alarm() returns the number of seconds remaining until + * any previously scheduled alarm was due to be delivered, + * or zero if there was no previously scheduled alarm. + * reference : lxr.free-electrons.com/source/kernel/itimer.c?v=2.6.35#L272 + */ + unsigned long ret; + unsigned long sec = 0; + unsigned long usec = 0; + + if (tmp) { + ret = tmp->expire_time - install_time; + sec = ret / 1000000; + usec = ret % 1000000; + if ((!sec && usec) || usec >=500000) + sec++; + } + return sec; } int init_async (void) diff --git a/LibOS/shim/src/sys/shim_exit.c b/LibOS/shim/src/sys/shim_exit.c index 0f60b57e..46eb4bbd 100644 --- a/LibOS/shim/src/sys/shim_exit.c +++ b/LibOS/shim/src/sys/shim_exit.c @@ -131,6 +131,8 @@ int try_process_exit (int error_code) { struct shim_thread * cur_thread = get_cur_thread(); + cur_thread->exit_code = -error_code; + if (cur_thread->in_vm) thread_exit(cur_thread, true); diff --git a/LibOS/shim/test/apps/ltp/PASSED b/LibOS/shim/test/apps/ltp/PASSED index 42dd1818..36086925 100644 --- a/LibOS/shim/test/apps/ltp/PASSED +++ b/LibOS/shim/test/apps/ltp/PASSED @@ -8,6 +8,7 @@ alarm02,3 clone01,1 clone03,1 clone04,1 +clone05,1 clone06,1 clone07,1 close02,1 diff --git a/LibOS/shim/test/apps/ltp/README b/LibOS/shim/test/apps/ltp/README new file mode 100644 index 00000000..602cac9d --- /dev/null +++ b/LibOS/shim/test/apps/ltp/README @@ -0,0 +1,29 @@ +LTP FOR GRAPHENE +---------------- + +Running LTP test cases in Graphene : +1) run 'make' in LibOS/shim/test/apps/ltp +2) cd Graphene/LibOS/shim/test/regression +3) make regression + +The above command will start running LTP system call test cases in Graphene. + +It works in 2 steps: +1) Creates a testfile (Graphene/LibOS/shim/test/apps/ltp/syscalls.graphene) with all the LTP system call test cases to run, excluding the ones mentioned in Graphene/LibOS/shim/test/apps/ltp/BLOCKED. “BLOCKED” contains all the test cases which are hanging in the Graphene and thus are excluded from regression tests. +2) Calls Graphene/LibOS/shim/test/apps/ltp/fetch.py It runs the LTP test cases and display output on the terminal. + Some LTP testcases hangs in Graphene. This python script sets a timeout for each testcase referring the file 'TIMEOUTS'. Default timeout is set 20 seconds in the script. + It also shows, ‘new passed testcases’ (passed testcases which are not in Graphene/LibOS/shim/test/apps/ltp/PASSED) and ‘new failed testcases’ (failed testcases which are in ‘PASSED’). +It also creates files ‘run_output’, ‘Failed.csv’, ‘Passed.csv’, ‘Blocked.csv’ under Graphene/LibOS/shim/test/apps/ltp for reference. +Results are of 4 types : +[Pass] -> Testcase passed +[Failed] -> Testcase failed +[Hanged] -> Testcase hanged and thereafter killed +[Broken] -> Either system call is not implemented in Graphene or test preparation failed + +To run one particular testcase, execute following : +1) cd LibOS/shim/test/native +2) ./pal /ltp/testcases/kernel/syscalls/alarm/alarm01 + +In this way, one can debug one particular syscall testcase, 'alarm01' in this case. + +As you fix bugs, keep updating PASSED BLOCKED lists. diff --git a/LibOS/shim/test/apps/ltp/TIMEOUTS b/LibOS/shim/test/apps/ltp/TIMEOUTS new file mode 100644 index 00000000..03c9ab1d --- /dev/null +++ b/LibOS/shim/test/apps/ltp/TIMEOUTS @@ -0,0 +1,4 @@ +testcase,timeout +clone05,30 +alarm01,5 +alarm06,16 diff --git a/LibOS/shim/test/apps/ltp/edit_sys_tests.awk b/LibOS/shim/test/apps/ltp/edit_sys_tests.awk new file mode 100644 index 00000000..448f6952 --- /dev/null +++ b/LibOS/shim/test/apps/ltp/edit_sys_tests.awk @@ -0,0 +1,28 @@ +#!/usr/bin/awk -f +BEGIN{ + while(getline < "BLOCKED") { + test = $1$2$3 + blocked[test] + } +} +NF && ! /^#/ { + test = $2$3 + if($1=="splice02") { + s = "./pal_loader" + for (i=2; i<=NF; i++) { + s = s " " $i + if($i=="|") { + i++ + s = s " ./pal_loader " $i + } + } + print s + } + else if(! (test in blocked)) { + s = "./pal_loader" + for (i=2; i<=NF; i++) { + s = s " " $i + } + print s + } +} diff --git a/LibOS/shim/test/apps/ltp/fetch.py b/LibOS/shim/test/apps/ltp/fetch.py new file mode 100644 index 00000000..88e71403 --- /dev/null +++ b/LibOS/shim/test/apps/ltp/fetch.py @@ -0,0 +1,131 @@ +import subprocess +import csv +import os +import threading +import time +import signal + +class RunCmd(threading.Thread): + def __init__(self, cmd, timeout, test): + threading.Thread.__init__(self) + self.cmd = cmd + self.timeout = int(timeout) + self.output = "" + self.test = test + + def run(self): + self.p = subprocess.Popen(self.cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=os.setsid) + self.output, error = self.p.communicate() + outt = self.output.split("\n") + for output in outt: + toks = output.split() + subtest = "1" + if output: + output = output.strip() + print >>f1, output + out = output.split( ) + if "TFAIL" in output: + subtest = str(toks[1]) + test_subtest = toks[0] + "," + subtest + print >>failed_tests_fh, test_subtest + if test_subtest not in current_failed: + print CRED + "[Fail ] " + self.test + "," + str(subtest) + CEND + current_failed[test_subtest] = 1 + elif "TPASS" in output: + subtest = toks[1] + test_subtest = toks[0] + "," + subtest + print >>passed_tests_fh, test_subtest + if test_subtest not in current_passed: + current_passed[test_subtest] = 1 + print CGREEN + "[Pass ] " + self.test + "," + str(subtest) + CEND + elif "TINFO" in output: + continue + elif "TCONF" in output or "TBROK" in output or "error" in output: + if toks[0] == "self.test": + subtest = str(toks[1]) + test_subtest = toks[0] + "," + subtest + print >>broken_tests_fh, toks[0] + "," + subtest + if test_subtest not in current_blocked and toks[0] not in current_hanged: + print "[Broken ] " + self.test + "," + str(subtest) #Syscall not implemented or test preparation failed + current_blocked[test_subtest] = 1 + #else: + # print "[Broken ] " + self.test #Syscall not implemented or test preparation failed + self.p.wait() + + def Run(self): + self.start() + self.join(self.timeout) + + if self.is_alive(): + os.killpg(os.getpgid(self.p.pid), signal.SIGTERM) + print CRED + "[Hanged ] " + self.test + CEND + current_hanged[self.test] = 1 + time.sleep(1) + +CRED = '\033[91m' +CGREEN = '\033[92m' +CEND = '\033[0m' +DEFAULT_TIMEOUT = 20 + +resultfile = "run_output" +stablePass = "PASSED" +timeouts = "TIMEOUTS" +failed_tests_file = "Failed.csv" +passed_tests_file = "Passed.csv" +broken_tests_file = "Broken.csv" + +f1 = open(resultfile, 'w') +failed_tests_fh = open(failed_tests_file, 'w', 0) +passed_tests_fh = open(passed_tests_file, 'w', 0) +broken_tests_fh = open(broken_tests_file, 'w', 0) + +failed_tests_fh.write("Test,Subtest number,Status\n") +passed_tests_fh.write("Test,Subtest number\n") +broken_tests_fh.write("Test,Subtest number,Status\n") + +current_passed = dict() +current_failed = dict() +current_blocked = dict() +current_hanged = dict() +timeouts_dict = dict() + +with open(timeouts, 'rb') as csvfile: + test_timeout = csv.reader(csvfile) + test_timeout.next() + for row in test_timeout: + test = row[0] + timeout = row[1] + timeouts_dict[test] = timeout + +os.chdir("opt/ltp/testcases/bin") +with open('../../../../syscalls.graphene') as testcases: + for line in testcases: + tokens = line.split( ) + test = tokens[1] + if test=="seq": + test = tokens[6] #splice02 + try: + timeout = timeouts_dict[test] + except KeyError: + timeout = DEFAULT_TIMEOUT + RunCmd([line], timeout, test).Run() +os.chdir("../../../..") + +stable_passed = dict() +with open(stablePass, 'rb') as csvfile: + test_subtest = csv.reader(csvfile) + test_subtest.next() + for row in test_subtest: + tst = row[0] + "," + row[1] + stable_passed[tst] = 1 + +print "\n\nRESULT [Difference] :\n---------------------\n" + +for test in stable_passed: + if not test in current_passed: + print CRED + "Test '" + test + "' did not pass in the current run!!" + CEND + +for test in current_passed: + if not test in stable_passed: + print CGREEN + "Test '" + test + "' passed in the current run!!" + CEND +print "\n" \ No newline at end of file diff --git a/LibOS/shim/test/apps/ltp/run_in_graphene.awk b/LibOS/shim/test/apps/ltp/run_in_graphene.awk index 881367e4..678dc46c 100755 --- a/LibOS/shim/test/apps/ltp/run_in_graphene.awk +++ b/LibOS/shim/test/apps/ltp/run_in_graphene.awk @@ -20,7 +20,7 @@ # # Chia-Che Tsai, Fall 2016 # -NF && ! /^#/ { +NF && ! /^#/ && ! /epoll/ { s=$1 "_graphene ./pal_loader" for (i = 2; i <= NF; i++) { s = s " " $i diff --git a/LibOS/shim/test/apps/ltp/syscalls.sh b/LibOS/shim/test/apps/ltp/syscalls.sh new file mode 100755 index 00000000..659bc655 --- /dev/null +++ b/LibOS/shim/test/apps/ltp/syscalls.sh @@ -0,0 +1,6 @@ +#!/bin/sh +cd `dirname $0` +export LTPROOT=$PWD"/opt/ltp" +awk -f edit_sys_tests.awk $LTPROOT/runtest/syscalls > syscalls.graphene +cd $LTPROOT/../.. +python fetch.py diff --git a/LibOS/shim/test/regression/Makefile b/LibOS/shim/test/regression/Makefile index 64cb9ca9..31655f87 100644 --- a/LibOS/shim/test/regression/Makefile +++ b/LibOS/shim/test/regression/Makefile @@ -49,7 +49,8 @@ regression: $(target) @for f in $(wildcard 00_*.py); do env $(PYTHONENV) python $$f; done @echo "\n\nLarge File Support:" @for f in $(wildcard 90_*.py); do env $(PYTHONENV) python $$f; done - @echo "\n\n" + @echo "\n\nLTP tests for system calls:" + ../apps/ltp/syscalls.sh clean-tmp: - rm -rf *.tmp + rm -rf *.tmp ../apps/ltp/*.csv