PageRenderTime 85ms CodeModel.GetById 14ms app.highlight 61ms RepoModel.GetById 0ms app.codeStats 1ms

/src/rt/rust_builtin.cpp

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