syscall_time: Handle by McKernel
refs: #1036 Change-Id: Ifa81b613c7ee8d95ae7cdf3dd54643f60526fa73
This commit is contained in:
committed by
Masamichi Takagi
parent
5e760db417
commit
c23bc8d401
@ -114,7 +114,7 @@ SYSCALL_HANDLED(160, setrlimit)
|
|||||||
SYSCALL_HANDLED(164, settimeofday)
|
SYSCALL_HANDLED(164, settimeofday)
|
||||||
SYSCALL_HANDLED(186, gettid)
|
SYSCALL_HANDLED(186, gettid)
|
||||||
SYSCALL_HANDLED(200, tkill)
|
SYSCALL_HANDLED(200, tkill)
|
||||||
SYSCALL_DELEGATED(201, time)
|
SYSCALL_HANDLED(201, time)
|
||||||
SYSCALL_HANDLED(202, futex)
|
SYSCALL_HANDLED(202, futex)
|
||||||
SYSCALL_HANDLED(203, sched_setaffinity)
|
SYSCALL_HANDLED(203, sched_setaffinity)
|
||||||
SYSCALL_HANDLED(204, sched_getaffinity)
|
SYSCALL_HANDLED(204, sched_getaffinity)
|
||||||
|
|||||||
@ -1719,6 +1719,11 @@ SYSCALL_DECLARE(arch_prctl)
|
|||||||
ihk_mc_syscall_arg1(ctx));
|
ihk_mc_syscall_arg1(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SYSCALL_DECLARE(time)
|
||||||
|
{
|
||||||
|
return time();
|
||||||
|
}
|
||||||
|
|
||||||
static int vdso_get_vdso_info(void)
|
static int vdso_get_vdso_info(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
@ -2683,10 +2688,20 @@ out:
|
|||||||
time_t time(void) {
|
time_t time(void) {
|
||||||
struct syscall_request sreq IHK_DMA_ALIGN;
|
struct syscall_request sreq IHK_DMA_ALIGN;
|
||||||
struct thread *thread = cpu_local_var(current);
|
struct thread *thread = cpu_local_var(current);
|
||||||
time_t ret;
|
struct timespec ats;
|
||||||
sreq.number = __NR_time;
|
time_t ret = 0;
|
||||||
sreq.args[0] = (uintptr_t)NULL;
|
|
||||||
ret = (time_t)do_syscall(&sreq, ihk_mc_get_processor_id(), thread->proc->pid);
|
if (gettime_local_support) {
|
||||||
|
calculate_time_from_tsc(&ats);
|
||||||
|
ret = ats.tv_sec;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sreq.number = __NR_time;
|
||||||
|
sreq.args[0] = (uintptr_t)NULL;
|
||||||
|
ret = (time_t)do_syscall(&sreq, ihk_mc_get_processor_id(),
|
||||||
|
thread->proc->pid);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,51 +31,6 @@ struct tod_data_s tod_data
|
|||||||
.version = IHK_ATOMIC64_INIT(0),
|
.version = IHK_ATOMIC64_INIT(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void cpu_pause_for_vsyscall(void)
|
|
||||||
{
|
|
||||||
asm volatile ("pause" ::: "memory");
|
|
||||||
return;
|
|
||||||
} /* cpu_pause_for_vsyscall() */
|
|
||||||
|
|
||||||
static inline void calculate_time_from_tsc(struct timespec *ts)
|
|
||||||
{
|
|
||||||
long ver;
|
|
||||||
unsigned long current_tsc;
|
|
||||||
__time_t sec_delta;
|
|
||||||
long ns_delta;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
while ((ver = ihk_atomic64_read(&tod_data.version)) & 1) {
|
|
||||||
/* settimeofday() is in progress */
|
|
||||||
cpu_pause_for_vsyscall();
|
|
||||||
}
|
|
||||||
rmb();
|
|
||||||
*ts = tod_data.origin;
|
|
||||||
rmb();
|
|
||||||
if (ver == ihk_atomic64_read(&tod_data.version)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* settimeofday() has intervened */
|
|
||||||
cpu_pause_for_vsyscall();
|
|
||||||
}
|
|
||||||
|
|
||||||
current_tsc = rdtsc();
|
|
||||||
sec_delta = current_tsc / tod_data.clocks_per_sec;
|
|
||||||
ns_delta = NS_PER_SEC * (current_tsc % tod_data.clocks_per_sec)
|
|
||||||
/ tod_data.clocks_per_sec;
|
|
||||||
/* calc. of ns_delta overflows if clocks_per_sec exceeds 18.44 GHz */
|
|
||||||
|
|
||||||
ts->tv_sec += sec_delta;
|
|
||||||
ts->tv_nsec += ns_delta;
|
|
||||||
if (ts->tv_nsec >= NS_PER_SEC) {
|
|
||||||
ts->tv_nsec -= NS_PER_SEC;
|
|
||||||
++ts->tv_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} /* calculate_time_from_tsc() */
|
|
||||||
|
|
||||||
int vsyscall_gettimeofday(struct timeval *tv, void *tz)
|
int vsyscall_gettimeofday(struct timeval *tv, void *tz)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|||||||
@ -484,6 +484,7 @@ int arch_setup_vdso(void);
|
|||||||
int arch_cpu_read_write_register(struct ihk_os_cpu_register *desc,
|
int arch_cpu_read_write_register(struct ihk_os_cpu_register *desc,
|
||||||
enum mcctrl_os_cpu_operation op);
|
enum mcctrl_os_cpu_operation op);
|
||||||
struct vm_range_numa_policy *vm_range_policy_search(struct process_vm *vm, uintptr_t addr);
|
struct vm_range_numa_policy *vm_range_policy_search(struct process_vm *vm, uintptr_t addr);
|
||||||
|
void calculate_time_from_tsc(struct timespec *ts);
|
||||||
time_t time(void);
|
time_t time(void);
|
||||||
long do_futex(int n, unsigned long arg0, unsigned long arg1,
|
long do_futex(int n, unsigned long arg0, unsigned long arg1,
|
||||||
unsigned long arg2, unsigned long arg3,
|
unsigned long arg2, unsigned long arg3,
|
||||||
|
|||||||
@ -114,7 +114,6 @@ char *syscall_name[] MCKERNEL_UNUSED = {
|
|||||||
|
|
||||||
static ihk_spinlock_t tod_data_lock = SPIN_LOCK_UNLOCKED;
|
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 unsigned long uti_desc; /* Address of struct uti_desc object in syscall_intercept.c */
|
||||||
static void calculate_time_from_tsc(struct timespec *ts);
|
|
||||||
|
|
||||||
void save_syscall_return_value(int num, unsigned long rc);
|
void save_syscall_return_value(int num, unsigned long rc);
|
||||||
extern long alloc_debugreg(struct thread *thread);
|
extern long alloc_debugreg(struct thread *thread);
|
||||||
@ -6954,7 +6953,7 @@ SYSCALL_DECLARE(get_cpu_id)
|
|||||||
return ihk_mc_get_processor_id();
|
return ihk_mc_get_processor_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculate_time_from_tsc(struct timespec *ts)
|
void calculate_time_from_tsc(struct timespec *ts)
|
||||||
{
|
{
|
||||||
long ver;
|
long ver;
|
||||||
unsigned long current_tsc;
|
unsigned long current_tsc;
|
||||||
|
|||||||
112
test/issues/1036/C1036.sh
Normal file
112
test/issues/1036/C1036.sh
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
if [ -f $HOME/mck_test_config ]; then
|
||||||
|
. $HOME/mck_test_config
|
||||||
|
else
|
||||||
|
BIN=
|
||||||
|
SBIN=
|
||||||
|
OSTEST=
|
||||||
|
LTP=
|
||||||
|
fi
|
||||||
|
BOOTPARAM="-c 1-7,9-15,17-23,25-31 -m 10G@0,10G@1 -r 1-7:0+9-15:8+17-23:16+25-31:24"
|
||||||
|
|
||||||
|
if [ "x$BINDIR" = x ];then
|
||||||
|
BINDIR="$BIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "x$SBINDIR" = x ];then
|
||||||
|
SBINDIR="$SBIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "x$OSTESTDIR" = x ]; then
|
||||||
|
OSTESTDIR="$OSTEST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "x$LTPDIR" = x ]; then
|
||||||
|
LTPDIR="$LTP/testcases"
|
||||||
|
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 [ ! -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 [ ! -x $BINDIR/mcexec ]; then
|
||||||
|
echo mcexec: not found >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
strace -f -c -o ./CT_001.strc $BINDIR/mcexec ./CT_001
|
||||||
|
|
||||||
|
tid=002
|
||||||
|
echo "*** CT_$tid start *******************************"
|
||||||
|
echo "* Check syscall_time is not delegated to mcexec"
|
||||||
|
echo "* Result of strace -f -c (expect time is NOT contained)"
|
||||||
|
cat ./CT_001.strc
|
||||||
|
|
||||||
|
grep -e "time$" ./CT_001.strc &> /dev/null
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
echo "*** CT_$tid: PASSED"
|
||||||
|
else
|
||||||
|
echo "*** CT_$tid: FAILED"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
tid=001
|
||||||
|
echo "*** LT_$tid start *******************************"
|
||||||
|
$BINDIR/mcexec $LTPDIR/bin/time01 2>&1 | tee ./LT_${tid}.txt
|
||||||
|
ok=`grep TPASS LT_${tid}.txt | wc -l`
|
||||||
|
ng=`grep TFAIL LT_${tid}.txt | wc -l`
|
||||||
|
if [ $ng = 0 ]; then
|
||||||
|
echo "*** LT_$tid: PASSED (ok:$ok)"
|
||||||
|
else
|
||||||
|
echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
tid=002
|
||||||
|
echo "*** LT_$tid start *******************************"
|
||||||
|
$BINDIR/mcexec $LTPDIR/bin/time02 2>&1 | tee ./LT_${tid}.txt
|
||||||
|
ok=`grep TPASS LT_${tid}.txt | wc -l`
|
||||||
|
ng=`grep TFAIL LT_${tid}.txt | wc -l`
|
||||||
|
if [ $ng = 0 ]; then
|
||||||
|
echo "*** LT_$tid: PASSED (ok:$ok)"
|
||||||
|
else
|
||||||
|
echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
tid=003
|
||||||
|
echo "*** LT_$tid start *******************************"
|
||||||
|
$BINDIR/mcexec $LTPDIR/bin/gettimeofday01 2>&1 | tee ./LT_${tid}.txt
|
||||||
|
ok=`grep TPASS LT_${tid}.txt | wc -l`
|
||||||
|
ng=`grep TFAIL LT_${tid}.txt | wc -l`
|
||||||
|
if [ $ng = 0 ]; then
|
||||||
|
echo "*** LT_$tid: PASSED (ok:$ok)"
|
||||||
|
else
|
||||||
|
echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
tid=004
|
||||||
|
echo "*** LT_$tid start *******************************"
|
||||||
|
$BINDIR/mcexec $LTPDIR/bin/gettimeofday02 2>&1 | tee ./LT_${tid}.txt
|
||||||
|
ok=`grep PASS LT_${tid}.txt | wc -l`
|
||||||
|
ng=`grep TFAIL LT_${tid}.txt | wc -l`
|
||||||
|
if [ $ng = 0 ]; then
|
||||||
|
echo "*** LT_$tid: PASSED (ok:$ok)"
|
||||||
|
else
|
||||||
|
echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
47
test/issues/1036/CT_001.c
Normal file
47
test/issues/1036/CT_001.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
#include "./test_chk.h"
|
||||||
|
|
||||||
|
#define TEST_NAME "CT_001"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
long sys_ret;
|
||||||
|
int ng_flag = 0;
|
||||||
|
|
||||||
|
printf("*** %s start *******************************\n", TEST_NAME);
|
||||||
|
|
||||||
|
/* get seconds since the Epoch by glibc time() */
|
||||||
|
now = time(NULL);
|
||||||
|
|
||||||
|
/* get seconds since the Epoch by syscall_time */
|
||||||
|
sys_ret = syscall(__NR_time, NULL);
|
||||||
|
|
||||||
|
if (now != sys_ret) {
|
||||||
|
/* check again only once */
|
||||||
|
now = time(NULL);
|
||||||
|
if (now != sys_ret) {
|
||||||
|
ng_flag = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("glibc time(): %ld seconds\n", now);
|
||||||
|
printf("sys_time : %ld seconds\n", sys_ret);
|
||||||
|
|
||||||
|
OKNG(ng_flag != 0, "check seconds since the Epoch");
|
||||||
|
printf("*** %s PASSED\n\n", TEST_NAME);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fn_fail:
|
||||||
|
|
||||||
|
printf("*** %s FAILED\n\n", TEST_NAME);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
17
test/issues/1036/Makefile
Normal file
17
test/issues/1036/Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
CC = gcc
|
||||||
|
TARGET=CT_001
|
||||||
|
|
||||||
|
CPPFLAGS =
|
||||||
|
LDFLAGS =
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
CT_001: CT_001.c
|
||||||
|
$(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test: all
|
||||||
|
@sh ./C1036.sh
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET) *.o
|
||||||
|
|
||||||
38
test/issues/1036/README
Normal file
38
test/issues/1036/README
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
【Issue#1036 動作確認】
|
||||||
|
□ テスト内容
|
||||||
|
1. Issueで報告された要望が実現されていることの確認
|
||||||
|
CT_001: timeシステムコールで取得される秒数の確認
|
||||||
|
timeシステムコールで取得された秒数と、glibcのtime()関数で
|
||||||
|
取得された秒数が等しいことを確認する
|
||||||
|
CT_002: timeシステムコールがLinuxに移譲されないことを確認
|
||||||
|
straceコマンドを用いて、mcexecがtimeシステムコールを
|
||||||
|
呼び出していないことを確認する
|
||||||
|
|
||||||
|
2. 既存のtime機能に影響がないことをLTPを用いて確認
|
||||||
|
LT_001: ltp-syscall_time01
|
||||||
|
time(2)の基本動作の確認
|
||||||
|
LT_002: ltp-syscall_time02
|
||||||
|
time(2)の返り値と、引数に指定した領域に格納される値が一致することを確認
|
||||||
|
LT_003: ltp-syscall_gettimeofday01
|
||||||
|
不正な引数を指定してgettimeofday(2)を実行した場合、エラー値が返り、
|
||||||
|
errnoにEFAULTが設定されることを確認
|
||||||
|
LT_004: ltp-syscall_gettimeofday02
|
||||||
|
gettimeofday(2)で取得される時刻が増加し続けることを確認する
|
||||||
|
|
||||||
|
□ 実行手順
|
||||||
|
McKernelのインストール先や、OSTEST, LTPの配置場所は、
|
||||||
|
$HOME/mck_test_config を参照している
|
||||||
|
mck_test_config は、McKernelをビルドした際に生成される
|
||||||
|
mck_test_config.sample ファイルを$HOMEにコピーし、適宜編集する
|
||||||
|
|
||||||
|
$ make test
|
||||||
|
|
||||||
|
実行できない場合は、C1036.shの以下の行を適切に書き換えた後に実行。
|
||||||
|
BIN= mcexec が存在するパス
|
||||||
|
SBIN= mcreboot.sh が存在するパス
|
||||||
|
OSTEST= OSTESTが存在するパス
|
||||||
|
LTP= LTPが存在するパス
|
||||||
|
|
||||||
|
□ 実行結果
|
||||||
|
result.log 参照。
|
||||||
|
すべての項目をPASSしていることを確認。
|
||||||
73
test/issues/1036/result.log
Normal file
73
test/issues/1036/result.log
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
*** CT_001 start *******************************
|
||||||
|
glibc time(): 1536804078 seconds
|
||||||
|
sys_time : 1536804078 seconds
|
||||||
|
[OK] check seconds since the Epoch
|
||||||
|
*** CT_001 PASSED
|
||||||
|
|
||||||
|
*** CT_002 start *******************************
|
||||||
|
* Check syscall_time is not delegated to mcexec
|
||||||
|
* Result of strace -f -c (expect time is NOT contained)
|
||||||
|
% time seconds usecs/call calls errors syscall
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
58.26 0.033991 1133 30 futex
|
||||||
|
31.92 0.018621 71 264 ioctl
|
||||||
|
4.48 0.002614 7 392 356 open
|
||||||
|
1.44 0.000839 6 146 108 stat
|
||||||
|
0.84 0.000491 5 97 mmap
|
||||||
|
0.80 0.000468 6 81 read
|
||||||
|
0.51 0.000299 5 66 mprotect
|
||||||
|
0.26 0.000151 5 32 set_robust_list
|
||||||
|
0.21 0.000120 4 30 gettid
|
||||||
|
0.19 0.000110 3 35 fstat
|
||||||
|
0.17 0.000099 3 33 close
|
||||||
|
0.14 0.000079 16 5 3 access
|
||||||
|
0.12 0.000071 2 30 clone
|
||||||
|
0.10 0.000057 3 19 getrlimit
|
||||||
|
0.08 0.000048 5 10 munmap
|
||||||
|
0.07 0.000043 0 122 rt_sigaction
|
||||||
|
0.06 0.000033 7 5 write
|
||||||
|
0.05 0.000032 6 5 1 openat
|
||||||
|
0.05 0.000027 3 9 lseek
|
||||||
|
0.05 0.000027 3 8 getdents
|
||||||
|
0.03 0.000019 3 6 brk
|
||||||
|
0.03 0.000018 4 5 personality
|
||||||
|
0.03 0.000017 17 1 mlock
|
||||||
|
0.03 0.000016 16 1 epoll_ctl
|
||||||
|
0.02 0.000011 6 2 execve
|
||||||
|
0.01 0.000007 7 1 pread
|
||||||
|
0.01 0.000007 4 2 arch_prctl
|
||||||
|
0.01 0.000006 6 1 lstat
|
||||||
|
0.01 0.000004 2 2 rt_sigprocmask
|
||||||
|
0.01 0.000004 4 1 getcwd
|
||||||
|
0.01 0.000004 2 2 sched_getaffinity
|
||||||
|
0.01 0.000003 3 1 getpgid
|
||||||
|
0.01 0.000003 2 2 set_tid_address
|
||||||
|
0.00 0.000000 0 1 epoll_create
|
||||||
|
0.00 0.000000 0 1 eventfd2
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
100.00 0.058339 1448 468 total
|
||||||
|
*** CT_002: PASSED
|
||||||
|
|
||||||
|
*** LT_001 start *******************************
|
||||||
|
time01 1 TPASS : time(0) returned 1536804078
|
||||||
|
*** LT_001: PASSED (ok:1)
|
||||||
|
|
||||||
|
*** LT_002 start *******************************
|
||||||
|
time02 1 TPASS : time() returned value 1536804078, stored value 1536804078 are same
|
||||||
|
*** LT_002: PASSED (ok:1)
|
||||||
|
|
||||||
|
*** LT_003 start *******************************
|
||||||
|
gettimeofday01 1 TPASS : gettimeofday(2) set the errno EFAULT correctly
|
||||||
|
*** LT_003: PASSED (ok:1)
|
||||||
|
|
||||||
|
*** LT_004 start *******************************
|
||||||
|
tst_test.c:934: INFO: Timeout per run is 0h 05m 00s
|
||||||
|
gettimeofday02.c:89: INFO: gettimeofday() called 7968855 times
|
||||||
|
gettimeofday02.c:90: PASS: gettimeofday() monotonous in 10 seconds
|
||||||
|
|
||||||
|
Summary:
|
||||||
|
passed 1
|
||||||
|
failed 0
|
||||||
|
skipped 0
|
||||||
|
warnings 0
|
||||||
|
*** LT_004: PASSED (ok:0)
|
||||||
23
test/issues/1036/test_chk.h
Normal file
23
test/issues/1036/test_chk.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef HEADER_TEST_CHK_H
|
||||||
|
#define HEADER_TEST_CHK_H
|
||||||
|
|
||||||
|
#define CHKANDJUMP(cond, ...) do {\
|
||||||
|
if (cond) {\
|
||||||
|
fprintf(stderr, " [NG] ");\
|
||||||
|
fprintf(stderr, __VA_ARGS__);\
|
||||||
|
fprintf(stderr, " failed\n");\
|
||||||
|
goto fn_fail;\
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define OKNG(cond, ...) do {\
|
||||||
|
if (cond) {\
|
||||||
|
CHKANDJUMP(cond, __VA_ARGS__);\
|
||||||
|
} else {\
|
||||||
|
fprintf(stdout, " [OK] ");\
|
||||||
|
fprintf(stdout, __VA_ARGS__);\
|
||||||
|
fprintf(stdout, "\n");\
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user