VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/darwin/sched-darwin.cpp@ 92258

Last change on this file since 92258 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.0 KB
Line 
1/* $Id: sched-darwin.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - Scheduling, Darwin.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_THREAD
32#include <mach/thread_act.h>
33#include <mach/thread_policy.h>
34#include <mach/thread_info.h>
35#include <mach/host_info.h>
36#include <mach/mach_init.h>
37#include <mach/mach_host.h>
38#include <sched.h>
39#include <pthread.h>
40#include <limits.h>
41#include <errno.h>
42
43#include <iprt/thread.h>
44#include <iprt/log.h>
45#include <iprt/assert.h>
46#include <iprt/errcore.h>
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49#include "internal/sched.h"
50#include "internal/thread.h"
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * Configuration of one priority.
58 */
59typedef struct
60{
61 /** The priority. */
62 RTPROCPRIORITY enmPriority;
63 /** The name of this priority. */
64 const char *pszName;
65 /** Array scheduler attributes corresponding to each of the thread types. */
66 struct
67 {
68 /** For sanity include the array index. */
69 RTTHREADTYPE enmType;
70 /** The desired mach base_priority value. */
71 int iBasePriority;
72 /** The suggested priority value. (Same as iBasePriority seems to do the
73 * trick.) */
74 int iPriority;
75 } aTypes[RTTHREADTYPE_END];
76} PROCPRIORITY;
77
78
79/*********************************************************************************************************************************
80* Global Variables *
81*********************************************************************************************************************************/
82/**
83 * Array of static priority configurations.
84 *
85 * ASSUMES that pthread_setschedparam takes a sched_priority argument in the
86 * range 0..127, which is translated into mach base_priority 0..63 and mach
87 * importance -31..32 (among other things). We also ASSUMES SCHED_OTHER.
88 *
89 * The base_priority range can be checked with tstDarwinSched, we're assuming it's
90 * 0..63 for user processes.
91 *
92 * Further we observe that fseventsd and mds both run at (mach) priority 50,
93 * while Finder runs at 47. At priority 63 we find the dynamic pager, the login
94 * window, UserEventAgent, SystemUIServer and coreaudiod. We do not wish to upset the
95 * dynamic pager, UI or audio, but we wish for I/O to not be bothered by spotlight
96 * (mds/fseventsd).
97 */
98static const PROCPRIORITY g_aPriorities[] =
99{
100 {
101 RTPROCPRIORITY_DEFAULT, "Default",
102 {
103 { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
104 { RTTHREADTYPE_INFREQUENT_POLLER, 29, 29 },
105 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 30, 30 },
106 { RTTHREADTYPE_EMULATION, 31, 31 }, /* the default priority */
107 { RTTHREADTYPE_DEFAULT, 32, 32 },
108 { RTTHREADTYPE_GUI, 32, 32 },
109 { RTTHREADTYPE_MAIN_WORKER, 32, 32 },
110 { RTTHREADTYPE_VRDP_IO, 39, 39 },
111 { RTTHREADTYPE_DEBUGGER, 42, 42 },
112 { RTTHREADTYPE_MSG_PUMP, 47, 47 },
113 { RTTHREADTYPE_IO, 52, 52 },
114 { RTTHREADTYPE_TIMER, 55, 55 }
115 }
116 },
117 {
118 RTPROCPRIORITY_LOW, "Low",
119 {
120 { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
121 { RTTHREADTYPE_INFREQUENT_POLLER, 20, 20 },
122 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 22, 22 },
123 { RTTHREADTYPE_EMULATION, 24, 24 },
124 { RTTHREADTYPE_DEFAULT, 28, 28 },
125 { RTTHREADTYPE_GUI, 29, 29 },
126 { RTTHREADTYPE_MAIN_WORKER, 30, 30 },
127 { RTTHREADTYPE_VRDP_IO, 31, 31 },
128 { RTTHREADTYPE_DEBUGGER, 31, 31 },
129 { RTTHREADTYPE_MSG_PUMP, 31, 31 },
130 { RTTHREADTYPE_IO, 31, 31 },
131 { RTTHREADTYPE_TIMER, 31, 31 }
132 }
133 },
134 {
135 RTPROCPRIORITY_NORMAL, "Normal",
136 {
137 { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
138 { RTTHREADTYPE_INFREQUENT_POLLER, 29, 29 },
139 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 30, 30 },
140 { RTTHREADTYPE_EMULATION, 31, 31 }, /* the default priority */
141 { RTTHREADTYPE_DEFAULT, 32, 32 },
142 { RTTHREADTYPE_GUI, 32, 32 },
143 { RTTHREADTYPE_MAIN_WORKER, 32, 32 },
144 { RTTHREADTYPE_VRDP_IO, 39, 39 },
145 { RTTHREADTYPE_DEBUGGER, 42, 42 },
146 { RTTHREADTYPE_MSG_PUMP, 47, 47 },
147 { RTTHREADTYPE_IO, 52, 52 },
148 { RTTHREADTYPE_TIMER, 55, 55 }
149 }
150 },
151 {
152 RTPROCPRIORITY_HIGH, "High",
153 {
154 { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
155 { RTTHREADTYPE_INFREQUENT_POLLER, 30, 30 },
156 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 31, 31 },
157 { RTTHREADTYPE_EMULATION, 32, 32 },
158 { RTTHREADTYPE_DEFAULT, 40, 40 },
159 { RTTHREADTYPE_GUI, 41, 41 },
160 { RTTHREADTYPE_MAIN_WORKER, 43, 43 },
161 { RTTHREADTYPE_VRDP_IO, 45, 45 },
162 { RTTHREADTYPE_DEBUGGER, 47, 47 },
163 { RTTHREADTYPE_MSG_PUMP, 49, 49 },
164 { RTTHREADTYPE_IO, 57, 57 },
165 { RTTHREADTYPE_TIMER, 61, 61 }
166 }
167 },
168 /* last */
169 {
170 RTPROCPRIORITY_FLAT, "Flat",
171 {
172 { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
173 { RTTHREADTYPE_INFREQUENT_POLLER, 31, 31 },
174 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 31, 31 },
175 { RTTHREADTYPE_EMULATION, 31, 31 },
176 { RTTHREADTYPE_DEFAULT, 31, 31 },
177 { RTTHREADTYPE_GUI, 31, 31 },
178 { RTTHREADTYPE_MAIN_WORKER, 31, 31 },
179 { RTTHREADTYPE_VRDP_IO, 31, 31 },
180 { RTTHREADTYPE_DEBUGGER, 31, 31 },
181 { RTTHREADTYPE_MSG_PUMP, 31, 31 },
182 { RTTHREADTYPE_IO, 31, 31 },
183 { RTTHREADTYPE_TIMER, 31, 31 }
184 }
185 },
186};
187
188
189/**
190 * The dynamic default priority configuration.
191 *
192 * This can be recalulated at runtime depending on what the
193 * system allow us to do. Presently we don't do this as it seems
194 * Darwin generally lets us do whatever we want.
195 *
196 * @remarks this is the same as "Normal" above.
197 */
198static PROCPRIORITY g_aDefaultPriority =
199{
200 RTPROCPRIORITY_DEFAULT, "Default",
201 {
202 { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
203 { RTTHREADTYPE_INFREQUENT_POLLER, 29, 29 },
204 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 30, 30 },
205 { RTTHREADTYPE_EMULATION, 31, 31 }, /* the default priority */
206 { RTTHREADTYPE_DEFAULT, 32, 32 },
207 { RTTHREADTYPE_GUI, 32, 32 },
208 { RTTHREADTYPE_MAIN_WORKER, 32, 32 },
209 { RTTHREADTYPE_VRDP_IO, 39, 39 },
210 { RTTHREADTYPE_DEBUGGER, 42, 42 },
211 { RTTHREADTYPE_MSG_PUMP, 47, 47 },
212 { RTTHREADTYPE_IO, 52, 52 },
213 { RTTHREADTYPE_TIMER, 55, 55 }
214 }
215};
216
217
218/** Pointer to the current priority configuration. */
219static const PROCPRIORITY *g_pProcessPriority = &g_aDefaultPriority;
220
221
222/**
223 * Get's the priority information for the current thread.
224 *
225 * @returns The base priority
226 * @param pThread The thread to get it for. NULL for current.
227 */
228static int rtSchedDarwinGetBasePriority(PRTTHREADINT pThread)
229{
230 /* the base_priority. */
231 mach_msg_type_number_t Count = POLICY_TIMESHARE_INFO_COUNT;
232 struct policy_timeshare_info TSInfo = {0,0,0,0,0};
233 kern_return_t krc = thread_info(!pThread ? mach_thread_self() : pthread_mach_thread_np((pthread_t)pThread->Core.Key),
234 THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&TSInfo, &Count);
235 Assert(krc == KERN_SUCCESS); NOREF(krc);
236
237 return TSInfo.base_priority;
238}
239
240
241DECLHIDDEN(int) rtSchedNativeCalcDefaultPriority(RTTHREADTYPE enmType)
242{
243 Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
244
245 /*
246 * Get the current priority.
247 */
248 int iBasePriority = rtSchedDarwinGetBasePriority(NULL);
249 Assert(iBasePriority >= 0 && iBasePriority <= 63);
250
251 /*
252 * If it doesn't match the default, select the closest one from the table.
253 */
254 int offBest = RT_ABS(g_pProcessPriority->aTypes[enmType].iBasePriority - iBasePriority);
255 if (offBest)
256 {
257 for (unsigned i = 0; i < RT_ELEMENTS(g_aPriorities); i++)
258 {
259 int off = RT_ABS(g_aPriorities[i].aTypes[enmType].iBasePriority - iBasePriority);
260 if (off < offBest)
261 {
262 g_pProcessPriority = &g_aPriorities[i];
263 if (!off)
264 break;
265 offBest = off;
266 }
267 }
268 }
269
270 return VINF_SUCCESS;
271}
272
273
274DECLHIDDEN(int) rtProcNativeSetPriority(RTPROCPRIORITY enmPriority)
275{
276 Assert(enmPriority > RTPROCPRIORITY_INVALID && enmPriority < RTPROCPRIORITY_LAST);
277
278 /*
279 * No checks necessary, we assume we can set any priority in the user process range.
280 */
281 const PROCPRIORITY *pProcessPriority = &g_aDefaultPriority;
282 for (unsigned i = 0; i < RT_ELEMENTS(g_aPriorities); i++)
283 if (g_aPriorities[i].enmPriority == enmPriority)
284 {
285 pProcessPriority = &g_aPriorities[i];
286 break;
287 }
288 Assert(pProcessPriority != &g_aDefaultPriority);
289 ASMAtomicUoWritePtr(&g_pProcessPriority, pProcessPriority);
290
291 return VINF_SUCCESS;
292}
293
294
295DECLHIDDEN(int) rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
296{
297 Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
298 AssertMsg(g_pProcessPriority && g_pProcessPriority->aTypes[enmType].enmType == enmType,
299 ("enmType=%d entry=%d\n", enmType, g_pProcessPriority->aTypes[enmType].enmType));
300
301 /*
302 * Get the current policy and params first since there are
303 * opaque members in the param structure and we don't wish to
304 * change the policy.
305 */
306 int iSchedPolicy = SCHED_OTHER;
307 struct sched_param SchedParam = {0, {0,0,0,0} };
308 int err = pthread_getschedparam((pthread_t)pThread->Core.Key, &iSchedPolicy, &SchedParam);
309 if (!err)
310 {
311 int const iDesiredBasePriority = g_pProcessPriority->aTypes[enmType].iBasePriority;
312 int iPriority = g_pProcessPriority->aTypes[enmType].iPriority;
313
314 /*
315 * First try with the given pthread priority number.
316 * Then make adjustments in case we missed the desired base priority (interface
317 * changed or whatever - its using an obsolete mach api).
318 */
319 SchedParam.sched_priority = iPriority;
320 err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
321 if (!err)
322 {
323 int i = 0;
324 int iBasePriority = rtSchedDarwinGetBasePriority(pThread);
325
326 while ( !err
327 && iBasePriority < iDesiredBasePriority
328 && i++ < 256)
329 {
330 SchedParam.sched_priority = ++iPriority;
331 err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
332 iBasePriority = rtSchedDarwinGetBasePriority(pThread);
333 }
334
335 while ( !err
336 && iPriority > 0
337 && iBasePriority > iDesiredBasePriority
338 && i++ < 256)
339 {
340 SchedParam.sched_priority = --iPriority;
341 err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
342 iBasePriority = rtSchedDarwinGetBasePriority(pThread);
343 }
344
345 return VINF_SUCCESS;
346 }
347 }
348 int rc = RTErrConvertFromErrno(err);
349 AssertMsgRC(rc, ("rc=%Rrc err=%d iSchedPolicy=%d sched_priority=%d\n",
350 rc, err, iSchedPolicy, SchedParam.sched_priority));
351 return rc;
352}
353
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette