]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.cpp
std: Remove at_exit API. Unused
[rust.git] / src / rt / rust_builtin.cpp
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_sched_loop.h"
14 #include "rust_task.h"
15 #include "rust_util.h"
16 #include "rust_scheduler.h"
17 #include "sync/timer.h"
18 #include "sync/rust_thread.h"
19 #include "rust_abi.h"
20 #include "vg/valgrind.h"
21
22 #include <time.h>
23
24 #ifdef __APPLE__
25 #include <crt_externs.h>
26 #endif
27
28 #if !defined(__WIN32__)
29 #include <sys/time.h>
30 #endif
31
32 #ifdef __FreeBSD__
33 extern char **environ;
34 #endif
35
36 #ifdef __ANDROID__
37 time_t
38 timegm(struct tm *tm)
39 {
40     time_t ret;
41     char *tz;
42
43     tz = getenv("TZ");
44     setenv("TZ", "", 1);
45     tzset();
46     ret = mktime(tm);
47     if (tz)
48         setenv("TZ", tz, 1);
49     else
50         unsetenv("TZ");
51     tzset();
52     return ret;
53 }
54 #endif
55
56 #if defined(__WIN32__)
57 extern "C" CDECL char**
58 rust_env_pairs() {
59     return 0;
60 }
61 #else
62 extern "C" CDECL char**
63 rust_env_pairs() {
64 #ifdef __APPLE__
65     char **environ = *_NSGetEnviron();
66 #endif
67     return environ;
68 }
69 #endif
70
71 extern "C" CDECL void *
72 rust_local_realloc(rust_opaque_box *ptr, size_t size) {
73     rust_task *task = rust_get_current_task();
74     return task->boxed.realloc(ptr, size);
75 }
76
77 extern "C" CDECL size_t
78 rand_seed_size() {
79     return rng_seed_size();
80 }
81
82 extern "C" CDECL void
83 rand_gen_seed(uint8_t* dest, size_t size) {
84     rng_gen_seed(dest, size);
85 }
86
87 extern "C" CDECL void *
88 rand_new_seeded(uint8_t* seed, size_t seed_size) {
89     assert(seed != NULL);
90     rust_rng *rng = (rust_rng *) malloc(sizeof(rust_rng));
91     assert(rng != NULL && "rng alloc failed");
92     rng_init(rng, NULL, seed, seed_size);
93     return rng;
94 }
95
96 extern "C" CDECL uint32_t
97 rand_next(rust_rng *rng) {
98     return rng_gen_u32(rng);
99 }
100
101 extern "C" CDECL void
102 rand_free(rust_rng *rng) {
103     free(rng);
104 }
105
106
107 /* Debug helpers strictly to verify ABI conformance.
108  *
109  * FIXME (#2665): move these into a testcase when the testsuite
110  * understands how to have explicit C files included.
111  */
112
113 struct quad {
114     uint64_t a;
115     uint64_t b;
116     uint64_t c;
117     uint64_t d;
118 };
119
120 struct floats {
121     double a;
122     uint8_t b;
123     double c;
124 };
125
126 extern "C" quad
127 debug_abi_1(quad q) {
128     quad qq = { q.c + 1,
129                 q.d - 1,
130                 q.a + 1,
131                 q.b - 1 };
132     return qq;
133 }
134
135 extern "C" floats
136 debug_abi_2(floats f) {
137     floats ff = { f.c + 1.0,
138                   0xff,
139                   f.a - 1.0 };
140     return ff;
141 }
142
143 extern "C" int
144 debug_static_mut;
145
146 int debug_static_mut = 3;
147
148 extern "C" void
149 debug_static_mut_check_four() {
150     assert(debug_static_mut == 4);
151 }
152
153 /* Debug builtins for std::dbg. */
154
155 static void
156 debug_tydesc_helper(type_desc *t)
157 {
158     rust_task *task = rust_get_current_task();
159     LOG(task, stdlib, "  size %" PRIdPTR ", align %" PRIdPTR,
160         t->size, t->align);
161 }
162
163 extern "C" CDECL void
164 debug_tydesc(type_desc *t) {
165     rust_task *task = rust_get_current_task();
166     LOG(task, stdlib, "debug_tydesc");
167     debug_tydesc_helper(t);
168 }
169
170 extern "C" CDECL void
171 debug_opaque(type_desc *t, uint8_t *front) {
172     rust_task *task = rust_get_current_task();
173     LOG(task, stdlib, "debug_opaque");
174     debug_tydesc_helper(t);
175     // Account for alignment. `front` may not indeed be the
176     // front byte of the passed-in argument
177     if (((uintptr_t)front % t->align) != 0) {
178         front = (uint8_t *)align_to((uintptr_t)front, (size_t)t->align);
179     }
180     for (uintptr_t i = 0; i < t->size; ++front, ++i) {
181         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
182     }
183 }
184
185 extern "C" CDECL void
186 debug_box(type_desc *t, rust_opaque_box *box) {
187     rust_task *task = rust_get_current_task();
188     LOG(task, stdlib, "debug_box(0x%" PRIxPTR ")", box);
189     debug_tydesc_helper(t);
190     LOG(task, stdlib, "  refcount %" PRIdPTR,
191         box->ref_count - 1);  // -1 because we ref'ed for this call
192     uint8_t *data = (uint8_t *)box_body(box);
193     for (uintptr_t i = 0; i < t->size; ++i) {
194         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, data[i]);
195     }
196 }
197
198 struct rust_tag {
199     uintptr_t discriminant;
200     uint8_t variant[];
201 };
202
203 extern "C" CDECL void
204 debug_tag(type_desc *t, rust_tag *tag) {
205     rust_task *task = rust_get_current_task();
206
207     LOG(task, stdlib, "debug_tag");
208     debug_tydesc_helper(t);
209     LOG(task, stdlib, "  discriminant %" PRIdPTR, tag->discriminant);
210
211     for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
212         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i,
213             tag->variant[i]);
214 }
215
216 extern "C" CDECL void
217 debug_fn(type_desc *t, fn_env_pair *fn) {
218     rust_task *task = rust_get_current_task();
219     LOG(task, stdlib, "debug_fn");
220     debug_tydesc_helper(t);
221     LOG(task, stdlib, " fn at 0x%" PRIxPTR, fn->f);
222     LOG(task, stdlib, "  env at 0x%" PRIxPTR, fn->env);
223     if (fn->env) {
224         LOG(task, stdlib, "    refcount %" PRIdPTR, fn->env->ref_count);
225     }
226 }
227
228 extern "C" CDECL void *
229 debug_ptrcast(type_desc *from_ty,
230               type_desc *to_ty,
231               void *ptr) {
232     rust_task *task = rust_get_current_task();
233     LOG(task, stdlib, "debug_ptrcast from");
234     debug_tydesc_helper(from_ty);
235     LOG(task, stdlib, "to");
236     debug_tydesc_helper(to_ty);
237     return ptr;
238 }
239
240 extern "C" CDECL void *
241 debug_get_stk_seg() {
242     rust_task *task = rust_get_current_task();
243     return task->stk;
244 }
245
246 extern "C" CDECL char*
247 #if defined(__WIN32__)
248 rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
249     return entry_ptr->cFileName;
250 }
251 #else
252 rust_list_dir_val(dirent* entry_ptr) {
253     return entry_ptr->d_name;
254 }
255 #endif
256
257 extern "C" CDECL size_t
258 #if defined(__WIN32__)
259 rust_list_dir_wfd_size() {
260     return sizeof(WIN32_FIND_DATAW);
261 }
262 #else
263 rust_list_dir_wfd_size() {
264     return 0;
265 }
266 #endif
267
268 extern "C" CDECL void*
269 #if defined(__WIN32__)
270 rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) {
271     if(wfd == NULL) {
272         return 0;
273     }
274     else {
275         return wfd->cFileName;
276     }
277 }
278 #else
279 rust_list_dir_wfd_fp_buf(void* wfd) {
280     return 0;
281 }
282 #endif
283
284 extern "C" CDECL int
285 rust_path_is_dir(char *path) {
286     struct stat buf;
287     if (stat(path, &buf)) {
288         return 0;
289     }
290     return S_ISDIR(buf.st_mode);
291 }
292
293 extern "C" CDECL int
294 rust_path_exists(char *path) {
295     struct stat buf;
296     if (stat(path, &buf)) {
297         return 0;
298     }
299     return 1;
300 }
301
302 extern "C" CDECL FILE* rust_get_stdin() {return stdin;}
303 extern "C" CDECL FILE* rust_get_stdout() {return stdout;}
304 extern "C" CDECL FILE* rust_get_stderr() {return stderr;}
305
306 #if defined(__WIN32__)
307 extern "C" CDECL void
308 get_time(int64_t *sec, int32_t *nsec) {
309     FILETIME fileTime;
310     GetSystemTimeAsFileTime(&fileTime);
311
312     // A FILETIME contains a 64-bit value representing the number of
313     // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
314     // http://support.microsoft.com/kb/167296/en-us
315     ULARGE_INTEGER ul;
316     ul.LowPart = fileTime.dwLowDateTime;
317     ul.HighPart = fileTime.dwHighDateTime;
318     uint64_t ns_since_1601 = ul.QuadPart / 10;
319
320     const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000ull;
321     uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
322     *sec = ns_since_1970 / 1000000;
323     *nsec = (ns_since_1970 % 1000000) * 1000;
324 }
325 #else
326 extern "C" CDECL void
327 get_time(int64_t *sec, int32_t *nsec) {
328 #ifdef __APPLE__
329     struct timeval tv;
330     gettimeofday(&tv, NULL);
331     *sec = tv.tv_sec;
332     *nsec = tv.tv_usec * 1000;
333 #else
334     timespec ts;
335     clock_gettime(CLOCK_REALTIME, &ts);
336     *sec = ts.tv_sec;
337     *nsec = ts.tv_nsec;
338 #endif
339 }
340 #endif
341
342 extern "C" CDECL void
343 precise_time_ns(uint64_t *ns) {
344     timer t;
345     *ns = t.time_ns();
346 }
347
348 struct rust_tm {
349     int32_t tm_sec;
350     int32_t tm_min;
351     int32_t tm_hour;
352     int32_t tm_mday;
353     int32_t tm_mon;
354     int32_t tm_year;
355     int32_t tm_wday;
356     int32_t tm_yday;
357     int32_t tm_isdst;
358     int32_t tm_gmtoff;
359     rust_str *tm_zone;
360     int32_t tm_nsec;
361 };
362
363 void rust_tm_to_tm(rust_tm* in_tm, tm* out_tm) {
364     memset(out_tm, 0, sizeof(tm));
365     out_tm->tm_sec = in_tm->tm_sec;
366     out_tm->tm_min = in_tm->tm_min;
367     out_tm->tm_hour = in_tm->tm_hour;
368     out_tm->tm_mday = in_tm->tm_mday;
369     out_tm->tm_mon = in_tm->tm_mon;
370     out_tm->tm_year = in_tm->tm_year;
371     out_tm->tm_wday = in_tm->tm_wday;
372     out_tm->tm_yday = in_tm->tm_yday;
373     out_tm->tm_isdst = in_tm->tm_isdst;
374 }
375
376 void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
377                    const char *zone, int32_t nsec) {
378     out_tm->tm_sec = in_tm->tm_sec;
379     out_tm->tm_min = in_tm->tm_min;
380     out_tm->tm_hour = in_tm->tm_hour;
381     out_tm->tm_mday = in_tm->tm_mday;
382     out_tm->tm_mon = in_tm->tm_mon;
383     out_tm->tm_year = in_tm->tm_year;
384     out_tm->tm_wday = in_tm->tm_wday;
385     out_tm->tm_yday = in_tm->tm_yday;
386     out_tm->tm_isdst = in_tm->tm_isdst;
387     out_tm->tm_gmtoff = gmtoff;
388     out_tm->tm_nsec = nsec;
389
390     if (zone != NULL) {
391         size_t size = strlen(zone);
392         reserve_vec_exact(&out_tm->tm_zone, size + 1);
393         memcpy(out_tm->tm_zone->data, zone, size);
394         out_tm->tm_zone->fill = size + 1;
395         out_tm->tm_zone->data[size] = '\0';
396     }
397 }
398
399 #if defined(__WIN32__)
400 #define TZSET() _tzset()
401 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
402 #define GMTIME(clock, result) gmtime_s((result), (clock))
403 #define LOCALTIME(clock, result) localtime_s((result), (clock))
404 #define TIMEGM(result) _mkgmtime64(result)
405 #else
406 struct tm* GMTIME(const time_t *clock, tm *result) {
407     struct tm* t = gmtime(clock);
408     if (t == NULL || result == NULL) { return NULL; }
409     *result = *t;
410     return result;
411 }
412 struct tm* LOCALTIME(const time_t *clock, tm *result) {
413     struct tm* t = localtime(clock);
414     if (t == NULL || result == NULL) { return NULL; }
415     *result = *t;
416     return result;
417 }
418 #define TIMEGM(result) mktime((result)) - _timezone
419 #endif
420 #else
421 #define TZSET() tzset()
422 #define GMTIME(clock, result) gmtime_r((clock), (result))
423 #define LOCALTIME(clock, result) localtime_r((clock), (result))
424 #define TIMEGM(result) timegm(result)
425 #endif
426
427 extern "C" CDECL void
428 rust_tzset() {
429     TZSET();
430 }
431
432 extern "C" CDECL void
433 rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
434     tm tm;
435     time_t s = sec;
436     GMTIME(&s, &tm);
437
438     tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
439 }
440
441 extern "C" CDECL void
442 rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
443     tm tm;
444     time_t s = sec;
445     LOCALTIME(&s, &tm);
446
447 #if defined(__WIN32__)
448     int32_t gmtoff = -timezone;
449     char zone[64];
450     strftime(zone, sizeof(zone), "%Z", &tm);
451 #else
452     int32_t gmtoff = tm.tm_gmtoff;
453     const char *zone = tm.tm_zone;
454 #endif
455
456     tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
457 }
458
459 extern "C" CDECL int64_t
460 rust_timegm(rust_tm* timeptr) {
461     tm t;
462     rust_tm_to_tm(timeptr, &t);
463     return TIMEGM(&t);
464 }
465
466 extern "C" CDECL int64_t
467 rust_mktime(rust_tm* timeptr) {
468     tm t;
469     rust_tm_to_tm(timeptr, &t);
470     return mktime(&t);
471 }
472
473 extern "C" CDECL rust_sched_id
474 rust_get_sched_id() {
475     rust_task *task = rust_get_current_task();
476     return task->sched->get_id();
477 }
478
479 extern "C" CDECL int
480 rust_get_argc() {
481     rust_task *task = rust_get_current_task();
482     return task->kernel->env->argc;
483 }
484
485 extern "C" CDECL char**
486 rust_get_argv() {
487     rust_task *task = rust_get_current_task();
488     return task->kernel->env->argv;
489 }
490
491 extern "C" CDECL rust_sched_id
492 rust_new_sched(uintptr_t threads) {
493     rust_task *task = rust_get_current_task();
494     assert(threads > 0 && "Can't create a scheduler with no threads, silly!");
495     return task->kernel->create_scheduler(threads);
496 }
497
498 extern "C" CDECL rust_task_id
499 get_task_id() {
500     rust_task *task = rust_get_current_task();
501     return task->id;
502 }
503
504 static rust_task*
505 new_task_common(rust_scheduler *sched, rust_task *parent) {
506     return sched->create_task(parent, NULL);
507 }
508
509 extern "C" CDECL rust_task*
510 new_task() {
511     rust_task *task = rust_get_current_task();
512     rust_sched_id sched_id = task->kernel->main_sched_id();
513     rust_scheduler *sched = task->kernel->get_scheduler_by_id(sched_id);
514     assert(sched != NULL && "should always have a main scheduler");
515     return new_task_common(sched, task);
516 }
517
518 extern "C" CDECL rust_task*
519 rust_new_task_in_sched(rust_sched_id id) {
520     rust_task *task = rust_get_current_task();
521     rust_scheduler *sched = task->kernel->get_scheduler_by_id(id);
522     if (sched == NULL)
523         return NULL;
524     return new_task_common(sched, task);
525 }
526
527 extern "C" rust_task *
528 rust_get_task() {
529     return rust_get_current_task();
530 }
531
532 extern "C" rust_task *
533 rust_try_get_task() {
534     return rust_try_get_current_task();
535 }
536
537 extern "C" CDECL stk_seg *
538 rust_get_stack_segment() {
539     return rust_get_current_task()->stk;
540 }
541
542 extern "C" CDECL stk_seg *
543 rust_get_c_stack() {
544     return rust_get_current_task()->get_c_stack();
545 }
546
547 extern "C" CDECL void
548 start_task(rust_task *target, fn_env_pair *f) {
549     target->start(f->f, f->env, NULL);
550 }
551
552 extern "C" CDECL size_t
553 rust_sched_current_nonlazy_threads() {
554     rust_task *task = rust_get_current_task();
555     return task->sched->number_of_threads();
556 }
557
558 extern "C" CDECL size_t
559 rust_sched_threads() {
560     rust_task *task = rust_get_current_task();
561     return task->sched->max_number_of_threads();
562 }
563
564 // This is called by an intrinsic on the Rust stack and must run
565 // entirely in the red zone. Do not call on the C stack.
566 extern "C" CDECL MUST_CHECK bool
567 rust_task_yield(rust_task *task, bool *killed) {
568     return task->yield();
569 }
570
571 extern "C" CDECL void
572 rust_set_exit_status(intptr_t code) {
573     rust_task *task = rust_get_current_task();
574     task->kernel->set_exit_status((int)code);
575 }
576
577 extern void log_console_on();
578
579 extern "C" CDECL void
580 rust_log_console_on() {
581     log_console_on();
582 }
583
584 extern void log_console_off();
585
586 extern "C" CDECL void
587 rust_log_console_off() {
588     log_console_off();
589 }
590
591 extern bool should_log_console();
592
593 extern "C" CDECL uintptr_t
594 rust_should_log_console() {
595     return (uintptr_t)should_log_console();
596 }
597
598 extern "C" CDECL void
599 rust_dbg_breakpoint() {
600     BREAKPOINT_AWESOME;
601 }
602
603 extern "C" CDECL rust_sched_id
604 rust_osmain_sched_id() {
605     rust_task *task = rust_get_current_task();
606     return task->kernel->osmain_sched_id();
607 }
608
609 extern "C" void
610 rust_task_inhibit_kill(rust_task *task) {
611     task->inhibit_kill();
612 }
613
614 extern "C" void
615 rust_task_allow_kill(rust_task *task) {
616     task->allow_kill();
617 }
618
619 extern "C" void
620 rust_task_inhibit_yield(rust_task *task) {
621     task->inhibit_yield();
622 }
623
624 extern "C" void
625 rust_task_allow_yield(rust_task *task) {
626     task->allow_yield();
627 }
628
629 extern "C" void
630 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
631     task->kill();
632 }
633
634 extern "C" void
635 rust_task_kill_all(rust_task *task) { /* Used for linked failure */
636     task->fail_sched_loop();
637     // This must not happen twice.
638     static bool main_taskgroup_failed = false;
639     assert(!main_taskgroup_failed);
640     main_taskgroup_failed = true;
641 }
642
643 extern "C" CDECL
644 bool rust_task_is_unwinding(rust_task *rt) {
645     return rt->unwinding;
646 }
647
648 extern "C" lock_and_signal*
649 rust_create_little_lock() {
650     return new lock_and_signal();
651 }
652
653 extern "C" void
654 rust_destroy_little_lock(lock_and_signal *lock) {
655     delete lock;
656 }
657
658 extern "C" void
659 rust_lock_little_lock(lock_and_signal *lock) {
660     lock->lock();
661 }
662
663 extern "C" void
664 rust_unlock_little_lock(lock_and_signal *lock) {
665     lock->unlock();
666 }
667
668 // get/atexit task_local_data can run on the rust stack for speed.
669 extern "C" void **
670 rust_get_task_local_data(rust_task *task) {
671     return &task->task_local_data;
672 }
673 extern "C" void
674 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
675     task->task_local_data_cleanup = cleanup_fn;
676 }
677
678 // set/get/atexit task_borrow_list can run on the rust stack for speed.
679 extern "C" void *
680 rust_take_task_borrow_list(rust_task *task) {
681     void *r = task->borrow_list;
682     task->borrow_list = NULL;
683     return r;
684 }
685 extern "C" void
686 rust_set_task_borrow_list(rust_task *task, void *data) {
687     assert(task->borrow_list == NULL);
688     assert(data != NULL);
689     task->borrow_list = data;
690 }
691
692 extern "C" void
693 task_clear_event_reject(rust_task *task) {
694     task->clear_event_reject();
695 }
696
697 // Waits on an event, returning the pointer to the event that unblocked this
698 // task.
699 extern "C" MUST_CHECK bool
700 task_wait_event(rust_task *task, void **result) {
701     // Maybe (if not too slow) assert that the passed in task is the currently
702     // running task. We wouldn't want to wait some other task.
703
704     return task->wait_event(result);
705 }
706
707 extern "C" void
708 task_signal_event(rust_task *target, void *event) {
709     target->signal_event(event);
710 }
711
712 // Can safely run on the rust stack.
713 extern "C" void
714 rust_task_ref(rust_task *task) {
715     task->ref();
716 }
717
718 // Don't run on the rust stack!
719 extern "C" void
720 rust_task_deref(rust_task *task) {
721     task->deref();
722 }
723
724 // Don't run on the Rust stack!
725 extern "C" void
726 rust_log_str(uint32_t level, const char *str, size_t size) {
727     rust_task *task = rust_get_current_task();
728     task->sched_loop->get_log().log(task, level, "%.*s", (int)size, str);
729 }
730
731 extern "C" CDECL void      record_sp_limit(void *limit);
732
733 class raw_thread: public rust_thread {
734 public:
735     fn_env_pair fn;
736
737     raw_thread(fn_env_pair fn) : fn(fn) { }
738
739     virtual void run() {
740         record_sp_limit(0);
741         fn.f(fn.env, NULL);
742     }
743 };
744
745 extern "C" raw_thread*
746 rust_raw_thread_start(fn_env_pair *fn) {
747     assert(fn);
748     raw_thread *thread = new raw_thread(*fn);
749     thread->start();
750     return thread;
751 }
752
753 extern "C" void
754 rust_raw_thread_join_delete(raw_thread *thread) {
755     assert(thread);
756     thread->join();
757     delete thread;
758 }
759
760 #ifndef _WIN32
761 #include <sys/types.h>
762 #include <dirent.h>
763
764 extern "C" DIR*
765 rust_opendir(char *dirname) {
766     return opendir(dirname);
767 }
768
769 extern "C" dirent*
770 rust_readdir(DIR *dirp) {
771     return readdir(dirp);
772 }
773
774 #else
775
776 extern "C" void
777 rust_opendir() {
778 }
779
780 extern "C" void
781 rust_readdir() {
782 }
783
784 #endif
785
786 extern "C" rust_env*
787 rust_get_rt_env() {
788     rust_task *task = rust_get_current_task();
789     return task->kernel->env;
790 }
791
792 #ifndef _WIN32
793 pthread_key_t rt_key = -1;
794 #else
795 DWORD rt_key = -1;
796 #endif
797
798 extern "C" void*
799 rust_get_rt_tls_key() {
800     return &rt_key;
801 }
802
803 // Initialize the TLS key used by the new scheduler
804 extern "C" CDECL void
805 rust_initialize_rt_tls_key() {
806
807     static lock_and_signal init_lock;
808     static bool initialized = false;
809
810     scoped_lock with(init_lock);
811
812     if (!initialized) {
813
814 #ifndef _WIN32
815         assert(!pthread_key_create(&rt_key, NULL));
816 #else
817         rt_key = TlsAlloc();
818         assert(rt_key != TLS_OUT_OF_INDEXES);
819 #endif
820
821         initialized = true;
822     }
823 }
824
825 extern "C" CDECL memory_region*
826 rust_new_memory_region(uintptr_t synchronized,
827                        uintptr_t detailed_leaks,
828                        uintptr_t poison_on_free) {
829     return new memory_region((bool)synchronized,
830                              (bool)detailed_leaks,
831                              (bool)poison_on_free);
832 }
833
834 extern "C" CDECL void
835 rust_delete_memory_region(memory_region *region) {
836     delete region;
837 }
838
839 extern "C" CDECL boxed_region*
840 rust_current_boxed_region() {
841     rust_task *task = rust_get_current_task();
842     return &task->boxed;
843 }
844
845 extern "C" CDECL boxed_region*
846 rust_new_boxed_region(memory_region *region,
847                       uintptr_t poison_on_free) {
848     return new boxed_region(region, poison_on_free);
849 }
850
851 extern "C" CDECL void
852 rust_delete_boxed_region(boxed_region *region) {
853     delete region;
854 }
855
856 extern "C" CDECL rust_opaque_box*
857 rust_boxed_region_malloc(boxed_region *region, type_desc *td, size_t size) {
858     return region->malloc(td, size);
859 }
860
861 extern "C" CDECL rust_opaque_box*
862 rust_boxed_region_realloc(boxed_region *region, rust_opaque_box *ptr, size_t size) {
863     return region->realloc(ptr, size);
864 }
865
866 extern "C" CDECL void
867 rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) {
868     region->free(box);
869 }
870
871 typedef void *(rust_try_fn)(void*, void*);
872
873 extern "C" CDECL uintptr_t
874 rust_try(rust_try_fn f, void *fptr, void *env) {
875     try {
876         f(fptr, env);
877     } catch (uintptr_t token) {
878         assert(token != 0);
879         return token;
880     }
881     return 0;
882 }
883
884 extern "C" CDECL void
885 rust_begin_unwind(uintptr_t token) {
886 #ifndef __WIN32__
887     throw token;
888 #else
889     abort();
890 #endif
891 }
892
893 extern "C" CDECL uintptr_t
894 rust_running_on_valgrind() {
895     return RUNNING_ON_VALGRIND;
896 }
897
898 extern int get_num_cpus();
899
900 extern "C" CDECL uintptr_t
901 rust_get_num_cpus() {
902     return get_num_cpus();
903 }
904
905 static lock_and_signal global_args_lock;
906 static uintptr_t global_args_ptr = 0;
907
908 extern "C" CDECL void
909 rust_take_global_args_lock() {
910     global_args_lock.lock();
911 }
912
913 extern "C" CDECL void
914 rust_drop_global_args_lock() {
915     global_args_lock.unlock();
916 }
917
918 extern "C" CDECL uintptr_t*
919 rust_get_global_args_ptr() {
920     return &global_args_ptr;
921 }
922
923 static lock_and_signal exit_status_lock;
924 static uintptr_t exit_status = 0;
925
926 extern "C" CDECL void
927 rust_set_exit_status_newrt(uintptr_t code) {
928     scoped_lock with(exit_status_lock);
929     exit_status = code;
930 }
931
932 extern "C" CDECL uintptr_t
933 rust_get_exit_status_newrt() {
934     scoped_lock with(exit_status_lock);
935     return exit_status;
936 }
937
938 static lock_and_signal change_dir_lock;
939
940 extern "C" CDECL void
941 rust_take_change_dir_lock() {
942     global_args_lock.lock();
943 }
944
945 extern "C" CDECL void
946 rust_drop_change_dir_lock() {
947     global_args_lock.unlock();
948 }
949
950 //
951 // Local Variables:
952 // mode: C++
953 // fill-column: 78;
954 // indent-tabs-mode: nil
955 // c-basic-offset: 4
956 // buffer-file-coding-system: utf-8-unix
957 // End:
958 //