1/************************************************************************** 2 * 3 * Copyright 2008-2010 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29#include "os_misc.h" 30#include "os_file.h" 31#include "macros.h" 32 33#include <stdarg.h> 34 35 36#if DETECT_OS_WINDOWS 37 38#ifndef WIN32_LEAN_AND_MEAN 39#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 40#endif 41#include <windows.h> 42#include <stdio.h> 43#include <stdlib.h> 44 45#else 46 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <inttypes.h> 51 52#endif 53 54 55#if DETECT_OS_ANDROID 56# define LOG_TAG "MESA" 57# include <unistd.h> 58# include <log/log.h> 59# include <cutils/properties.h> 60#elif DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD 61# include <unistd.h> 62#elif DETECT_OS_OPENBSD || DETECT_OS_FREEBSD 63# include <sys/resource.h> 64# include <sys/sysctl.h> 65#elif DETECT_OS_APPLE || DETECT_OS_BSD 66# include <sys/sysctl.h> 67#elif DETECT_OS_HAIKU 68# include <kernel/OS.h> 69#elif DETECT_OS_WINDOWS 70# include <windows.h> 71#else 72#error unexpected platform in os_sysinfo.c 73#endif 74 75 76void 77os_log_message(const char *message) 78{ 79 /* If the GALLIUM_LOG_FILE environment variable is set to a valid filename, 80 * write all messages to that file. 81 */ 82 static FILE *fout = NULL; 83 84 if (!fout) { 85#ifdef DEBUG 86 /* one-time init */ 87 const char *filename = os_get_option("GALLIUM_LOG_FILE"); 88 if (filename) { 89 const char *mode = "w"; 90 if (filename[0] == '+') { 91 /* If the filename is prefixed with '+' then open the file for 92 * appending instead of normal writing. 93 */ 94 mode = "a"; 95 filename++; /* skip the '+' */ 96 } 97 fout = fopen(filename, mode); 98 } 99#endif 100 if (!fout) 101 fout = stderr; 102 } 103 104#if DETECT_OS_WINDOWS 105 OutputDebugStringA(message); 106 if(GetConsoleWindow() && !IsDebuggerPresent()) { 107 fflush(stdout); 108 fputs(message, fout); 109 fflush(fout); 110 } 111 else if (fout != stderr) { 112 fputs(message, fout); 113 fflush(fout); 114 } 115#else /* !DETECT_OS_WINDOWS */ 116 fflush(stdout); 117 fputs(message, fout); 118 fflush(fout); 119# if DETECT_OS_ANDROID 120 LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", message); 121# endif 122#endif 123} 124 125#if DETECT_OS_ANDROID 126# include <ctype.h> 127# include "hash_table.h" 128# include "ralloc.h" 129# include "simple_mtx.h" 130 131static struct hash_table *options_tbl; 132 133static void 134options_tbl_fini(void) 135{ 136 _mesa_hash_table_destroy(options_tbl, NULL); 137} 138 139/** 140 * Get an option value from android's property system, as a fallback to 141 * getenv() (which is generally less useful on android due to processes 142 * typically being forked from the zygote. 143 * 144 * The option name used for getenv is translated into a property name 145 * by: 146 * 147 * 1) convert to lowercase 148 * 2) replace '_' with '.' 149 * 3) if necessary, prepend "mesa." 150 * 151 * For example: 152 * - MESA_EXTENSION_OVERRIDE -> mesa.extension.override 153 * - GALLIUM_HUD -> mesa.gallium.hud 154 * 155 * Note that we use a hashtable for two purposes: 156 * 1) Avoid re-translating the option name on subsequent lookups 157 * 2) Avoid leaking memory. Because property_get() returns the 158 * property value into a user allocated buffer, we cannot return 159 * that directly to the caller, so we need to strdup(). With the 160 * hashtable, subsquent lookups can return the existing string. 161 */ 162static const char * 163os_get_android_option(const char *name) 164{ 165 if (!options_tbl) { 166 options_tbl = _mesa_hash_table_create(NULL, _mesa_hash_string, 167 _mesa_key_string_equal); 168 atexit(options_tbl_fini); 169 } 170 171 struct hash_entry *entry = _mesa_hash_table_search(options_tbl, name); 172 if (entry) { 173 return entry->data; 174 } 175 176 char value[PROPERTY_VALUE_MAX]; 177 char key[PROPERTY_KEY_MAX]; 178 char *p = key, *end = key + PROPERTY_KEY_MAX; 179 /* add "mesa." prefix if necessary: */ 180 if (strstr(name, "MESA_") != name) 181 p += strlcpy(p, "mesa.", end - p); 182 p += strlcpy(p, name, end - p); 183 for (int i = 0; key[i]; i++) { 184 if (key[i] == '_') { 185 key[i] = '.'; 186 } else { 187 key[i] = tolower(key[i]); 188 } 189 } 190 191 const char *opt = NULL; 192 int len = property_get(key, value, NULL); 193 if (len > 1) { 194 opt = ralloc_strdup(options_tbl, value); 195 } 196 197 _mesa_hash_table_insert(options_tbl, name, (void *)opt); 198 199 return opt; 200} 201#endif 202 203 204#if !defined(EMBEDDED_DEVICE) 205const char * 206os_get_option(const char *name) 207{ 208 const char *opt = getenv(name); 209#if DETECT_OS_ANDROID 210 if (!opt) { 211 opt = os_get_android_option(name); 212 } 213#endif 214 return opt; 215} 216#endif /* !EMBEDDED_DEVICE */ 217 218/** 219 * Return the size of the total physical memory. 220 * \param size returns the size of the total physical memory 221 * \return true for success, or false on failure 222 */ 223bool 224os_get_total_physical_memory(uint64_t *size) 225{ 226#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD 227 const long phys_pages = sysconf(_SC_PHYS_PAGES); 228 const long page_size = sysconf(_SC_PAGE_SIZE); 229 230 if (phys_pages <= 0 || page_size <= 0) 231 return false; 232 233 *size = (uint64_t)phys_pages * (uint64_t)page_size; 234 return true; 235#elif DETECT_OS_APPLE || DETECT_OS_BSD 236 size_t len = sizeof(*size); 237 int mib[2]; 238 239 mib[0] = CTL_HW; 240#if DETECT_OS_APPLE 241 mib[1] = HW_MEMSIZE; 242#elif DETECT_OS_NETBSD || DETECT_OS_OPENBSD 243 mib[1] = HW_PHYSMEM64; 244#elif DETECT_OS_FREEBSD 245 mib[1] = HW_REALMEM; 246#elif DETECT_OS_DRAGONFLY 247 mib[1] = HW_PHYSMEM; 248#else 249#error Unsupported *BSD 250#endif 251 252 return (sysctl(mib, 2, size, &len, NULL, 0) == 0); 253#elif DETECT_OS_HAIKU 254 system_info info; 255 status_t ret; 256 257 ret = get_system_info(&info); 258 if (ret != B_OK || info.max_pages <= 0) 259 return false; 260 261 *size = (uint64_t)info.max_pages * (uint64_t)B_PAGE_SIZE; 262 return true; 263#elif DETECT_OS_WINDOWS 264 MEMORYSTATUSEX status; 265 BOOL ret; 266 267 status.dwLength = sizeof(status); 268 ret = GlobalMemoryStatusEx(&status); 269 *size = status.ullTotalPhys; 270 return (ret == TRUE); 271#else 272#error unexpected platform in os_sysinfo.c 273 return false; 274#endif 275} 276 277bool 278os_get_available_system_memory(uint64_t *size) 279{ 280#if DETECT_OS_LINUX 281 char *meminfo = os_read_file("/proc/meminfo", NULL); 282 if (!meminfo) 283 return false; 284 285 char *str = strstr(meminfo, "MemAvailable:"); 286 if (!str) { 287 free(meminfo); 288 return false; 289 } 290 291 uint64_t kb_mem_available; 292 if (sscanf(str, "MemAvailable: %" PRIu64, &kb_mem_available) == 1) { 293 free(meminfo); 294 *size = kb_mem_available << 10; 295 return true; 296 } 297 298 free(meminfo); 299 return false; 300#elif DETECT_OS_OPENBSD || DETECT_OS_FREEBSD 301 struct rlimit rl; 302#if DETECT_OS_OPENBSD 303 int mib[] = { CTL_HW, HW_USERMEM64 }; 304#elif DETECT_OS_FREEBSD 305 int mib[] = { CTL_HW, HW_USERMEM }; 306#endif 307 int64_t mem_available; 308 size_t len = sizeof(mem_available); 309 310 /* physmem - wired */ 311 if (sysctl(mib, 2, &mem_available, &len, NULL, 0) == -1) 312 return false; 313 314 /* static login.conf limit */ 315 if (getrlimit(RLIMIT_DATA, &rl) == -1) 316 return false; 317 318 *size = MIN2(mem_available, rl.rlim_cur); 319 return true; 320#else 321 return false; 322#endif 323} 324 325/** 326 * Return the size of a page 327 * \param size returns the size of a page 328 * \return true for success, or false on failure 329 */ 330bool 331os_get_page_size(uint64_t *size) 332{ 333#if DETECT_OS_UNIX && !DETECT_OS_APPLE && !DETECT_OS_HAIKU 334 const long page_size = sysconf(_SC_PAGE_SIZE); 335 336 if (page_size <= 0) 337 return false; 338 339 *size = (uint64_t)page_size; 340 return true; 341#elif DETECT_OS_HAIKU 342 *size = (uint64_t)B_PAGE_SIZE; 343 return true; 344#elif DETECT_OS_WINDOWS 345 SYSTEM_INFO SysInfo; 346 347 GetSystemInfo(&SysInfo); 348 *size = SysInfo.dwPageSize; 349 return true; 350#elif DETECT_OS_APPLE 351 size_t len = sizeof(*size); 352 int mib[2]; 353 354 mib[0] = CTL_HW; 355 mib[1] = HW_PAGESIZE; 356 return (sysctl(mib, 2, size, &len, NULL, 0) == 0); 357#else 358#error unexpected platform in os_sysinfo.c 359 return false; 360#endif 361} 362