]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.cpp
a8e1e7a0be4ba5b82d5c17276c4f4db268bac190
[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     for (uintptr_t i = 0; i < t->size; ++front, ++i) {
245
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);
250
251         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
252     }
253 }
254
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]);
265     }
266 }
267
268 struct rust_tag {
269     uintptr_t discriminant;
270     uint8_t variant[];
271 };
272
273 extern "C" CDECL void
274 debug_tag(type_desc *t, rust_tag *tag) {
275     rust_task *task = rust_get_current_task();
276
277     LOG(task, stdlib, "debug_tag");
278     debug_tydesc_helper(t);
279     LOG(task, stdlib, "  discriminant %" PRIdPTR, tag->discriminant);
280
281     for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
282         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i,
283             tag->variant[i]);
284 }
285
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);
293     if (fn->env) {
294         LOG(task, stdlib, "    refcount %" PRIdPTR, fn->env->ref_count);
295     }
296 }
297
298 extern "C" CDECL void *
299 debug_ptrcast(type_desc *from_ty,
300               type_desc *to_ty,
301               void *ptr) {
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);
307     return ptr;
308 }
309
310 extern "C" CDECL void *
311 debug_get_stk_seg() {
312     rust_task *task = rust_get_current_task();
313     return task->stk;
314 }
315
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) {
324         do {
325             rust_str *str = make_str(task->kernel, FindFileData.cFileName,
326                                      strlen(FindFileData.cFileName),
327                                      "list_files_str");
328             strings.push(str);
329         } while (FindNextFile(hFind, &FindFileData));
330         FindClose(hFind);
331     }
332 #else
333     DIR *dirp = opendir((char*)path->body.data);
334   if (dirp) {
335       struct dirent *dp;
336       while ((dp = readdir(dirp))) {
337           rust_vec_box *str = make_str(task->kernel, dp->d_name,
338                                        strlen(dp->d_name),
339                                        "list_files_str");
340           strings.push(str);
341       }
342       closedir(dirp);
343   }
344 #endif
345
346   rust_vec_box *vec = (rust_vec_box *)
347       task->kernel->malloc(vec_size<rust_vec_box*>(strings.size()),
348                            "list_files_vec");
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);
352   return vec;
353 }
354
355 extern "C" CDECL rust_vec_box*
356 rust_list_files2(rust_str **path) {
357     return rust_list_files(*path);
358 }
359
360 extern "C" CDECL int
361 rust_path_is_dir(char *path) {
362     struct stat buf;
363     if (stat(path, &buf)) {
364         return 0;
365     }
366     return S_ISDIR(buf.st_mode);
367 }
368
369 extern "C" CDECL int
370 rust_path_exists(char *path) {
371     struct stat buf;
372     if (stat(path, &buf)) {
373         return 0;
374     }
375     return 1;
376 }
377
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;}
381
382 #if defined(__WIN32__)
383 extern "C" CDECL void
384 get_time(int64_t *sec, int32_t *nsec) {
385     FILETIME fileTime;
386     GetSystemTimeAsFileTime(&fileTime);
387
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
391     ULARGE_INTEGER ul;
392     ul.LowPart = fileTime.dwLowDateTime;
393     ul.HighPart = fileTime.dwHighDateTime;
394     uint64_t ns_since_1601 = ul.QuadPart / 10;
395
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;
400 }
401 #else
402 extern "C" CDECL void
403 get_time(int64_t *sec, int32_t *nsec) {
404 #ifdef __APPLE__
405     struct timeval tv;
406     gettimeofday(&tv, NULL);
407     *sec = tv.tv_sec;
408     *nsec = tv.tv_usec * 1000;
409 #else
410     timespec ts;
411     clock_gettime(CLOCK_REALTIME, &ts);
412     *sec = ts.tv_sec;
413     *nsec = ts.tv_nsec;
414 #endif
415 }
416 #endif
417
418 extern "C" CDECL void
419 precise_time_ns(uint64_t *ns) {
420     timer t;
421     *ns = t.time_ns();
422 }
423
424 struct rust_tm {
425     int32_t tm_sec;
426     int32_t tm_min;
427     int32_t tm_hour;
428     int32_t tm_mday;
429     int32_t tm_mon;
430     int32_t tm_year;
431     int32_t tm_wday;
432     int32_t tm_yday;
433     int32_t tm_isdst;
434     int32_t tm_gmtoff;
435     rust_str *tm_zone;
436     int32_t tm_nsec;
437 };
438
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;
450 }
451
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;
465
466     if (zone != NULL) {
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';
473     }
474 }
475
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)
482 #else
483 struct tm* GMTIME(const time_t *clock, tm *result) {
484     struct tm* t = gmtime(clock);
485     if (t == NULL || result == NULL) { return NULL; }
486     *result = *t;
487     return result;
488 }
489 struct tm* LOCALTIME(const time_t *clock, tm *result) {
490     struct tm* t = localtime(clock);
491     if (t == NULL || result == NULL) { return NULL; }
492     *result = *t;
493     return result;
494 }
495 #define TIMEGM(result) mktime((result)) - _timezone
496 #endif
497 #else
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)
502 #endif
503
504 extern "C" CDECL void
505 rust_tzset() {
506     TZSET();
507 }
508
509 extern "C" CDECL void
510 rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
511     tm tm;
512     time_t s = *sec;
513     GMTIME(&s, &tm);
514
515     tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec);
516 }
517
518 extern "C" CDECL void
519 rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
520     tm tm;
521     time_t s = *sec;
522     LOCALTIME(&s, &tm);
523
524 #if defined(__WIN32__)
525     int32_t gmtoff = -timezone;
526     char zone[64];
527     strftime(zone, sizeof(zone), "%Z", &tm);
528 #else
529     int32_t gmtoff = tm.tm_gmtoff;
530     const char *zone = tm.tm_zone;
531 #endif
532
533     tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec);
534 }
535
536 extern "C" CDECL void
537 rust_timegm(rust_tm* timeptr, int64_t *out) {
538     tm t;
539     rust_tm_to_tm(timeptr, &t);
540     *out = TIMEGM(&t);
541 }
542
543 extern "C" CDECL void
544 rust_mktime(rust_tm* timeptr, int64_t *out) {
545     tm t;
546     rust_tm_to_tm(timeptr, &t);
547     *out = mktime(&t);
548 }
549
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();
554 }
555
556 extern "C" CDECL uintptr_t
557 rust_num_threads() {
558     rust_task *task = rust_get_current_task();
559     return task->kernel->env->num_sched_threads;
560 }
561
562 extern "C" CDECL int
563 rust_get_argc() {
564     rust_task *task = rust_get_current_task();
565     return task->kernel->env->argc;
566 }
567
568 extern "C" CDECL char**
569 rust_get_argv() {
570     rust_task *task = rust_get_current_task();
571     return task->kernel->env->argv;
572 }
573
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);
579 }
580
581 extern "C" CDECL rust_task_id
582 get_task_id() {
583     rust_task *task = rust_get_current_task();
584     return task->id;
585 }
586
587 static rust_task*
588 new_task_common(rust_scheduler *sched, rust_task *parent) {
589     return sched->create_task(parent, NULL);
590 }
591
592 extern "C" CDECL rust_task*
593 new_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);
599 }
600
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);
605     if (sched == NULL)
606         return NULL;
607     return new_task_common(sched, task);
608 }
609
610 extern "C" rust_task *
611 rust_get_task() {
612     return rust_get_current_task();
613 }
614
615 extern "C" CDECL stk_seg *
616 rust_get_stack_segment() {
617     return rust_get_current_task()->stk;
618 }
619
620 extern "C" CDECL void
621 start_task(rust_task *target, fn_env_pair *f) {
622     target->start(f->f, f->env, NULL);
623 }
624
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();
629 }
630
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();
635 }
636
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();
642 }
643
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);
648 }
649
650 extern void log_console_on();
651
652 extern "C" CDECL void
653 rust_log_console_on() {
654     log_console_on();
655 }
656
657 extern void log_console_off(rust_env *env);
658
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);
663 }
664
665 extern "C" CDECL lock_and_signal *
666 rust_dbg_lock_create() {
667     return new lock_and_signal();
668 }
669
670 extern "C" CDECL void
671 rust_dbg_lock_destroy(lock_and_signal *lock) {
672     assert(lock);
673     delete lock;
674 }
675
676 extern "C" CDECL void
677 rust_dbg_lock_lock(lock_and_signal *lock) {
678     assert(lock);
679     lock->lock();
680 }
681
682 extern "C" CDECL void
683 rust_dbg_lock_unlock(lock_and_signal *lock) {
684     assert(lock);
685     lock->unlock();
686 }
687
688 extern "C" CDECL void
689 rust_dbg_lock_wait(lock_and_signal *lock) {
690     assert(lock);
691     lock->wait();
692 }
693
694 extern "C" CDECL void
695 rust_dbg_lock_signal(lock_and_signal *lock) {
696     assert(lock);
697     lock->signal();
698 }
699
700 typedef void *(*dbg_callback)(void*);
701
702 extern "C" CDECL void *
703 rust_dbg_call(dbg_callback cb, void *data) {
704     return cb(data);
705 }
706
707 extern "C" CDECL void rust_dbg_do_nothing() { }
708
709 extern "C" CDECL void
710 rust_dbg_breakpoint() {
711     BREAKPOINT_AWESOME;
712 }
713
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();
718 }
719
720 extern "C" void
721 rust_task_inhibit_kill(rust_task *task) {
722     task->inhibit_kill();
723 }
724
725 extern "C" void
726 rust_task_allow_kill(rust_task *task) {
727     task->allow_kill();
728 }
729
730 extern "C" void
731 rust_task_inhibit_yield(rust_task *task) {
732     task->inhibit_yield();
733 }
734
735 extern "C" void
736 rust_task_allow_yield(rust_task *task) {
737     task->allow_yield();
738 }
739
740 extern "C" void
741 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
742     task->kill();
743 }
744
745 extern "C" void
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;
752 }
753
754 extern "C" CDECL
755 bool rust_task_is_unwinding(rust_task *rt) {
756     return rt->unwinding;
757 }
758
759 extern "C" lock_and_signal*
760 rust_create_little_lock() {
761     return new lock_and_signal();
762 }
763
764 extern "C" void
765 rust_destroy_little_lock(lock_and_signal *lock) {
766     delete lock;
767 }
768
769 extern "C" void
770 rust_lock_little_lock(lock_and_signal *lock) {
771     lock->lock();
772 }
773
774 extern "C" void
775 rust_unlock_little_lock(lock_and_signal *lock) {
776     lock->unlock();
777 }
778
779 // set/get/atexit task_local_data can run on the rust stack for speed.
780 extern "C" void *
781 rust_get_task_local_data(rust_task *task) {
782     return task->task_local_data;
783 }
784 extern "C" void
785 rust_set_task_local_data(rust_task *task, void *data) {
786     task->task_local_data = data;
787 }
788 extern "C" void
789 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
790     task->task_local_data_cleanup = cleanup_fn;
791 }
792
793 extern "C" void
794 task_clear_event_reject(rust_task *task) {
795     task->clear_event_reject();
796 }
797
798 // Waits on an event, returning the pointer to the event that unblocked this
799 // task.
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.
804
805     return task->wait_event(result);
806 }
807
808 extern "C" void
809 task_signal_event(rust_task *target, void *event) {
810     target->signal_event(event);
811 }
812
813 // Can safely run on the rust stack.
814 extern "C" void
815 rust_task_ref(rust_task *task) {
816     task->ref();
817 }
818
819 // Don't run on the rust stack!
820 extern "C" void
821 rust_task_deref(rust_task *task) {
822     task->deref();
823 }
824
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];
830     if (glue_fn)
831         glue_fn(0, 0, 0, root);
832 }
833
834 // Don't run on the Rust stack!
835 extern "C" void
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);
839 }
840
841 extern "C" CDECL void      record_sp_limit(void *limit);
842
843 class raw_thread: public rust_thread {
844 public:
845     fn_env_pair *fn;
846
847     raw_thread(fn_env_pair *fn) : fn(fn) { }
848
849     virtual void run() {
850         record_sp_limit(0);
851         fn->f(NULL, fn->env, NULL);
852     }
853 };
854
855 extern "C" raw_thread*
856 rust_raw_thread_start(fn_env_pair *fn) {
857     assert(fn);
858     raw_thread *thread = new raw_thread(fn);
859     thread->start();
860     return thread;
861 }
862
863 extern "C" void
864 rust_raw_thread_join_delete(raw_thread *thread) {
865     assert(thread);
866     thread->join();
867     delete thread;
868 }
869
870 extern "C" void
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);
874 }
875
876 extern "C" void *
877 rust_get_global_data_ptr() {
878     rust_task *task = rust_get_current_task();
879     return &task->kernel->global_data;
880 }
881
882 extern "C" void
883 rust_inc_kernel_live_count() {
884     rust_task *task = rust_get_current_task();
885     task->kernel->inc_live_count();
886 }
887
888 extern "C" void
889 rust_dec_kernel_live_count() {
890     rust_task *task = rust_get_current_task();
891     task->kernel->dec_live_count();
892 }
893
894 //
895 // Local Variables:
896 // mode: C++
897 // fill-column: 78;
898 // indent-tabs-mode: nil
899 // c-basic-offset: 4
900 // buffer-file-coding-system: utf-8-unix
901 // End:
902 //