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