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.
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.
11 /* Foreign builtins. */
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"
20 #include "vg/valgrind.h"
25 #include <crt_externs.h>
28 #if !defined(__WIN32__)
33 extern char **environ;
56 #if defined(__WIN32__)
57 extern "C" CDECL char**
62 extern "C" CDECL char**
65 char **environ = *_NSGetEnviron();
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);
77 extern "C" CDECL size_t
79 return rng_seed_size();
83 rand_gen_seed(uint8_t* dest, size_t size) {
84 rng_gen_seed(dest, size);
87 extern "C" CDECL void *
88 rand_new_seeded(uint8_t* seed, size_t seed_size) {
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);
96 extern "C" CDECL uint32_t
97 rand_next(rust_rng *rng) {
98 return rng_gen_u32(rng);
101 extern "C" CDECL void
102 rand_free(rust_rng *rng) {
107 /* Debug helpers strictly to verify ABI conformance.
109 * FIXME (#2665): move these into a testcase when the testsuite
110 * understands how to have explicit C files included.
127 debug_abi_1(quad q) {
136 debug_abi_2(floats f) {
137 floats ff = { f.c + 1.0,
146 int debug_static_mut = 3;
149 debug_static_mut_check_four() {
150 assert(debug_static_mut == 4);
153 /* Debug builtins for std::dbg. */
156 debug_tydesc_helper(type_desc *t)
158 rust_task *task = rust_get_current_task();
159 LOG(task, stdlib, " size %" PRIdPTR ", align %" PRIdPTR,
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);
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);
180 for (uintptr_t i = 0; i < t->size; ++front, ++i) {
181 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
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]);
199 uintptr_t discriminant;
203 extern "C" CDECL void
204 debug_tag(type_desc *t, rust_tag *tag) {
205 rust_task *task = rust_get_current_task();
207 LOG(task, stdlib, "debug_tag");
208 debug_tydesc_helper(t);
209 LOG(task, stdlib, " discriminant %" PRIdPTR, tag->discriminant);
211 for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
212 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i,
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);
224 LOG(task, stdlib, " refcount %" PRIdPTR, fn->env->ref_count);
228 extern "C" CDECL void *
229 debug_ptrcast(type_desc *from_ty,
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);
240 extern "C" CDECL void *
241 debug_get_stk_seg() {
242 rust_task *task = rust_get_current_task();
246 extern "C" CDECL char*
247 #if defined(__WIN32__)
248 rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
249 return entry_ptr->cFileName;
252 rust_list_dir_val(dirent* entry_ptr) {
253 return entry_ptr->d_name;
257 extern "C" CDECL size_t
258 #if defined(__WIN32__)
259 rust_list_dir_wfd_size() {
260 return sizeof(WIN32_FIND_DATAW);
263 rust_list_dir_wfd_size() {
268 extern "C" CDECL void*
269 #if defined(__WIN32__)
270 rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) {
275 return wfd->cFileName;
279 rust_list_dir_wfd_fp_buf(void* wfd) {
285 rust_path_is_dir(char *path) {
287 if (stat(path, &buf)) {
290 return S_ISDIR(buf.st_mode);
294 rust_path_exists(char *path) {
296 if (stat(path, &buf)) {
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;}
306 #if defined(__WIN32__)
307 extern "C" CDECL void
308 get_time(int64_t *sec, int32_t *nsec) {
310 GetSystemTimeAsFileTime(&fileTime);
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
316 ul.LowPart = fileTime.dwLowDateTime;
317 ul.HighPart = fileTime.dwHighDateTime;
318 uint64_t ns_since_1601 = ul.QuadPart / 10;
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;
326 extern "C" CDECL void
327 get_time(int64_t *sec, int32_t *nsec) {
330 gettimeofday(&tv, NULL);
332 *nsec = tv.tv_usec * 1000;
335 clock_gettime(CLOCK_REALTIME, &ts);
342 extern "C" CDECL void
343 precise_time_ns(uint64_t *ns) {
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;
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;
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';
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)
406 struct tm* GMTIME(const time_t *clock, tm *result) {
407 struct tm* t = gmtime(clock);
408 if (t == NULL || result == NULL) { return NULL; }
412 struct tm* LOCALTIME(const time_t *clock, tm *result) {
413 struct tm* t = localtime(clock);
414 if (t == NULL || result == NULL) { return NULL; }
418 #define TIMEGM(result) mktime((result)) - _timezone
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)
427 extern "C" CDECL void
432 extern "C" CDECL void
433 rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
438 tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
441 extern "C" CDECL void
442 rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
447 #if defined(__WIN32__)
448 int32_t gmtoff = -timezone;
450 strftime(zone, sizeof(zone), "%Z", &tm);
452 int32_t gmtoff = tm.tm_gmtoff;
453 const char *zone = tm.tm_zone;
456 tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
459 extern "C" CDECL int64_t
460 rust_timegm(rust_tm* timeptr) {
462 rust_tm_to_tm(timeptr, &t);
466 extern "C" CDECL int64_t
467 rust_mktime(rust_tm* timeptr) {
469 rust_tm_to_tm(timeptr, &t);
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();
481 rust_task *task = rust_get_current_task();
482 return task->kernel->env->argc;
485 extern "C" CDECL char**
487 rust_task *task = rust_get_current_task();
488 return task->kernel->env->argv;
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);
498 extern "C" CDECL rust_task_id
500 rust_task *task = rust_get_current_task();
505 new_task_common(rust_scheduler *sched, rust_task *parent) {
506 return sched->create_task(parent, NULL);
509 extern "C" CDECL rust_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);
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);
524 return new_task_common(sched, task);
527 extern "C" rust_task *
529 return rust_get_current_task();
532 extern "C" rust_task *
533 rust_try_get_task() {
534 return rust_try_get_current_task();
537 extern "C" CDECL stk_seg *
538 rust_get_stack_segment() {
539 return rust_get_current_task()->stk;
542 extern "C" CDECL stk_seg *
544 return rust_get_current_task()->get_c_stack();
547 extern "C" CDECL void
548 start_task(rust_task *target, fn_env_pair *f) {
549 target->start(f->f, f->env, NULL);
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();
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();
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();
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);
577 extern void log_console_on();
579 extern "C" CDECL void
580 rust_log_console_on() {
584 extern void log_console_off();
586 extern "C" CDECL void
587 rust_log_console_off() {
591 extern bool should_log_console();
593 extern "C" CDECL uintptr_t
594 rust_should_log_console() {
595 return (uintptr_t)should_log_console();
598 extern "C" CDECL void
599 rust_dbg_breakpoint() {
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();
610 rust_task_inhibit_kill(rust_task *task) {
611 task->inhibit_kill();
615 rust_task_allow_kill(rust_task *task) {
620 rust_task_inhibit_yield(rust_task *task) {
621 task->inhibit_yield();
625 rust_task_allow_yield(rust_task *task) {
630 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
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;
644 bool rust_task_is_unwinding(rust_task *rt) {
645 return rt->unwinding;
648 extern "C" lock_and_signal*
649 rust_create_little_lock() {
650 return new lock_and_signal();
654 rust_destroy_little_lock(lock_and_signal *lock) {
659 rust_lock_little_lock(lock_and_signal *lock) {
664 rust_unlock_little_lock(lock_and_signal *lock) {
668 // get/atexit task_local_data can run on the rust stack for speed.
670 rust_get_task_local_data(rust_task *task) {
671 return &task->task_local_data;
674 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
675 task->task_local_data_cleanup = cleanup_fn;
678 // set/get/atexit task_borrow_list can run on the rust stack for speed.
680 rust_take_task_borrow_list(rust_task *task) {
681 void *r = task->borrow_list;
682 task->borrow_list = NULL;
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;
693 task_clear_event_reject(rust_task *task) {
694 task->clear_event_reject();
697 // Waits on an event, returning the pointer to the event that unblocked this
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.
704 return task->wait_event(result);
708 task_signal_event(rust_task *target, void *event) {
709 target->signal_event(event);
712 // Can safely run on the rust stack.
714 rust_task_ref(rust_task *task) {
718 // Don't run on the rust stack!
720 rust_task_deref(rust_task *task) {
724 // Don't run on the Rust stack!
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);
731 extern "C" CDECL void record_sp_limit(void *limit);
733 class raw_thread: public rust_thread {
737 raw_thread(fn_env_pair fn) : fn(fn) { }
745 extern "C" raw_thread*
746 rust_raw_thread_start(fn_env_pair *fn) {
748 raw_thread *thread = new raw_thread(*fn);
754 rust_raw_thread_join_delete(raw_thread *thread) {
761 #include <sys/types.h>
765 rust_opendir(char *dirname) {
766 return opendir(dirname);
770 rust_readdir(DIR *dirp) {
771 return readdir(dirp);
788 rust_task *task = rust_get_current_task();
789 return task->kernel->env;
793 pthread_key_t rt_key = -1;
799 rust_get_rt_tls_key() {
803 // Initialize the TLS key used by the new scheduler
804 extern "C" CDECL void
805 rust_initialize_rt_tls_key() {
807 static lock_and_signal init_lock;
808 static bool initialized = false;
810 scoped_lock with(init_lock);
815 assert(!pthread_key_create(&rt_key, NULL));
818 assert(rt_key != TLS_OUT_OF_INDEXES);
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);
834 extern "C" CDECL void
835 rust_delete_memory_region(memory_region *region) {
839 extern "C" CDECL boxed_region*
840 rust_current_boxed_region() {
841 rust_task *task = rust_get_current_task();
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);
851 extern "C" CDECL void
852 rust_delete_boxed_region(boxed_region *region) {
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);
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);
866 extern "C" CDECL void
867 rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) {
871 typedef void *(rust_try_fn)(void*, void*);
873 extern "C" CDECL uintptr_t
874 rust_try(rust_try_fn f, void *fptr, void *env) {
877 } catch (uintptr_t token) {
884 extern "C" CDECL void
885 rust_begin_unwind(uintptr_t token) {
893 extern "C" CDECL uintptr_t
894 rust_running_on_valgrind() {
895 return RUNNING_ON_VALGRIND;
898 extern int get_num_cpus();
900 extern "C" CDECL uintptr_t
901 rust_get_num_cpus() {
902 return get_num_cpus();
905 static lock_and_signal global_args_lock;
906 static uintptr_t global_args_ptr = 0;
908 extern "C" CDECL void
909 rust_take_global_args_lock() {
910 global_args_lock.lock();
913 extern "C" CDECL void
914 rust_drop_global_args_lock() {
915 global_args_lock.unlock();
918 extern "C" CDECL uintptr_t*
919 rust_get_global_args_ptr() {
920 return &global_args_ptr;
923 static lock_and_signal exit_status_lock;
924 static uintptr_t exit_status = 0;
926 extern "C" CDECL void
927 rust_set_exit_status_newrt(uintptr_t code) {
928 scoped_lock with(exit_status_lock);
932 extern "C" CDECL uintptr_t
933 rust_get_exit_status_newrt() {
934 scoped_lock with(exit_status_lock);
938 static lock_and_signal change_dir_lock;
940 extern "C" CDECL void
941 rust_take_change_dir_lock() {
942 global_args_lock.lock();
945 extern "C" CDECL void
946 rust_drop_change_dir_lock() {
947 global_args_lock.unlock();
954 // indent-tabs-mode: nil
956 // buffer-file-coding-system: utf-8-unix