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@
25 #include <System/sys/proc.h>
30 #include <sys/resource.h>
32 #include <sys/errno.h>
35 #include <mach/mach.h>
36 #include <mach/task_policy.h>
39 #include <spawn_private.h>
40 #include <sys/spawn_internal.h>
42 #define QOS_PARAMETER_LATENCY 0
43 #define QOS_PARAMETER_THROUGHPUT 1
45 extern char **environ
;
47 static void usage(void);
48 static int parse_disk_policy(const char *strpolicy
);
49 static int parse_qos_tier(const char *strpolicy
, int parameter
);
50 static uint64_t parse_qos_clamp(const char *qos_string
);
52 int main(int argc
, char * argv
[])
56 posix_spawnattr_t attr
;
57 extern char **environ
;
58 bool flagx
= false, flagX
= false, flagb
= false, flagB
= false, flaga
= false;
59 int flagd
= -1, flagg
= -1;
60 struct task_qos_policy qosinfo
= { LATENCY_QOS_TIER_UNSPECIFIED
, THROUGHPUT_QOS_TIER_UNSPECIFIED
};
61 uint64_t qos_clamp
= POSIX_SPAWN_PROC_CLAMP_NONE
;
63 while ((ch
= getopt(argc
, argv
, "xXbBd:g:c:t:l:p:a")) != -1) {
78 flagd
= parse_disk_policy(optarg
);
80 warnx("Could not parse '%s' as a disk policy", optarg
);
85 flagg
= parse_disk_policy(optarg
);
87 warnx("Could not parse '%s' as a disk policy", optarg
);
92 qos_clamp
= parse_qos_clamp(optarg
);
93 if (qos_clamp
== POSIX_SPAWN_PROC_CLAMP_NONE
) {
94 warnx("Could not parse '%s' as a QoS clamp", optarg
);
99 qosinfo
.task_throughput_qos_tier
= parse_qos_tier(optarg
, QOS_PARAMETER_THROUGHPUT
);
100 if (qosinfo
.task_throughput_qos_tier
== -1) {
101 warnx("Could not parse '%s' as a qos tier", optarg
);
106 qosinfo
.task_latency_qos_tier
= parse_qos_tier(optarg
, QOS_PARAMETER_LATENCY
);
107 if (qosinfo
.task_latency_qos_tier
== -1) {
108 warnx("Could not parse '%s' as a qos tier", optarg
);
115 warnx("Invalid pid '%s' specified", optarg
);
130 if (pid
== 0 && argc
== 0) {
134 if (pid
!= 0 && (flagx
|| flagX
|| flagg
!= -1 || flagd
!= -1)) {
135 warnx("Incompatible option(s) used with -p");
140 warnx("Incompatible options -x, -X");
144 if (flagb
&& flagB
) {
145 warnx("Incompatible options -b, -B");
149 if (flagB
&& pid
== 0) {
150 warnx("The -B option can only be used with the -p option");
155 ret
= setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY
, IOPOL_SCOPE_PROCESS
, IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE
);
157 err(EX_SOFTWARE
, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
162 ret
= setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY
, IOPOL_SCOPE_PROCESS
, IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT
);
164 err(EX_SOFTWARE
, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
169 ret
= setpriority(PRIO_DARWIN_PROCESS
, pid
, PRIO_DARWIN_BG
);
171 err(EX_SOFTWARE
, "setpriority()");
176 ret
= setpriority(PRIO_DARWIN_PROCESS
, pid
, 0);
178 err(EX_SOFTWARE
, "setpriority()");
183 ret
= setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, flagd
);
185 err(EX_SOFTWARE
, "setiopolicy_np(...IOPOL_SCOPE_PROCESS...)");
190 ret
= setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_DARWIN_BG
, flagg
);
192 err(EX_SOFTWARE
, "setiopolicy_np(...IOPOL_SCOPE_DARWIN_BG...)");
196 if (qosinfo
.task_latency_qos_tier
!= LATENCY_QOS_TIER_UNSPECIFIED
||
197 qosinfo
.task_throughput_qos_tier
!= THROUGHPUT_QOS_TIER_UNSPECIFIED
){
200 ret
= task_name_for_pid(mach_task_self(), pid
, &task
);
201 if (ret
!= KERN_SUCCESS
) {
202 err(EX_SOFTWARE
, "task_name_for_pid(%d) failed", pid
);
206 task
= mach_task_self();
208 ret
= task_policy_set((task_t
)task
, TASK_OVERRIDE_QOS_POLICY
, (task_policy_t
)&qosinfo
, TASK_QOS_POLICY_COUNT
);
209 if (ret
!= KERN_SUCCESS
){
210 err(EX_SOFTWARE
, "task_policy_set(...TASK_OVERRIDE_QOS_POLICY...)");
217 ret
= posix_spawnattr_init(&attr
);
218 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_init");
220 ret
= posix_spawnattr_setflags(&attr
, POSIX_SPAWN_SETEXEC
);
221 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_setflags");
223 if (qos_clamp
!= POSIX_SPAWN_PROC_CLAMP_NONE
) {
224 ret
= posix_spawnattr_set_qos_clamp_np(&attr
, qos_clamp
);
225 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_set_qos_clamp_np");
229 ret
= posix_spawnattr_setprocesstype_np(&attr
, POSIX_SPAWN_PROC_TYPE_APP_DEFAULT
);
230 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_setprocesstype_np");
232 ret
= posix_spawnattr_set_darwin_role_np(&attr
, PRIO_DARWIN_ROLE_UI
);
233 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawnattr_set_darwin_role_np");
236 ret
= posix_spawnp(&pid
, argv
[0], NULL
, &attr
, argv
, environ
);
237 if (ret
!= 0) errc(EX_NOINPUT
, ret
, "posix_spawn");
242 static void usage(void)
244 fprintf(stderr
, "Usage: %s [-x|-X] [-d <policy>] [-g policy] [-c clamp] [-b] [-t <tier>]\n"
245 " [-l <tier>] [-a] <program> [<pargs> [...]]\n", getprogname());
246 fprintf(stderr
, " %s [-b|-B] [-t <tier>] [-l <tier>] -p pid\n", getprogname());
250 static int parse_disk_policy(const char *strpolicy
)
255 /* first try as an integer */
256 policy
= strtol(strpolicy
, &endptr
, 0);
257 if (endptr
&& (endptr
[0] == '\0') && (strpolicy
[0] != '\0')) {
258 /* parsed complete string as a number */
262 if (0 == strcasecmp(strpolicy
, "DEFAULT") ) {
263 return IOPOL_DEFAULT
;
264 } else if (0 == strcasecmp(strpolicy
, "IMPORTANT")) {
265 return IOPOL_IMPORTANT
;
266 } else if (0 == strcasecmp(strpolicy
, "PASSIVE")) {
267 return IOPOL_PASSIVE
;
268 } else if (0 == strcasecmp(strpolicy
, "THROTTLE")) {
269 return IOPOL_THROTTLE
;
270 } else if (0 == strcasecmp(strpolicy
, "UTILITY")) {
271 return IOPOL_UTILITY
;
272 } else if (0 == strcasecmp(strpolicy
, "STANDARD")) {
273 return IOPOL_STANDARD
;
279 static int parse_qos_tier(const char *strtier
, int parameter
){
283 /* first try as an integer */
284 policy
= strtol(strtier
, &endptr
, 0);
285 if (endptr
&& (endptr
[0] == '\0') && (strtier
[0] != '\0')) {
288 return parameter
? THROUGHPUT_QOS_TIER_0
: LATENCY_QOS_TIER_0
;
291 return parameter
? THROUGHPUT_QOS_TIER_1
: LATENCY_QOS_TIER_1
;
294 return parameter
? THROUGHPUT_QOS_TIER_2
: LATENCY_QOS_TIER_2
;
297 return parameter
? THROUGHPUT_QOS_TIER_3
: LATENCY_QOS_TIER_3
;
300 return parameter
? THROUGHPUT_QOS_TIER_4
: LATENCY_QOS_TIER_4
;
303 return parameter
? THROUGHPUT_QOS_TIER_5
: LATENCY_QOS_TIER_5
;
314 static uint64_t parse_qos_clamp(const char *qos_string
) {
316 if (0 == strcasecmp(qos_string
, "utility") ) {
317 return POSIX_SPAWN_PROC_CLAMP_UTILITY
;
318 } else if (0 == strcasecmp(qos_string
, "background")) {
319 return POSIX_SPAWN_PROC_CLAMP_BACKGROUND
;
320 } else if (0 == strcasecmp(qos_string
, "maintenance")) {
321 return POSIX_SPAWN_PROC_CLAMP_MAINTENANCE
;
323 return POSIX_SPAWN_PROC_CLAMP_NONE
;