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