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