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