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