]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.cpp
rt: get rid of rust_fn and replace with fn_env_pair plus a little cleanup.
[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
21 #include <time.h>
22
23 #ifdef __APPLE__
24 #include <crt_externs.h>
25 #endif
26
27 #if !defined(__WIN32__)
28 #include <sys/time.h>
29 #endif
30
31 #ifdef __FreeBSD__
32 extern char **environ;
33 #endif
34
35 #ifdef __ANDROID__
36 time_t
37 timegm(struct tm *tm)
38 {
39     time_t ret;
40     char *tz;
41
42     tz = getenv("TZ");
43     setenv("TZ", "", 1);
44     tzset();
45     ret = mktime(tm);
46     if (tz)
47         setenv("TZ", tz, 1);
48     else
49         unsetenv("TZ");
50     tzset();
51     return ret;
52 }
53 #endif
54
55 extern "C" CDECL rust_str *
56 rust_getcwd() {
57     rust_task *task = rust_get_current_task();
58     LOG(task, task, "rust_getcwd()");
59
60     char cbuf[BUF_BYTES];
61
62 #if defined(__WIN32__)
63     if (!_getcwd(cbuf, sizeof(cbuf))) {
64 #else
65         if (!getcwd(cbuf, sizeof(cbuf))) {
66 #endif
67         task->fail();
68         return NULL;
69     }
70
71     return make_str(task->kernel, cbuf, strlen(cbuf), "rust_str(getcwd)");
72 }
73
74 #if defined(__WIN32__)
75 extern "C" CDECL rust_vec_box *
76 rust_env_pairs() {
77     rust_task *task = rust_get_current_task();
78     size_t envc = 0;
79     LPTCH ch = GetEnvironmentStringsA();
80     LPTCH c;
81     for (c = ch; *c; c += strlen(c) + 1) {
82         ++envc;
83     }
84     c = ch;
85     rust_vec_box *v = (rust_vec_box *)
86         task->kernel->malloc(vec_size<rust_vec_box*>(envc),
87                        "str vec interior");
88     v->body.fill = v->body.alloc = sizeof(rust_vec*) * envc;
89     for (size_t i = 0; i < envc; ++i) {
90         size_t n = strlen(c);
91         rust_str *str = make_str(task->kernel, c, n, "str");
92         ((rust_str**)&v->body.data)[i] = str;
93         c += n + 1;
94     }
95     if (ch) {
96         FreeEnvironmentStrings(ch);
97     }
98     return v;
99 }
100 #else
101 extern "C" CDECL rust_vec_box *
102 rust_env_pairs() {
103     rust_task *task = rust_get_current_task();
104 #ifdef __APPLE__
105     char **environ = *_NSGetEnviron();
106 #endif
107     char **e = environ;
108     size_t envc = 0;
109     while (*e) {
110         ++envc; ++e;
111     }
112     return make_str_vec(task->kernel, envc, environ);
113 }
114 #endif
115
116 extern "C" CDECL void
117 vec_reserve_shared_actual(type_desc* ty, rust_vec_box** vp,
118                           size_t n_elts) {
119     rust_task *task = rust_get_current_task();
120     reserve_vec_exact_shared(task, vp, n_elts * ty->size);
121 }
122
123 // This is completely misnamed.
124 extern "C" CDECL void
125 vec_reserve_shared(type_desc* ty, rust_vec_box** vp,
126                    size_t n_elts) {
127     rust_task *task = rust_get_current_task();
128     reserve_vec_exact(task, vp, n_elts * ty->size);
129 }
130
131 extern "C" CDECL rust_vec*
132 rand_seed() {
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),
136                                             "rand_seed");
137     v->fill = v->alloc = size;
138     isaac_seed(task->kernel, (uint8_t*) &v->data, size);
139     return v;
140 }
141
142 extern "C" CDECL void *
143 rand_new() {
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");
147     if (!rctx) {
148         task->fail();
149         return NULL;
150     }
151     isaac_init(thread->kernel, rctx, NULL);
152     return rctx;
153 }
154
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),
160                                              "rand_new_seeded");
161     if (!rctx) {
162         task->fail();
163         return NULL;
164     }
165     isaac_init(thread->kernel, rctx, seed);
166     return rctx;
167 }
168
169 extern "C" CDECL void *
170 rand_new_seeded2(rust_vec_box** seed) {
171     return rand_new_seeded(*seed);
172 }
173
174 extern "C" CDECL size_t
175 rand_next(randctx *rctx) {
176     return isaac_rand(rctx);
177 }
178
179 extern "C" CDECL void
180 rand_free(randctx *rctx) {
181     rust_task *task = rust_get_current_task();
182     task->free(rctx);
183 }
184
185
186 /* Debug helpers strictly to verify ABI conformance.
187  *
188  * FIXME (#2665): move these into a testcase when the testsuite
189  * understands how to have explicit C files included.
190  */
191
192 struct quad {
193     uint64_t a;
194     uint64_t b;
195     uint64_t c;
196     uint64_t d;
197 };
198
199 struct floats {
200     double a;
201     uint8_t b;
202     double c;
203 };
204
205 extern "C" quad
206 debug_abi_1(quad q) {
207     quad qq = { q.c + 1,
208                 q.d - 1,
209                 q.a + 1,
210                 q.b - 1 };
211     return qq;
212 }
213
214 extern "C" floats
215 debug_abi_2(floats f) {
216     floats ff = { f.c + 1.0,
217                   0xff,
218                   f.a - 1.0 };
219     return ff;
220 }
221
222 /* Debug builtins for std::dbg. */
223
224 static void
225 debug_tydesc_helper(type_desc *t)
226 {
227     rust_task *task = rust_get_current_task();
228     LOG(task, stdlib, "  size %" PRIdPTR ", align %" PRIdPTR,
229         t->size, t->align);
230 }
231
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);
237 }
238
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
246     // argument.
247     for (uintptr_t i = 0; i < t->size; ++front, ++i) {
248         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
249     }
250 }
251
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]);
262     }
263 }
264
265 struct rust_tag {
266     uintptr_t discriminant;
267     uint8_t variant[];
268 };
269
270 extern "C" CDECL void
271 debug_tag(type_desc *t, rust_tag *tag) {
272     rust_task *task = rust_get_current_task();
273
274     LOG(task, stdlib, "debug_tag");
275     debug_tydesc_helper(t);
276     LOG(task, stdlib, "  discriminant %" PRIdPTR, tag->discriminant);
277
278     for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
279         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i,
280             tag->variant[i]);
281 }
282
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);
290     if (fn->env) {
291         LOG(task, stdlib, "    refcount %" PRIdPTR, fn->env->ref_count);
292     }
293 }
294
295 extern "C" CDECL void *
296 debug_ptrcast(type_desc *from_ty,
297               type_desc *to_ty,
298               void *ptr) {
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);
304     return ptr;
305 }
306
307 extern "C" CDECL void *
308 debug_get_stk_seg() {
309     rust_task *task = rust_get_current_task();
310     return task->stk;
311 }
312
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) {
321         do {
322             rust_str *str = make_str(task->kernel, FindFileData.cFileName,
323                                      strlen(FindFileData.cFileName),
324                                      "list_files_str");
325             strings.push(str);
326         } while (FindNextFile(hFind, &FindFileData));
327         FindClose(hFind);
328     }
329 #else
330     DIR *dirp = opendir((char*)path->body.data);
331   if (dirp) {
332       struct dirent *dp;
333       while ((dp = readdir(dirp))) {
334           rust_vec_box *str = make_str(task->kernel, dp->d_name,
335                                        strlen(dp->d_name),
336                                        "list_files_str");
337           strings.push(str);
338       }
339       closedir(dirp);
340   }
341 #endif
342
343   rust_vec_box *vec = (rust_vec_box *)
344       task->kernel->malloc(vec_size<rust_vec_box*>(strings.size()),
345                            "list_files_vec");
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);
349   return vec;
350 }
351
352 extern "C" CDECL rust_vec_box*
353 rust_list_files2(rust_str **path) {
354     return rust_list_files(*path);
355 }
356
357 extern "C" CDECL int
358 rust_path_is_dir(char *path) {
359     struct stat buf;
360     if (stat(path, &buf)) {
361         return 0;
362     }
363     return S_ISDIR(buf.st_mode);
364 }
365
366 extern "C" CDECL int
367 rust_path_exists(char *path) {
368     struct stat buf;
369     if (stat(path, &buf)) {
370         return 0;
371     }
372     return 1;
373 }
374
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;}
378
379 #if defined(__WIN32__)
380 extern "C" CDECL void
381 get_time(int64_t *sec, int32_t *nsec) {
382     FILETIME fileTime;
383     GetSystemTimeAsFileTime(&fileTime);
384
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
388     ULARGE_INTEGER ul;
389     ul.LowPart = fileTime.dwLowDateTime;
390     ul.HighPart = fileTime.dwHighDateTime;
391     uint64_t ns_since_1601 = ul.QuadPart / 10;
392
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;
397 }
398 #else
399 extern "C" CDECL void
400 get_time(int64_t *sec, int32_t *nsec) {
401 #ifdef __APPLE__
402     struct timeval tv;
403     gettimeofday(&tv, NULL);
404     *sec = tv.tv_sec;
405     *nsec = tv.tv_usec * 1000;
406 #else
407     timespec ts;
408     clock_gettime(CLOCK_REALTIME, &ts);
409     *sec = ts.tv_sec;
410     *nsec = ts.tv_nsec;
411 #endif
412 }
413 #endif
414
415 extern "C" CDECL void
416 precise_time_ns(uint64_t *ns) {
417     timer t;
418     *ns = t.time_ns();
419 }
420
421 struct rust_tm {
422     int32_t tm_sec;
423     int32_t tm_min;
424     int32_t tm_hour;
425     int32_t tm_mday;
426     int32_t tm_mon;
427     int32_t tm_year;
428     int32_t tm_wday;
429     int32_t tm_yday;
430     int32_t tm_isdst;
431     int32_t tm_gmtoff;
432     rust_str *tm_zone;
433     int32_t tm_nsec;
434 };
435
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;
447 }
448
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;
462
463     if (zone != NULL) {
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';
470     }
471 }
472
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)
479 #else
480 struct tm* GMTIME(const time_t *clock, tm *result) {
481     struct tm* t = gmtime(clock);
482     if (t == NULL || result == NULL) { return NULL; }
483     *result = *t;
484     return result;
485 }
486 struct tm* LOCALTIME(const time_t *clock, tm *result) {
487     struct tm* t = localtime(clock);
488     if (t == NULL || result == NULL) { return NULL; }
489     *result = *t;
490     return result;
491 }
492 #define TIMEGM(result) mktime((result)) - _timezone
493 #endif
494 #else
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)
499 #endif
500
501 extern "C" CDECL void
502 rust_tzset() {
503     TZSET();
504 }
505
506 extern "C" CDECL void
507 rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
508     tm tm;
509     time_t s = *sec;
510     GMTIME(&s, &tm);
511
512     tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec);
513 }
514
515 extern "C" CDECL void
516 rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
517     tm tm;
518     time_t s = *sec;
519     LOCALTIME(&s, &tm);
520
521 #if defined(__WIN32__)
522     int32_t gmtoff = -timezone;
523     char zone[64];
524     strftime(zone, sizeof(zone), "%Z", &tm);
525 #else
526     int32_t gmtoff = tm.tm_gmtoff;
527     const char *zone = tm.tm_zone;
528 #endif
529
530     tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec);
531 }
532
533 extern "C" CDECL void
534 rust_timegm(rust_tm* timeptr, int64_t *out) {
535     tm t;
536     rust_tm_to_tm(timeptr, &t);
537     *out = TIMEGM(&t);
538 }
539
540 extern "C" CDECL void
541 rust_mktime(rust_tm* timeptr, int64_t *out) {
542     tm t;
543     rust_tm_to_tm(timeptr, &t);
544     *out = mktime(&t);
545 }
546
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();
551 }
552
553 extern "C" CDECL uintptr_t
554 rust_num_threads() {
555     rust_task *task = rust_get_current_task();
556     return task->kernel->env->num_sched_threads;
557 }
558
559 extern "C" CDECL int
560 rust_get_argc() {
561     rust_task *task = rust_get_current_task();
562     return task->kernel->env->argc;
563 }
564
565 extern "C" CDECL char**
566 rust_get_argv() {
567     rust_task *task = rust_get_current_task();
568     return task->kernel->env->argv;
569 }
570
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);
576 }
577
578 extern "C" CDECL rust_task_id
579 get_task_id() {
580     rust_task *task = rust_get_current_task();
581     return task->id;
582 }
583
584 static rust_task*
585 new_task_common(rust_scheduler *sched, rust_task *parent) {
586     return sched->create_task(parent, NULL);
587 }
588
589 extern "C" CDECL rust_task*
590 new_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);
596 }
597
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);
602     if (sched == NULL)
603         return NULL;
604     return new_task_common(sched, task);
605 }
606
607 extern "C" rust_task *
608 rust_get_task() {
609     return rust_get_current_task();
610 }
611
612 extern "C" CDECL stk_seg *
613 rust_get_stack_segment() {
614     return rust_get_current_task()->stk;
615 }
616
617 extern "C" CDECL void
618 start_task(rust_task *target, fn_env_pair *f) {
619     target->start(f->f, f->env, NULL);
620 }
621
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();
626 }
627
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();
632 }
633
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();
639 }
640
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);
645 }
646
647 extern void log_console_on();
648
649 extern "C" CDECL void
650 rust_log_console_on() {
651     log_console_on();
652 }
653
654 extern void log_console_off(rust_env *env);
655
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);
660 }
661
662 extern "C" CDECL lock_and_signal *
663 rust_dbg_lock_create() {
664     return new lock_and_signal();
665 }
666
667 extern "C" CDECL void
668 rust_dbg_lock_destroy(lock_and_signal *lock) {
669     assert(lock);
670     delete lock;
671 }
672
673 extern "C" CDECL void
674 rust_dbg_lock_lock(lock_and_signal *lock) {
675     assert(lock);
676     lock->lock();
677 }
678
679 extern "C" CDECL void
680 rust_dbg_lock_unlock(lock_and_signal *lock) {
681     assert(lock);
682     lock->unlock();
683 }
684
685 extern "C" CDECL void
686 rust_dbg_lock_wait(lock_and_signal *lock) {
687     assert(lock);
688     lock->wait();
689 }
690
691 extern "C" CDECL void
692 rust_dbg_lock_signal(lock_and_signal *lock) {
693     assert(lock);
694     lock->signal();
695 }
696
697 typedef void *(*dbg_callback)(void*);
698
699 extern "C" CDECL void *
700 rust_dbg_call(dbg_callback cb, void *data) {
701     return cb(data);
702 }
703
704 extern "C" CDECL void rust_dbg_do_nothing() { }
705
706 extern "C" CDECL void
707 rust_dbg_breakpoint() {
708     BREAKPOINT_AWESOME;
709 }
710
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();
715 }
716
717 extern "C" void
718 rust_task_inhibit_kill(rust_task *task) {
719     task->inhibit_kill();
720 }
721
722 extern "C" void
723 rust_task_allow_kill(rust_task *task) {
724     task->allow_kill();
725 }
726
727 extern "C" void
728 rust_task_inhibit_yield(rust_task *task) {
729     task->inhibit_yield();
730 }
731
732 extern "C" void
733 rust_task_allow_yield(rust_task *task) {
734     task->allow_yield();
735 }
736
737 extern "C" void
738 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
739     task->kill();
740 }
741
742 extern "C" void
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;
749 }
750
751 extern "C" CDECL
752 bool rust_task_is_unwinding(rust_task *rt) {
753     return rt->unwinding;
754 }
755
756 extern "C" lock_and_signal*
757 rust_create_little_lock() {
758     return new lock_and_signal();
759 }
760
761 extern "C" void
762 rust_destroy_little_lock(lock_and_signal *lock) {
763     delete lock;
764 }
765
766 extern "C" void
767 rust_lock_little_lock(lock_and_signal *lock) {
768     lock->lock();
769 }
770
771 extern "C" void
772 rust_unlock_little_lock(lock_and_signal *lock) {
773     lock->unlock();
774 }
775
776 // set/get/atexit task_local_data can run on the rust stack for speed.
777 extern "C" void *
778 rust_get_task_local_data(rust_task *task) {
779     return task->task_local_data;
780 }
781 extern "C" void
782 rust_set_task_local_data(rust_task *task, void *data) {
783     task->task_local_data = data;
784 }
785 extern "C" void
786 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
787     task->task_local_data_cleanup = cleanup_fn;
788 }
789
790 extern "C" void
791 task_clear_event_reject(rust_task *task) {
792     task->clear_event_reject();
793 }
794
795 // Waits on an event, returning the pointer to the event that unblocked this
796 // task.
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.
801
802     return task->wait_event(result);
803 }
804
805 extern "C" void
806 task_signal_event(rust_task *target, void *event) {
807     target->signal_event(event);
808 }
809
810 // Can safely run on the rust stack.
811 extern "C" void
812 rust_task_ref(rust_task *task) {
813     task->ref();
814 }
815
816 // Don't run on the rust stack!
817 extern "C" void
818 rust_task_deref(rust_task *task) {
819     task->deref();
820 }
821
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];
827     if (glue_fn)
828         glue_fn(0, 0, 0, root);
829 }
830
831 // Don't run on the Rust stack!
832 extern "C" void
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);
836 }
837
838 extern "C" CDECL void      record_sp_limit(void *limit);
839
840 class raw_thread: public rust_thread {
841 public:
842     fn_env_pair *fn;
843
844     raw_thread(fn_env_pair *fn) : fn(fn) { }
845
846     virtual void run() {
847         record_sp_limit(0);
848         fn->f(NULL, fn->env, NULL);
849     }
850 };
851
852 extern "C" raw_thread*
853 rust_raw_thread_start(fn_env_pair *fn) {
854     assert(fn);
855     raw_thread *thread = new raw_thread(fn);
856     thread->start();
857     return thread;
858 }
859
860 extern "C" void
861 rust_raw_thread_join_delete(raw_thread *thread) {
862     assert(thread);
863     thread->join();
864     delete thread;
865 }
866
867 extern "C" void
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);
871 }
872
873 extern "C" void *
874 rust_get_global_data_ptr() {
875     rust_task *task = rust_get_current_task();
876     return &task->kernel->global_data;
877 }
878
879 extern "C" void
880 rust_inc_kernel_live_count() {
881     rust_task *task = rust_get_current_task();
882     task->kernel->inc_live_count();
883 }
884
885 extern "C" void
886 rust_dec_kernel_live_count() {
887     rust_task *task = rust_get_current_task();
888     task->kernel->dec_live_count();
889 }
890
891 //
892 // Local Variables:
893 // mode: C++
894 // fill-column: 78;
895 // indent-tabs-mode: nil
896 // c-basic-offset: 4
897 // buffer-file-coding-system: utf-8-unix
898 // End:
899 //