1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * Test PR_GET_TIMERSLACK and PR_SET_TIMERSLACK of prctl(2).
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * - Each thread has two associated timer slack values: a "default"
13f08c3bdfSopenharmony_ci *   value, and a "current" value. PR_SET_TIMERSLACK sets the "current"
14f08c3bdfSopenharmony_ci *   timer slack value for the calling thread.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * - When a new thread is created, the two timer slack values are made
17f08c3bdfSopenharmony_ci *   the same as the "current" value of the creating thread.
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci * - The maximum timer slack value is ULONG_MAX. On 32bit machines, it
20f08c3bdfSopenharmony_ci *   is a valid value(about 4s). On 64bit machines, it is about 500 years
21f08c3bdfSopenharmony_ci *   and no person will set this over 4s.  prctl return value is int, so
22f08c3bdfSopenharmony_ci *   we test themaximum value is INT_MAX.
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * - we also check current value via /proc/self/timerslack_ns if it is
25f08c3bdfSopenharmony_ci *   supported.
26f08c3bdfSopenharmony_ci */
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_ci#include <sys/prctl.h>
29f08c3bdfSopenharmony_ci#include <string.h>
30f08c3bdfSopenharmony_ci#include <stdio.h>
31f08c3bdfSopenharmony_ci#include <stdlib.h>
32f08c3bdfSopenharmony_ci#include <linux/limits.h>
33f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
34f08c3bdfSopenharmony_ci#include "lapi/prctl.h"
35f08c3bdfSopenharmony_ci#include "tst_test.h"
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci#define PROC_TIMERSLACK_PATH "/proc/self/timerslack_ns"
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cistatic void check_reset_timerslack(char *message);
40f08c3bdfSopenharmony_cistatic void check_get_timerslack(char *message, unsigned long value);
41f08c3bdfSopenharmony_cistatic void check_inherit_timerslack(char *message, unsigned long value);
42f08c3bdfSopenharmony_cistatic unsigned long origin_value;
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_cistatic struct tcase {
45f08c3bdfSopenharmony_ci	void (*func_check)();
46f08c3bdfSopenharmony_ci	unsigned long setvalue;
47f08c3bdfSopenharmony_ci	unsigned long expvalue;
48f08c3bdfSopenharmony_ci	char message[50];
49f08c3bdfSopenharmony_ci} tcases[] = {
50f08c3bdfSopenharmony_ci	{check_reset_timerslack, 0, 50000, "Reset"},
51f08c3bdfSopenharmony_ci	{check_get_timerslack, 1, 1, "Min"},
52f08c3bdfSopenharmony_ci	{check_get_timerslack, 70000, 70000, "Middle"},
53f08c3bdfSopenharmony_ci	{check_get_timerslack, INT_MAX, INT_MAX, "Max"},
54f08c3bdfSopenharmony_ci	{check_inherit_timerslack, 70000, 70000, "Child process"},
55f08c3bdfSopenharmony_ci};
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_cistatic int proc_flag = 1;
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_cistatic void check_reset_timerslack(char *message)
60f08c3bdfSopenharmony_ci{
61f08c3bdfSopenharmony_ci	check_get_timerslack(message, origin_value);
62f08c3bdfSopenharmony_ci}
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_cistatic void check_get_timerslack(char *message, unsigned long value)
65f08c3bdfSopenharmony_ci{
66f08c3bdfSopenharmony_ci	TEST(prctl(PR_GET_TIMERSLACK));
67f08c3bdfSopenharmony_ci	if ((unsigned long)TST_RET == value)
68f08c3bdfSopenharmony_ci		tst_res(TPASS, "%s prctl(PR_GET_TIMERSLACK) got %lu expectedly",
69f08c3bdfSopenharmony_ci				message, value);
70f08c3bdfSopenharmony_ci	else
71f08c3bdfSopenharmony_ci		tst_res(TFAIL, "%s prctl(PR_GET_TIMERSLACK) expected %lu got %lu",
72f08c3bdfSopenharmony_ci				message, value, TST_RET);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	if (proc_flag)
75f08c3bdfSopenharmony_ci		TST_ASSERT_INT(PROC_TIMERSLACK_PATH, value);
76f08c3bdfSopenharmony_ci}
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_cistatic void check_inherit_timerslack(char *message, unsigned long value)
79f08c3bdfSopenharmony_ci{
80f08c3bdfSopenharmony_ci	int pid;
81f08c3bdfSopenharmony_ci	unsigned long current_value;
82f08c3bdfSopenharmony_ci	unsigned long default_value;
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
85f08c3bdfSopenharmony_ci	if (pid == 0) {
86f08c3bdfSopenharmony_ci		current_value = prctl(PR_GET_TIMERSLACK);
87f08c3bdfSopenharmony_ci		prctl(PR_SET_TIMERSLACK, 0);
88f08c3bdfSopenharmony_ci		default_value = prctl(PR_GET_TIMERSLACK);
89f08c3bdfSopenharmony_ci		if (current_value == value && default_value == value)
90f08c3bdfSopenharmony_ci			tst_res(TPASS,
91f08c3bdfSopenharmony_ci				"%s two timer slack values are made the same as the current value(%lu) of the creating thread.",
92f08c3bdfSopenharmony_ci				message, value);
93f08c3bdfSopenharmony_ci		else
94f08c3bdfSopenharmony_ci			tst_res(TFAIL,
95f08c3bdfSopenharmony_ci				"%s current_value is %lu, default value is %lu, the parent current value is %lu",
96f08c3bdfSopenharmony_ci				message, current_value, default_value, value);
97f08c3bdfSopenharmony_ci	}
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_cistatic void verify_prctl(unsigned int n)
102f08c3bdfSopenharmony_ci{
103f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	TEST(prctl(PR_SET_TIMERSLACK, tc->setvalue));
106f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
107f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "prctl(PR_SET_TIMERSLACK, %lu) failed",
108f08c3bdfSopenharmony_ci					  tc->setvalue);
109f08c3bdfSopenharmony_ci		return;
110f08c3bdfSopenharmony_ci	}
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	tst_res(TPASS, "prctl(PR_SET_TIMERSLACK, %lu) succeed", tc->setvalue);
113f08c3bdfSopenharmony_ci	tc->func_check(tc->message, tc->expvalue);
114f08c3bdfSopenharmony_ci}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_cistatic void setup(void)
117f08c3bdfSopenharmony_ci{
118f08c3bdfSopenharmony_ci	if (access(PROC_TIMERSLACK_PATH, F_OK) == -1) {
119f08c3bdfSopenharmony_ci		tst_res(TCONF, "proc doesn't support timerslack_ns interface");
120f08c3bdfSopenharmony_ci		proc_flag = 0;
121f08c3bdfSopenharmony_ci	}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_ci	TEST(prctl(PR_GET_TIMERSLACK));
124f08c3bdfSopenharmony_ci	origin_value = TST_RET;
125f08c3bdfSopenharmony_ci	tst_res(TINFO, "current timerslack value is %lu", origin_value);
126f08c3bdfSopenharmony_ci}
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_cistatic struct tst_test test = {
129f08c3bdfSopenharmony_ci	.setup = setup,
130f08c3bdfSopenharmony_ci	.test = verify_prctl,
131f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
132f08c3bdfSopenharmony_ci	.forks_child = 1,
133f08c3bdfSopenharmony_ci};
134