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