]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.c
auto merge of #10576 : thestinger/rust/gc, 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 #if defined(__WIN32__)
114 void
115 rust_get_time(int64_t *sec, int32_t *nsec) {
116     FILETIME fileTime;
117     GetSystemTimeAsFileTime(&fileTime);
118
119     // A FILETIME contains a 64-bit value representing the number of
120     // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
121     // http://support.microsoft.com/kb/167296/en-us
122     ULARGE_INTEGER ul;
123     ul.LowPart = fileTime.dwLowDateTime;
124     ul.HighPart = fileTime.dwHighDateTime;
125     uint64_t ns_since_1601 = ul.QuadPart / 10;
126
127     const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000ull;
128     uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
129     *sec = ns_since_1970 / 1000000;
130     *nsec = (ns_since_1970 % 1000000) * 1000;
131 }
132 #else
133 void
134 rust_get_time(int64_t *sec, int32_t *nsec) {
135 #ifdef __APPLE__
136     struct timeval tv;
137     gettimeofday(&tv, NULL);
138     *sec = tv.tv_sec;
139     *nsec = tv.tv_usec * 1000;
140 #else
141     struct timespec ts;
142     clock_gettime(CLOCK_REALTIME, &ts);
143     *sec = ts.tv_sec;
144     *nsec = ts.tv_nsec;
145 #endif
146 }
147 #endif
148
149 const int64_t ns_per_s = 1000000000LL;
150
151 void
152 rust_precise_time_ns(uint64_t *ns) {
153
154 #ifdef __APPLE__
155     uint64_t time = mach_absolute_time();
156     mach_timebase_info_data_t info = {0, 0};
157     if (info.denom == 0) {
158         mach_timebase_info(&info);
159     }
160     uint64_t time_nano = time * (info.numer / info.denom);
161     *ns = time_nano;
162 #elif __WIN32__
163     LARGE_INTEGER ticks_per_s;
164     BOOL query_result = QueryPerformanceFrequency(&ticks_per_s);
165     assert(query_result);
166     if (ticks_per_s.QuadPart == 0LL) {
167         ticks_per_s.QuadPart = 1LL;
168     }
169     LARGE_INTEGER ticks;
170     query_result = QueryPerformanceCounter(&ticks);
171     assert(query_result);
172     *ns = (uint64_t)((ticks.QuadPart * ns_per_s) / ticks_per_s.QuadPart);
173 #else
174     struct timespec ts;
175     clock_gettime(CLOCK_MONOTONIC, &ts);
176     *ns = (uint64_t)(ts.tv_sec * ns_per_s + ts.tv_nsec);
177 #endif
178 }
179
180 typedef struct
181 {
182     size_t fill;    // in bytes; if zero, heapified
183     size_t alloc;   // in bytes
184     uint8_t data[0];
185 } rust_vec;
186
187 typedef rust_vec rust_str;
188
189 typedef struct {
190     int32_t tm_sec;
191     int32_t tm_min;
192     int32_t tm_hour;
193     int32_t tm_mday;
194     int32_t tm_mon;
195     int32_t tm_year;
196     int32_t tm_wday;
197     int32_t tm_yday;
198     int32_t tm_isdst;
199     int32_t tm_gmtoff;
200     rust_str *tm_zone;
201     int32_t tm_nsec;
202 } rust_tm;
203
204 void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) {
205     memset(out_tm, 0, sizeof(struct tm));
206     out_tm->tm_sec = in_tm->tm_sec;
207     out_tm->tm_min = in_tm->tm_min;
208     out_tm->tm_hour = in_tm->tm_hour;
209     out_tm->tm_mday = in_tm->tm_mday;
210     out_tm->tm_mon = in_tm->tm_mon;
211     out_tm->tm_year = in_tm->tm_year;
212     out_tm->tm_wday = in_tm->tm_wday;
213     out_tm->tm_yday = in_tm->tm_yday;
214     out_tm->tm_isdst = in_tm->tm_isdst;
215 }
216
217 void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
218                    const char *zone, int32_t nsec) {
219     out_tm->tm_sec = in_tm->tm_sec;
220     out_tm->tm_min = in_tm->tm_min;
221     out_tm->tm_hour = in_tm->tm_hour;
222     out_tm->tm_mday = in_tm->tm_mday;
223     out_tm->tm_mon = in_tm->tm_mon;
224     out_tm->tm_year = in_tm->tm_year;
225     out_tm->tm_wday = in_tm->tm_wday;
226     out_tm->tm_yday = in_tm->tm_yday;
227     out_tm->tm_isdst = in_tm->tm_isdst;
228     out_tm->tm_gmtoff = gmtoff;
229     out_tm->tm_nsec = nsec;
230
231     if (zone != NULL) {
232         size_t size = strlen(zone);
233         assert(out_tm->tm_zone->alloc >= size);
234         memcpy(out_tm->tm_zone->data, zone, size);
235         out_tm->tm_zone->fill = size;
236     }
237 }
238
239 #if defined(__WIN32__)
240 #define TZSET() _tzset()
241 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
242 #define GMTIME(clock, result) gmtime_s((result), (clock))
243 #define LOCALTIME(clock, result) localtime_s((result), (clock))
244 #define TIMEGM(result) _mkgmtime64(result)
245 #else
246 struct tm* GMTIME(const time_t *clock, struct tm *result) {
247     struct tm* t = gmtime(clock);
248     if (t == NULL || result == NULL) { return NULL; }
249     *result = *t;
250     return result;
251 }
252 struct tm* LOCALTIME(const time_t *clock, struct tm *result) {
253     struct tm* t = localtime(clock);
254     if (t == NULL || result == NULL) { return NULL; }
255     *result = *t;
256     return result;
257 }
258 #define TIMEGM(result) mktime((result)) - _timezone
259 #endif
260 #else
261 #define TZSET() tzset()
262 #define GMTIME(clock, result) gmtime_r((clock), (result))
263 #define LOCALTIME(clock, result) localtime_r((clock), (result))
264 #define TIMEGM(result) timegm(result)
265 #endif
266
267 void
268 rust_tzset() {
269     TZSET();
270 }
271
272 void
273 rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
274     struct tm tm;
275     time_t s = sec;
276     GMTIME(&s, &tm);
277
278     tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
279 }
280
281 void
282 rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
283     struct tm tm;
284     time_t s = sec;
285     LOCALTIME(&s, &tm);
286
287     const char* zone = NULL;
288 #if defined(__WIN32__)
289     int32_t gmtoff = -timezone;
290     wchar_t wbuffer[64] = {0};
291     char buffer[256] = {0};
292     // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418),
293     // so time zone should be converted from UTF-16 string.
294     // Since wcsftime depends on setlocale() result,
295     // instead we convert it using MultiByteToWideChar.
296     if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) {
297         // ANSI -> UTF-16
298         MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t));
299         // UTF-16 -> UTF-8
300         WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
301         zone = buffer;
302     }
303 #else
304     int32_t gmtoff = tm.tm_gmtoff;
305     zone = tm.tm_zone;
306 #endif
307
308     tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
309 }
310
311 int64_t
312 rust_timegm(rust_tm* timeptr) {
313     struct tm t;
314     rust_tm_to_tm(timeptr, &t);
315     return TIMEGM(&t);
316 }
317
318 int64_t
319 rust_mktime(rust_tm* timeptr) {
320     struct tm t;
321     rust_tm_to_tm(timeptr, &t);
322     return mktime(&t);
323 }
324
325 #ifndef _WIN32
326 #include <sys/types.h>
327 #include <dirent.h>
328
329 DIR*
330 rust_opendir(char *dirname) {
331     return opendir(dirname);
332 }
333
334 struct dirent*
335 rust_readdir(DIR *dirp) {
336     return readdir(dirp);
337 }
338
339 #else
340
341 void
342 rust_opendir() {
343 }
344
345 void
346 rust_readdir() {
347 }
348
349 #endif
350
351 uintptr_t
352 rust_running_on_valgrind() {
353     return RUNNING_ON_VALGRIND;
354 }
355
356 #if defined(__WIN32__)
357 int
358 get_num_cpus() {
359     SYSTEM_INFO sysinfo;
360     GetSystemInfo(&sysinfo);
361
362     return (int) sysinfo.dwNumberOfProcessors;
363 }
364 #elif defined(__BSD__)
365 int
366 get_num_cpus() {
367     /* swiped from http://stackoverflow.com/questions/150355/
368        programmatically-find-the-number-of-cores-on-a-machine */
369
370     unsigned int numCPU;
371     int mib[4];
372     size_t len = sizeof(numCPU);
373
374     /* set the mib for hw.ncpu */
375     mib[0] = CTL_HW;
376     mib[1] = HW_AVAILCPU;  // alternatively, try HW_NCPU;
377
378     /* get the number of CPUs from the system */
379     sysctl(mib, 2, &numCPU, &len, NULL, 0);
380
381     if( numCPU < 1 ) {
382         mib[1] = HW_NCPU;
383         sysctl( mib, 2, &numCPU, &len, NULL, 0 );
384
385         if( numCPU < 1 ) {
386             numCPU = 1;
387         }
388     }
389     return numCPU;
390 }
391 #elif defined(__GNUC__)
392 int
393 get_num_cpus() {
394     return sysconf(_SC_NPROCESSORS_ONLN);
395 }
396 #endif
397
398 uintptr_t
399 rust_get_num_cpus() {
400     return get_num_cpus();
401 }
402
403 unsigned int
404 rust_valgrind_stack_register(void *start, void *end) {
405   return VALGRIND_STACK_REGISTER(start, end);
406 }
407
408 void
409 rust_valgrind_stack_deregister(unsigned int id) {
410   VALGRIND_STACK_DEREGISTER(id);
411 }
412
413 #if defined(__WIN32__)
414
415 void
416 rust_unset_sigprocmask() {
417     // empty stub for windows to keep linker happy
418 }
419
420 #else
421
422 #include <signal.h>
423 #include <unistd.h>
424
425 void
426 rust_unset_sigprocmask() {
427     // this can't be safely converted to rust code because the
428     // representation of sigset_t is platform-dependent
429     sigset_t sset;
430     sigemptyset(&sset);
431     sigprocmask(SIG_SETMASK, &sset, NULL);
432 }
433
434 #endif
435
436 #if defined(__WIN32__)
437 void
438 win32_require(LPCTSTR fn, BOOL ok) {
439     if (!ok) {
440         LPTSTR buf;
441         DWORD err = GetLastError();
442         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
443                       FORMAT_MESSAGE_FROM_SYSTEM |
444                       FORMAT_MESSAGE_IGNORE_INSERTS,
445                       NULL, err,
446                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
447                       (LPTSTR) &buf, 0, NULL );
448         fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf);
449         LocalFree((HLOCAL)buf);
450         abort();
451     }
452 }
453
454 void
455 rust_win32_rand_acquire(HCRYPTPROV* phProv) {
456     win32_require
457         (_T("CryptAcquireContext"),
458          // changes to the parameters here should be reflected in the docs of
459          // std::rand::os::OSRng
460          CryptAcquireContext(phProv, NULL, NULL, PROV_RSA_FULL,
461                              CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
462
463 }
464 void
465 rust_win32_rand_gen(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer) {
466     win32_require
467         (_T("CryptGenRandom"), CryptGenRandom(hProv, dwLen, pbBuffer));
468 }
469 void
470 rust_win32_rand_release(HCRYPTPROV hProv) {
471     win32_require
472         (_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
473 }
474
475 #else
476
477 // these symbols are listed in rustrt.def.in, so they need to exist; but they
478 // should never be called.
479
480 void
481 rust_win32_rand_acquire() {
482     abort();
483 }
484 void
485 rust_win32_rand_gen() {
486     abort();
487 }
488 void
489 rust_win32_rand_release() {
490     abort();
491 }
492
493 #endif
494
495 #if defined(__WIN32__)
496
497 int
498 rust_crit_section_size() { return sizeof(CRITICAL_SECTION); }
499 int
500 rust_pthread_mutex_t_size() { return 0; }
501 int
502 rust_pthread_cond_t_size() { return 0; }
503
504 #else
505
506 int
507 rust_crit_section_size() { return 0; }
508 int
509 rust_pthread_mutex_t_size() { return sizeof(pthread_mutex_t); }
510 int
511 rust_pthread_cond_t_size() { return sizeof(pthread_cond_t); }
512
513 #endif
514
515 //
516 // Local Variables:
517 // mode: C++
518 // fill-column: 78;
519 // indent-tabs-mode: nil
520 // c-basic-offset: 4
521 // buffer-file-coding-system: utf-8-unix
522 // End:
523 //