os.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
  4. */
  5. #include <bx/string.h>
  6. #include <bx/os.h>
  7. #include <bx/uint32_t.h>
  8. #if BX_CRT_MSVC
  9. # include <direct.h>
  10. #else
  11. # include <unistd.h>
  12. #endif // BX_CRT_MSVC
  13. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
  14. # ifndef WIN32_LEAN_AND_MEAN
  15. # define WIN32_LEAN_AND_MEAN
  16. # endif // WIN32_LEAN_AND_MEAN
  17. # include <windows.h>
  18. # include <psapi.h>
  19. #elif BX_PLATFORM_ANDROID \
  20. || BX_PLATFORM_BSD \
  21. || BX_PLATFORM_EMSCRIPTEN \
  22. || BX_PLATFORM_HAIKU \
  23. || BX_PLATFORM_HURD \
  24. || BX_PLATFORM_IOS \
  25. || BX_PLATFORM_LINUX \
  26. || BX_PLATFORM_NX \
  27. || BX_PLATFORM_OSX \
  28. || BX_PLATFORM_PS4 \
  29. || BX_PLATFORM_RPI
  30. # include <sched.h> // sched_yield
  31. # if BX_PLATFORM_BSD \
  32. || BX_PLATFORM_HAIKU \
  33. || BX_PLATFORM_IOS \
  34. || BX_PLATFORM_OSX \
  35. || BX_PLATFORM_PS4
  36. # include <pthread.h> // mach_port_t
  37. # endif // BX_PLATFORM_*
  38. # include <time.h> // nanosleep
  39. # if !BX_PLATFORM_PS4
  40. # include <dlfcn.h> // dlopen, dlclose, dlsym
  41. # endif // !BX_PLATFORM_PS4
  42. # if BX_PLATFORM_ANDROID
  43. # include <malloc.h> // mallinfo
  44. # elif BX_PLATFORM_LINUX \
  45. || BX_PLATFORM_RPI
  46. # include <stdio.h> // fopen
  47. # include <unistd.h> // syscall
  48. # include <sys/syscall.h>
  49. # elif BX_PLATFORM_HAIKU
  50. # include <stdio.h> // fopen
  51. # include <unistd.h> // syscall
  52. # elif BX_PLATFORM_OSX
  53. # include <mach/mach.h> // mach_task_basic_info
  54. # elif BX_PLATFORM_HURD
  55. # include <stdio.h> // fopen
  56. # include <pthread/pthread.h> // pthread_self
  57. # elif BX_PLATFORM_ANDROID
  58. # include "debug.h" // getTid is not implemented...
  59. # endif // BX_PLATFORM_ANDROID
  60. #endif // BX_PLATFORM_
  61. namespace bx
  62. {
  63. void sleep(uint32_t _ms)
  64. {
  65. #if BX_PLATFORM_WINDOWS
  66. ::Sleep(_ms);
  67. #elif BX_PLATFORM_XBOXONE \
  68. || BX_PLATFORM_WINRT \
  69. || BX_CRT_NONE
  70. BX_UNUSED(_ms);
  71. debugOutput("sleep is not implemented"); debugBreak();
  72. #else
  73. timespec req = { (time_t)_ms/1000, (long)( (_ms%1000)*1000000) };
  74. timespec rem = { 0, 0 };
  75. ::nanosleep(&req, &rem);
  76. #endif // BX_PLATFORM_
  77. }
  78. void yield()
  79. {
  80. #if BX_PLATFORM_WINDOWS
  81. ::SwitchToThread();
  82. #elif BX_PLATFORM_XBOXONE \
  83. || BX_PLATFORM_WINRT \
  84. || BX_CRT_NONE
  85. debugOutput("yield is not implemented"); debugBreak();
  86. #else
  87. ::sched_yield();
  88. #endif // BX_PLATFORM_
  89. }
  90. uint32_t getTid()
  91. {
  92. #if BX_PLATFORM_WINDOWS
  93. return ::GetCurrentThreadId();
  94. #elif BX_PLATFORM_LINUX \
  95. || BX_PLATFORM_RPI
  96. return (pid_t)::syscall(SYS_gettid);
  97. #elif BX_PLATFORM_IOS \
  98. || BX_PLATFORM_OSX
  99. return (mach_port_t)::pthread_mach_thread_np(pthread_self() );
  100. #elif BX_PLATFORM_BSD
  101. return *(uint32_t*)::pthread_self();
  102. #elif BX_PLATFORM_HURD
  103. return (pthread_t)::pthread_self();
  104. #else
  105. debugOutput("getTid is not implemented"); debugBreak();
  106. return 0;
  107. #endif // BX_PLATFORM_
  108. }
  109. size_t getProcessMemoryUsed()
  110. {
  111. #if BX_PLATFORM_ANDROID
  112. struct mallinfo mi = mallinfo();
  113. return mi.uordblks;
  114. #elif BX_PLATFORM_LINUX \
  115. || BX_PLATFORM_HURD
  116. FILE* file = fopen("/proc/self/statm", "r");
  117. if (NULL == file)
  118. {
  119. return 0;
  120. }
  121. long pages = 0;
  122. int items = fscanf(file, "%*s%ld", &pages);
  123. fclose(file);
  124. return 1 == items
  125. ? pages * sysconf(_SC_PAGESIZE)
  126. : 0
  127. ;
  128. #elif BX_PLATFORM_OSX
  129. # if defined(MACH_TASK_BASIC_INFO)
  130. mach_task_basic_info info;
  131. mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
  132. int const result = task_info(mach_task_self()
  133. , MACH_TASK_BASIC_INFO
  134. , (task_info_t)&info
  135. , &infoCount
  136. );
  137. # else
  138. task_basic_info info;
  139. mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT;
  140. int const result = task_info(mach_task_self()
  141. , TASK_BASIC_INFO
  142. , (task_info_t)&info
  143. , &infoCount
  144. );
  145. # endif // defined(MACH_TASK_BASIC_INFO)
  146. if (KERN_SUCCESS != result)
  147. {
  148. return 0;
  149. }
  150. return info.resident_size;
  151. #elif BX_PLATFORM_WINDOWS
  152. PROCESS_MEMORY_COUNTERS pmc;
  153. GetProcessMemoryInfo(GetCurrentProcess()
  154. , &pmc
  155. , sizeof(pmc)
  156. );
  157. return pmc.WorkingSetSize;
  158. #else
  159. return 0;
  160. #endif // BX_PLATFORM_*
  161. }
  162. void* dlopen(const FilePath& _filePath)
  163. {
  164. #if BX_PLATFORM_WINDOWS
  165. return (void*)::LoadLibraryA(_filePath.getCPtr() );
  166. #elif BX_PLATFORM_EMSCRIPTEN \
  167. || BX_PLATFORM_PS4 \
  168. || BX_PLATFORM_XBOXONE \
  169. || BX_PLATFORM_WINRT \
  170. || BX_CRT_NONE
  171. BX_UNUSED(_filePath);
  172. return NULL;
  173. #else
  174. void* so = ::dlopen(_filePath.getCPtr(), RTLD_LOCAL|RTLD_LAZY);
  175. BX_WARN(NULL != so, "dlopen failed: \"%s\".", ::dlerror() );
  176. return so;
  177. #endif // BX_PLATFORM_
  178. }
  179. void dlclose(void* _handle)
  180. {
  181. if (NULL == _handle)
  182. {
  183. return;
  184. }
  185. #if BX_PLATFORM_WINDOWS
  186. ::FreeLibrary( (HMODULE)_handle);
  187. #elif BX_PLATFORM_EMSCRIPTEN \
  188. || BX_PLATFORM_PS4 \
  189. || BX_PLATFORM_XBOXONE \
  190. || BX_PLATFORM_WINRT \
  191. || BX_CRT_NONE
  192. BX_UNUSED(_handle);
  193. #else
  194. ::dlclose(_handle);
  195. #endif // BX_PLATFORM_
  196. }
  197. void* dlsym(void* _handle, const StringView& _symbol)
  198. {
  199. const int32_t symbolMax = _symbol.getLength()+1;
  200. char* symbol = (char*)alloca(symbolMax);
  201. strCopy(symbol, symbolMax, _symbol);
  202. #if BX_PLATFORM_WINDOWS
  203. return (void*)::GetProcAddress( (HMODULE)_handle, symbol);
  204. #elif BX_PLATFORM_EMSCRIPTEN \
  205. || BX_PLATFORM_PS4 \
  206. || BX_PLATFORM_XBOXONE \
  207. || BX_PLATFORM_WINRT \
  208. || BX_CRT_NONE
  209. BX_UNUSED(_handle, symbol);
  210. return NULL;
  211. #else
  212. return ::dlsym(_handle, symbol);
  213. #endif // BX_PLATFORM_
  214. }
  215. bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name)
  216. {
  217. const int32_t nameMax = _name.getLength()+1;
  218. char* name = (char*)alloca(nameMax);
  219. strCopy(name, nameMax, _name);
  220. #if BX_PLATFORM_WINDOWS
  221. DWORD len = ::GetEnvironmentVariableA(name, _out, *_inOutSize);
  222. bool result = len != 0 && len < *_inOutSize;
  223. *_inOutSize = len;
  224. return result;
  225. #elif BX_PLATFORM_EMSCRIPTEN \
  226. || BX_PLATFORM_PS4 \
  227. || BX_PLATFORM_XBOXONE \
  228. || BX_PLATFORM_WINRT \
  229. || BX_CRT_NONE
  230. BX_UNUSED(name, _out, _inOutSize);
  231. return false;
  232. #else
  233. const char* ptr = ::getenv(name);
  234. uint32_t len = 0;
  235. bool result = false;
  236. if (NULL != ptr)
  237. {
  238. len = (uint32_t)strLen(ptr);
  239. result = len != 0 && len < *_inOutSize;
  240. if (len < *_inOutSize)
  241. {
  242. strCopy(_out, *_inOutSize, ptr);
  243. }
  244. }
  245. *_inOutSize = len;
  246. return result;
  247. #endif // BX_PLATFORM_
  248. }
  249. void setEnv(const StringView& _name, const StringView& _value)
  250. {
  251. const int32_t nameMax = _name.getLength()+1;
  252. char* name = (char*)alloca(nameMax);
  253. strCopy(name, nameMax, _name);
  254. char* value = NULL;
  255. if (!_value.isEmpty() )
  256. {
  257. int32_t valueMax = _value.getLength()+1;
  258. value = (char*)alloca(valueMax);
  259. strCopy(value, valueMax, _value);
  260. }
  261. #if BX_PLATFORM_WINDOWS
  262. ::SetEnvironmentVariableA(name, value);
  263. #elif BX_PLATFORM_EMSCRIPTEN \
  264. || BX_PLATFORM_PS4 \
  265. || BX_PLATFORM_XBOXONE \
  266. || BX_PLATFORM_WINRT \
  267. || BX_CRT_NONE
  268. BX_UNUSED(name, value);
  269. #else
  270. if (NULL != value)
  271. {
  272. ::setenv(name, value, 1);
  273. }
  274. else
  275. {
  276. ::unsetenv(name);
  277. }
  278. #endif // BX_PLATFORM_
  279. }
  280. int chdir(const char* _path)
  281. {
  282. #if BX_PLATFORM_PS4 \
  283. || BX_PLATFORM_XBOXONE \
  284. || BX_PLATFORM_WINRT \
  285. || BX_CRT_NONE
  286. BX_UNUSED(_path);
  287. return -1;
  288. #elif BX_CRT_MSVC
  289. return ::_chdir(_path);
  290. #else
  291. return ::chdir(_path);
  292. #endif // BX_COMPILER_
  293. }
  294. void* exec(const char* const* _argv)
  295. {
  296. #if BX_PLATFORM_LINUX \
  297. || BX_PLATFORM_HURD
  298. pid_t pid = fork();
  299. if (0 == pid)
  300. {
  301. int result = execvp(_argv[0], const_cast<char *const*>(&_argv[1]) );
  302. BX_UNUSED(result);
  303. return NULL;
  304. }
  305. return (void*)uintptr_t(pid);
  306. #elif BX_PLATFORM_WINDOWS
  307. STARTUPINFOA si;
  308. memSet(&si, 0, sizeof(STARTUPINFOA) );
  309. si.cb = sizeof(STARTUPINFOA);
  310. PROCESS_INFORMATION pi;
  311. memSet(&pi, 0, sizeof(PROCESS_INFORMATION) );
  312. int32_t total = 0;
  313. for (uint32_t ii = 0; NULL != _argv[ii]; ++ii)
  314. {
  315. total += (int32_t)strLen(_argv[ii]) + 1;
  316. }
  317. char* temp = (char*)alloca(total);
  318. int32_t len = 0;
  319. for(uint32_t ii = 0; NULL != _argv[ii]; ++ii)
  320. {
  321. len += snprintf(&temp[len], uint32_imax(0, total-len)
  322. , "%s "
  323. , _argv[ii]
  324. );
  325. }
  326. bool ok = !!CreateProcessA(_argv[0]
  327. , temp
  328. , NULL
  329. , NULL
  330. , false
  331. , 0
  332. , NULL
  333. , NULL
  334. , &si
  335. , &pi
  336. );
  337. if (ok)
  338. {
  339. return pi.hProcess;
  340. }
  341. return NULL;
  342. #else
  343. BX_UNUSED(_argv);
  344. return NULL;
  345. #endif // BX_PLATFORM_LINUX || BX_PLATFORM_HURD
  346. }
  347. void exit(int32_t _exitCode)
  348. {
  349. ::exit(_exitCode);
  350. }
  351. } // namespace bx