darwin.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. #include "uv.h"
  21. #include "internal.h"
  22. #include <assert.h>
  23. #include <stdint.h>
  24. #include <errno.h>
  25. #include <dlfcn.h>
  26. #include <mach/mach.h>
  27. #include <mach/mach_time.h>
  28. #include <mach-o/dyld.h> /* _NSGetExecutablePath */
  29. #include <sys/resource.h>
  30. #include <sys/sysctl.h>
  31. #include <unistd.h> /* sysconf */
  32. #if !TARGET_OS_IPHONE
  33. #include "darwin-stub.h"
  34. #endif
  35. static uv_once_t once = UV_ONCE_INIT;
  36. static uint64_t (*time_func)(void);
  37. static mach_timebase_info_data_t timebase;
  38. typedef unsigned char UInt8;
  39. int uv__platform_loop_init(uv_loop_t* loop) {
  40. loop->cf_state = NULL;
  41. if (uv__kqueue_init(loop))
  42. return UV__ERR(errno);
  43. return 0;
  44. }
  45. void uv__platform_loop_delete(uv_loop_t* loop) {
  46. uv__fsevents_loop_delete(loop);
  47. }
  48. static void uv__hrtime_init_once(void) {
  49. if (KERN_SUCCESS != mach_timebase_info(&timebase))
  50. abort();
  51. time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
  52. if (time_func == NULL)
  53. time_func = mach_absolute_time;
  54. }
  55. uint64_t uv__hrtime(uv_clocktype_t type) {
  56. uv_once(&once, uv__hrtime_init_once);
  57. return time_func() * timebase.numer / timebase.denom;
  58. }
  59. int uv_exepath(char* buffer, size_t* size) {
  60. /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
  61. char abspath[PATH_MAX * 2 + 1];
  62. char exepath[PATH_MAX + 1];
  63. uint32_t exepath_size;
  64. size_t abspath_size;
  65. if (buffer == NULL || size == NULL || *size == 0)
  66. return UV_EINVAL;
  67. exepath_size = sizeof(exepath);
  68. if (_NSGetExecutablePath(exepath, &exepath_size))
  69. return UV_EIO;
  70. if (realpath(exepath, abspath) != abspath)
  71. return UV__ERR(errno);
  72. abspath_size = strlen(abspath);
  73. if (abspath_size == 0)
  74. return UV_EIO;
  75. *size -= 1;
  76. if (*size > abspath_size)
  77. *size = abspath_size;
  78. memcpy(buffer, abspath, *size);
  79. buffer[*size] = '\0';
  80. return 0;
  81. }
  82. uint64_t uv_get_free_memory(void) {
  83. vm_statistics_data_t info;
  84. mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
  85. if (host_statistics(mach_host_self(), HOST_VM_INFO,
  86. (host_info_t)&info, &count) != KERN_SUCCESS) {
  87. return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
  88. }
  89. return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
  90. }
  91. uint64_t uv_get_total_memory(void) {
  92. uint64_t info;
  93. int which[] = {CTL_HW, HW_MEMSIZE};
  94. size_t size = sizeof(info);
  95. if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
  96. return UV__ERR(errno);
  97. return (uint64_t) info;
  98. }
  99. uint64_t uv_get_constrained_memory(void) {
  100. return 0; /* Memory constraints are unknown. */
  101. }
  102. void uv_loadavg(double avg[3]) {
  103. struct loadavg info;
  104. size_t size = sizeof(info);
  105. int which[] = {CTL_VM, VM_LOADAVG};
  106. if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
  107. avg[0] = (double) info.ldavg[0] / info.fscale;
  108. avg[1] = (double) info.ldavg[1] / info.fscale;
  109. avg[2] = (double) info.ldavg[2] / info.fscale;
  110. }
  111. int uv_resident_set_memory(size_t* rss) {
  112. mach_msg_type_number_t count;
  113. task_basic_info_data_t info;
  114. kern_return_t err;
  115. count = TASK_BASIC_INFO_COUNT;
  116. err = task_info(mach_task_self(),
  117. TASK_BASIC_INFO,
  118. (task_info_t) &info,
  119. &count);
  120. (void) &err;
  121. /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
  122. * KERN_SUCCESS implies a libuv bug.
  123. */
  124. assert(err == KERN_SUCCESS);
  125. *rss = info.resident_size;
  126. return 0;
  127. }
  128. int uv_uptime(double* uptime) {
  129. time_t now;
  130. struct timeval info;
  131. size_t size = sizeof(info);
  132. static int which[] = {CTL_KERN, KERN_BOOTTIME};
  133. if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
  134. return UV__ERR(errno);
  135. now = time(NULL);
  136. *uptime = now - info.tv_sec;
  137. return 0;
  138. }
  139. static int uv__get_cpu_speed(uint64_t* speed) {
  140. /* IOKit */
  141. void (*pIOObjectRelease)(io_object_t);
  142. kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*);
  143. CFMutableDictionaryRef (*pIOServiceMatching)(const char*);
  144. kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t,
  145. CFMutableDictionaryRef,
  146. io_iterator_t*);
  147. io_service_t (*pIOIteratorNext)(io_iterator_t);
  148. CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t,
  149. CFStringRef,
  150. CFAllocatorRef,
  151. IOOptionBits);
  152. /* CoreFoundation */
  153. CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
  154. const char*,
  155. CFStringEncoding);
  156. CFStringEncoding (*pCFStringGetSystemEncoding)(void);
  157. UInt8 *(*pCFDataGetBytePtr)(CFDataRef);
  158. CFIndex (*pCFDataGetLength)(CFDataRef);
  159. void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*);
  160. void (*pCFRelease)(CFTypeRef);
  161. void* core_foundation_handle;
  162. void* iokit_handle;
  163. int err;
  164. kern_return_t kr;
  165. mach_port_t mach_port;
  166. io_iterator_t it;
  167. io_object_t service;
  168. mach_port = 0;
  169. err = UV_ENOENT;
  170. core_foundation_handle = dlopen("/System/Library/Frameworks/"
  171. "CoreFoundation.framework/"
  172. "Versions/A/CoreFoundation",
  173. RTLD_LAZY | RTLD_LOCAL);
  174. iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
  175. "Versions/A/IOKit",
  176. RTLD_LAZY | RTLD_LOCAL);
  177. if (core_foundation_handle == NULL || iokit_handle == NULL)
  178. goto out;
  179. #define V(handle, symbol) \
  180. do { \
  181. *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
  182. if (p ## symbol == NULL) \
  183. goto out; \
  184. } \
  185. while (0)
  186. V(iokit_handle, IOMasterPort);
  187. V(iokit_handle, IOServiceMatching);
  188. V(iokit_handle, IOServiceGetMatchingServices);
  189. V(iokit_handle, IOIteratorNext);
  190. V(iokit_handle, IOObjectRelease);
  191. V(iokit_handle, IORegistryEntryCreateCFProperty);
  192. V(core_foundation_handle, CFStringCreateWithCString);
  193. V(core_foundation_handle, CFStringGetSystemEncoding);
  194. V(core_foundation_handle, CFDataGetBytePtr);
  195. V(core_foundation_handle, CFDataGetLength);
  196. V(core_foundation_handle, CFDataGetBytes);
  197. V(core_foundation_handle, CFRelease);
  198. #undef V
  199. #define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
  200. kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
  201. assert(kr == KERN_SUCCESS);
  202. CFMutableDictionaryRef classes_to_match
  203. = pIOServiceMatching("IOPlatformDevice");
  204. kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
  205. assert(kr == KERN_SUCCESS);
  206. service = pIOIteratorNext(it);
  207. CFStringRef device_type_str = S("device_type");
  208. CFStringRef clock_frequency_str = S("clock-frequency");
  209. while (service != 0) {
  210. CFDataRef data;
  211. data = pIORegistryEntryCreateCFProperty(service,
  212. device_type_str,
  213. NULL,
  214. 0);
  215. if (data) {
  216. const UInt8* raw = pCFDataGetBytePtr(data);
  217. if (strncmp((char*)raw, "cpu", 3) == 0 ||
  218. strncmp((char*)raw, "processor", 9) == 0) {
  219. CFDataRef freq_ref;
  220. freq_ref = pIORegistryEntryCreateCFProperty(service,
  221. clock_frequency_str,
  222. NULL,
  223. 0);
  224. if (freq_ref) {
  225. uint32_t freq;
  226. CFIndex len = pCFDataGetLength(freq_ref);
  227. CFRange range;
  228. range.location = 0;
  229. range.length = len;
  230. pCFDataGetBytes(freq_ref, range, (UInt8*)&freq);
  231. *speed = freq;
  232. pCFRelease(freq_ref);
  233. pCFRelease(data);
  234. break;
  235. }
  236. }
  237. pCFRelease(data);
  238. }
  239. service = pIOIteratorNext(it);
  240. }
  241. pIOObjectRelease(it);
  242. err = 0;
  243. out:
  244. if (core_foundation_handle != NULL)
  245. dlclose(core_foundation_handle);
  246. if (iokit_handle != NULL)
  247. dlclose(iokit_handle);
  248. mach_port_deallocate(mach_task_self(), mach_port);
  249. return err;
  250. }
  251. int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
  252. unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
  253. multiplier = ((uint64_t)1000L / ticks);
  254. char model[512];
  255. size_t size;
  256. unsigned int i;
  257. natural_t numcpus;
  258. mach_msg_type_number_t msg_type;
  259. processor_cpu_load_info_data_t *info;
  260. uv_cpu_info_t* cpu_info;
  261. uint64_t cpuspeed;
  262. int err;
  263. size = sizeof(model);
  264. if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
  265. sysctlbyname("hw.model", &model, &size, NULL, 0)) {
  266. return UV__ERR(errno);
  267. }
  268. err = uv__get_cpu_speed(&cpuspeed);
  269. if (err < 0)
  270. return err;
  271. if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
  272. (processor_info_array_t*)&info,
  273. &msg_type) != KERN_SUCCESS) {
  274. return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
  275. }
  276. *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
  277. if (!(*cpu_infos)) {
  278. vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
  279. return UV_ENOMEM;
  280. }
  281. *count = numcpus;
  282. for (i = 0; i < numcpus; i++) {
  283. cpu_info = &(*cpu_infos)[i];
  284. cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
  285. cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
  286. cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
  287. cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
  288. cpu_info->cpu_times.irq = 0;
  289. cpu_info->model = uv__strdup(model);
  290. cpu_info->speed = cpuspeed/1000000;
  291. }
  292. vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
  293. return 0;
  294. }