]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.cpp
b16006e1f91a163d4c11fe9e822cb5d9f5a84064
[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 #include "rust_port.h"
21
22 #include <time.h>
23
24 #ifdef __APPLE__
25 #include <crt_externs.h>
26 #endif
27
28 #if !defined(__WIN32__)
29 #include <sys/time.h>
30 #endif
31
32 #ifdef __FreeBSD__
33 extern char **environ;
34 #endif
35
36 extern "C" CDECL rust_str*
37 last_os_error() {
38     rust_task *task = rust_get_current_task();
39
40     LOG(task, task, "last_os_error()");
41
42 #if defined(__WIN32__)
43     LPTSTR buf;
44     DWORD err = GetLastError();
45     DWORD res = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
46                               FORMAT_MESSAGE_FROM_SYSTEM |
47                               FORMAT_MESSAGE_IGNORE_INSERTS,
48                               NULL, err,
49                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
50                               (LPTSTR) &buf, 0, NULL);
51     if (!res) {
52         task->fail();
53         return NULL;
54     }
55 #elif defined(_GNU_SOURCE)
56     char cbuf[BUF_BYTES];
57     char *buf = strerror_r(errno, cbuf, sizeof(cbuf));
58     if (!buf) {
59         task->fail();
60         return NULL;
61     }
62 #else
63     char buf[BUF_BYTES];
64     int err = strerror_r(errno, buf, sizeof(buf));
65     if (err) {
66         task->fail();
67         return NULL;
68     }
69 #endif
70
71     rust_str * st = make_str(task->kernel, buf, strlen(buf),
72                              "last_os_error");
73 #ifdef __WIN32__
74     LocalFree((HLOCAL)buf);
75 #endif
76     return st;
77 }
78
79 extern "C" CDECL rust_str *
80 rust_getcwd() {
81     rust_task *task = rust_get_current_task();
82     LOG(task, task, "rust_getcwd()");
83
84     char cbuf[BUF_BYTES];
85
86 #if defined(__WIN32__)
87     if (!_getcwd(cbuf, sizeof(cbuf))) {
88 #else
89         if (!getcwd(cbuf, sizeof(cbuf))) {
90 #endif
91         task->fail();
92         return NULL;
93     }
94
95     return make_str(task->kernel, cbuf, strlen(cbuf), "rust_str(getcwd)");
96 }
97
98 #if defined(__WIN32__)
99 extern "C" CDECL rust_vec_box *
100 rust_env_pairs() {
101     rust_task *task = rust_get_current_task();
102     size_t envc = 0;
103     LPTCH ch = GetEnvironmentStringsA();
104     LPTCH c;
105     for (c = ch; *c; c += strlen(c) + 1) {
106         ++envc;
107     }
108     c = ch;
109     rust_vec_box *v = (rust_vec_box *)
110         task->kernel->malloc(vec_size<rust_vec_box*>(envc),
111                        "str vec interior");
112     v->body.fill = v->body.alloc = sizeof(rust_vec*) * envc;
113     for (size_t i = 0; i < envc; ++i) {
114         size_t n = strlen(c);
115         rust_str *str = make_str(task->kernel, c, n, "str");
116         ((rust_str**)&v->body.data)[i] = str;
117         c += n + 1;
118     }
119     if (ch) {
120         FreeEnvironmentStrings(ch);
121     }
122     return v;
123 }
124 #else
125 extern "C" CDECL rust_vec_box *
126 rust_env_pairs() {
127     rust_task *task = rust_get_current_task();
128 #ifdef __APPLE__
129     char **environ = *_NSGetEnviron();
130 #endif
131     char **e = environ;
132     size_t envc = 0;
133     while (*e) {
134         ++envc; ++e;
135     }
136     return make_str_vec(task->kernel, envc, environ);
137 }
138 #endif
139
140 extern "C" CDECL void
141 vec_reserve_shared_actual(type_desc* ty, rust_vec_box** vp,
142                           size_t n_elts) {
143     rust_task *task = rust_get_current_task();
144     reserve_vec_exact_shared(task, vp, n_elts * ty->size);
145 }
146
147 // This is completely misnamed.
148 extern "C" CDECL void
149 vec_reserve_shared(type_desc* ty, rust_vec_box** vp,
150                    size_t n_elts) {
151     rust_task *task = rust_get_current_task();
152     reserve_vec_exact(task, vp, n_elts * ty->size);
153 }
154
155 extern "C" CDECL rust_vec*
156 rand_seed() {
157     size_t size = sizeof(ub4) * RANDSIZ;
158     rust_task *task = rust_get_current_task();
159     rust_vec *v = (rust_vec *) task->kernel->malloc(vec_size<uint8_t>(size),
160                                             "rand_seed");
161     v->fill = v->alloc = size;
162     isaac_seed(task->kernel, (uint8_t*) &v->data, size);
163     return v;
164 }
165
166 extern "C" CDECL void *
167 rand_new() {
168     rust_task *task = rust_get_current_task();
169     rust_sched_loop *thread = task->sched_loop;
170     randctx *rctx = (randctx *) task->malloc(sizeof(randctx), "rand_new");
171     if (!rctx) {
172         task->fail();
173         return NULL;
174     }
175     isaac_init(thread->kernel, rctx, NULL);
176     return rctx;
177 }
178
179 extern "C" CDECL void *
180 rand_new_seeded(rust_vec_box* seed) {
181     rust_task *task = rust_get_current_task();
182     rust_sched_loop *thread = task->sched_loop;
183     randctx *rctx = (randctx *) task->malloc(sizeof(randctx),
184                                              "rand_new_seeded");
185     if (!rctx) {
186         task->fail();
187         return NULL;
188     }
189     isaac_init(thread->kernel, rctx, seed);
190     return rctx;
191 }
192
193 extern "C" CDECL void *
194 rand_new_seeded2(rust_vec_box** seed) {
195     return rand_new_seeded(*seed);
196 }
197
198 extern "C" CDECL size_t
199 rand_next(randctx *rctx) {
200     return isaac_rand(rctx);
201 }
202
203 extern "C" CDECL void
204 rand_free(randctx *rctx) {
205     rust_task *task = rust_get_current_task();
206     task->free(rctx);
207 }
208
209
210 /* Debug helpers strictly to verify ABI conformance.
211  *
212  * FIXME (#2665): move these into a testcase when the testsuite
213  * understands how to have explicit C files included.
214  */
215
216 struct quad {
217     uint64_t a;
218     uint64_t b;
219     uint64_t c;
220     uint64_t d;
221 };
222
223 struct floats {
224     double a;
225     uint8_t b;
226     double c;
227 };
228
229 extern "C" quad
230 debug_abi_1(quad q) {
231     quad qq = { q.c + 1,
232                 q.d - 1,
233                 q.a + 1,
234                 q.b - 1 };
235     return qq;
236 }
237
238 extern "C" floats
239 debug_abi_2(floats f) {
240     floats ff = { f.c + 1.0,
241                   0xff,
242                   f.a - 1.0 };
243     return ff;
244 }
245
246 /* Debug builtins for std::dbg. */
247
248 static void
249 debug_tydesc_helper(type_desc *t)
250 {
251     rust_task *task = rust_get_current_task();
252     LOG(task, stdlib, "  size %" PRIdPTR ", align %" PRIdPTR,
253         t->size, t->align);
254 }
255
256 extern "C" CDECL void
257 debug_tydesc(type_desc *t) {
258     rust_task *task = rust_get_current_task();
259     LOG(task, stdlib, "debug_tydesc");
260     debug_tydesc_helper(t);
261 }
262
263 extern "C" CDECL void
264 debug_opaque(type_desc *t, uint8_t *front) {
265     rust_task *task = rust_get_current_task();
266     LOG(task, stdlib, "debug_opaque");
267     debug_tydesc_helper(t);
268     // FIXME (#2667) may want to actually account for alignment.
269     // `front` may not indeed be the front byte of the passed-in
270     // argument.
271     for (uintptr_t i = 0; i < t->size; ++front, ++i) {
272         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
273     }
274 }
275
276 // FIXME (#2667) this no longer reflects the actual structure of boxes!
277 struct rust_box {
278     RUST_REFCOUNTED(rust_box)
279
280     // FIXME (#2667) `data` could be aligned differently from the actual
281     // box body data
282     uint8_t data[];
283 };
284
285 extern "C" CDECL void
286 debug_box(type_desc *t, rust_box *box) {
287     rust_task *task = rust_get_current_task();
288     LOG(task, stdlib, "debug_box(0x%" PRIxPTR ")", box);
289     debug_tydesc_helper(t);
290     LOG(task, stdlib, "  refcount %" PRIdPTR,
291         box->ref_count - 1);  // -1 because we ref'ed for this call
292     for (uintptr_t i = 0; i < t->size; ++i) {
293         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, box->data[i]);
294     }
295 }
296
297 struct rust_tag {
298     uintptr_t discriminant;
299     uint8_t variant[];
300 };
301
302 extern "C" CDECL void
303 debug_tag(type_desc *t, rust_tag *tag) {
304     rust_task *task = rust_get_current_task();
305
306     LOG(task, stdlib, "debug_tag");
307     debug_tydesc_helper(t);
308     LOG(task, stdlib, "  discriminant %" PRIdPTR, tag->discriminant);
309
310     for (uintptr_t i = 0; i < t->size - sizeof(tag->discriminant); ++i)
311         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i,
312             tag->variant[i]);
313 }
314
315 struct rust_fn {
316     uintptr_t *thunk;
317     rust_box *closure;
318 };
319
320 extern "C" CDECL void
321 debug_fn(type_desc *t, rust_fn *fn) {
322     rust_task *task = rust_get_current_task();
323     LOG(task, stdlib, "debug_fn");
324     debug_tydesc_helper(t);
325     LOG(task, stdlib, "  thunk at 0x%" PRIxPTR, fn->thunk);
326     LOG(task, stdlib, "  closure at 0x%" PRIxPTR, fn->closure);
327     if (fn->closure) {
328         LOG(task, stdlib, "    refcount %" PRIdPTR, fn->closure->ref_count);
329     }
330 }
331
332 extern "C" CDECL void *
333 debug_ptrcast(type_desc *from_ty,
334               type_desc *to_ty,
335               void *ptr) {
336     rust_task *task = rust_get_current_task();
337     LOG(task, stdlib, "debug_ptrcast from");
338     debug_tydesc_helper(from_ty);
339     LOG(task, stdlib, "to");
340     debug_tydesc_helper(to_ty);
341     return ptr;
342 }
343
344 extern "C" CDECL void *
345 debug_get_stk_seg() {
346     rust_task *task = rust_get_current_task();
347     return task->stk;
348 }
349
350 extern "C" CDECL rust_vec_box*
351 rust_list_files(rust_str *path) {
352     rust_task *task = rust_get_current_task();
353     array_list<rust_str*> strings;
354 #if defined(__WIN32__)
355     WIN32_FIND_DATA FindFileData;
356     HANDLE hFind = FindFirstFile((char*)path->body.data, &FindFileData);
357     if (hFind != INVALID_HANDLE_VALUE) {
358         do {
359             rust_str *str = make_str(task->kernel, FindFileData.cFileName,
360                                      strlen(FindFileData.cFileName),
361                                      "list_files_str");
362             strings.push(str);
363         } while (FindNextFile(hFind, &FindFileData));
364         FindClose(hFind);
365     }
366 #else
367     DIR *dirp = opendir((char*)path->body.data);
368   if (dirp) {
369       struct dirent *dp;
370       while ((dp = readdir(dirp))) {
371           rust_vec_box *str = make_str(task->kernel, dp->d_name,
372                                        strlen(dp->d_name),
373                                        "list_files_str");
374           strings.push(str);
375       }
376       closedir(dirp);
377   }
378 #endif
379
380   rust_vec_box *vec = (rust_vec_box *)
381       task->kernel->malloc(vec_size<rust_vec_box*>(strings.size()),
382                            "list_files_vec");
383   size_t alloc_sz = sizeof(rust_vec*) * strings.size();
384   vec->body.fill = vec->body.alloc = alloc_sz;
385   memcpy(&vec->body.data[0], strings.data(), alloc_sz);
386   return vec;
387 }
388
389 extern "C" CDECL rust_vec_box*
390 rust_list_files2(rust_str **path) {
391     return rust_list_files(*path);
392 }
393
394 extern "C" CDECL int
395 rust_path_is_dir(char *path) {
396     struct stat buf;
397     if (stat(path, &buf)) {
398         return 0;
399     }
400     return S_ISDIR(buf.st_mode);
401 }
402
403 extern "C" CDECL int
404 rust_path_exists(char *path) {
405     struct stat buf;
406     if (stat(path, &buf)) {
407         return 0;
408     }
409     return 1;
410 }
411
412 extern "C" CDECL FILE* rust_get_stdin() {return stdin;}
413 extern "C" CDECL FILE* rust_get_stdout() {return stdout;}
414 extern "C" CDECL FILE* rust_get_stderr() {return stderr;}
415
416 extern "C" CDECL int
417 rust_ptr_eq(type_desc *t, rust_box *a, rust_box *b) {
418     return a == b;
419 }
420
421 #if defined(__WIN32__)
422 extern "C" CDECL void
423 get_time(int64_t *sec, int32_t *nsec) {
424     FILETIME fileTime;
425     GetSystemTimeAsFileTime(&fileTime);
426
427     // A FILETIME contains a 64-bit value representing the number of
428     // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
429     // http://support.microsoft.com/kb/167296/en-us
430     ULARGE_INTEGER ul;
431     ul.LowPart = fileTime.dwLowDateTime;
432     ul.HighPart = fileTime.dwHighDateTime;
433     uint64_t ns_since_1601 = ul.QuadPart / 10;
434
435     const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000u;
436     uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
437     *sec = ns_since_1970 / 1000000;
438     *nsec = (ns_since_1970 % 1000000) * 1000;
439 }
440 #else
441 extern "C" CDECL void
442 get_time(int64_t *sec, int32_t *nsec) {
443 #ifdef __APPLE__
444     struct timeval tv;
445     gettimeofday(&tv, NULL);
446     *sec = tv.tv_sec;
447     *nsec = tv.tv_usec * 1000;
448 #else
449     timespec ts;
450     clock_gettime(CLOCK_REALTIME, &ts);
451     *sec = ts.tv_sec;
452     *nsec = ts.tv_nsec;
453 #endif
454 }
455 #endif
456
457 extern "C" CDECL void
458 precise_time_ns(uint64_t *ns) {
459     timer t;
460     *ns = t.time_ns();
461 }
462
463 struct rust_tm {
464     int32_t tm_sec;
465     int32_t tm_min;
466     int32_t tm_hour;
467     int32_t tm_mday;
468     int32_t tm_mon;
469     int32_t tm_year;
470     int32_t tm_wday;
471     int32_t tm_yday;
472     int32_t tm_isdst;
473     int32_t tm_gmtoff;
474     rust_str *tm_zone;
475     int32_t tm_nsec;
476 };
477
478 void rust_tm_to_tm(rust_tm* in_tm, tm* out_tm) {
479     memset(out_tm, 0, sizeof(tm));
480     out_tm->tm_sec = in_tm->tm_sec;
481     out_tm->tm_min = in_tm->tm_min;
482     out_tm->tm_hour = in_tm->tm_hour;
483     out_tm->tm_mday = in_tm->tm_mday;
484     out_tm->tm_mon = in_tm->tm_mon;
485     out_tm->tm_year = in_tm->tm_year;
486     out_tm->tm_wday = in_tm->tm_wday;
487     out_tm->tm_yday = in_tm->tm_yday;
488     out_tm->tm_isdst = in_tm->tm_isdst;
489 }
490
491 void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
492                    const char *zone, int32_t nsec) {
493     out_tm->tm_sec = in_tm->tm_sec;
494     out_tm->tm_min = in_tm->tm_min;
495     out_tm->tm_hour = in_tm->tm_hour;
496     out_tm->tm_mday = in_tm->tm_mday;
497     out_tm->tm_mon = in_tm->tm_mon;
498     out_tm->tm_year = in_tm->tm_year;
499     out_tm->tm_wday = in_tm->tm_wday;
500     out_tm->tm_yday = in_tm->tm_yday;
501     out_tm->tm_isdst = in_tm->tm_isdst;
502     out_tm->tm_gmtoff = gmtoff;
503     out_tm->tm_nsec = nsec;
504
505     if (zone != NULL) {
506         rust_task *task = rust_get_current_task();
507         size_t size = strlen(zone);
508         reserve_vec_exact(task, &out_tm->tm_zone, size + 1);
509         memcpy(out_tm->tm_zone->body.data, zone, size);
510         out_tm->tm_zone->body.fill = size + 1;
511         out_tm->tm_zone->body.data[size] = '\0';
512     }
513 }
514
515 #if defined(__WIN32__)
516 #define TZSET() _tzset()
517 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
518 #define GMTIME(clock, result) gmtime_s((result), (clock))
519 #define LOCALTIME(clock, result) localtime_s((result), (clock))
520 #define TIMEGM(result) _mkgmtime64(result)
521 #else
522 struct tm* GMTIME(const time_t *clock, tm *result) {
523     struct tm* t = gmtime(clock);
524     if (t == NULL || result == NULL) { return NULL; }
525     *result = *t;
526     return result;
527 }
528 struct tm* LOCALTIME(const time_t *clock, tm *result) {
529     struct tm* t = localtime(clock);
530     if (t == NULL || result == NULL) { return NULL; }
531     *result = *t;
532     return result;
533 }
534 #define TIMEGM(result) mktime((result)) - _timezone
535 #endif
536 #else
537 #define TZSET() tzset()
538 #define GMTIME(clock, result) gmtime_r((clock), (result))
539 #define LOCALTIME(clock, result) localtime_r((clock), (result))
540 #define TIMEGM(result) timegm(result)
541 #endif
542
543 extern "C" CDECL void
544 rust_tzset() {
545     TZSET();
546 }
547
548 extern "C" CDECL void
549 rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
550     tm tm;
551     time_t s = *sec;
552     GMTIME(&s, &tm);
553
554     tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec);
555 }
556
557 extern "C" CDECL void
558 rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
559     tm tm;
560     time_t s = *sec;
561     LOCALTIME(&s, &tm);
562
563 #if defined(__WIN32__)
564     int32_t gmtoff = -timezone;
565     char zone[64];
566     strftime(zone, sizeof(zone), "%Z", &tm);
567 #else
568     int32_t gmtoff = tm.tm_gmtoff;
569     const char *zone = tm.tm_zone;
570 #endif
571
572     tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec);
573 }
574
575 extern "C" CDECL void
576 rust_timegm(rust_tm* timeptr, int64_t *out) {
577     tm t;
578     rust_tm_to_tm(timeptr, &t);
579     *out = TIMEGM(&t);
580 }
581
582 extern "C" CDECL void
583 rust_mktime(rust_tm* timeptr, int64_t *out) {
584     tm t;
585     rust_tm_to_tm(timeptr, &t);
586     *out = mktime(&t);
587 }
588
589 extern "C" CDECL rust_sched_id
590 rust_get_sched_id() {
591     rust_task *task = rust_get_current_task();
592     return task->sched->get_id();
593 }
594
595 extern "C" CDECL uintptr_t
596 rust_num_threads() {
597     rust_task *task = rust_get_current_task();
598     return task->kernel->env->num_sched_threads;
599 }
600
601 extern "C" CDECL int
602 rust_get_argc() {
603     rust_task *task = rust_get_current_task();
604     return task->kernel->env->argc;
605 }
606
607 extern "C" CDECL char**
608 rust_get_argv() {
609     rust_task *task = rust_get_current_task();
610     return task->kernel->env->argv;
611 }
612
613 extern "C" CDECL rust_sched_id
614 rust_new_sched(uintptr_t threads) {
615     rust_task *task = rust_get_current_task();
616     assert(threads > 0 && "Can't create a scheduler with no threads, silly!");
617     return task->kernel->create_scheduler(threads);
618 }
619
620 extern "C" CDECL rust_task_id
621 get_task_id() {
622     rust_task *task = rust_get_current_task();
623     return task->id;
624 }
625
626 static rust_task*
627 new_task_common(rust_scheduler *sched, rust_task *parent) {
628     return sched->create_task(parent, NULL);
629 }
630
631 extern "C" CDECL rust_task*
632 new_task() {
633     rust_task *task = rust_get_current_task();
634     return new_task_common(task->sched, task);
635 }
636
637 extern "C" CDECL rust_task*
638 rust_new_task_in_sched(rust_sched_id id) {
639     rust_task *task = rust_get_current_task();
640     rust_scheduler *sched = task->kernel->get_scheduler_by_id(id);
641     if (sched == NULL)
642         return NULL;
643     return new_task_common(sched, task);
644 }
645
646 extern "C" rust_task *
647 rust_get_task() {
648     return rust_get_current_task();
649 }
650
651 extern "C" CDECL stk_seg *
652 rust_get_stack_segment() {
653     return rust_get_current_task()->stk;
654 }
655
656 extern "C" CDECL void
657 start_task(rust_task *target, fn_env_pair *f) {
658     target->start(f->f, f->env, NULL);
659 }
660
661 extern "C" CDECL size_t
662 rust_sched_current_nonlazy_threads() {
663     rust_task *task = rust_get_current_task();
664     return task->sched->number_of_threads();
665 }
666
667 extern "C" CDECL size_t
668 rust_sched_threads() {
669     rust_task *task = rust_get_current_task();
670     return task->sched->max_number_of_threads();
671 }
672
673 extern "C" CDECL rust_port*
674 rust_port_take(rust_port_id id) {
675     rust_task *task = rust_get_current_task();
676     return task->kernel->get_port_by_id(id);
677 }
678
679 extern "C" CDECL void
680 rust_port_drop(rust_port *p) {
681     assert(p != NULL);
682     p->deref();
683 }
684
685 extern "C" CDECL rust_task_id
686 rust_port_task(rust_port *p) {
687     assert(p != NULL);
688     return p->task->id;
689 }
690
691 extern "C" CDECL rust_port*
692 new_port(size_t unit_sz) {
693     rust_task *task = rust_get_current_task();
694     LOG(task, comm, "new_port(task=0x%" PRIxPTR " (%s), unit_sz=%d)",
695         (uintptr_t) task, task->name, unit_sz);
696     // port starts with refcount == 1
697     return new (task->kernel, "rust_port") rust_port(task, unit_sz);
698 }
699
700 extern "C" CDECL void
701 rust_port_begin_detach(rust_port *port, uintptr_t *yield) {
702     rust_task *task = rust_get_current_task();
703     LOG(task, comm, "rust_port_detach(0x%" PRIxPTR ")", (uintptr_t) port);
704     port->begin_detach(yield);
705 }
706
707 extern "C" CDECL void
708 rust_port_end_detach(rust_port *port) {
709     port->end_detach();
710 }
711
712 extern "C" CDECL void
713 del_port(rust_port *port) {
714     rust_task *task = rust_get_current_task();
715     LOG(task, comm, "del_port(0x%" PRIxPTR ")", (uintptr_t) port);
716     delete port;
717 }
718
719 extern "C" CDECL size_t
720 rust_port_size(rust_port *port) {
721     return port->size();
722 }
723
724 extern "C" CDECL rust_port_id
725 get_port_id(rust_port *port) {
726     return port->id;
727 }
728
729 extern "C" CDECL uintptr_t
730 rust_port_id_send(rust_port_id target_port_id, void *sptr) {
731     rust_task *task = rust_get_current_task();
732     return (uintptr_t)task->kernel->send_to_port(target_port_id, sptr);
733 }
734
735 // This is called by an intrinsic on the Rust stack and must run
736 // entirely in the red zone. Do not call on the C stack.
737 extern "C" CDECL MUST_CHECK bool
738 rust_task_yield(rust_task *task, bool *killed) {
739     return task->yield();
740 }
741
742 extern "C" CDECL void
743 port_recv(uintptr_t *dptr, rust_port *port, uintptr_t *yield) {
744     port->receive(dptr, yield);
745 }
746
747 extern "C" CDECL void
748 rust_port_select(rust_port **dptr, rust_port **ports,
749                  size_t n_ports, uintptr_t *yield) {
750     rust_task *task = rust_get_current_task();
751     rust_port_selector *selector = task->get_port_selector();
752     selector->select(task, dptr, ports, n_ports, yield);
753 }
754
755 extern "C" CDECL void
756 rust_set_exit_status(intptr_t code) {
757     rust_task *task = rust_get_current_task();
758     task->kernel->set_exit_status((int)code);
759 }
760
761 extern void log_console_on();
762
763 extern "C" CDECL void
764 rust_log_console_on() {
765     log_console_on();
766 }
767
768 extern void log_console_off(rust_env *env);
769
770 extern "C" CDECL void
771 rust_log_console_off() {
772     rust_task *task = rust_get_current_task();
773     log_console_off(task->kernel->env);
774 }
775
776 extern "C" CDECL lock_and_signal *
777 rust_dbg_lock_create() {
778     return new lock_and_signal();
779 }
780
781 extern "C" CDECL void
782 rust_dbg_lock_destroy(lock_and_signal *lock) {
783     assert(lock);
784     delete lock;
785 }
786
787 extern "C" CDECL void
788 rust_dbg_lock_lock(lock_and_signal *lock) {
789     assert(lock);
790     lock->lock();
791 }
792
793 extern "C" CDECL void
794 rust_dbg_lock_unlock(lock_and_signal *lock) {
795     assert(lock);
796     lock->unlock();
797 }
798
799 extern "C" CDECL void
800 rust_dbg_lock_wait(lock_and_signal *lock) {
801     assert(lock);
802     lock->wait();
803 }
804
805 extern "C" CDECL void
806 rust_dbg_lock_signal(lock_and_signal *lock) {
807     assert(lock);
808     lock->signal();
809 }
810
811 typedef void *(*dbg_callback)(void*);
812
813 extern "C" CDECL void *
814 rust_dbg_call(dbg_callback cb, void *data) {
815     return cb(data);
816 }
817
818 extern "C" CDECL void rust_dbg_do_nothing() { }
819
820 extern "C" CDECL void
821 rust_dbg_breakpoint() {
822     BREAKPOINT_AWESOME;
823 }
824
825 extern "C" CDECL rust_sched_id
826 rust_osmain_sched_id() {
827     rust_task *task = rust_get_current_task();
828     return task->kernel->osmain_sched_id();
829 }
830
831 extern "C" CDECL bool
832 rust_compare_and_swap_ptr(intptr_t *address,
833                           intptr_t oldval, intptr_t newval) {
834     return sync::compare_and_swap(address, oldval, newval);
835 }
836
837 extern "C" CDECL void
838 rust_task_weaken(rust_port_id chan) {
839     rust_task *task = rust_get_current_task();
840     task->kernel->weaken_task(chan);
841 }
842
843 extern "C" CDECL void
844 rust_task_unweaken(rust_port_id chan) {
845     rust_task *task = rust_get_current_task();
846     task->kernel->unweaken_task(chan);
847 }
848
849 extern "C" CDECL uintptr_t*
850 rust_global_env_chan_ptr() {
851     rust_task *task = rust_get_current_task();
852     return task->kernel->get_global_env_chan();
853 }
854
855 extern "C" void
856 rust_task_inhibit_kill(rust_task *task) {
857     task->inhibit_kill();
858 }
859
860 extern "C" void
861 rust_task_allow_kill(rust_task *task) {
862     task->allow_kill();
863 }
864
865 extern "C" void
866 rust_task_inhibit_yield(rust_task *task) {
867     task->inhibit_yield();
868 }
869
870 extern "C" void
871 rust_task_allow_yield(rust_task *task) {
872     task->allow_yield();
873 }
874
875 extern "C" void
876 rust_task_kill_other(rust_task *task) { /* Used for linked failure */
877     task->kill();
878 }
879
880 extern "C" void
881 rust_task_kill_all(rust_task *task) { /* Used for linked failure */
882     task->fail_sched_loop();
883     // This must not happen twice.
884     static bool main_taskgroup_failed = false;
885     assert(!main_taskgroup_failed);
886     main_taskgroup_failed = true;
887 }
888
889 extern "C" CDECL
890 bool rust_task_is_unwinding(rust_task *rt) {
891     return rt->unwinding;
892 }
893
894 extern "C" lock_and_signal*
895 rust_create_little_lock() {
896     return new lock_and_signal();
897 }
898
899 extern "C" void
900 rust_destroy_little_lock(lock_and_signal *lock) {
901     delete lock;
902 }
903
904 extern "C" void
905 rust_lock_little_lock(lock_and_signal *lock) {
906     lock->lock();
907 }
908
909 extern "C" void
910 rust_unlock_little_lock(lock_and_signal *lock) {
911     lock->unlock();
912 }
913
914 // set/get/atexit task_local_data can run on the rust stack for speed.
915 extern "C" void *
916 rust_get_task_local_data(rust_task *task) {
917     return task->task_local_data;
918 }
919 extern "C" void
920 rust_set_task_local_data(rust_task *task, void *data) {
921     task->task_local_data = data;
922 }
923 extern "C" void
924 rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) {
925     task->task_local_data_cleanup = cleanup_fn;
926 }
927
928 extern "C" void
929 task_clear_event_reject(rust_task *task) {
930     task->clear_event_reject();
931 }
932
933 // Waits on an event, returning the pointer to the event that unblocked this
934 // task.
935 extern "C" MUST_CHECK bool
936 task_wait_event(rust_task *task, void **result) {
937     // Maybe (if not too slow) assert that the passed in task is the currently
938     // running task. We wouldn't want to wait some other task.
939
940     return task->wait_event(result);
941 }
942
943 extern "C" void
944 task_signal_event(rust_task *target, void *event) {
945     target->signal_event(event);
946 }
947
948 // Can safely run on the rust stack.
949 extern "C" void
950 rust_task_ref(rust_task *task) {
951     task->ref();
952 }
953
954 // Don't run on the rust stack!
955 extern "C" void
956 rust_task_deref(rust_task *task) {
957     task->deref();
958 }
959
960 // Must call on rust stack.
961 extern "C" CDECL void
962 rust_call_tydesc_glue(void *root, size_t *tydesc, size_t glue_index) {
963     void (*glue_fn)(void *, void *, void *, void *) =
964         (void (*)(void *, void *, void *, void *))tydesc[glue_index];
965     if (glue_fn)
966         glue_fn(0, 0, 0, root);
967 }
968
969 // Don't run on the Rust stack!
970 extern "C" void
971 rust_log_str(uint32_t level, const char *str, size_t size) {
972     rust_task *task = rust_get_current_task();
973     task->sched_loop->get_log().log(task, level, "%.*s", (int)size, str);
974 }
975
976 extern "C" CDECL void      record_sp_limit(void *limit);
977
978 class raw_thread: public rust_thread {
979 public:
980     fn_env_pair *fn;
981
982     raw_thread(fn_env_pair *fn) : fn(fn) { }
983
984     virtual void run() {
985         record_sp_limit(0);
986         fn->f(NULL, fn->env, NULL);
987     }
988 };
989
990 extern "C" raw_thread*
991 rust_raw_thread_start(fn_env_pair *fn) {
992     assert(fn);
993     raw_thread *thread = new raw_thread(fn);
994     thread->start();
995     return thread;
996 }
997
998 extern "C" void
999 rust_raw_thread_join_delete(raw_thread *thread) {
1000     assert(thread);
1001     thread->join();
1002     delete thread;
1003 }
1004
1005
1006 //
1007 // Local Variables:
1008 // mode: C++
1009 // fill-column: 78;
1010 // indent-tabs-mode: nil
1011 // c-basic-offset: 4
1012 // buffer-file-coding-system: utf-8-unix
1013 // End:
1014 //