1 /*
2 * Copyright (c) 2004 Ulrich Drepper <drepper@redhat.com>
3 * Copyright (c) 2005 Roland McGrath <roland@redhat.com>
4 * Copyright (c) 2012-2015 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2014-2023 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: LGPL-2.1-or-later
9 */
10
11 #include "defs.h"
12
13 #include <sched.h>
14 #include "sched_attr.h"
15
16 #include "xlat/schedulers.h"
17 #include "xlat/sched_flags.h"
18
19 SYS_FUNC(sched_getscheduler)
20 {
21 if (entering(tcp)) {
22 /* pid */
23 printpid(tcp, tcp->u_arg[0], PT_TGID);
24 } else if (!syserror(tcp)) {
25 tcp->auxstr = xlookup(schedulers, (kernel_ulong_t) tcp->u_rval);
26 return RVAL_STR;
27 }
28 return 0;
29 }
30
31 SYS_FUNC(sched_setscheduler)
32 {
33 /* pid */
34 printpid(tcp, tcp->u_arg[0], PT_TGID);
35 tprint_arg_next();
36
37 /* policy */
38 printxval(schedulers, tcp->u_arg[1], "SCHED_???");
39 tprint_arg_next();
40
41 /* param */
42 printnum_int(tcp, tcp->u_arg[2], "%d");
43
44 return RVAL_DECODED;
45 }
46
47 SYS_FUNC(sched_getparam)
48 {
49 if (entering(tcp)) {
50 /* pid */
51 printpid(tcp, tcp->u_arg[0], PT_TGID);
52 tprint_arg_next();
53 } else {
54 /* param */
55 printnum_int(tcp, tcp->u_arg[1], "%d");
56 }
57 return 0;
58 }
59
60 SYS_FUNC(sched_setparam)
61 {
62 /* pid */
63 printpid(tcp, tcp->u_arg[0], PT_TGID);
64 tprint_arg_next();
65
66 /* param */
67 printnum_int(tcp, tcp->u_arg[1], "%d");
68
69 return RVAL_DECODED;
70 }
71
72 SYS_FUNC(sched_get_priority_min)
73 {
74 /* policy */
75 printxval(schedulers, tcp->u_arg[0], "SCHED_???");
76
77 return RVAL_DECODED;
78 }
79
80 static int
81 do_sched_rr_get_interval(struct tcb *const tcp,
82 const print_obj_by_addr_fn print_ts)
83 {
84 if (entering(tcp)) {
85 /* pid */
86 printpid(tcp, tcp->u_arg[0], PT_TGID);
87 tprint_arg_next();
88 } else {
89 /* tp */
90 if (syserror(tcp))
91 printaddr(tcp->u_arg[1]);
92 else
93 print_ts(tcp, tcp->u_arg[1]);
94 }
95 return 0;
96 }
97
98 #if HAVE_ARCH_TIME32_SYSCALLS
99 SYS_FUNC(sched_rr_get_interval_time32)
100 {
101 return do_sched_rr_get_interval(tcp, print_timespec32);
102 }
103 #endif
104
105 SYS_FUNC(sched_rr_get_interval_time64)
106 {
107 return do_sched_rr_get_interval(tcp, print_timespec64);
108 }
109
110 static void
111 print_sched_attr(struct tcb *const tcp, const kernel_ulong_t addr,
112 unsigned int usize)
113 {
114 struct sched_attr attr = {};
115 unsigned int size;
116 bool is_set = false;
117
118 if (usize) {
119 /* called from sched_getattr */
120 size = usize <= sizeof(attr) ? usize : (unsigned) sizeof(attr);
121 if (umoven_or_printaddr(tcp, addr, size, &attr))
122 return;
123 /* the number of bytes written by the kernel */
124 size = attr.size;
125 } else {
126 /* called from sched_setattr */
127 is_set = true;
128
129 if (umove_or_printaddr(tcp, addr, &attr.size))
130 return;
131 usize = attr.size;
132 if (!usize)
133 usize = SCHED_ATTR_MIN_SIZE;
134 size = usize <= sizeof(attr) ? usize : (unsigned) sizeof(attr);
135 if (size >= SCHED_ATTR_MIN_SIZE) {
136 if (umoven_or_printaddr(tcp, addr, size, &attr))
137 return;
138 }
139 }
140
141 tprint_struct_begin();
142 PRINT_FIELD_U(attr, size);
143
144 if (size < SCHED_ATTR_MIN_SIZE)
145 goto end;
146
147 if (!is_set || (int)attr.sched_policy < 0 || !(attr.sched_flags & (SCHED_FLAG_KEEP_POLICY | SCHED_FLAG_KEEP_PARAMS))) {
148 tprint_struct_next();
149 PRINT_FIELD_XVAL(attr, sched_policy, schedulers,
150 "SCHED_???");
151 }
152 tprint_struct_next();
153 PRINT_FIELD_FLAGS(attr, sched_flags, sched_flags, "SCHED_FLAG_???");
154
155
156 if (!is_set || !(attr.sched_flags & SCHED_FLAG_KEEP_PARAMS)) {
157 tprint_struct_next();
158 PRINT_FIELD_D(attr, sched_nice);
159 tprint_struct_next();
160 PRINT_FIELD_U(attr, sched_priority);
161 tprint_struct_next();
162 PRINT_FIELD_U(attr, sched_runtime);
163 tprint_struct_next();
164 PRINT_FIELD_U(attr, sched_deadline);
165 tprint_struct_next();
166 PRINT_FIELD_U(attr, sched_period);
167 }
168
169 if (size < SCHED_ATTR_SIZE_VER1)
170 goto end;
171
172 tprint_struct_next();
173 PRINT_FIELD_U(attr, sched_util_min);
174 tprint_struct_next();
175 PRINT_FIELD_U(attr, sched_util_max);
176
177 end:
178 if ((is_set ? usize : attr.size) > size) {
179 tprint_struct_next();
180 tprint_more_data_follows();
181 }
182
183 tprint_struct_end();
184 }
185
186 SYS_FUNC(sched_setattr)
187 {
188 if (entering(tcp)) {
189 /* pid */
190 printpid(tcp, tcp->u_arg[0], PT_TGID);
191 tprint_arg_next();
192
193 /* attr */
194 print_sched_attr(tcp, tcp->u_arg[1], 0);
195 } else {
196 struct sched_attr attr;
197
198 if (verbose(tcp) && tcp->u_error == E2BIG
199 && umove(tcp, tcp->u_arg[1], &attr.size) == 0) {
200 tprint_value_changed();
201 tprint_struct_begin();
202 PRINT_FIELD_U(attr, size);
203 tprint_struct_end();
204 }
205 tprint_arg_next();
206
207 /* flags */
208 PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
209 }
210
211 return 0;
212 }
213
214 SYS_FUNC(sched_getattr)
215 {
216 if (entering(tcp)) {
217 /* pid */
218 printpid(tcp, tcp->u_arg[0], PT_TGID);
219 tprint_arg_next();
220 } else {
221 const unsigned int size = tcp->u_arg[2];
222
223 /* attr */
224 if (size)
225 print_sched_attr(tcp, tcp->u_arg[1], size);
226 else
227 printaddr(tcp->u_arg[1]);
228 tprint_arg_next();
229
230 /* size */
231 #ifdef AARCH64
232 /*
233 * Due to a subtle gcc bug that leads to miscompiled aarch64
234 * kernels, the 3rd argument of sched_getattr is not quite 32-bit
235 * as on other architectures. For more details see
236 * https://lists.strace.io/pipermail/strace-devel/2017-March/006085.html
237 */
238 if (syserror(tcp)) {
239 tprint_flags_begin();
240 print_abnormal_hi(tcp->u_arg[2]);
241 PRINT_VAL_U(size);
242 tprint_flags_end();
243 } else
244 #endif
245 {
246 PRINT_VAL_U(size);
247 }
248 tprint_arg_next();
249
250 /* flags */
251 PRINT_VAL_U((unsigned int) tcp->u_arg[3]);
252 }
253
254 return 0;
255 }