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