Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
5 | | * |
6 | | * This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, you can obtain one at https://mozilla.org/MPL/2.0/. |
9 | | * |
10 | | * See the COPYRIGHT file distributed with this work for additional |
11 | | * information regarding copyright ownership. |
12 | | */ |
13 | | |
14 | | #include <inttypes.h> |
15 | | #include <sys/stat.h> |
16 | | |
17 | | #include <isc/os.h> |
18 | | #include <isc/types.h> |
19 | | #include <isc/util.h> |
20 | | #include <isc/uv.h> |
21 | | |
22 | | #include "os_p.h" |
23 | | |
24 | | static unsigned int isc__os_ncpus = 0; |
25 | | static unsigned long isc__os_cacheline = ISC_OS_CACHELINE_SIZE; |
26 | | static mode_t isc__os_umask = 0; |
27 | | |
28 | | /* |
29 | | * The affinity support for non-Linux is in the review in the upstream |
30 | | * yet, but will be included in the upcoming version of libuv. |
31 | | */ |
32 | | #if (UV_VERSION_HEX >= UV_VERSION(1, 44, 0) && defined(__linux__)) || \ |
33 | | UV_VERSION_HEX > UV_VERSION(1, 48, 0) |
34 | | |
35 | | static void |
36 | | ncpus_initialize(void) { |
37 | | isc__os_ncpus = uv_available_parallelism(); |
38 | | } |
39 | | |
40 | | #else /* UV_VERSION_HEX >= UV_VERSION(1, 44, 0) */ |
41 | | |
42 | | #include <sys/param.h> /* for NetBSD */ |
43 | | #if HAVE_SYS_SYSCTL_H && !defined(__linux__) |
44 | | #include <sys/sysctl.h> |
45 | | #endif |
46 | | #include <sys/types.h> /* for OpenBSD */ |
47 | | #include <unistd.h> |
48 | | |
49 | | static int |
50 | 0 | sysconf_ncpus(void) { |
51 | 0 | long ncpus = sysconf(_SC_NPROCESSORS_ONLN); |
52 | 0 | return (int)ncpus; |
53 | 0 | } |
54 | | |
55 | | #if HAVE_SYSCTLBYNAME |
56 | | static int |
57 | | sysctlbyname_ncpus(void) { |
58 | | int ncpu; |
59 | | size_t len = sizeof(ncpu); |
60 | | static const char *mib[] = { |
61 | | "hw.activecpu", |
62 | | "hw.logicalcpu", |
63 | | "hw.ncpu", |
64 | | }; |
65 | | |
66 | | for (size_t i = 0; i < ARRAY_SIZE(mib); i++) { |
67 | | int r = sysctlbyname(mib[i], &ncpu, &len, NULL, 0); |
68 | | if (r != -1) { |
69 | | return ncpu; |
70 | | } |
71 | | } |
72 | | return -1; |
73 | | } |
74 | | #endif /* HAVE_SYSCTLBYNAME */ |
75 | | |
76 | | #if HAVE_SYS_SYSCTL_H && !defined(__linux__) |
77 | | static int |
78 | | sysctl_ncpus(void) { |
79 | | int ncpu; |
80 | | size_t len = sizeof(ncpu); |
81 | | static int mib[][2] = { |
82 | | #ifdef HW_NCPUONLINE |
83 | | { CTL_HW, HW_NCPUONLINE }, |
84 | | #endif |
85 | | { CTL_HW, HW_NCPU }, |
86 | | }; |
87 | | |
88 | | for (size_t i = 0; i < ARRAY_SIZE(mib); i++) { |
89 | | int r = sysctl(mib[i], ARRAY_SIZE(mib[i]), &ncpu, &len, NULL, |
90 | | 0); |
91 | | if (r != -1) { |
92 | | return ncpu; |
93 | | } |
94 | | } |
95 | | return -1; |
96 | | } |
97 | | #endif /* HAVE_SYS_SYSCTL_H */ |
98 | | |
99 | | #if defined(HAVE_SCHED_GETAFFINITY) |
100 | | #include <sched.h> |
101 | | |
102 | | /* |
103 | | * Administrators may wish to constrain the set of cores that BIND runs |
104 | | * on via the 'taskset' or 'numactl' programs (or equivalent on other |
105 | | * O/S), for example to achieve higher (or more stable) performance by |
106 | | * more closely associating threads with individual NIC rx queues. If |
107 | | * the admin has used taskset, it follows that BIND ought to |
108 | | * automatically use the given number of CPUs rather than the system |
109 | | * wide count. |
110 | | */ |
111 | | static int |
112 | 22 | sched_affinity_ncpus(void) { |
113 | 22 | cpu_set_t cpus; |
114 | 22 | int r = sched_getaffinity(0, sizeof(cpus), &cpus); |
115 | 22 | if (r != -1) { |
116 | 22 | return CPU_COUNT(&cpus); |
117 | 22 | } |
118 | 0 | return -1; |
119 | 22 | } |
120 | | #endif |
121 | | |
122 | | /* |
123 | | * Affinity detecting variant of sched_affinity_cpus() for FreeBSD |
124 | | */ |
125 | | #if defined(HAVE_CPUSET_GETAFFINITY) |
126 | | #include <sys/cpuset.h> |
127 | | #include <sys/param.h> |
128 | | |
129 | | static int |
130 | | cpuset_affinity_ncpus(void) { |
131 | | cpuset_t cpus; |
132 | | int r = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, |
133 | | sizeof(cpus), &cpus); |
134 | | if (r != -1) { |
135 | | return CPU_COUNT(&cpus); |
136 | | } |
137 | | return -1; |
138 | | } |
139 | | #endif |
140 | | |
141 | | static void |
142 | 22 | ncpus_initialize(void) { |
143 | | #if defined(HAVE_CPUSET_GETAFFINITY) |
144 | | if (isc__os_ncpus <= 0) { |
145 | | isc__os_ncpus = cpuset_affinity_ncpus(); |
146 | | } |
147 | | #endif |
148 | 22 | #if defined(HAVE_SCHED_GETAFFINITY) |
149 | 22 | if (isc__os_ncpus <= 0) { |
150 | 22 | isc__os_ncpus = sched_affinity_ncpus(); |
151 | 22 | } |
152 | 22 | #endif |
153 | | #if HAVE_SYSCTLBYNAME |
154 | | if (isc__os_ncpus <= 0) { |
155 | | isc__os_ncpus = sysctlbyname_ncpus(); |
156 | | } |
157 | | #endif |
158 | | #if HAVE_SYS_SYSCTL_H && !defined(__linux__) |
159 | | if (isc__os_ncpus <= 0) { |
160 | | isc__os_ncpus = sysctl_ncpus(); |
161 | | } |
162 | | #endif |
163 | 22 | if (isc__os_ncpus <= 0) { |
164 | 0 | isc__os_ncpus = sysconf_ncpus(); |
165 | 0 | } |
166 | 22 | if (isc__os_ncpus <= 0) { |
167 | 0 | isc__os_ncpus = 1; |
168 | 0 | } |
169 | 22 | } |
170 | | |
171 | | #endif /* UV_VERSION_HEX >= UV_VERSION(1, 38, 0) */ |
172 | | |
173 | | static void |
174 | 22 | umask_initialize(void) { |
175 | 22 | isc__os_umask = umask(0); |
176 | 22 | (void)umask(isc__os_umask); |
177 | 22 | } |
178 | | |
179 | | unsigned int |
180 | 22 | isc_os_ncpus(void) { |
181 | 22 | return isc__os_ncpus; |
182 | 22 | } |
183 | | |
184 | | unsigned long |
185 | 0 | isc_os_cacheline(void) { |
186 | 0 | return isc__os_cacheline; |
187 | 0 | } |
188 | | |
189 | | mode_t |
190 | 0 | isc_os_umask(void) { |
191 | 0 | return isc__os_umask; |
192 | 0 | } |
193 | | |
194 | | void |
195 | 22 | isc__os_initialize(void) { |
196 | 22 | umask_initialize(); |
197 | 22 | ncpus_initialize(); |
198 | 22 | #if defined(_SC_LEVEL1_DCACHE_LINESIZE) |
199 | 22 | long s = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
200 | 22 | if (s > 0 && (unsigned long)s > isc__os_cacheline) { |
201 | 0 | isc__os_cacheline = s; |
202 | 0 | } |
203 | 22 | #endif |
204 | 22 | } |
205 | | |
206 | | void |
207 | 0 | isc__os_shutdown(void) { |
208 | 0 | /* empty, but defined for completeness */; |
209 | 0 | } |