]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.cpp
7e69e2e4ccb9958fcb1c9d65905e2c971377c63c
[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 extern "C" void
761 rust_register_exit_function(spawn_fn runner, fn_env_pair *f) {
762     rust_task *task = rust_get_current_task();
763     task->kernel->register_exit_function(runner, f);
764 }
765
766 extern "C" intptr_t*
767 rust_get_global_data_ptr() {
768     rust_task *task = rust_get_current_task();
769     return &task->kernel->global_data;
770 }
771
772 extern "C" void
773 rust_inc_kernel_live_count() {
774     rust_task *task = rust_get_current_task();
775     task->kernel->inc_live_count();
776 }
777
778 extern "C" void
779 rust_dec_kernel_live_count() {
780     rust_task *task = rust_get_current_task();
781     task->kernel->dec_live_count();
782 }
783
784 #ifndef _WIN32
785 #include <sys/types.h>
786 #include <dirent.h>
787
788 extern "C" DIR*
789 rust_opendir(char *dirname) {
790     return opendir(dirname);
791 }
792
793 extern "C" dirent*
794 rust_readdir(DIR *dirp) {
795     return readdir(dirp);
796 }
797
798 #else
799
800 extern "C" void
801 rust_opendir() {
802 }
803
804 extern "C" void
805 rust_readdir() {
806 }
807
808 #endif
809
810 extern "C" rust_env*
811 rust_get_rt_env() {
812     rust_task *task = rust_get_current_task();
813     return task->kernel->env;
814 }
815
816 #ifndef _WIN32
817 pthread_key_t rt_key = -1;
818 #else
819 DWORD rt_key = -1;
820 #endif
821
822 extern "C" void*
823 rust_get_rt_tls_key() {
824     return &rt_key;
825 }
826
827 // Initialize the TLS key used by the new scheduler
828 extern "C" CDECL void
829 rust_initialize_rt_tls_key() {
830
831     static lock_and_signal init_lock;
832     static bool initialized = false;
833
834     scoped_lock with(init_lock);
835
836     if (!initialized) {
837
838 #ifndef _WIN32
839         assert(!pthread_key_create(&rt_key, NULL));
840 #else
841         rt_key = TlsAlloc();
842         assert(rt_key != TLS_OUT_OF_INDEXES);
843 #endif
844
845         initialized = true;
846     }
847 }
848
849 extern "C" CDECL memory_region*
850 rust_new_memory_region(uintptr_t synchronized,
851                        uintptr_t detailed_leaks,
852                        uintptr_t poison_on_free) {
853     return new memory_region((bool)synchronized,
854                              (bool)detailed_leaks,
855                              (bool)poison_on_free);
856 }
857
858 extern "C" CDECL void
859 rust_delete_memory_region(memory_region *region) {
860     delete region;
861 }
862
863 extern "C" CDECL boxed_region*
864 rust_current_boxed_region() {
865     rust_task *task = rust_get_current_task();
866     return &task->boxed;
867 }
868
869 extern "C" CDECL boxed_region*
870 rust_new_boxed_region(memory_region *region,
871                       uintptr_t poison_on_free) {
872     return new boxed_region(region, poison_on_free);
873 }
874
875 extern "C" CDECL void
876 rust_delete_boxed_region(boxed_region *region) {
877     delete region;
878 }
879
880 extern "C" CDECL rust_opaque_box*
881 rust_boxed_region_malloc(boxed_region *region, type_desc *td, size_t size) {
882     return region->malloc(td, size);
883 }
884
885 extern "C" CDECL rust_opaque_box*
886 rust_boxed_region_realloc(boxed_region *region, rust_opaque_box *ptr, size_t size) {
887     return region->realloc(ptr, size);
888 }
889
890 extern "C" CDECL void
891 rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) {
892     region->free(box);
893 }
894
895 typedef void *(rust_try_fn)(void*, void*);
896
897 extern "C" CDECL uintptr_t
898 rust_try(rust_try_fn f, void *fptr, void *env) {
899     try {
900         f(fptr, env);
901     } catch (uintptr_t token) {
902         assert(token != 0);
903         return token;
904     }
905     return 0;
906 }
907
908 extern "C" CDECL void
909 rust_begin_unwind(uintptr_t token) {
910 #ifndef __WIN32__
911     throw token;
912 #else
913     abort();
914 #endif
915 }
916
917 extern "C" CDECL uintptr_t
918 rust_running_on_valgrind() {
919     return RUNNING_ON_VALGRIND;
920 }
921
922 extern int get_num_cpus();
923
924 extern "C" CDECL uintptr_t
925 rust_get_num_cpus() {
926     return get_num_cpus();
927 }
928
929 static lock_and_signal global_args_lock;
930 static uintptr_t global_args_ptr = 0;
931
932 extern "C" CDECL void
933 rust_take_global_args_lock() {
934     global_args_lock.lock();
935 }
936
937 extern "C" CDECL void
938 rust_drop_global_args_lock() {
939     global_args_lock.unlock();
940 }
941
942 extern "C" CDECL uintptr_t*
943 rust_get_global_args_ptr() {
944     return &global_args_ptr;
945 }
946
947 static lock_and_signal exit_status_lock;
948 static uintptr_t exit_status = 0;
949
950 extern "C" CDECL void
951 rust_set_exit_status_newrt(uintptr_t code) {
952     scoped_lock with(exit_status_lock);
953     exit_status = code;
954 }
955
956 extern "C" CDECL uintptr_t
957 rust_get_exit_status_newrt() {
958     scoped_lock with(exit_status_lock);
959     return exit_status;
960 }
961
962 //
963 // Local Variables:
964 // mode: C++
965 // fill-column: 78;
966 // indent-tabs-mode: nil
967 // c-basic-offset: 4
968 // buffer-file-coding-system: utf-8-unix
969 // End:
970 //