1 : /*
2 : * Copyright 2009 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 : /*
7 : * Mac OSX thread priority support.
8 : */
9 :
10 : #include <mach/mach_init.h>
11 : #include <mach/mach_time.h>
12 : #include <mach/thread_policy.h>
13 : #include <mach/thread_act.h>
14 : #include <pthread.h>
15 :
16 : #include "native_client/src/shared/platform/nacl_log.h"
17 : #include "native_client/src/trusted/service_runtime/include/sys/nacl_nice.h"
18 :
19 : /* MyConvertToHostTime converts nanoseconds to the time base used by MacOS.
20 : * Typically the time base is nanoseconds, and the conversion is trivial.
21 : * To avoid having to drag in the entire CoreAudio framework just for this
22 : * subroutine, it is reimplemented here in terms of mach_timebase_info which
23 : * is in the MacOS core.
24 : * To understand that this implementation is correct, have a look at
25 : * CAHostTimeBase::ConvertFromNanos(uint64 inNanos) in CAHostTimeBase.h
26 : */
27 : static struct mach_timebase_info gTimeBase;
28 : void NaClThreadNiceInit(void) {
29 275 : if (mach_timebase_info(&gTimeBase) != KERN_SUCCESS) {
30 0 : NaClLog(LOG_WARNING, "mach_timebase_info failed\n");
31 0 : gTimeBase.numer = 1;
32 0 : gTimeBase.denom = 1;
33 0 : }
34 275 : if (gTimeBase.denom == 0) {
35 0 : NaClLog(LOG_WARNING, "mach_timebase_info returned bogus result\n");
36 0 : gTimeBase.numer = 1;
37 0 : gTimeBase.denom = 1;
38 0 : }
39 275 : }
40 :
41 0 : static uint64_t MyConvertToHostTime(uint64_t nanos) {
42 0 : double math_tmp = 0.0;
43 :
44 0 : math_tmp = gTimeBase.numer;
45 0 : math_tmp *= nanos;
46 0 : math_tmp /= gTimeBase.denom;
47 0 : return (uint64_t)math_tmp;
48 : }
49 :
50 0 : int nacl_thread_nice(int nacl_nice) {
51 0 : kern_return_t kr;
52 :
53 : /*
54 : * Don't use mach_thread_self() because it requires a separate
55 : * mach_port_deallocate() system call to release it. Instead, rely on
56 : * pthread's cached copy of the port.
57 : */
58 0 : thread_act_t mthread = pthread_mach_thread_np(pthread_self());
59 :
60 0 : switch (nacl_nice) {
61 : case NICE_REALTIME: {
62 0 : struct thread_time_constraint_policy tcpolicy;
63 0 : const int kPeriodInNanoseconds = 2902490;
64 0 : const float kDutyCycle = 0.5;
65 0 : const float kDutyMax = 0.85;
66 0 : tcpolicy.period = MyConvertToHostTime(kPeriodInNanoseconds);
67 0 : tcpolicy.computation = kDutyCycle * tcpolicy.period;
68 0 : tcpolicy.constraint = kDutyMax * tcpolicy.period;
69 0 : tcpolicy.preemptible = 1;
70 : /* Sadly it appears that a MacOS system can be locked up by too
71 : * many real-time threads. So use normal priority until we figure
72 : * out a way to control things globally.
73 : */
74 : /* kr = thread_policy_set(mthread, THREAD_TIME_CONSTRAINT_POLICY,
75 : * (thread_policy_t)&tcpolicy,
76 : * THREAD_TIME_CONSTRAINT_POLICY_COUNT);
77 : */
78 0 : kr = thread_policy_set(mthread, THREAD_PRECEDENCE_POLICY,
79 : (thread_policy_t)&tcpolicy,
80 : THREAD_PRECEDENCE_POLICY_COUNT);
81 : }
82 0 : break;
83 : case NICE_BACKGROUND: {
84 0 : struct thread_precedence_policy tppolicy;
85 0 : tppolicy.importance = 0; /* IDLE_PRI */
86 0 : kr = thread_policy_set(mthread, THREAD_PRECEDENCE_POLICY,
87 : (thread_policy_t)&tppolicy,
88 : THREAD_PRECEDENCE_POLICY_COUNT);
89 : }
90 0 : break;
91 : case NICE_NORMAL: {
92 0 : struct thread_standard_policy tspolicy;
93 0 : kr = thread_policy_set(mthread, THREAD_STANDARD_POLICY,
94 : (thread_policy_t)&tspolicy,
95 : THREAD_STANDARD_POLICY_COUNT);
96 : }
97 0 : break;
98 : default:
99 0 : NaClLog(LOG_WARNING, "nacl_thread_nice() failed (bad nice value).\n");
100 0 : return -1;
101 : break;
102 : }
103 0 : if (kr != KERN_SUCCESS) {
104 0 : NaClLog(LOG_WARNING, "nacl_thread_nice() failed.\n");
105 0 : return -1;
106 : } else {
107 0 : return 0;
108 : }
109 0 : }
|