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"
24 #include <crt_externs.h>
27 #if !defined(__WIN32__)
32 extern char **environ;
55 extern "C" CDECL rust_str *
57 rust_task *task = rust_get_current_task();
58 LOG(task, task, "rust_getcwd()");
62 #if defined(__WIN32__)
63 if (!_getcwd(cbuf, sizeof(cbuf))) {
65 if (!getcwd(cbuf, sizeof(cbuf))) {
71 return make_str(task->kernel, cbuf, strlen(cbuf), "rust_str(getcwd)");
74 #if defined(__WIN32__)
75 extern "C" CDECL rust_vec_box *
77 rust_task *task = rust_get_current_task();
79 LPTCH ch = GetEnvironmentStringsA();
81 for (c = ch; *c; c += strlen(c) + 1) {
85 rust_vec_box *v = (rust_vec_box *)
86 task->kernel->malloc(vec_size<rust_vec_box*>(envc),
88 v->body.fill = v->body.alloc = sizeof(rust_vec*) * envc;
89 for (size_t i = 0; i < envc; ++i) {
91 rust_str *str = make_str(task->kernel, c, n, "str");
92 ((rust_str**)&v->body.data)[i] = str;
96 FreeEnvironmentStrings(ch);
101 extern "C" CDECL rust_vec_box *
103 rust_task *task = rust_get_current_task();
105 char **environ = *_NSGetEnviron();
112 return make_str_vec(task->kernel, envc, environ);
116 extern "C" CDECL void
117 vec_reserve_shared_actual(type_desc* ty, rust_vec_box** vp,
119 rust_task *task = rust_get_current_task();
120 reserve_vec_exact_shared(task, vp, n_elts * ty->size);
123 // This is completely misnamed.
124 extern "C" CDECL void
125 vec_reserve_shared(type_desc* ty, rust_vec_box** vp,
127 rust_task *task = rust_get_current_task();
128 reserve_vec_exact(task, vp, n_elts * ty->size);
131 extern "C" CDECL rust_vec*
133 size_t size = sizeof(ub4) * RANDSIZ;
134 rust_task *task = rust_get_current_task();
135 rust_vec *v = (rust_vec *) task->kernel->malloc(vec_size<uint8_t>(size),
137 v->fill = v->alloc = size;
138 isaac_seed(task->kernel, (uint8_t*) &v->data, size);
142 extern "C" CDECL void *
144 rust_task *task = rust_get_current_task();
145 rust_sched_loop *thread = task->sched_loop;
146 randctx *rctx = (randctx *) task->malloc(sizeof(randctx), "rand_new");
151 isaac_init(thread->kernel, rctx, NULL);
155 extern "C" CDECL void *
156 rand_new_seeded(rust_vec_box* seed) {
157 rust_task *task = rust_get_current_task();
158 rust_sched_loop *thread = task->sched_loop;
159 randctx *rctx = (randctx *) task->malloc(sizeof(randctx),
165 isaac_init(thread->kernel, rctx, seed);
169 extern "C" CDECL void *
170 rand_new_seeded2(rust_vec_box** seed) {
171 return rand_new_seeded(*seed);
174 extern "C" CDECL size_t
175 rand_next(randctx *rctx) {
176 return isaac_rand(rctx);
179 extern "C" CDECL void
180 rand_free(randctx *rctx) {
181 rust_task *task = rust_get_current_task();
186 /* Debug helpers strictly to verify ABI conformance.
188 * FIXME (#2665): move these into a testcase when the testsuite
189 * understands how to have explicit C files included.
206 debug_abi_1(quad q) {
215 debug_abi_2(floats f) {
216 floats ff = { f.c + 1.0,
222 /* Debug builtins for std::dbg. */
225 debug_tydesc_helper(type_desc *t)
227 rust_task *task = rust_get_current_task();
228 LOG(task, stdlib, " size %" PRIdPTR ", align %" PRIdPTR,
232 extern "C" CDECL void
233 debug_tydesc(type_desc *t) {
234 rust_task *task = rust_get_current_task();
235 LOG(task, stdlib, "debug_tydesc");
236 debug_tydesc_helper(t);
239 extern "C" CDECL void
240 debug_opaque(type_desc *t, uint8_t *front) {
241 rust_task *task = rust_get_current_task();
242 LOG(task, stdlib, "debug_opaque");
243 debug_tydesc_helper(t);
244 for (uintptr_t i = 0; i < t->size; ++front, ++i) {
246 // Account for alignment. `front` may not indeed be the
247 // front byte of the passed-in argument
248 if (((uintptr_t)front % t->align) != 0)
249 front = (uint8_t *)align_to((uintptr_t)front, (size_t)t->align);
251 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
255 extern "C" CDECL void
256 debug_box(type_desc *t, rust_opaque_box *box) {
257 rust_task *task = rust_get_current_task();
258 LOG(task, stdlib, "debug_box(0x%" PRIxPTR ")", box);
259 debug_tydesc_helper(t);
260 LOG(task, stdlib, " refcount %" PRIdPTR,
261 box->ref_count - 1); // -1 because we ref'ed for this call
262 uint8_t *data = (uint8_t *)box_body(box);
263 for (uintptr_t i = 0; i < t->size; ++i) {
264 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i, data[i]);
269 uintptr_t discriminant;
273 extern "C" CDECL void
274 debug_tag(type_desc *t, rust_tag *tag) {
275 rust_task *task = rust_get_current_task();
277 LOG(task, stdlib, "debug_tag");
278 debug_tydesc_helper(t);
279 LOG(task, stdlib, " discriminant %" PRIdPTR, tag->discriminant);
281 for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
282 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i,
286 extern "C" CDECL void
287 debug_fn(type_desc *t, fn_env_pair *fn) {
288 rust_task *task = rust_get_current_task();
289 LOG(task, stdlib, "debug_fn");
290 debug_tydesc_helper(t);
291 LOG(task, stdlib, " fn at 0x%" PRIxPTR, fn->f);
292 LOG(task, stdlib, " env at 0x%" PRIxPTR, fn->env);
294 LOG(task, stdlib, " refcount %" PRIdPTR, fn->env->ref_count);
298 extern "C" CDECL void *
299 debug_ptrcast(type_desc *from_ty,
302 rust_task *task = rust_get_current_task();
303 LOG(task, stdlib, "debug_ptrcast from");
304 debug_tydesc_helper(from_ty);
305 LOG(task, stdlib, "to");
306 debug_tydesc_helper(to_ty);
310 extern "C" CDECL void *
311 debug_get_stk_seg() {
312 rust_task *task = rust_get_current_task();
316 extern "C" CDECL rust_vec_box*
317 rust_list_files(rust_str *path) {
318 rust_task *task = rust_get_current_task();
319 array_list<rust_str*> strings;
320 #if defined(__WIN32__)
321 WIN32_FIND_DATA FindFileData;
322 HANDLE hFind = FindFirstFile((char*)path->body.data, &FindFileData);
323 if (hFind != INVALID_HANDLE_VALUE) {
325 rust_str *str = make_str(task->kernel, FindFileData.cFileName,
326 strlen(FindFileData.cFileName),
329 } while (FindNextFile(hFind, &FindFileData));
333 DIR *dirp = opendir((char*)path->body.data);
336 while ((dp = readdir(dirp))) {
337 rust_vec_box *str = make_str(task->kernel, dp->d_name,
346 rust_vec_box *vec = (rust_vec_box *)
347 task->kernel->malloc(vec_size<rust_vec_box*>(strings.size()),
349 size_t alloc_sz = sizeof(rust_vec*) * strings.size();
350 vec->body.fill = vec->body.alloc = alloc_sz;
351 memcpy(&vec->body.data[0], strings.data(), alloc_sz);
355 extern "C" CDECL rust_vec_box*
356 rust_list_files2(rust_str **path) {
357 return rust_list_files(*path);
361 rust_path_is_dir(char *path) {
363 if (stat(path, &buf)) {
366 return S_ISDIR(buf.st_mode);
370 rust_path_exists(char *path) {
372 if (stat(path, &buf)) {
378 extern "C" CDECL FILE* rust_get_stdin() {return stdin;}
379 extern "C" CDECL FILE* rust_get_stdout() {return stdout;}
380 extern "C" CDECL FILE* rust_get_stderr() {return stderr;}
382 #if defined(__WIN32__)
383 extern "C" CDECL void
384 get_time(int64_t *sec, int32_t *nsec) {
386 GetSystemTimeAsFileTime(&fileTime);
388 // A FILETIME contains a 64-bit value representing the number of
389 // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
390 // http://support.microsoft.com/kb/167296/en-us
392 ul.LowPart = fileTime.dwLowDateTime;
393 ul.HighPart = fileTime.dwHighDateTime;
394 uint64_t ns_since_1601 = ul.QuadPart / 10;
396 const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000u;
397 uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
398 *sec = ns_since_1970 / 1000000;
399 *nsec = (ns_since_1970 % 1000000) * 1000;
402 extern "C" CDECL void
403 get_time(int64_t *sec, int32_t *nsec) {
406 gettimeofday(&tv, NULL);
408 *nsec = tv.tv_usec * 1000;
411 clock_gettime(CLOCK_REALTIME, &ts);
418 extern "C" CDECL void
419 precise_time_ns(uint64_t *ns) {
439 void rust_tm_to_tm(rust_tm* in_tm, tm* out_tm) {
440 memset(out_tm, 0, sizeof(tm));
441 out_tm->tm_sec = in_tm->tm_sec;
442 out_tm->tm_min = in_tm->tm_min;
443 out_tm->tm_hour = in_tm->tm_hour;
444 out_tm->tm_mday = in_tm->tm_mday;
445 out_tm->tm_mon = in_tm->tm_mon;
446 out_tm->tm_year = in_tm->tm_year;
447 out_tm->tm_wday = in_tm->tm_wday;
448 out_tm->tm_yday = in_tm->tm_yday;
449 out_tm->tm_isdst = in_tm->tm_isdst;
452 void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
453 const char *zone, int32_t nsec) {
454 out_tm->tm_sec = in_tm->tm_sec;
455 out_tm->tm_min = in_tm->tm_min;
456 out_tm->tm_hour = in_tm->tm_hour;
457 out_tm->tm_mday = in_tm->tm_mday;
458 out_tm->tm_mon = in_tm->tm_mon;
459 out_tm->tm_year = in_tm->tm_year;
460 out_tm->tm_wday = in_tm->tm_wday;
461 out_tm->tm_yday = in_tm->tm_yday;
462 out_tm->tm_isdst = in_tm->tm_isdst;
463 out_tm->tm_gmtoff = gmtoff;
464 out_tm->tm_nsec = nsec;
467 rust_task *task = rust_get_current_task();
468 size_t size = strlen(zone);
469 reserve_vec_exact(task, &out_tm->tm_zone, size + 1);
470 memcpy(out_tm->tm_zone->body.data, zone, size);
471 out_tm->tm_zone->body.fill = size + 1;
472 out_tm->tm_zone->body.data[size] = '\0';
476 #if defined(__WIN32__)
477 #define TZSET() _tzset()
478 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
479 #define GMTIME(clock, result) gmtime_s((result), (clock))
480 #define LOCALTIME(clock, result) localtime_s((result), (clock))
481 #define TIMEGM(result) _mkgmtime64(result)
483 struct tm* GMTIME(const time_t *clock, tm *result) {
484 struct tm* t = gmtime(clock);
485 if (t == NULL || result == NULL) { return NULL; }
489 struct tm* LOCALTIME(const time_t *clock, tm *result) {
490 struct tm* t = localtime(clock);
491 if (t == NULL || result == NULL) { return NULL; }
495 #define TIMEGM(result) mktime((result)) - _timezone
498 #define TZSET() tzset()
499 #define GMTIME(clock, result) gmtime_r((clock), (result))
500 #define LOCALTIME(clock, result) localtime_r((clock), (result))
501 #define TIMEGM(result) timegm(result)
504 extern "C" CDECL void
509 extern "C" CDECL void
510 rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
515 tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec);
518 extern "C" CDECL void
519 rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
524 #if defined(__WIN32__)
525 int32_t gmtoff = -timezone;
527 strftime(zone, sizeof(zone), "%Z", &tm);
529 int32_t gmtoff = tm.tm_gmtoff;
530 const char *zone = tm.tm_zone;
533 tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec);
536 extern "C" CDECL void
537 rust_timegm(rust_tm* timeptr, int64_t *out) {
539 rust_tm_to_tm(timeptr, &t);
543 extern "C" CDECL void
544 rust_mktime(rust_tm* timeptr, int64_t *out) {
546 rust_tm_to_tm(timeptr, &t);
550 extern "C" CDECL rust_sched_id
551 rust_get_sched_id() {
552 rust_task *task = rust_get_current_task();
553 return task->sched->get_id();
556 extern "C" CDECL uintptr_t
558 rust_task *task = rust_get_current_task();
559 return task->kernel->env->num_sched_threads;
564 rust_task *task = rust_get_current_task();
565 return task->kernel->env->argc;
568 extern "C" CDECL char**
570 rust_task *task = rust_get_current_task();
571 return task->kernel->env->argv;
574 extern "C" CDECL rust_sched_id
575 rust_new_sched(uintptr_t threads) {
576 rust_task *task = rust_get_current_task();
577 assert(threads > 0 && "Can't create a scheduler with no threads, silly!");
578 return task->kernel->create_scheduler(threads);
581 extern "C" CDECL rust_task_id
583 rust_task *task = rust_get_current_task();
588 new_task_common(rust_scheduler *sched, rust_task *parent) {
589 return sched->create_task(parent, NULL);
592 extern "C" CDECL rust_task*
594 rust_task *task = rust_get_current_task();
595 rust_sched_id sched_id = task->kernel->main_sched_id();
596 rust_scheduler *sched = task->kernel->get_scheduler_by_id(sched_id);
597 assert(sched != NULL && "should always have a main scheduler");
598 return new_task_common(sched, task);
601 extern "C" CDECL rust_task*
602 rust_new_task_in_sched(rust_sched_id id) {
603 rust_task *task = rust_get_current_task();
604 rust_scheduler *sched = task->kernel->get_scheduler_by_id(id);
607 return new_task_common(sched, task);
610 extern "C" rust_task *
612 return rust_get_current_task();
615 extern "C" CDECL stk_seg *
616 rust_get_stack_segment() {
617 return rust_get_current_task()->stk;
620 extern "C" CDECL void
621 start_task(rust_task *target, fn_env_pair *f) {
622 target->start(f->f, f->env, NULL);
625 extern "C" CDECL size_t
626 rust_sched_current_nonlazy_threads() {
627 rust_task *task = rust_get_current_task();
628 return task->sched->number_of_threads();
631 extern "C" CDECL size_t
632 rust_sched_threads() {
633 rust_task *task = rust_get_current_task();
634 return task->sched->max_number_of_threads();
637 // This is called by an intrinsic on the Rust stack and must run
638 // entirely in the red zone. Do not call on the C stack.
639 extern "C" CDECL MUST_CHECK bool
640 rust_task_yield(rust_task *task, bool *killed) {
641 return task->yield();
644 extern "C" CDECL void
645 rust_set_exit_status(intptr_t code) {
646 rust_task *task = rust_get_current_task();
647 task->kernel->set_exit_status((int)code);
650 extern void log_console_on();
652 extern "C" CDECL void
653 rust_log_console_on() {
657 extern void log_console_off(rust_env *env);
659 extern "C" CDECL void
660 rust_log_console_off() {
661 rust_task *task = rust_get_current_task();
662 log_console_off(task->kernel->env);
665 extern "C" CDECL lock_and_signal *
666 rust_dbg_lock_create() {
667 return new lock_and_signal();
670 extern "C" CDECL void
671 rust_dbg_lock_destroy(lock_and_signal *lock) {
676 extern "C" CDECL void
677 rust_dbg_lock_lock(lock_and_signal *lock) {
682 extern "C" CDECL void
683 rust_dbg_lock_unlock(lock_and_signal *lock) {
688 extern "C" CDECL void
689 rust_dbg_lock_wait(lock_and_signal *lock) {
694 extern "C" CDECL void
695 rust_dbg_lock_signal(lock_and_signal *lock) {
700 typedef void *(*dbg_callback)(void*);
702 extern "C" CDECL void *
703 rust_dbg_call(dbg_callback cb, void *data) {
707 extern "C" CDECL void rust_dbg_do_nothing() { }
709 extern "C" CDECL void
710 rust_dbg_breakpoint() {
714 extern "C" CDECL rust_sched_id
715 rust_osmain_sched_id() {
716 rust_task *task = rust_get_current_task();
717 return task->kernel->osmain_sched_id();
721 rust_task_inhibit_kill(rust_task *task) {
722 task->inhibit_kill();
726 rust_task_allow_kill(rust_task *task) {
731 rust_task_inhibit_yield(rust_task *task) {
732 task->inhibit_yield();
736 rust_task_allow_yield(rust_task *task) {
741 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
746 rust_task_kill_all(rust_task *task) { /* Used for linked failure */
747 task->fail_sched_loop();
748 // This must not happen twice.
749 static bool main_taskgroup_failed = false;
750 assert(!main_taskgroup_failed);
751 main_taskgroup_failed = true;
755 bool rust_task_is_unwinding(rust_task *rt) {
756 return rt->unwinding;
759 extern "C" lock_and_signal*
760 rust_create_little_lock() {
761 return new lock_and_signal();
765 rust_destroy_little_lock(lock_and_signal *lock) {
770 rust_lock_little_lock(lock_and_signal *lock) {
775 rust_unlock_little_lock(lock_and_signal *lock) {
779 // set/get/atexit task_local_data can run on the rust stack for speed.
781 rust_get_task_local_data(rust_task *task) {
782 return task->task_local_data;
785 rust_set_task_local_data(rust_task *task, void *data) {
786 task->task_local_data = data;
789 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
790 task->task_local_data_cleanup = cleanup_fn;
794 task_clear_event_reject(rust_task *task) {
795 task->clear_event_reject();
798 // Waits on an event, returning the pointer to the event that unblocked this
800 extern "C" MUST_CHECK bool
801 task_wait_event(rust_task *task, void **result) {
802 // Maybe (if not too slow) assert that the passed in task is the currently
803 // running task. We wouldn't want to wait some other task.
805 return task->wait_event(result);
809 task_signal_event(rust_task *target, void *event) {
810 target->signal_event(event);
813 // Can safely run on the rust stack.
815 rust_task_ref(rust_task *task) {
819 // Don't run on the rust stack!
821 rust_task_deref(rust_task *task) {
825 // Must call on rust stack.
826 extern "C" CDECL void
827 rust_call_tydesc_glue(void *root, size_t *tydesc, size_t glue_index) {
828 void (*glue_fn)(void *, void *, void *, void *) =
829 (void (*)(void *, void *, void *, void *))tydesc[glue_index];
831 glue_fn(0, 0, 0, root);
834 // Don't run on the Rust stack!
836 rust_log_str(uint32_t level, const char *str, size_t size) {
837 rust_task *task = rust_get_current_task();
838 task->sched_loop->get_log().log(task, level, "%.*s", (int)size, str);
841 extern "C" CDECL void record_sp_limit(void *limit);
843 class raw_thread: public rust_thread {
847 raw_thread(fn_env_pair *fn) : fn(fn) { }
851 fn->f(NULL, fn->env, NULL);
855 extern "C" raw_thread*
856 rust_raw_thread_start(fn_env_pair *fn) {
858 raw_thread *thread = new raw_thread(fn);
864 rust_raw_thread_join_delete(raw_thread *thread) {
871 rust_register_exit_function(spawn_fn runner, fn_env_pair *f) {
872 rust_task *task = rust_get_current_task();
873 task->kernel->register_exit_function(runner, f);
877 rust_get_global_data_ptr() {
878 rust_task *task = rust_get_current_task();
879 return &task->kernel->global_data;
883 rust_inc_kernel_live_count() {
884 rust_task *task = rust_get_current_task();
885 task->kernel->inc_live_count();
889 rust_dec_kernel_live_count() {
890 rust_task *task = rust_get_current_task();
891 task->kernel->dec_live_count();
898 // indent-tabs-mode: nil
900 // buffer-file-coding-system: utf-8-unix