2 * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
29 #include <sys/resource.h>
31 #include <sys/errno.h>
34 #include <mach/mach.h>
35 #include <mach/task_policy.h>
38 #include <spawn_private.h>
39 #include <sys/spawn_internal.h>
41 #define QOS_PARAMETER_LATENCY 0
42 #define QOS_PARAMETER_THROUGHPUT 1
44 extern char **environ
;
46 static void usage(void);
47 static int parse_disk_policy(const char *strpolicy
);
48 static int parse_qos_tier(const char *strpolicy
, int parameter
);
49 static uint64_t parse_qos_clamp(const char *qos_string
);
51 int main(int argc
, char * argv
[])
55 posix_spawnattr_t attr
;
56 extern char **environ
;
57 bool flagx
= false, flagX
= false, flagb
= false, flagB
= false, flaga
= false;
58 int flagd
= -1, flagg
= -1;
59 struct task_qos_policy qosinfo
= { LATENCY_QOS_TIER_UNSPECIFIED
, THROUGHPUT_QOS_TIER_UNSPECIFIED
};
60 uint64_t qos_clamp
= POSIX_SPAWN_PROC_CLAMP_NONE
;
62 while ((ch
= getopt(argc
, argv
, "xXbBd:g:c:t:l:p:a")) != -1) {
77 flagd
= parse_disk_policy(optarg
);
79 warnx("Could not parse '%s' as a disk policy", optarg
);
84 flagg
= parse_disk_policy(optarg
);
86 warnx("Could not parse '%s' as a disk policy", optarg
);
91 qos_clamp
= parse_qos_clamp(optarg
);
92 if (qos_clamp
== POSIX_SPAWN_PROC_CLAMP_NONE
) {
93 warnx("Could not parse '%s' as a QoS clamp", optarg
);
98 qosinfo
.task_throughput_qos_tier
= parse_qos_tier(optarg
, QOS_PARAMETER_THROUGHPUT
);
99 if (qosinfo
.task_throughput_qos_tier
== -1) {
100 warnx("Could not parse '%s' as a qos tier", optarg
);
105 qosinfo
.task_latency_qos_tier
= parse_qos_tier(optarg
, QOS_PARAMETER_LATENCY
);
106 if (qosinfo
.task_latency_qos_tier
== -1) {
107 warnx("Could not parse '%s' as a qos tier", optarg
);
114 warnx("Invalid pid '%s' specified", optarg
);
129 if (pid
== 0 && argc
== 0) {
133 if (pid
!= 0 && (flagx
|| flagX
|| flagg
!= -1 || flagd
!= -1)) {
134 warnx("Incompatible option(s) used with -p");
139 warnx("Incompatible options -x, -X");
143 if (flagb
&& flagB
) {
144 warnx("Incompatible options -b, -B");
148 if (flagB
&& pid
== 0) {
149 warnx("The -B option can only be used with the -p option");
154 ret
= setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY
, IOPOL_SCOPE_PROCESS
, IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE
);
156 err(EX_SOFTWARE
, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
161 ret
= setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY
, IOPOL_SCOPE_PROCESS
, IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT
);
163 err(EX_SOFTWARE
, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
168 ret
= setpriority(PRIO_DARWIN_PROCESS
, pid
, PRIO_DARWIN_BG
);
170 err(EX_SOFTWARE
, "setpriority()");
175 ret
= setpriority(PRIO_DARWIN_PROCESS
, pid
, 0);
177 err(EX_SOFTWARE
, "setpriority()");
182 ret
= setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, flagd
);
184 err(EX_SOFTWARE
, "setiopolicy_np(...IOPOL_SCOPE_PROCESS...)");
189 ret
= setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_DARWIN_BG
, flagg
);
191 err(EX_SOFTWARE
, "setiopolicy_np(...IOPOL_SCOPE_DARWIN_BG...)");
195 if (qosinfo
.task_latency_qos_tier
!= LATENCY_QOS_TIER_UNSPECIFIED
||
196 qosinfo
.task_throughput_qos_tier
!= THROUGHPUT_QOS_TIER_UNSPECIFIED
){
199 ret
= task_for_pid(mach_task_self(), pid
, &task
);
200 if (ret
!= KERN_SUCCESS
) {
201 err(EX_SOFTWARE
, "task_for_pid(%d) failed", pid
);
205 task
= mach_task_self();
207 ret
= task_policy_set((task_t
)task
, TASK_OVERRIDE_QOS_POLICY
, (task_policy_t
)&qosinfo
, TASK_QOS_POLICY_COUNT
);
208 if (ret
!= KERN_SUCCESS
){
209 err(EX_SOFTWARE
, "task_policy_set(...TASK_OVERRIDE_QOS_POLICY...)");
216 ret
= posix_spawnattr_init(&attr
);
217 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_init");
219 ret
= posix_spawnattr_setflags(&attr
, POSIX_SPAWN_SETEXEC
);
220 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_setflags");
222 if (qos_clamp
!= POSIX_SPAWN_PROC_CLAMP_NONE
) {
223 ret
= posix_spawnattr_set_qos_clamp_np(&attr
, qos_clamp
);
224 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_set_qos_clamp_np");
228 ret
= posix_spawnattr_setprocesstype_np(&attr
, POSIX_SPAWN_PROC_TYPE_APP_DEFAULT
);
229 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_setprocesstype_np");
231 ret
= posix_spawnattr_set_darwin_role_np(&attr
, PRIO_DARWIN_ROLE_UI
);
232 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_set_darwin_role_np");
235 ret
= posix_spawnp(&pid
, argv
[0], NULL
, &attr
, argv
, environ
);
236 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawn");
241 static void usage(void)
243 fprintf(stderr
, "Usage: %s [-x|-X] [-d <policy>] [-g policy] [-c clamp] [-b] [-t <tier>]\n"
244 " [-l <tier>] [-a] <program> [<pargs> [...]]\n", getprogname());
245 fprintf(stderr
, " %s [-b|-B] [-t <tier>] [-l <tier>] -p pid\n", getprogname());
249 static int parse_disk_policy(const char *strpolicy
)
254 /* first try as an integer */
255 policy
= strtol(strpolicy
, &endptr
, 0);
256 if (endptr
&& (endptr
[0] == '\0') && (strpolicy
[0] != '\0')) {
257 /* parsed complete string as a number */
261 if (0 == strcasecmp(strpolicy
, "DEFAULT") ) {
262 return IOPOL_DEFAULT
;
263 } else if (0 == strcasecmp(strpolicy
, "IMPORTANT")) {
264 return IOPOL_IMPORTANT
;
265 } else if (0 == strcasecmp(strpolicy
, "PASSIVE")) {
266 return IOPOL_PASSIVE
;
267 } else if (0 == strcasecmp(strpolicy
, "THROTTLE")) {
268 return IOPOL_THROTTLE
;
269 } else if (0 == strcasecmp(strpolicy
, "UTILITY")) {
270 return IOPOL_UTILITY
;
271 } else if (0 == strcasecmp(strpolicy
, "STANDARD")) {
272 return IOPOL_STANDARD
;
278 static int parse_qos_tier(const char *strtier
, int parameter
){
282 /* first try as an integer */
283 policy
= strtol(strtier
, &endptr
, 0);
284 if (endptr
&& (endptr
[0] == '\0') && (strtier
[0] != '\0')) {
287 return parameter
? THROUGHPUT_QOS_TIER_0
: LATENCY_QOS_TIER_0
;
290 return parameter
? THROUGHPUT_QOS_TIER_1
: LATENCY_QOS_TIER_1
;
293 return parameter
? THROUGHPUT_QOS_TIER_2
: LATENCY_QOS_TIER_2
;
296 return parameter
? THROUGHPUT_QOS_TIER_3
: LATENCY_QOS_TIER_3
;
299 return parameter
? THROUGHPUT_QOS_TIER_4
: LATENCY_QOS_TIER_4
;
302 return parameter
? THROUGHPUT_QOS_TIER_5
: LATENCY_QOS_TIER_5
;
313 static uint64_t parse_qos_clamp(const char *qos_string
) {
315 if (0 == strcasecmp(qos_string
, "utility") ) {
316 return POSIX_SPAWN_PROC_CLAMP_UTILITY
;
317 } else if (0 == strcasecmp(qos_string
, "background")) {
318 return POSIX_SPAWN_PROC_CLAMP_BACKGROUND
;
319 } else if (0 == strcasecmp(qos_string
, "maintenance")) {
320 return POSIX_SPAWN_PROC_CLAMP_MAINTENANCE
;
322 return POSIX_SPAWN_PROC_CLAMP_NONE
;