| /* |
| * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd |
| * Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, |
| * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, |
| * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> |
| * Copyright (c) 2016 Linux Test Project |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it would be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include <limits.h> |
| |
| #include "lapi/syscalls.h" |
| #include "tst_sig_proc.h" |
| #include "tst_timer.h" |
| #include "tst_test.h" |
| |
| static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) |
| { |
| } |
| |
| enum test_type { |
| NORMAL, |
| SEND_SIGINT, |
| }; |
| |
| #define TYPE_NAME(x) .ttype = x, .desc = #x |
| |
| struct test_case { |
| clockid_t clk_id; /* clock_* clock type parameter */ |
| int ttype; /* test type (enum) */ |
| const char *desc; /* test description (name) */ |
| int flags; /* clock_nanosleep flags parameter */ |
| struct timespec rq; |
| int exp_ret; |
| int exp_err; |
| }; |
| |
| /* |
| * test status of errors on man page |
| * EINTR v (function was interrupted by a signal) |
| * EINVAL v (invalid tv_nsec, etc.) |
| */ |
| |
| static struct test_case tcase[] = { |
| { |
| TYPE_NAME(NORMAL), |
| .clk_id = CLOCK_REALTIME, |
| .flags = 0, |
| .rq = (struct timespec) {.tv_sec = 0, .tv_nsec = -1}, |
| .exp_ret = EINVAL, |
| .exp_err = 0, |
| }, |
| { |
| TYPE_NAME(NORMAL), |
| .clk_id = CLOCK_REALTIME, |
| .flags = 0, |
| .rq = (struct timespec) {.tv_sec = 0, .tv_nsec = 1000000000}, |
| .exp_ret = EINVAL, |
| .exp_err = 0, |
| }, |
| { |
| TYPE_NAME(NORMAL), |
| .clk_id = CLOCK_THREAD_CPUTIME_ID, |
| .flags = 0, |
| .rq = (struct timespec) {.tv_sec = 0, .tv_nsec = 500000000}, |
| .exp_ret = EINVAL, |
| .exp_err = 0, |
| }, |
| { |
| TYPE_NAME(SEND_SIGINT), |
| .clk_id = CLOCK_REALTIME, |
| .flags = 0, |
| .rq = (struct timespec) {.tv_sec = 10, .tv_nsec = 0}, |
| .exp_ret = EINTR, |
| .exp_err = 0, |
| }, |
| }; |
| |
| void setup(void) |
| { |
| SAFE_SIGNAL(SIGINT, sighandler); |
| } |
| |
| static void do_test(unsigned int i) |
| { |
| struct test_case *tc = &tcase[i]; |
| struct timespec rm = {0}; |
| pid_t pid = 0; |
| |
| tst_res(TINFO, "case %s", tc->desc); |
| |
| if (tc->ttype == SEND_SIGINT) |
| pid = create_sig_proc(SIGINT, 40, 500000); |
| |
| TEST(clock_nanosleep(tc->clk_id, tc->flags, &tc->rq, &rm)); |
| |
| if (pid) { |
| SAFE_KILL(pid, SIGTERM); |
| SAFE_WAIT(NULL); |
| } |
| |
| if (tc->ttype == SEND_SIGINT) { |
| long long expect_ms = tst_timespec_to_ms(tc->rq); |
| long long remain_ms = tst_timespec_to_ms(rm); |
| |
| tst_res(TINFO, "remain time: %lds %ldns", rm.tv_sec, rm.tv_nsec); |
| |
| if (!rm.tv_sec && !rm.tv_nsec) { |
| tst_res(TFAIL | TTERRNO, |
| "The clock_nanosleep() haven't updated" |
| " timestamp with remaining time"); |
| return; |
| } |
| |
| if (remain_ms > expect_ms) { |
| tst_res(TFAIL| TTERRNO, |
| "remaining time > requested time (%lld > %lld)", |
| remain_ms, expect_ms); |
| return; |
| } |
| } |
| |
| if (TEST_RETURN != tc->exp_ret) { |
| tst_res(TFAIL | TTERRNO, "returned %ld, expected %d," |
| " expected errno: %s (%d)", TEST_RETURN, |
| tc->exp_ret, tst_strerrno(tc->exp_err), tc->exp_err); |
| return; |
| } |
| |
| tst_res(TPASS, "returned %s (%ld)", |
| tst_strerrno(TEST_RETURN), TEST_RETURN); |
| } |
| |
| static struct tst_test test = { |
| .tcnt = ARRAY_SIZE(tcase), |
| .test = do_test, |
| .setup = setup, |
| .forks_child = 1, |
| }; |