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