Coverage Report

Created: 2026-06-07 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/os.c
Line
Count
Source
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 <ctype.h>
15
#include <inttypes.h>
16
#include <sys/stat.h>
17
#include <sys/utsname.h>
18
19
#include <isc/os.h>
20
#include <isc/string.h>
21
#include <isc/types.h>
22
#include <isc/util.h>
23
#include <isc/uv.h>
24
25
#include "os_p.h"
26
#include "thread_p.h"
27
28
static unsigned int isc__os_ncpus = 0;
29
static unsigned long isc__os_cacheline = ISC_OS_CACHELINE_SIZE;
30
static mode_t isc__os_umask = 0;
31
static int kernel_major = -1, kernel_minor = -1, kernel_patch = -1;
32
static char kernel_name[64];
33
34
/*
35
 * The affinity support for non-Linux is in the review in the upstream
36
 * yet, but will be included in the upcoming version of libuv.
37
 */
38
#if (UV_VERSION_HEX >= UV_VERSION(1, 44, 0) && defined(__linux__)) || \
39
  UV_VERSION_HEX > UV_VERSION(1, 48, 0)
40
41
static void
42
22
ncpus_initialize(void) {
43
22
  isc__os_ncpus = uv_available_parallelism();
44
22
}
45
46
#else /* UV_VERSION_HEX >= UV_VERSION(1, 44, 0) */
47
48
#include <sys/param.h> /* for NetBSD */
49
#if HAVE_SYS_SYSCTL_H && !defined(__linux__)
50
#include <sys/sysctl.h>
51
#endif
52
#include <sys/types.h> /* for OpenBSD */
53
#include <unistd.h>
54
55
static int
56
sysconf_ncpus(void) {
57
  long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
58
  return (int)ncpus;
59
}
60
61
#if HAVE_SYSCTLBYNAME
62
static int
63
sysctlbyname_ncpus(void) {
64
  int ncpu;
65
  size_t len = sizeof(ncpu);
66
  static const char *mib[] = {
67
    "hw.activecpu",
68
    "hw.logicalcpu",
69
    "hw.ncpu",
70
  };
71
72
  for (size_t i = 0; i < ARRAY_SIZE(mib); i++) {
73
    int r = sysctlbyname(mib[i], &ncpu, &len, NULL, 0);
74
    if (r != -1) {
75
      return ncpu;
76
    }
77
  }
78
  return -1;
79
}
80
#endif /* HAVE_SYSCTLBYNAME */
81
82
#if HAVE_SYS_SYSCTL_H && !defined(__linux__)
83
static int
84
sysctl_ncpus(void) {
85
  int ncpu;
86
  size_t len = sizeof(ncpu);
87
  static int mib[][2] = {
88
#ifdef HW_NCPUONLINE
89
    { CTL_HW, HW_NCPUONLINE },
90
#endif
91
    { CTL_HW, HW_NCPU },
92
  };
93
94
  for (size_t i = 0; i < ARRAY_SIZE(mib); i++) {
95
    int r = sysctl(mib[i], ARRAY_SIZE(mib[i]), &ncpu, &len, NULL,
96
             0);
97
    if (r != -1) {
98
      return ncpu;
99
    }
100
  }
101
  return -1;
102
}
103
#endif /* HAVE_SYS_SYSCTL_H */
104
105
#if defined(HAVE_SCHED_GETAFFINITY)
106
#include <sched.h>
107
108
/*
109
 * Administrators may wish to constrain the set of cores that BIND runs
110
 * on via the 'taskset' or 'numactl' programs (or equivalent on other
111
 * O/S), for example to achieve higher (or more stable) performance by
112
 * more closely associating threads with individual NIC rx queues. If
113
 * the admin has used taskset, it follows that BIND ought to
114
 * automatically use the given number of CPUs rather than the system
115
 * wide count.
116
 */
117
static int
118
sched_affinity_ncpus(void) {
119
  cpu_set_t cpus;
120
  int r = sched_getaffinity(0, sizeof(cpus), &cpus);
121
  if (r != -1) {
122
    return CPU_COUNT(&cpus);
123
  }
124
  return -1;
125
}
126
#endif
127
128
/*
129
 * Affinity detecting variant of sched_affinity_cpus() for FreeBSD
130
 */
131
#if defined(HAVE_CPUSET_GETAFFINITY)
132
#include <sys/cpuset.h>
133
#include <sys/param.h>
134
135
static int
136
cpuset_affinity_ncpus(void) {
137
  cpuset_t cpus;
138
  int r = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
139
           sizeof(cpus), &cpus);
140
  if (r != -1) {
141
    return CPU_COUNT(&cpus);
142
  }
143
  return -1;
144
}
145
#endif
146
147
static void
148
ncpus_initialize(void) {
149
#if defined(HAVE_CPUSET_GETAFFINITY)
150
  if (isc__os_ncpus <= 0) {
151
    isc__os_ncpus = cpuset_affinity_ncpus();
152
  }
153
#endif
154
#if defined(HAVE_SCHED_GETAFFINITY)
155
  if (isc__os_ncpus <= 0) {
156
    isc__os_ncpus = sched_affinity_ncpus();
157
  }
158
#endif
159
#if HAVE_SYSCTLBYNAME
160
  if (isc__os_ncpus <= 0) {
161
    isc__os_ncpus = sysctlbyname_ncpus();
162
  }
163
#endif
164
#if HAVE_SYS_SYSCTL_H && !defined(__linux__)
165
  if (isc__os_ncpus <= 0) {
166
    isc__os_ncpus = sysctl_ncpus();
167
  }
168
#endif
169
  if (isc__os_ncpus <= 0) {
170
    isc__os_ncpus = sysconf_ncpus();
171
  }
172
  if (isc__os_ncpus <= 0) {
173
    isc__os_ncpus = 1;
174
  }
175
}
176
177
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 38, 0) */
178
179
static void
180
22
umask_initialize(void) {
181
22
  isc__os_umask = umask(0);
182
22
  (void)umask(isc__os_umask);
183
22
}
184
185
static void
186
22
kernel_initialize(void) {
187
22
  struct utsname buffer;
188
189
22
  if (uname(&buffer) == -1) {
190
0
    return;
191
0
  }
192
193
22
  (void)sscanf(buffer.release, "%d.%d.%d", &kernel_major, &kernel_minor,
194
22
         &kernel_patch);
195
22
  (void)strlcpy(kernel_name, buffer.sysname, sizeof(kernel_name));
196
22
}
197
198
unsigned int
199
22
isc_os_ncpus(void) {
200
22
  return isc__os_ncpus;
201
22
}
202
203
unsigned long
204
0
isc_os_cacheline(void) {
205
0
  return isc__os_cacheline;
206
0
}
207
208
mode_t
209
0
isc_os_umask(void) {
210
0
  return isc__os_umask;
211
0
}
212
213
void
214
0
isc_os_kernel(char **name, int *major, int *minor, int *patch) {
215
0
  SET_IF_NOT_NULL(name, kernel_name)
216
0
  SET_IF_NOT_NULL(major, kernel_major);
217
0
  SET_IF_NOT_NULL(minor, kernel_minor);
218
0
  SET_IF_NOT_NULL(patch, kernel_patch);
219
0
}
220
221
void
222
22
isc__os_initialize(void) {
223
22
  umask_initialize();
224
22
  ncpus_initialize();
225
22
  kernel_initialize();
226
22
#if defined(_SC_LEVEL1_DCACHE_LINESIZE)
227
22
  long s = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
228
22
  if (s > 0 && (unsigned long)s > isc__os_cacheline) {
229
0
    isc__os_cacheline = s;
230
0
  }
231
22
#endif
232
233
22
  pthread_attr_init(&isc__thread_attr);
234
235
22
  size_t stacksize = isc_thread_getstacksize();
236
22
  if (stacksize != 0 && stacksize < THREAD_MINSTACKSIZE) {
237
0
    isc_thread_setstacksize(THREAD_MINSTACKSIZE);
238
0
  }
239
22
}
240
241
void
242
0
isc__os_shutdown(void) {
243
0
  pthread_attr_destroy(&isc__thread_attr);
244
0
}