diff options
Diffstat (limited to 'drivers/unix/os_unix.cpp')
-rw-r--r-- | drivers/unix/os_unix.cpp | 302 |
1 files changed, 253 insertions, 49 deletions
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index fc06291a3a..967699c5f3 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -1,32 +1,32 @@ -/*************************************************************************/ -/* os_unix.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ +/**************************************************************************/ +/* os_unix.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ #include "os_unix.h" @@ -41,9 +41,12 @@ #include "drivers/unix/thread_posix.h" #include "servers/rendering_server.h" -#ifdef __APPLE__ +#if defined(__APPLE__) #include <mach-o/dyld.h> +#include <mach/host_info.h> +#include <mach/mach_host.h> #include <mach/mach_time.h> +#include <sys/sysctl.h> #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) @@ -51,6 +54,19 @@ #include <sys/sysctl.h> #endif +#if defined(__FreeBSD__) +#include <kvm.h> +#endif + +#if defined(__OpenBSD__) +#include <sys/swap.h> +#include <uvm/uvmexp.h> +#endif + +#if defined(__NetBSD__) +#include <uvm/uvm_extern.h> +#endif + #include <dlfcn.h> #include <errno.h> #include <poll.h> @@ -59,6 +75,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> #include <time.h> @@ -149,15 +166,9 @@ Vector<String> OS_Unix::get_video_adapter_driver_info() const { return Vector<String>(); } -String OS_Unix::get_stdin_string(bool p_block) { - if (p_block) { - char buff[1024]; - String ret = stdin_buf + fgets(buff, 1024, stdin); - stdin_buf = ""; - return ret; - } - - return ""; +String OS_Unix::get_stdin_string() { + char buff[1024]; + return String::utf8(fgets(buff, 1024, stdin)); } Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) { @@ -280,6 +291,192 @@ uint64_t OS_Unix::get_ticks_usec() const { return longtime; } +Dictionary OS_Unix::get_memory_info() const { + Dictionary meminfo; + + meminfo["physical"] = -1; + meminfo["free"] = -1; + meminfo["available"] = -1; + meminfo["stack"] = -1; + +#if defined(__APPLE__) + int pagesize = 0; + size_t len = sizeof(pagesize); + if (sysctlbyname("vm.pagesize", &pagesize, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.pagesize, error code: %d - %s", errno, strerror(errno))); + } + + int64_t phy_mem = 0; + len = sizeof(phy_mem); + if (sysctlbyname("hw.memsize", &phy_mem, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get hw.memsize, error code: %d - %s", errno, strerror(errno))); + } + + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + vm_statistics64_data_t vmstat; + if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) { + ERR_PRINT(vformat("Could not get host vm statistics.")); + } + struct xsw_usage swap_used; + len = sizeof(swap_used); + if (sysctlbyname("vm.swapusage", &swap_used, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.swapusage, error code: %d - %s", errno, strerror(errno))); + } + + if (phy_mem != 0) { + meminfo["physical"] = phy_mem; + } + if (vmstat.free_count * (int64_t)pagesize != 0) { + meminfo["free"] = vmstat.free_count * (int64_t)pagesize; + } + if (swap_used.xsu_avail + vmstat.free_count * (int64_t)pagesize != 0) { + meminfo["available"] = swap_used.xsu_avail + vmstat.free_count * (int64_t)pagesize; + } +#elif defined(__FreeBSD__) + int pagesize = 0; + size_t len = sizeof(pagesize); + if (sysctlbyname("vm.stats.vm.v_page_size", &pagesize, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.stats.vm.v_page_size, error code: %d - %s", errno, strerror(errno))); + } + + uint64_t mtotal = 0; + len = sizeof(mtotal); + if (sysctlbyname("vm.stats.vm.v_page_count", &mtotal, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.stats.vm.v_page_count, error code: %d - %s", errno, strerror(errno))); + } + uint64_t mfree = 0; + len = sizeof(mfree); + if (sysctlbyname("vm.stats.vm.v_free_count", &mfree, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.stats.vm.v_free_count, error code: %d - %s", errno, strerror(errno))); + } + + uint64_t stotal = 0; + uint64_t sused = 0; + char errmsg[_POSIX2_LINE_MAX] = {}; + kvm_t *kd = kvm_openfiles(nullptr, "/dev/null", nullptr, 0, errmsg); + if (kd == nullptr) { + ERR_PRINT(vformat("kvm_openfiles failed, error: %s", errmsg)); + } else { + struct kvm_swap swap_info[32]; + int count = kvm_getswapinfo(kd, swap_info, 32, 0); + for (int i = 0; i < count; i++) { + stotal += swap_info[i].ksw_total; + sused += swap_info[i].ksw_used; + } + kvm_close(kd); + } + + if (mtotal * pagesize != 0) { + meminfo["physical"] = mtotal * pagesize; + } + if (mfree * pagesize != 0) { + meminfo["free"] = mfree * pagesize; + } + if ((mfree + stotal - sused) * pagesize != 0) { + meminfo["available"] = (mfree + stotal - sused) * pagesize; + } +#elif defined(__OpenBSD__) + int pagesize = sysconf(_SC_PAGESIZE); + + const int mib[] = { CTL_VM, VM_UVMEXP }; + uvmexp uvmexp_info; + size_t len = sizeof(uvmexp_info); + if (sysctl(mib, 2, &uvmexp_info, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get CTL_VM, VM_UVMEXP, error code: %d - %s", errno, strerror(errno))); + } + + uint64_t stotal = 0; + uint64_t sused = 0; + int count = swapctl(SWAP_NSWAP, 0, 0); + if (count > 0) { + swapent swap_info[count]; + count = swapctl(SWAP_STATS, swap_info, count); + + for (int i = 0; i < count; i++) { + if (swap_info[i].se_flags & SWF_ENABLE) { + sused += swap_info[i].se_inuse; + stotal += swap_info[i].se_nblks; + } + } + } + + if (uvmexp_info.npages * pagesize != 0) { + meminfo["physical"] = uvmexp_info.npages * pagesize; + } + if (uvmexp_info.free * pagesize != 0) { + meminfo["free"] = uvmexp_info.free * pagesize; + } + if ((uvmexp_info.free * pagesize) + (stotal - sused) * DEV_BSIZE != 0) { + meminfo["available"] = (uvmexp_info.free * pagesize) + (stotal - sused) * DEV_BSIZE; + } +#elif defined(__NetBSD__) + int pagesize = sysconf(_SC_PAGESIZE); + + const int mib[] = { CTL_VM, VM_UVMEXP2 }; + uvmexp_sysctl uvmexp_info; + size_t len = sizeof(uvmexp_info); + if (sysctl(mib, 2, &uvmexp_info, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get CTL_VM, VM_UVMEXP2, error code: %d - %s", errno, strerror(errno))); + } + + if (uvmexp_info.npages * pagesize != 0) { + meminfo["physical"] = uvmexp_info.npages * pagesize; + } + if (uvmexp_info.free * pagesize != 0) { + meminfo["free"] = uvmexp_info.free * pagesize; + } + if ((uvmexp_info.free + uvmexp_info.swpages - uvmexp_info.swpginuse) * pagesize != 0) { + meminfo["available"] = (uvmexp_info.free + uvmexp_info.swpages - uvmexp_info.swpginuse) * pagesize; + } +#else + Error err; + Ref<FileAccess> f = FileAccess::open("/proc/meminfo", FileAccess::READ, &err); + uint64_t mtotal = 0; + uint64_t mfree = 0; + uint64_t sfree = 0; + while (f.is_valid() && !f->eof_reached()) { + String s = f->get_line().strip_edges(); + if (s.begins_with("MemTotal:")) { + Vector<String> stok = s.replace("MemTotal:", "").strip_edges().split(" "); + if (stok.size() == 2) { + mtotal = stok[0].to_int() * 1024; + } + } + if (s.begins_with("MemFree:")) { + Vector<String> stok = s.replace("MemFree:", "").strip_edges().split(" "); + if (stok.size() == 2) { + mfree = stok[0].to_int() * 1024; + } + } + if (s.begins_with("SwapFree:")) { + Vector<String> stok = s.replace("SwapFree:", "").strip_edges().split(" "); + if (stok.size() == 2) { + sfree = stok[0].to_int() * 1024; + } + } + } + + if (mtotal != 0) { + meminfo["physical"] = mtotal; + } + if (mfree != 0) { + meminfo["free"] = mfree; + } + if (mfree + sfree != 0) { + meminfo["available"] = mfree + sfree; + } +#endif + + rlimit stackinfo = {}; + getrlimit(RLIMIT_STACK, &stackinfo); + + if (stackinfo.rlim_cur != 0) { + meminfo["stack"] = (int64_t)stackinfo.rlim_cur; + } + + return meminfo; +} + Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. @@ -417,10 +614,6 @@ bool OS_Unix::is_process_running(const ProcessID &p_pid) const { return true; } -bool OS_Unix::has_environment(const String &p_var) const { - return getenv(p_var.utf8().get_data()) != nullptr; -} - String OS_Unix::get_locale() const { if (!has_environment("LANG")) { return "en"; @@ -493,6 +686,10 @@ Error OS_Unix::set_cwd(const String &p_cwd) { return OK; } +bool OS_Unix::has_environment(const String &p_var) const { + return getenv(p_var.utf8().get_data()) != nullptr; +} + String OS_Unix::get_environment(const String &p_var) const { if (getenv(p_var.utf8().get_data())) { return getenv(p_var.utf8().get_data()); @@ -500,16 +697,23 @@ String OS_Unix::get_environment(const String &p_var) const { return ""; } -bool OS_Unix::set_environment(const String &p_var, const String &p_value) const { - return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0; +void OS_Unix::set_environment(const String &p_var, const String &p_value) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + int err = setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ 1); + ERR_FAIL_COND_MSG(err != 0, vformat("Failed setting environment variable '%s', the system is out of memory.", p_var)); +} + +void OS_Unix::unset_environment(const String &p_var) const { + ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); + unsetenv(p_var.utf8().get_data()); } String OS_Unix::get_user_data_dir() const { - String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name")); + String appname = get_safe_dir_name(GLOBAL_GET("application/config/name")); if (!appname.is_empty()) { - bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir"); + bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir"); if (use_custom_dir) { - String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true); + String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true); if (custom_dir.is_empty()) { custom_dir = appname; } @@ -565,7 +769,7 @@ String OS_Unix::get_executable_path() const { WARN_PRINT("MAXPATHLEN is too small"); } - String path(resolved_path); + String path = String::utf8(resolved_path); delete[] resolved_path; return path; |