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 // FIXME (#2667) may want to actually account for alignment.
245 // `front` may not indeed be the front byte of the passed-in
247 for (uintptr_t i = 0; i < t->size; ++front, ++i) {
248 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
252 extern "C" CDECL void
253 debug_box(type_desc *t, rust_opaque_box *box) {
254 rust_task *task = rust_get_current_task();
255 LOG(task, stdlib, "debug_box(0x%" PRIxPTR ")", box);
256 debug_tydesc_helper(t);
257 LOG(task, stdlib, " refcount %" PRIdPTR,
258 box->ref_count - 1); // -1 because we ref'ed for this call
259 uint8_t *data = (uint8_t *)box_body(box);
260 for (uintptr_t i = 0; i < t->size; ++i) {
261 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i, data[i]);
266 uintptr_t discriminant;
270 extern "C" CDECL void
271 debug_tag(type_desc *t, rust_tag *tag) {
272 rust_task *task = rust_get_current_task();
274 LOG(task, stdlib, "debug_tag");
275 debug_tydesc_helper(t);
276 LOG(task, stdlib, " discriminant %" PRIdPTR, tag->discriminant);
278 for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
279 LOG(task, stdlib, " byte %" PRIdPTR ": 0x%" PRIx8, i,
283 extern "C" CDECL void
284 debug_fn(type_desc *t, fn_env_pair *fn) {
285 rust_task *task = rust_get_current_task();
286 LOG(task, stdlib, "debug_fn");
287 debug_tydesc_helper(t);
288 LOG(task, stdlib, " fn at 0x%" PRIxPTR, fn->f);
289 LOG(task, stdlib, " env at 0x%" PRIxPTR, fn->env);
291 LOG(task, stdlib, " refcount %" PRIdPTR, fn->env->ref_count);
295 extern "C" CDECL void *
296 debug_ptrcast(type_desc *from_ty,
299 rust_task *task = rust_get_current_task();
300 LOG(task, stdlib, "debug_ptrcast from");
301 debug_tydesc_helper(from_ty);
302 LOG(task, stdlib, "to");
303 debug_tydesc_helper(to_ty);
307 extern "C" CDECL void *
308 debug_get_stk_seg() {
309 rust_task *task = rust_get_current_task();
313 extern "C" CDECL rust_vec_box*
314 rust_list_files(rust_str *path) {
315 rust_task *task = rust_get_current_task();
316 array_list<rust_str*> strings;
317 #if defined(__WIN32__)
318 WIN32_FIND_DATA FindFileData;
319 HANDLE hFind = FindFirstFile((char*)path->body.data, &FindFileData);
320 if (hFind != INVALID_HANDLE_VALUE) {
322 rust_str *str = make_str(task->kernel, FindFileData.cFileName,
323 strlen(FindFileData.cFileName),
326 } while (FindNextFile(hFind, &FindFileData));
330 DIR *dirp = opendir((char*)path->body.data);
333 while ((dp = readdir(dirp))) {
334 rust_vec_box *str = make_str(task->kernel, dp->d_name,
343 rust_vec_box *vec = (rust_vec_box *)
344 task->kernel->malloc(vec_size<rust_vec_box*>(strings.size()),
346 size_t alloc_sz = sizeof(rust_vec*) * strings.size();
347 vec->body.fill = vec->body.alloc = alloc_sz;
348 memcpy(&vec->body.data[0], strings.data(), alloc_sz);
352 extern "C" CDECL rust_vec_box*
353 rust_list_files2(rust_str **path) {
354 return rust_list_files(*path);
358 rust_path_is_dir(char *path) {
360 if (stat(path, &buf)) {
363 return S_ISDIR(buf.st_mode);
367 rust_path_exists(char *path) {
369 if (stat(path, &buf)) {
375 extern "C" CDECL FILE* rust_get_stdin() {return stdin;}
376 extern "C" CDECL FILE* rust_get_stdout() {return stdout;}
377 extern "C" CDECL FILE* rust_get_stderr() {return stderr;}
379 #if defined(__WIN32__)
380 extern "C" CDECL void
381 get_time(int64_t *sec, int32_t *nsec) {
383 GetSystemTimeAsFileTime(&fileTime);
385 // A FILETIME contains a 64-bit value representing the number of
386 // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
387 // http://support.microsoft.com/kb/167296/en-us
389 ul.LowPart = fileTime.dwLowDateTime;
390 ul.HighPart = fileTime.dwHighDateTime;
391 uint64_t ns_since_1601 = ul.QuadPart / 10;
393 const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000u;
394 uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
395 *sec = ns_since_1970 / 1000000;
396 *nsec = (ns_since_1970 % 1000000) * 1000;
399 extern "C" CDECL void
400 get_time(int64_t *sec, int32_t *nsec) {
403 gettimeofday(&tv, NULL);
405 *nsec = tv.tv_usec * 1000;
408 clock_gettime(CLOCK_REALTIME, &ts);
415 extern "C" CDECL void
416 precise_time_ns(uint64_t *ns) {
436 void rust_tm_to_tm(rust_tm* in_tm, tm* out_tm) {
437 memset(out_tm, 0, sizeof(tm));
438 out_tm->tm_sec = in_tm->tm_sec;
439 out_tm->tm_min = in_tm->tm_min;
440 out_tm->tm_hour = in_tm->tm_hour;
441 out_tm->tm_mday = in_tm->tm_mday;
442 out_tm->tm_mon = in_tm->tm_mon;
443 out_tm->tm_year = in_tm->tm_year;
444 out_tm->tm_wday = in_tm->tm_wday;
445 out_tm->tm_yday = in_tm->tm_yday;
446 out_tm->tm_isdst = in_tm->tm_isdst;
449 void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
450 const char *zone, int32_t nsec) {
451 out_tm->tm_sec = in_tm->tm_sec;
452 out_tm->tm_min = in_tm->tm_min;
453 out_tm->tm_hour = in_tm->tm_hour;
454 out_tm->tm_mday = in_tm->tm_mday;
455 out_tm->tm_mon = in_tm->tm_mon;
456 out_tm->tm_year = in_tm->tm_year;
457 out_tm->tm_wday = in_tm->tm_wday;
458 out_tm->tm_yday = in_tm->tm_yday;
459 out_tm->tm_isdst = in_tm->tm_isdst;
460 out_tm->tm_gmtoff = gmtoff;
461 out_tm->tm_nsec = nsec;
464 rust_task *task = rust_get_current_task();
465 size_t size = strlen(zone);
466 reserve_vec_exact(task, &out_tm->tm_zone, size + 1);
467 memcpy(out_tm->tm_zone->body.data, zone, size);
468 out_tm->tm_zone->body.fill = size + 1;
469 out_tm->tm_zone->body.data[size] = '\0';
473 #if defined(__WIN32__)
474 #define TZSET() _tzset()
475 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
476 #define GMTIME(clock, result) gmtime_s((result), (clock))
477 #define LOCALTIME(clock, result) localtime_s((result), (clock))
478 #define TIMEGM(result) _mkgmtime64(result)
480 struct tm* GMTIME(const time_t *clock, tm *result) {
481 struct tm* t = gmtime(clock);
482 if (t == NULL || result == NULL) { return NULL; }
486 struct tm* LOCALTIME(const time_t *clock, tm *result) {
487 struct tm* t = localtime(clock);
488 if (t == NULL || result == NULL) { return NULL; }
492 #define TIMEGM(result) mktime((result)) - _timezone
495 #define TZSET() tzset()
496 #define GMTIME(clock, result) gmtime_r((clock), (result))
497 #define LOCALTIME(clock, result) localtime_r((clock), (result))
498 #define TIMEGM(result) timegm(result)
501 extern "C" CDECL void
506 extern "C" CDECL void
507 rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
512 tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec);
515 extern "C" CDECL void
516 rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
521 #if defined(__WIN32__)
522 int32_t gmtoff = -timezone;
524 strftime(zone, sizeof(zone), "%Z", &tm);
526 int32_t gmtoff = tm.tm_gmtoff;
527 const char *zone = tm.tm_zone;
530 tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec);
533 extern "C" CDECL void
534 rust_timegm(rust_tm* timeptr, int64_t *out) {
536 rust_tm_to_tm(timeptr, &t);
540 extern "C" CDECL void
541 rust_mktime(rust_tm* timeptr, int64_t *out) {
543 rust_tm_to_tm(timeptr, &t);
547 extern "C" CDECL rust_sched_id
548 rust_get_sched_id() {
549 rust_task *task = rust_get_current_task();
550 return task->sched->get_id();
553 extern "C" CDECL uintptr_t
555 rust_task *task = rust_get_current_task();
556 return task->kernel->env->num_sched_threads;
561 rust_task *task = rust_get_current_task();
562 return task->kernel->env->argc;
565 extern "C" CDECL char**
567 rust_task *task = rust_get_current_task();
568 return task->kernel->env->argv;
571 extern "C" CDECL rust_sched_id
572 rust_new_sched(uintptr_t threads) {
573 rust_task *task = rust_get_current_task();
574 assert(threads > 0 && "Can't create a scheduler with no threads, silly!");
575 return task->kernel->create_scheduler(threads);
578 extern "C" CDECL rust_task_id
580 rust_task *task = rust_get_current_task();
585 new_task_common(rust_scheduler *sched, rust_task *parent) {
586 return sched->create_task(parent, NULL);
589 extern "C" CDECL rust_task*
591 rust_task *task = rust_get_current_task();
592 rust_sched_id sched_id = task->kernel->main_sched_id();
593 rust_scheduler *sched = task->kernel->get_scheduler_by_id(sched_id);
594 assert(sched != NULL && "should always have a main scheduler");
595 return new_task_common(sched, task);
598 extern "C" CDECL rust_task*
599 rust_new_task_in_sched(rust_sched_id id) {
600 rust_task *task = rust_get_current_task();
601 rust_scheduler *sched = task->kernel->get_scheduler_by_id(id);
604 return new_task_common(sched, task);
607 extern "C" rust_task *
609 return rust_get_current_task();
612 extern "C" CDECL stk_seg *
613 rust_get_stack_segment() {
614 return rust_get_current_task()->stk;
617 extern "C" CDECL void
618 start_task(rust_task *target, fn_env_pair *f) {
619 target->start(f->f, f->env, NULL);
622 extern "C" CDECL size_t
623 rust_sched_current_nonlazy_threads() {
624 rust_task *task = rust_get_current_task();
625 return task->sched->number_of_threads();
628 extern "C" CDECL size_t
629 rust_sched_threads() {
630 rust_task *task = rust_get_current_task();
631 return task->sched->max_number_of_threads();
634 // This is called by an intrinsic on the Rust stack and must run
635 // entirely in the red zone. Do not call on the C stack.
636 extern "C" CDECL MUST_CHECK bool
637 rust_task_yield(rust_task *task, bool *killed) {
638 return task->yield();
641 extern "C" CDECL void
642 rust_set_exit_status(intptr_t code) {
643 rust_task *task = rust_get_current_task();
644 task->kernel->set_exit_status((int)code);
647 extern void log_console_on();
649 extern "C" CDECL void
650 rust_log_console_on() {
654 extern void log_console_off(rust_env *env);
656 extern "C" CDECL void
657 rust_log_console_off() {
658 rust_task *task = rust_get_current_task();
659 log_console_off(task->kernel->env);
662 extern "C" CDECL lock_and_signal *
663 rust_dbg_lock_create() {
664 return new lock_and_signal();
667 extern "C" CDECL void
668 rust_dbg_lock_destroy(lock_and_signal *lock) {
673 extern "C" CDECL void
674 rust_dbg_lock_lock(lock_and_signal *lock) {
679 extern "C" CDECL void
680 rust_dbg_lock_unlock(lock_and_signal *lock) {
685 extern "C" CDECL void
686 rust_dbg_lock_wait(lock_and_signal *lock) {
691 extern "C" CDECL void
692 rust_dbg_lock_signal(lock_and_signal *lock) {
697 typedef void *(*dbg_callback)(void*);
699 extern "C" CDECL void *
700 rust_dbg_call(dbg_callback cb, void *data) {
704 extern "C" CDECL void rust_dbg_do_nothing() { }
706 extern "C" CDECL void
707 rust_dbg_breakpoint() {
711 extern "C" CDECL rust_sched_id
712 rust_osmain_sched_id() {
713 rust_task *task = rust_get_current_task();
714 return task->kernel->osmain_sched_id();
718 rust_task_inhibit_kill(rust_task *task) {
719 task->inhibit_kill();
723 rust_task_allow_kill(rust_task *task) {
728 rust_task_inhibit_yield(rust_task *task) {
729 task->inhibit_yield();
733 rust_task_allow_yield(rust_task *task) {
738 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
743 rust_task_kill_all(rust_task *task) { /* Used for linked failure */
744 task->fail_sched_loop();
745 // This must not happen twice.
746 static bool main_taskgroup_failed = false;
747 assert(!main_taskgroup_failed);
748 main_taskgroup_failed = true;
752 bool rust_task_is_unwinding(rust_task *rt) {
753 return rt->unwinding;
756 extern "C" lock_and_signal*
757 rust_create_little_lock() {
758 return new lock_and_signal();
762 rust_destroy_little_lock(lock_and_signal *lock) {
767 rust_lock_little_lock(lock_and_signal *lock) {
772 rust_unlock_little_lock(lock_and_signal *lock) {
776 // set/get/atexit task_local_data can run on the rust stack for speed.
778 rust_get_task_local_data(rust_task *task) {
779 return task->task_local_data;
782 rust_set_task_local_data(rust_task *task, void *data) {
783 task->task_local_data = data;
786 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
787 task->task_local_data_cleanup = cleanup_fn;
791 task_clear_event_reject(rust_task *task) {
792 task->clear_event_reject();
795 // Waits on an event, returning the pointer to the event that unblocked this
797 extern "C" MUST_CHECK bool
798 task_wait_event(rust_task *task, void **result) {
799 // Maybe (if not too slow) assert that the passed in task is the currently
800 // running task. We wouldn't want to wait some other task.
802 return task->wait_event(result);
806 task_signal_event(rust_task *target, void *event) {
807 target->signal_event(event);
810 // Can safely run on the rust stack.
812 rust_task_ref(rust_task *task) {
816 // Don't run on the rust stack!
818 rust_task_deref(rust_task *task) {
822 // Must call on rust stack.
823 extern "C" CDECL void
824 rust_call_tydesc_glue(void *root, size_t *tydesc, size_t glue_index) {
825 void (*glue_fn)(void *, void *, void *, void *) =
826 (void (*)(void *, void *, void *, void *))tydesc[glue_index];
828 glue_fn(0, 0, 0, root);
831 // Don't run on the Rust stack!
833 rust_log_str(uint32_t level, const char *str, size_t size) {
834 rust_task *task = rust_get_current_task();
835 task->sched_loop->get_log().log(task, level, "%.*s", (int)size, str);
838 extern "C" CDECL void record_sp_limit(void *limit);
840 class raw_thread: public rust_thread {
844 raw_thread(fn_env_pair *fn) : fn(fn) { }
848 fn->f(NULL, fn->env, NULL);
852 extern "C" raw_thread*
853 rust_raw_thread_start(fn_env_pair *fn) {
855 raw_thread *thread = new raw_thread(fn);
861 rust_raw_thread_join_delete(raw_thread *thread) {
868 rust_register_exit_function(spawn_fn runner, fn_env_pair *f) {
869 rust_task *task = rust_get_current_task();
870 task->kernel->register_exit_function(runner, f);
874 rust_get_global_data_ptr() {
875 rust_task *task = rust_get_current_task();
876 return &task->kernel->global_data;
880 rust_inc_kernel_live_count() {
881 rust_task *task = rust_get_current_task();
882 task->kernel->inc_live_count();
886 rust_dec_kernel_live_count() {
887 rust_task *task = rust_get_current_task();
888 task->kernel->dec_live_count();
895 // indent-tabs-mode: nil
897 // buffer-file-coding-system: utf-8-unix