123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /*
- * Copyright (c) 2023 Ruwen Hahn <[email protected]>
- * Lain Bailey <[email protected]>
- * Marvin Scholz <[email protected]>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "base.h"
- #include "platform.h"
- #include "dstr.h"
- #include <dlfcn.h>
- #include <time.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/sysctl.h>
- #include <CoreServices/CoreServices.h>
- #include <mach/mach.h>
- #include <mach/mach_time.h>
- #include <mach-o/dyld.h>
- #include <IOKit/pwr_mgt/IOPMLib.h>
- #import <Cocoa/Cocoa.h>
- #include "apple/cfstring-utils.h"
- uint64_t os_gettime_ns(void)
- {
- return clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
- }
- /* gets the location [domain mask]/Library/Application Support/[name] */
- static int os_get_path_internal(char *dst, size_t size, const char *name, NSSearchPathDomainMask domainMask)
- {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, domainMask, YES);
- if ([paths count] == 0)
- bcrash("Could not get home directory (platform-cocoa)");
- NSString *application_support = paths[0];
- const char *base_path = [application_support UTF8String];
- if (!name || !*name)
- return snprintf(dst, size, "%s", base_path);
- else
- return snprintf(dst, size, "%s/%s", base_path, name);
- }
- static char *os_get_path_ptr_internal(const char *name, NSSearchPathDomainMask domainMask)
- {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, domainMask, YES);
- if ([paths count] == 0)
- bcrash("Could not get home directory (platform-cocoa)");
- NSString *application_support = paths[0];
- NSUInteger len = [application_support lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
- char *path_ptr = bmalloc(len + 1);
- path_ptr[len] = 0;
- memcpy(path_ptr, [application_support UTF8String], len);
- struct dstr path;
- dstr_init_move_array(&path, path_ptr);
- dstr_cat(&path, "/");
- dstr_cat(&path, name);
- return path.array;
- }
- int os_get_config_path(char *dst, size_t size, const char *name)
- {
- return os_get_path_internal(dst, size, name, NSUserDomainMask);
- }
- char *os_get_config_path_ptr(const char *name)
- {
- return os_get_path_ptr_internal(name, NSUserDomainMask);
- }
- int os_get_program_data_path(char *dst, size_t size, const char *name)
- {
- return os_get_path_internal(dst, size, name, NSLocalDomainMask);
- }
- char *os_get_program_data_path_ptr(const char *name)
- {
- return os_get_path_ptr_internal(name, NSLocalDomainMask);
- }
- char *os_get_executable_path_ptr(const char *name)
- {
- char exe[PATH_MAX];
- char abs_path[PATH_MAX];
- uint32_t size = sizeof(exe);
- struct dstr path;
- char *slash;
- if (_NSGetExecutablePath(exe, &size) != 0) {
- return NULL;
- }
- if (!realpath(exe, abs_path)) {
- return NULL;
- }
- dstr_init_copy(&path, abs_path);
- slash = strrchr(path.array, '/');
- if (slash) {
- size_t len = slash - path.array + 1;
- dstr_resize(&path, len);
- }
- if (name && *name) {
- dstr_cat(&path, name);
- }
- return path.array;
- }
- struct os_cpu_usage_info {
- int64_t last_cpu_time;
- int64_t last_sys_time;
- int core_count;
- };
- static inline void add_time_value(time_value_t *dst, time_value_t *a, time_value_t *b)
- {
- dst->microseconds = a->microseconds + b->microseconds;
- dst->seconds = a->seconds + b->seconds;
- if (dst->microseconds >= 1000000) {
- dst->seconds += dst->microseconds / 1000000;
- dst->microseconds %= 1000000;
- }
- }
- static bool get_time_info(int64_t *cpu_time, int64_t *sys_time)
- {
- mach_port_t task = mach_task_self();
- struct task_thread_times_info thread_data;
- struct task_basic_info_64 task_data;
- mach_msg_type_number_t count;
- kern_return_t kern_ret;
- time_value_t cur_time;
- *cpu_time = 0;
- *sys_time = 0;
- count = TASK_THREAD_TIMES_INFO_COUNT;
- kern_ret = task_info(task, TASK_THREAD_TIMES_INFO, (task_info_t) &thread_data, &count);
- if (kern_ret != KERN_SUCCESS)
- return false;
- count = TASK_BASIC_INFO_64_COUNT;
- kern_ret = task_info(task, TASK_BASIC_INFO_64, (task_info_t) &task_data, &count);
- if (kern_ret != KERN_SUCCESS)
- return false;
- add_time_value(&cur_time, &thread_data.user_time, &thread_data.system_time);
- add_time_value(&cur_time, &cur_time, &task_data.user_time);
- add_time_value(&cur_time, &cur_time, &task_data.system_time);
- *cpu_time = os_gettime_ns() / 1000;
- *sys_time = cur_time.seconds * 1000000 + cur_time.microseconds;
- return true;
- }
- os_cpu_usage_info_t *os_cpu_usage_info_start(void)
- {
- struct os_cpu_usage_info *info = bmalloc(sizeof(*info));
- if (!get_time_info(&info->last_cpu_time, &info->last_sys_time)) {
- bfree(info);
- return NULL;
- }
- info->core_count = (int) sysconf(_SC_NPROCESSORS_ONLN);
- return info;
- }
- double os_cpu_usage_info_query(os_cpu_usage_info_t *info)
- {
- int64_t sys_time, cpu_time;
- int64_t sys_time_delta, cpu_time_delta;
- if (!info || !get_time_info(&cpu_time, &sys_time))
- return 0.0;
- sys_time_delta = sys_time - info->last_sys_time;
- cpu_time_delta = cpu_time - info->last_cpu_time;
- if (cpu_time_delta == 0)
- return 0.0;
- info->last_sys_time = sys_time;
- info->last_cpu_time = cpu_time;
- return (double) sys_time_delta * 100.0 / (double) cpu_time_delta / (double) info->core_count;
- }
- void os_cpu_usage_info_destroy(os_cpu_usage_info_t *info)
- {
- if (info)
- bfree(info);
- }
- os_performance_token_t *os_request_high_performance(const char *reason)
- {
- @autoreleasepool {
- NSProcessInfo *processInfo = NSProcessInfo.processInfo;
- id activity = [processInfo beginActivityWithOptions:NSActivityUserInitiated reason:@(reason ? reason : "")];
- return CFBridgingRetain(activity);
- }
- }
- void os_end_high_performance(os_performance_token_t *token)
- {
- @autoreleasepool {
- NSProcessInfo *processInfo = NSProcessInfo.processInfo;
- [processInfo endActivity:CFBridgingRelease(token)];
- }
- }
- struct os_inhibit_info {
- CFStringRef reason;
- IOPMAssertionID sleep_id;
- IOPMAssertionID user_id;
- bool active;
- };
- os_inhibit_t *os_inhibit_sleep_create(const char *reason)
- {
- struct os_inhibit_info *info = bzalloc(sizeof(*info));
- if (!reason)
- info->reason = CFStringCreateWithCString(kCFAllocatorDefault, reason, kCFStringEncodingUTF8);
- else
- info->reason = CFStringCreateCopy(kCFAllocatorDefault, CFSTR(""));
- return info;
- }
- bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active)
- {
- IOReturn success;
- if (!info)
- return false;
- if (info->active == active)
- return false;
- if (active) {
- IOPMAssertionDeclareUserActivity(info->reason, kIOPMUserActiveLocal, &info->user_id);
- success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, info->reason,
- &info->sleep_id);
- if (success != kIOReturnSuccess) {
- blog(LOG_WARNING, "Failed to disable sleep");
- return false;
- }
- } else {
- IOPMAssertionRelease(info->sleep_id);
- }
- info->active = active;
- return true;
- }
- void os_inhibit_sleep_destroy(os_inhibit_t *info)
- {
- if (info) {
- os_inhibit_sleep_set_active(info, false);
- CFRelease(info->reason);
- bfree(info);
- }
- }
- static int physical_cores = 0;
- static int logical_cores = 0;
- static bool core_count_initialized = false;
- bool os_get_emulation_status(void)
- {
- #ifdef __aarch64__
- return false;
- #else
- int rosettaTranslated = 0;
- size_t size = sizeof(rosettaTranslated);
- if (sysctlbyname("sysctl.proc_translated", &rosettaTranslated, &size, NULL, 0) == -1)
- return false;
- return rosettaTranslated == 1;
- #endif
- }
- static void os_get_cores_internal(void)
- {
- if (core_count_initialized)
- return;
- core_count_initialized = true;
- size_t size;
- int ret;
- size = sizeof(physical_cores);
- ret = sysctlbyname("machdep.cpu.core_count", &physical_cores, &size, NULL, 0);
- if (ret != 0)
- return;
- ret = sysctlbyname("machdep.cpu.thread_count", &logical_cores, &size, NULL, 0);
- }
- int os_get_physical_cores(void)
- {
- if (!core_count_initialized)
- os_get_cores_internal();
- return physical_cores;
- }
- int os_get_logical_cores(void)
- {
- if (!core_count_initialized)
- os_get_cores_internal();
- return logical_cores;
- }
- static inline bool os_get_sys_memory_usage_internal(vm_statistics_t vmstat)
- {
- mach_msg_type_number_t out_count = HOST_VM_INFO_COUNT;
- if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) vmstat, &out_count) != KERN_SUCCESS)
- return false;
- return true;
- }
- uint64_t os_get_sys_free_size(void)
- {
- vm_statistics_data_t vmstat = {};
- if (!os_get_sys_memory_usage_internal(&vmstat))
- return 0;
- return vmstat.free_count * vm_page_size;
- }
- static uint64_t total_memory = 0;
- static bool total_memory_initialized = false;
- static void os_get_sys_total_size_internal()
- {
- total_memory_initialized = true;
- size_t size;
- int ret;
- size = sizeof(total_memory);
- ret = sysctlbyname("hw.memsize", &total_memory, &size, NULL, 0);
- }
- uint64_t os_get_sys_total_size(void)
- {
- if (!total_memory_initialized)
- os_get_sys_total_size_internal();
- return total_memory;
- }
- static inline bool os_get_proc_memory_usage_internal(mach_task_basic_info_data_t *taskinfo)
- {
- const task_flavor_t flavor = MACH_TASK_BASIC_INFO;
- mach_msg_type_number_t out_count = MACH_TASK_BASIC_INFO_COUNT;
- if (task_info(mach_task_self(), flavor, (task_info_t) taskinfo, &out_count) != KERN_SUCCESS)
- return false;
- return true;
- }
- bool os_get_proc_memory_usage(os_proc_memory_usage_t *usage)
- {
- mach_task_basic_info_data_t taskinfo = {};
- if (!os_get_proc_memory_usage_internal(&taskinfo))
- return false;
- usage->resident_size = taskinfo.resident_size;
- usage->virtual_size = taskinfo.virtual_size;
- return true;
- }
- uint64_t os_get_proc_resident_size(void)
- {
- mach_task_basic_info_data_t taskinfo = {};
- if (!os_get_proc_memory_usage_internal(&taskinfo))
- return 0;
- return taskinfo.resident_size;
- }
- uint64_t os_get_proc_virtual_size(void)
- {
- mach_task_basic_info_data_t taskinfo = {};
- if (!os_get_proc_memory_usage_internal(&taskinfo))
- return 0;
- return taskinfo.virtual_size;
- }
- /* Obtains a copy of the contents of a CFString in specified encoding.
- * Returns char* (must be bfree'd by caller) or NULL on failure.
- */
- char *cfstr_copy_cstr(CFStringRef cfstring, CFStringEncoding cfstring_encoding)
- {
- if (!cfstring)
- return NULL;
- // Try the quick way to obtain the buffer
- const char *tmp_buffer = CFStringGetCStringPtr(cfstring, cfstring_encoding);
- if (tmp_buffer != NULL)
- return bstrdup(tmp_buffer);
- // The quick way did not work, try the more expensive one
- CFIndex length = CFStringGetLength(cfstring);
- CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, cfstring_encoding);
- // If result would exceed LONG_MAX, kCFNotFound is returned
- if (max_size == kCFNotFound)
- return NULL;
- // Account for the null terminator
- max_size++;
- char *buffer = bmalloc(max_size);
- if (buffer == NULL) {
- return NULL;
- }
- // Copy CFString in requested encoding to buffer
- Boolean success = CFStringGetCString(cfstring, buffer, max_size, cfstring_encoding);
- if (!success) {
- bfree(buffer);
- buffer = NULL;
- }
- return buffer;
- }
- /* Copies the contents of a CFString in specified encoding to a given dstr.
- * Returns true on success or false on failure.
- * In case of failure, the dstr capacity but not size is changed.
- */
- bool cfstr_copy_dstr(CFStringRef cfstring, CFStringEncoding cfstring_encoding, struct dstr *str)
- {
- if (!cfstring)
- return false;
- // Try the quick way to obtain the buffer
- const char *tmp_buffer = CFStringGetCStringPtr(cfstring, cfstring_encoding);
- if (tmp_buffer != NULL) {
- dstr_copy(str, tmp_buffer);
- return true;
- }
- // The quick way did not work, try the more expensive one
- CFIndex length = CFStringGetLength(cfstring);
- CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, cfstring_encoding);
- // If result would exceed LONG_MAX, kCFNotFound is returned
- if (max_size == kCFNotFound)
- return NULL;
- // Account for the null terminator
- max_size++;
- dstr_ensure_capacity(str, max_size);
- // Copy CFString in requested encoding to dstr buffer
- Boolean success = CFStringGetCString(cfstring, str->array, max_size, cfstring_encoding);
- if (success)
- dstr_resize(str, max_size);
- return (bool) success;
- }
|