Coverage Report

Created: 2025-08-26 06:58

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