misc.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "precompile.h"
  2. #include "toolkit.h"
  3. #include "internal.h"
  4. #include "dbgutil.h"
  5. /* Maximum environment variable size, including the terminating null */
  6. #define MAX_ENV_VAR_LENGTH 6092
  7. #define TOOLKIT__NANOSEC 1000000000
  8. static toolkit_once_t toolkit_init_guard_ = TOOLKIT_ONCE_INIT;
  9. /* Interval (in seconds) of the high-resolution clock. */
  10. static double hrtime_interval_ = 0;
  11. void toolkit__misc_init(void)
  12. {
  13. LARGE_INTEGER perf_frequency;
  14. /* Retrieve high-resolution timer frequency
  15. * and precompute its reciprocal.
  16. */
  17. toolkit_winapi_init();
  18. if (QueryPerformanceFrequency(&perf_frequency)) {
  19. hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
  20. }
  21. else {
  22. hrtime_interval_ = 0;
  23. }
  24. }
  25. void toolkit__once_init(void)
  26. {
  27. toolkit_once(&toolkit_init_guard_, toolkit__misc_init);
  28. }
  29. int toolkit_environ(toolkit_env_item_t** envitems, int* count)
  30. {
  31. wchar_t* env;
  32. wchar_t* penv;
  33. int i, cnt;
  34. toolkit_env_item_t* envitem;
  35. *envitems = NULL;
  36. *count = 0;
  37. env = GetEnvironmentStringsW();
  38. if (env == NULL)
  39. return 0;
  40. for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
  41. *envitems = (toolkit_env_item_t*)ZCALLOC(i, sizeof(**envitems));
  42. if (envitems == NULL) {
  43. FreeEnvironmentStringsW(env);
  44. return TOOLKIT_ENOMEM;
  45. }
  46. penv = env;
  47. cnt = 0;
  48. while (*penv != L'\0' && cnt < i) {
  49. char* buf;
  50. char* ptr;
  51. if (toolkit__convert_utf16_to_utf8(penv, -1, &buf) != 0)
  52. goto fail;
  53. /* Using buf + 1 here because we know that `buf` has length at least 1,
  54. * and some special environment variables on Windows start with a = sign. */
  55. ptr = strchr(buf + 1, '=');
  56. if (ptr == NULL) {
  57. FREE(buf);
  58. goto do_continue;
  59. }
  60. *ptr = '\0';
  61. envitem = &(*envitems)[cnt];
  62. envitem->name = buf;
  63. envitem->value = ptr + 1;
  64. cnt++;
  65. do_continue:
  66. penv += wcslen(penv) + 1;
  67. }
  68. FreeEnvironmentStringsW(env);
  69. *count = cnt;
  70. return 0;
  71. fail:
  72. FreeEnvironmentStringsW(env);
  73. for (i = 0; i < cnt; i++) {
  74. envitem = &(*envitems)[cnt];
  75. FREE(envitem->name);
  76. }
  77. FREE(*envitems);
  78. *envitems = NULL;
  79. *count = 0;
  80. return TOOLKIT_ENOMEM;
  81. }
  82. int toolkit_getenv(const char* name, char* buffer, size_t* size)
  83. {
  84. wchar_t var[MAX_ENV_VAR_LENGTH];
  85. wchar_t* name_w;
  86. DWORD bufsize;
  87. size_t len;
  88. int r;
  89. if (name == NULL || buffer == NULL || size == NULL || *size == 0)
  90. return TOOLKIT_EINVAL;
  91. r = toolkit__convert_utf8_to_utf16(name, -1, &name_w);
  92. if (r != 0)
  93. return r;
  94. SetLastError(ERROR_SUCCESS);
  95. len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
  96. FREE(name_w);
  97. TOOLKIT_ASSERT(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
  98. if (len == 0) {
  99. r = GetLastError();
  100. if (r != ERROR_SUCCESS)
  101. return toolkit_translate_sys_error(r);
  102. }
  103. /* Check how much space we need */
  104. bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
  105. if (bufsize == 0) {
  106. return toolkit_translate_sys_error(GetLastError());
  107. }
  108. else if (bufsize > * size) {
  109. *size = bufsize;
  110. return TOOLKIT_ENOBUFS;
  111. }
  112. /* Convert to UTF-8 */
  113. bufsize = WideCharToMultiByte(CP_UTF8,
  114. 0,
  115. var,
  116. -1,
  117. buffer,
  118. *size,
  119. NULL,
  120. NULL);
  121. if (bufsize == 0)
  122. return toolkit_translate_sys_error(GetLastError());
  123. *size = bufsize - 1;
  124. return 0;
  125. }
  126. int toolkit_setenv(const char* name, const char* value) {
  127. wchar_t* name_w;
  128. wchar_t* value_w;
  129. int r;
  130. if (name == NULL || value == NULL)
  131. return TOOLKIT_EINVAL;
  132. r = toolkit__convert_utf8_to_utf16(name, -1, &name_w);
  133. if (r != 0)
  134. return r;
  135. r = toolkit__convert_utf8_to_utf16(value, -1, &value_w);
  136. if (r != 0) {
  137. FREE(name_w);
  138. return r;
  139. }
  140. r = SetEnvironmentVariableW(name_w, value_w);
  141. FREE(name_w);
  142. FREE(value_w);
  143. if (r == 0)
  144. return toolkit_translate_sys_error(GetLastError());
  145. return 0;
  146. }
  147. int toolkit_unsetenv(const char* name) {
  148. wchar_t* name_w;
  149. int r;
  150. if (name == NULL)
  151. return TOOLKIT_EINVAL;
  152. r = toolkit__convert_utf8_to_utf16(name, -1, &name_w);
  153. if (r != 0)
  154. return r;
  155. r = SetEnvironmentVariableW(name_w, NULL);
  156. FREE(name_w);
  157. if (r == 0)
  158. return toolkit_translate_sys_error(GetLastError());
  159. return 0;
  160. }
  161. uint64_t toolkit_hrtime()
  162. {
  163. toolkit__once_init();
  164. return toolkit__hrtime(TOOLKIT__NANOSEC);
  165. }
  166. uint64_t toolkit__hrtime(double scale)
  167. {
  168. LARGE_INTEGER counter;
  169. /* If the performance interval is zero, there's no support. */
  170. if (hrtime_interval_ == 0) {
  171. return 0;
  172. }
  173. if (!QueryPerformanceCounter(&counter)) {
  174. return 0;
  175. }
  176. /* Because we have no guarantee about the order of magnitude of the
  177. * performance counter interval, integer math could cause this computation
  178. * to overflow. Therefore we resort to floating point math.
  179. */
  180. return (uint64_t)((double)counter.QuadPart * hrtime_interval_ * scale);
  181. }
  182. void toolkit_sleep(int msec)
  183. {
  184. Sleep(msec);
  185. }
  186. static int toolkit__get_handle(toolkit_pid_t pid, int access, HANDLE* handle)
  187. {
  188. int r;
  189. if (pid == 0)
  190. *handle = GetCurrentProcess();
  191. else
  192. *handle = OpenProcess(access, FALSE, pid);
  193. if (*handle == NULL) {
  194. r = GetLastError();
  195. if (r == ERROR_INVALID_PARAMETER)
  196. return TOOLKIT_ESRCH;
  197. else
  198. return toolkit_translate_sys_error(r);
  199. }
  200. return 0;
  201. }
  202. int toolkit_os_getpriority(toolkit_pid_t pid, int* priority)
  203. {
  204. HANDLE handle;
  205. int r;
  206. if (priority == NULL)
  207. return TOOLKIT_EINVAL;
  208. r = toolkit__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
  209. if (r != 0)
  210. return r;
  211. r = GetPriorityClass(handle);
  212. if (r == 0) {
  213. r = toolkit_translate_sys_error(GetLastError());
  214. } else {
  215. /* Map Windows priority classes to Unix nice values. */
  216. if (r == REALTIME_PRIORITY_CLASS)
  217. *priority = TOOLKIT_PRIORITY_HIGHEST;
  218. else if (r == HIGH_PRIORITY_CLASS)
  219. *priority = TOOLKIT_PRIORITY_HIGH;
  220. else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
  221. *priority = TOOLKIT_PRIORITY_ABOVE_NORMAL;
  222. else if (r == NORMAL_PRIORITY_CLASS)
  223. *priority = TOOLKIT_PRIORITY_NORMAL;
  224. else if (r == BELOW_NORMAL_PRIORITY_CLASS)
  225. *priority = TOOLKIT_PRIORITY_BELOW_NORMAL;
  226. else /* IDLE_PRIORITY_CLASS */
  227. *priority = TOOLKIT_PRIORITY_LOW;
  228. r = 0;
  229. }
  230. CloseHandle(handle);
  231. return r;
  232. }
  233. int toolkit_os_setpriority(toolkit_pid_t pid, int priority)
  234. {
  235. HANDLE handle;
  236. int priority_class;
  237. int r;
  238. /* Map Unix nice values to Windows priority classes. */
  239. if (priority < TOOLKIT_PRIORITY_HIGHEST || priority > TOOLKIT_PRIORITY_LOW)
  240. return TOOLKIT_EINVAL;
  241. else if (priority < TOOLKIT_PRIORITY_HIGH)
  242. priority_class = REALTIME_PRIORITY_CLASS;
  243. else if (priority < TOOLKIT_PRIORITY_ABOVE_NORMAL)
  244. priority_class = HIGH_PRIORITY_CLASS;
  245. else if (priority < TOOLKIT_PRIORITY_NORMAL)
  246. priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
  247. else if (priority < TOOLKIT_PRIORITY_BELOW_NORMAL)
  248. priority_class = NORMAL_PRIORITY_CLASS;
  249. else if (priority < TOOLKIT_PRIORITY_LOW)
  250. priority_class = BELOW_NORMAL_PRIORITY_CLASS;
  251. else
  252. priority_class = IDLE_PRIORITY_CLASS;
  253. r = toolkit__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
  254. if (r != 0)
  255. return r;
  256. if (SetPriorityClass(handle, priority_class) == 0)
  257. r = toolkit_translate_sys_error(GetLastError());
  258. CloseHandle(handle);
  259. return r;
  260. }