]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.c
auto merge of #10961 : brson/rust/lessc, r=alexcrichton
[rust.git] / src / rt / rust_builtin.c
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /* Foreign builtins. */
12
13 #include "vg/valgrind.h"
14
15 #include <stdint.h>
16 #include <time.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <stdlib.h>
20
21 #if !defined(__WIN32__)
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <dirent.h>
25 #include <signal.h>
26 #include <unistd.h>
27 #include <pthread.h>
28 #else
29 #include <windows.h>
30 #include <wincrypt.h>
31 #include <stdio.h>
32 #include <tchar.h>
33 #endif
34
35 #ifdef __APPLE__
36 #include <TargetConditionals.h>
37 #include <mach/mach_time.h>
38
39 #if !(TARGET_OS_IPHONE)
40 #include <crt_externs.h>
41 #endif
42 #endif
43
44 #ifdef __ANDROID__
45 time_t
46 timegm(struct tm *tm)
47 {
48     time_t ret;
49     char *tz;
50
51     tz = getenv("TZ");
52     if (tz)
53         tz = strdup(tz);
54     setenv("TZ", "", 1);
55     tzset();
56     ret = mktime(tm);
57     if (tz) {
58         setenv("TZ", tz, 1);
59         free(tz);
60     } else
61         unsetenv("TZ");
62     tzset();
63     return ret;
64 }
65 #endif
66
67 #ifdef __APPLE__
68 #if (TARGET_OS_IPHONE)
69 extern char **environ;
70 #endif
71 #endif
72
73 #if defined(__FreeBSD__) || defined(__linux__) || defined(__ANDROID__)
74 extern char **environ;
75 #endif
76
77 #if defined(__WIN32__)
78 char**
79 rust_env_pairs() {
80     return 0;
81 }
82 #else
83 char**
84 rust_env_pairs() {
85 #if defined(__APPLE__) && !(TARGET_OS_IPHONE)
86     char **environ = *_NSGetEnviron();
87 #endif
88     return environ;
89 }
90 #endif
91
92 char*
93 #if defined(__WIN32__)
94 rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
95     return entry_ptr->cFileName;
96 }
97 #else
98 rust_list_dir_val(struct dirent* entry_ptr) {
99     return entry_ptr->d_name;
100 }
101 #endif
102
103 size_t
104 #if defined(__WIN32__)
105 rust_list_dir_wfd_size() {
106     return sizeof(WIN32_FIND_DATAW);
107 }
108 #else
109 rust_list_dir_wfd_size() {
110     return 0;
111 }
112 #endif
113
114 void*
115 #if defined(__WIN32__)
116 rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) {
117     if(wfd == NULL) {
118         return 0;
119     }
120     else {
121         return wfd->cFileName;
122     }
123 }
124 #else
125 rust_list_dir_wfd_fp_buf(void* wfd) {
126     return 0;
127 }
128 #endif
129
130 #if defined(__WIN32__)
131 void
132 rust_get_time(int64_t *sec, int32_t *nsec) {
133     FILETIME fileTime;
134     GetSystemTimeAsFileTime(&fileTime);
135
136     // A FILETIME contains a 64-bit value representing the number of
137     // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
138     // http://support.microsoft.com/kb/167296/en-us
139     ULARGE_INTEGER ul;
140     ul.LowPart = fileTime.dwLowDateTime;
141     ul.HighPart = fileTime.dwHighDateTime;
142     uint64_t ns_since_1601 = ul.QuadPart / 10;
143
144     const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000ull;
145     uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
146     *sec = ns_since_1970 / 1000000;
147     *nsec = (ns_since_1970 % 1000000) * 1000;
148 }
149 #else
150 void
151 rust_get_time(int64_t *sec, int32_t *nsec) {
152 #ifdef __APPLE__
153     struct timeval tv;
154     gettimeofday(&tv, NULL);
155     *sec = tv.tv_sec;
156     *nsec = tv.tv_usec * 1000;
157 #else
158     struct timespec ts;
159     clock_gettime(CLOCK_REALTIME, &ts);
160     *sec = ts.tv_sec;
161     *nsec = ts.tv_nsec;
162 #endif
163 }
164 #endif
165
166 const int64_t ns_per_s = 1000000000LL;
167
168 void
169 rust_precise_time_ns(uint64_t *ns) {
170
171 #ifdef __APPLE__
172     uint64_t time = mach_absolute_time();
173     mach_timebase_info_data_t info = {0, 0};
174     if (info.denom == 0) {
175         mach_timebase_info(&info);
176     }
177     uint64_t time_nano = time * (info.numer / info.denom);
178     *ns = time_nano;
179 #elif __WIN32__
180     LARGE_INTEGER ticks_per_s;
181     BOOL query_result = QueryPerformanceFrequency(&ticks_per_s);
182     assert(query_result);
183     if (ticks_per_s.QuadPart == 0LL) {
184         ticks_per_s.QuadPart = 1LL;
185     }
186     LARGE_INTEGER ticks;
187     query_result = QueryPerformanceCounter(&ticks);
188     assert(query_result);
189     *ns = (uint64_t)((ticks.QuadPart * ns_per_s) / ticks_per_s.QuadPart);
190 #else
191     struct timespec ts;
192     clock_gettime(CLOCK_MONOTONIC, &ts);
193     *ns = (uint64_t)(ts.tv_sec * ns_per_s + ts.tv_nsec);
194 #endif
195 }
196
197 typedef struct
198 {
199     size_t fill;    // in bytes; if zero, heapified
200     size_t alloc;   // in bytes
201     uint8_t data[0];
202 } rust_vec;
203
204 typedef rust_vec rust_str;
205
206 typedef struct {
207     int32_t tm_sec;
208     int32_t tm_min;
209     int32_t tm_hour;
210     int32_t tm_mday;
211     int32_t tm_mon;
212     int32_t tm_year;
213     int32_t tm_wday;
214     int32_t tm_yday;
215     int32_t tm_isdst;
216     int32_t tm_gmtoff;
217     rust_str *tm_zone;
218     int32_t tm_nsec;
219 } rust_tm;
220
221 void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) {
222     memset(out_tm, 0, sizeof(struct tm));
223     out_tm->tm_sec = in_tm->tm_sec;
224     out_tm->tm_min = in_tm->tm_min;
225     out_tm->tm_hour = in_tm->tm_hour;
226     out_tm->tm_mday = in_tm->tm_mday;
227     out_tm->tm_mon = in_tm->tm_mon;
228     out_tm->tm_year = in_tm->tm_year;
229     out_tm->tm_wday = in_tm->tm_wday;
230     out_tm->tm_yday = in_tm->tm_yday;
231     out_tm->tm_isdst = in_tm->tm_isdst;
232 }
233
234 void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
235                    const char *zone, int32_t nsec) {
236     out_tm->tm_sec = in_tm->tm_sec;
237     out_tm->tm_min = in_tm->tm_min;
238     out_tm->tm_hour = in_tm->tm_hour;
239     out_tm->tm_mday = in_tm->tm_mday;
240     out_tm->tm_mon = in_tm->tm_mon;
241     out_tm->tm_year = in_tm->tm_year;
242     out_tm->tm_wday = in_tm->tm_wday;
243     out_tm->tm_yday = in_tm->tm_yday;
244     out_tm->tm_isdst = in_tm->tm_isdst;
245     out_tm->tm_gmtoff = gmtoff;
246     out_tm->tm_nsec = nsec;
247
248     if (zone != NULL) {
249         size_t size = strlen(zone);
250         assert(out_tm->tm_zone->alloc >= size);
251         memcpy(out_tm->tm_zone->data, zone, size);
252         out_tm->tm_zone->fill = size;
253     }
254 }
255
256 #if defined(__WIN32__)
257 #define TZSET() _tzset()
258 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
259 #define GMTIME(clock, result) gmtime_s((result), (clock))
260 #define LOCALTIME(clock, result) localtime_s((result), (clock))
261 #define TIMEGM(result) _mkgmtime64(result)
262 #else
263 struct tm* GMTIME(const time_t *clock, struct tm *result) {
264     struct tm* t = gmtime(clock);
265     if (t == NULL || result == NULL) { return NULL; }
266     *result = *t;
267     return result;
268 }
269 struct tm* LOCALTIME(const time_t *clock, struct tm *result) {
270     struct tm* t = localtime(clock);
271     if (t == NULL || result == NULL) { return NULL; }
272     *result = *t;
273     return result;
274 }
275 #define TIMEGM(result) mktime((result)) - _timezone
276 #endif
277 #else
278 #define TZSET() tzset()
279 #define GMTIME(clock, result) gmtime_r((clock), (result))
280 #define LOCALTIME(clock, result) localtime_r((clock), (result))
281 #define TIMEGM(result) timegm(result)
282 #endif
283
284 void
285 rust_tzset() {
286     TZSET();
287 }
288
289 void
290 rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
291     struct tm tm;
292     time_t s = sec;
293     GMTIME(&s, &tm);
294
295     tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
296 }
297
298 void
299 rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
300     struct tm tm;
301     time_t s = sec;
302     LOCALTIME(&s, &tm);
303
304     const char* zone = NULL;
305 #if defined(__WIN32__)
306     int32_t gmtoff = -timezone;
307     wchar_t wbuffer[64] = {0};
308     char buffer[256] = {0};
309     // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418),
310     // so time zone should be converted from UTF-16 string.
311     // Since wcsftime depends on setlocale() result,
312     // instead we convert it using MultiByteToWideChar.
313     if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) {
314         // ANSI -> UTF-16
315         MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t));
316         // UTF-16 -> UTF-8
317         WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
318         zone = buffer;
319     }
320 #else
321     int32_t gmtoff = tm.tm_gmtoff;
322     zone = tm.tm_zone;
323 #endif
324
325     tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
326 }
327
328 int64_t
329 rust_timegm(rust_tm* timeptr) {
330     struct tm t;
331     rust_tm_to_tm(timeptr, &t);
332     return TIMEGM(&t);
333 }
334
335 int64_t
336 rust_mktime(rust_tm* timeptr) {
337     struct tm t;
338     rust_tm_to_tm(timeptr, &t);
339     return mktime(&t);
340 }
341
342 #ifndef _WIN32
343
344 DIR*
345 rust_opendir(char *dirname) {
346     return opendir(dirname);
347 }
348
349 struct dirent*
350 rust_readdir(DIR *dirp) {
351     return readdir(dirp);
352 }
353
354 #else
355
356 void
357 rust_opendir() {
358 }
359
360 void
361 rust_readdir() {
362 }
363
364 #endif
365
366 uintptr_t
367 rust_running_on_valgrind() {
368     return RUNNING_ON_VALGRIND;
369 }
370
371 #if defined(__WIN32__)
372 int
373 get_num_cpus() {
374     SYSTEM_INFO sysinfo;
375     GetSystemInfo(&sysinfo);
376
377     return (int) sysinfo.dwNumberOfProcessors;
378 }
379 #elif defined(__BSD__)
380 int
381 get_num_cpus() {
382     /* swiped from http://stackoverflow.com/questions/150355/
383        programmatically-find-the-number-of-cores-on-a-machine */
384
385     unsigned int numCPU;
386     int mib[4];
387     size_t len = sizeof(numCPU);
388
389     /* set the mib for hw.ncpu */
390     mib[0] = CTL_HW;
391     mib[1] = HW_AVAILCPU;  // alternatively, try HW_NCPU;
392
393     /* get the number of CPUs from the system */
394     sysctl(mib, 2, &numCPU, &len, NULL, 0);
395
396     if( numCPU < 1 ) {
397         mib[1] = HW_NCPU;
398         sysctl( mib, 2, &numCPU, &len, NULL, 0 );
399
400         if( numCPU < 1 ) {
401             numCPU = 1;
402         }
403     }
404     return numCPU;
405 }
406 #elif defined(__GNUC__)
407 int
408 get_num_cpus() {
409     return sysconf(_SC_NPROCESSORS_ONLN);
410 }
411 #endif
412
413 uintptr_t
414 rust_get_num_cpus() {
415     return get_num_cpus();
416 }
417
418 unsigned int
419 rust_valgrind_stack_register(void *start, void *end) {
420   return VALGRIND_STACK_REGISTER(start, end);
421 }
422
423 void
424 rust_valgrind_stack_deregister(unsigned int id) {
425   VALGRIND_STACK_DEREGISTER(id);
426 }
427
428 #if defined(__WIN32__)
429
430 void
431 rust_unset_sigprocmask() {
432     // empty stub for windows to keep linker happy
433 }
434
435 #else
436
437 void
438 rust_unset_sigprocmask() {
439     // this can't be safely converted to rust code because the
440     // representation of sigset_t is platform-dependent
441     sigset_t sset;
442     sigemptyset(&sset);
443     sigprocmask(SIG_SETMASK, &sset, NULL);
444 }
445
446 #endif
447
448 #if defined(__WIN32__)
449 void
450 win32_require(LPCTSTR fn, BOOL ok) {
451     if (!ok) {
452         LPTSTR buf;
453         DWORD err = GetLastError();
454         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
455                       FORMAT_MESSAGE_FROM_SYSTEM |
456                       FORMAT_MESSAGE_IGNORE_INSERTS,
457                       NULL, err,
458                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
459                       (LPTSTR) &buf, 0, NULL );
460         fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf);
461         LocalFree((HLOCAL)buf);
462         abort();
463     }
464 }
465
466 void
467 rust_win32_rand_acquire(HCRYPTPROV* phProv) {
468     win32_require
469         (_T("CryptAcquireContext"),
470          // changes to the parameters here should be reflected in the docs of
471          // std::rand::os::OSRng
472          CryptAcquireContext(phProv, NULL, NULL, PROV_RSA_FULL,
473                              CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
474
475 }
476 void
477 rust_win32_rand_gen(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer) {
478     win32_require
479         (_T("CryptGenRandom"), CryptGenRandom(hProv, dwLen, pbBuffer));
480 }
481 void
482 rust_win32_rand_release(HCRYPTPROV hProv) {
483     win32_require
484         (_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
485 }
486
487 #else
488
489 // these symbols are listed in rustrt.def.in, so they need to exist; but they
490 // should never be called.
491
492 void
493 rust_win32_rand_acquire() {
494     abort();
495 }
496 void
497 rust_win32_rand_gen() {
498     abort();
499 }
500 void
501 rust_win32_rand_release() {
502     abort();
503 }
504
505 #endif
506
507 #if defined(__WIN32__)
508
509 int
510 rust_crit_section_size() { return sizeof(CRITICAL_SECTION); }
511 int
512 rust_pthread_mutex_t_size() { return 0; }
513 int
514 rust_pthread_cond_t_size() { return 0; }
515
516 #else
517
518 int
519 rust_crit_section_size() { return 0; }
520 int
521 rust_pthread_mutex_t_size() { return sizeof(pthread_mutex_t); }
522 int
523 rust_pthread_cond_t_size() { return sizeof(pthread_cond_t); }
524
525 #endif
526
527 //
528 // Local Variables:
529 // mode: C++
530 // fill-column: 78;
531 // indent-tabs-mode: nil
532 // c-basic-offset: 4
533 // buffer-file-coding-system: utf-8-unix
534 // End:
535 //