blob: 9ddc9a7d8304dc0ed27ed9d2156824ad0db81e18 [file] [log] [blame]
/*
* 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,
};