Coverage Report

Created: 2025-07-18 07:03

/src/bind9/lib/isc/os.c
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
}