Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmlibuv/src/unix/darwin.c
3156 views
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
* Permission is hereby granted, free of charge, to any person obtaining a copy
3
* of this software and associated documentation files (the "Software"), to
4
* deal in the Software without restriction, including without limitation the
5
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6
* sell copies of the Software, and to permit persons to whom the Software is
7
* furnished to do so, subject to the following conditions:
8
*
9
* The above copyright notice and this permission notice shall be included in
10
* all copies or substantial portions of the Software.
11
*
12
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18
* IN THE SOFTWARE.
19
*/
20
21
#include "uv.h"
22
#include "internal.h"
23
24
#include <assert.h>
25
#include <stdint.h>
26
#include <errno.h>
27
28
#include <dlfcn.h>
29
#include <mach/mach.h>
30
#include <mach/mach_time.h>
31
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
32
#include <sys/resource.h>
33
#include <sys/sysctl.h>
34
#include <unistd.h> /* sysconf */
35
36
#include "darwin-stub.h"
37
38
static uv_once_t once = UV_ONCE_INIT;
39
static uint64_t (*time_func)(void);
40
static mach_timebase_info_data_t timebase;
41
42
typedef unsigned char UInt8;
43
44
int uv__platform_loop_init(uv_loop_t* loop) {
45
loop->cf_state = NULL;
46
47
if (uv__kqueue_init(loop))
48
return UV__ERR(errno);
49
50
return 0;
51
}
52
53
54
void uv__platform_loop_delete(uv_loop_t* loop) {
55
uv__fsevents_loop_delete(loop);
56
}
57
58
59
static void uv__hrtime_init_once(void) {
60
if (KERN_SUCCESS != mach_timebase_info(&timebase))
61
abort();
62
63
time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
64
if (time_func == NULL)
65
time_func = mach_absolute_time;
66
}
67
68
69
uint64_t uv__hrtime(uv_clocktype_t type) {
70
uv_once(&once, uv__hrtime_init_once);
71
return time_func() * timebase.numer / timebase.denom;
72
}
73
74
75
int uv_exepath(char* buffer, size_t* size) {
76
/* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
77
char abspath[PATH_MAX * 2 + 1];
78
char exepath[PATH_MAX + 1];
79
uint32_t exepath_size;
80
size_t abspath_size;
81
82
if (buffer == NULL || size == NULL || *size == 0)
83
return UV_EINVAL;
84
85
exepath_size = sizeof(exepath);
86
if (_NSGetExecutablePath(exepath, &exepath_size))
87
return UV_EIO;
88
89
if (realpath(exepath, abspath) != abspath)
90
return UV__ERR(errno);
91
92
abspath_size = strlen(abspath);
93
if (abspath_size == 0)
94
return UV_EIO;
95
96
*size -= 1;
97
if (*size > abspath_size)
98
*size = abspath_size;
99
100
memcpy(buffer, abspath, *size);
101
buffer[*size] = '\0';
102
103
return 0;
104
}
105
106
107
uint64_t uv_get_free_memory(void) {
108
vm_statistics_data_t info;
109
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
110
111
if (host_statistics(mach_host_self(), HOST_VM_INFO,
112
(host_info_t)&info, &count) != KERN_SUCCESS) {
113
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
114
}
115
116
return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
117
}
118
119
120
uint64_t uv_get_total_memory(void) {
121
uint64_t info;
122
int which[] = {CTL_HW, HW_MEMSIZE};
123
size_t size = sizeof(info);
124
125
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
126
return UV__ERR(errno);
127
128
return (uint64_t) info;
129
}
130
131
132
uint64_t uv_get_constrained_memory(void) {
133
return 0; /* Memory constraints are unknown. */
134
}
135
136
137
void uv_loadavg(double avg[3]) {
138
struct loadavg info;
139
size_t size = sizeof(info);
140
int which[] = {CTL_VM, VM_LOADAVG};
141
142
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
143
144
avg[0] = (double) info.ldavg[0] / info.fscale;
145
avg[1] = (double) info.ldavg[1] / info.fscale;
146
avg[2] = (double) info.ldavg[2] / info.fscale;
147
}
148
149
150
int uv_resident_set_memory(size_t* rss) {
151
mach_msg_type_number_t count;
152
task_basic_info_data_t info;
153
kern_return_t err;
154
155
count = TASK_BASIC_INFO_COUNT;
156
err = task_info(mach_task_self(),
157
TASK_BASIC_INFO,
158
(task_info_t) &info,
159
&count);
160
(void) &err;
161
/* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
162
* KERN_SUCCESS implies a libuv bug.
163
*/
164
assert(err == KERN_SUCCESS);
165
*rss = info.resident_size;
166
167
return 0;
168
}
169
170
171
int uv_uptime(double* uptime) {
172
time_t now;
173
struct timeval info;
174
size_t size = sizeof(info);
175
static int which[] = {CTL_KERN, KERN_BOOTTIME};
176
177
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
178
return UV__ERR(errno);
179
180
now = time(NULL);
181
*uptime = now - info.tv_sec;
182
183
return 0;
184
}
185
186
static int uv__get_cpu_speed(uint64_t* speed) {
187
/* IOKit */
188
void (*pIOObjectRelease)(io_object_t);
189
kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*);
190
CFMutableDictionaryRef (*pIOServiceMatching)(const char*);
191
kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t,
192
CFMutableDictionaryRef,
193
io_iterator_t*);
194
io_service_t (*pIOIteratorNext)(io_iterator_t);
195
CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t,
196
CFStringRef,
197
CFAllocatorRef,
198
IOOptionBits);
199
200
/* CoreFoundation */
201
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
202
const char*,
203
CFStringEncoding);
204
CFStringEncoding (*pCFStringGetSystemEncoding)(void);
205
UInt8 *(*pCFDataGetBytePtr)(CFDataRef);
206
CFIndex (*pCFDataGetLength)(CFDataRef);
207
void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*);
208
void (*pCFRelease)(CFTypeRef);
209
210
void* core_foundation_handle;
211
void* iokit_handle;
212
int err;
213
214
kern_return_t kr;
215
mach_port_t mach_port;
216
io_iterator_t it;
217
io_object_t service;
218
219
mach_port = 0;
220
221
err = UV_ENOENT;
222
core_foundation_handle = dlopen("/System/Library/Frameworks/"
223
"CoreFoundation.framework/"
224
"CoreFoundation",
225
RTLD_LAZY | RTLD_LOCAL);
226
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
227
"IOKit",
228
RTLD_LAZY | RTLD_LOCAL);
229
230
if (core_foundation_handle == NULL || iokit_handle == NULL)
231
goto out;
232
233
#define V(handle, symbol) \
234
do { \
235
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
236
if (p ## symbol == NULL) \
237
goto out; \
238
} \
239
while (0)
240
V(iokit_handle, IOMasterPort);
241
V(iokit_handle, IOServiceMatching);
242
V(iokit_handle, IOServiceGetMatchingServices);
243
V(iokit_handle, IOIteratorNext);
244
V(iokit_handle, IOObjectRelease);
245
V(iokit_handle, IORegistryEntryCreateCFProperty);
246
V(core_foundation_handle, CFStringCreateWithCString);
247
V(core_foundation_handle, CFStringGetSystemEncoding);
248
V(core_foundation_handle, CFDataGetBytePtr);
249
V(core_foundation_handle, CFDataGetLength);
250
V(core_foundation_handle, CFDataGetBytes);
251
V(core_foundation_handle, CFRelease);
252
#undef V
253
254
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
255
256
kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
257
assert(kr == KERN_SUCCESS);
258
CFMutableDictionaryRef classes_to_match
259
= pIOServiceMatching("IOPlatformDevice");
260
kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
261
assert(kr == KERN_SUCCESS);
262
service = pIOIteratorNext(it);
263
264
CFStringRef device_type_str = S("device_type");
265
CFStringRef clock_frequency_str = S("clock-frequency");
266
267
while (service != 0) {
268
CFDataRef data;
269
data = pIORegistryEntryCreateCFProperty(service,
270
device_type_str,
271
NULL,
272
0);
273
if (data) {
274
const UInt8* raw = pCFDataGetBytePtr(data);
275
if (strncmp((char*)raw, "cpu", 3) == 0 ||
276
strncmp((char*)raw, "processor", 9) == 0) {
277
CFDataRef freq_ref;
278
freq_ref = pIORegistryEntryCreateCFProperty(service,
279
clock_frequency_str,
280
NULL,
281
0);
282
if (freq_ref) {
283
const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
284
CFIndex len = pCFDataGetLength(freq_ref);
285
if (len == 8)
286
memcpy(speed, freq_ref_ptr, 8);
287
else if (len == 4) {
288
uint32_t v;
289
memcpy(&v, freq_ref_ptr, 4);
290
*speed = v;
291
} else {
292
*speed = 0;
293
}
294
295
pCFRelease(freq_ref);
296
pCFRelease(data);
297
break;
298
}
299
}
300
pCFRelease(data);
301
}
302
303
service = pIOIteratorNext(it);
304
}
305
306
pIOObjectRelease(it);
307
308
err = 0;
309
310
if (device_type_str != NULL)
311
pCFRelease(device_type_str);
312
if (clock_frequency_str != NULL)
313
pCFRelease(clock_frequency_str);
314
315
out:
316
if (core_foundation_handle != NULL)
317
dlclose(core_foundation_handle);
318
319
if (iokit_handle != NULL)
320
dlclose(iokit_handle);
321
322
mach_port_deallocate(mach_task_self(), mach_port);
323
324
return err;
325
}
326
327
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
328
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
329
multiplier = ((uint64_t)1000L / ticks);
330
char model[512];
331
size_t size;
332
unsigned int i;
333
natural_t numcpus;
334
mach_msg_type_number_t msg_type;
335
processor_cpu_load_info_data_t *info;
336
uv_cpu_info_t* cpu_info;
337
uint64_t cpuspeed;
338
int err;
339
340
size = sizeof(model);
341
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
342
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
343
return UV__ERR(errno);
344
}
345
346
err = uv__get_cpu_speed(&cpuspeed);
347
if (err < 0)
348
return err;
349
350
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
351
(processor_info_array_t*)&info,
352
&msg_type) != KERN_SUCCESS) {
353
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
354
}
355
356
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
357
if (!(*cpu_infos)) {
358
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
359
return UV_ENOMEM;
360
}
361
362
*count = numcpus;
363
364
for (i = 0; i < numcpus; i++) {
365
cpu_info = &(*cpu_infos)[i];
366
367
cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
368
cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
369
cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
370
cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
371
cpu_info->cpu_times.irq = 0;
372
373
cpu_info->model = uv__strdup(model);
374
cpu_info->speed = cpuspeed/1000000;
375
}
376
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
377
378
return 0;
379
}
380
381