2010-06-23 21:03:09 -07:00
|
|
|
#include "rust_internal.h"
|
2011-06-15 22:04:31 -07:00
|
|
|
#include "rust_upcall.h"
|
2010-06-23 21:03:09 -07:00
|
|
|
|
|
|
|
// Upcalls.
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL char const *
|
|
|
|
str_buf(rust_task *task, rust_str *s);
|
2010-06-23 21:03:09 -07:00
|
|
|
|
2011-07-06 15:06:30 -07:00
|
|
|
#ifdef __i386__
|
|
|
|
void
|
|
|
|
check_stack(rust_task *task) {
|
|
|
|
void *esp;
|
|
|
|
asm volatile("movl %%esp,%0" : "=r" (esp));
|
|
|
|
if (esp < task->stk->data)
|
|
|
|
task->kernel->fatal("Out of stack space, sorry");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#warning "Stack checks are not supported on this architecture"
|
|
|
|
void
|
|
|
|
check_stack(rust_task *task) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" void
|
|
|
|
upcall_grow_task(rust_task *task, size_t n_frame_bytes) {
|
2011-06-28 12:15:41 -07:00
|
|
|
I(task->sched, false);
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
task->grow(n_frame_bytes);
|
|
|
|
}
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL
|
2011-04-19 12:21:57 +02:00
|
|
|
void upcall_log_int(rust_task *task, uint32_t level, int32_t i) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-06-28 12:15:41 -07:00
|
|
|
if (task->sched->log_lvl >= level)
|
|
|
|
task->sched->log(task, level, "rust: %" PRId32 " (0x%" PRIx32 ")",
|
2011-04-19 12:21:57 +02:00
|
|
|
i, i);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-22 17:25:40 -07:00
|
|
|
extern "C" CDECL
|
2011-04-19 12:21:57 +02:00
|
|
|
void upcall_log_float(rust_task *task, uint32_t level, float f) {
|
2011-03-21 17:12:05 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-06-28 12:15:41 -07:00
|
|
|
if (task->sched->log_lvl >= level)
|
|
|
|
task->sched->log(task, level, "rust: %12.12f", f);
|
2011-04-19 12:21:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL
|
|
|
|
void upcall_log_double(rust_task *task, uint32_t level, double *f) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-06-28 12:15:41 -07:00
|
|
|
if (task->sched->log_lvl >= level)
|
|
|
|
task->sched->log(task, level, "rust: %12.12f", *f);
|
2011-03-21 17:12:05 -07:00
|
|
|
}
|
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_log_str(rust_task *task, uint32_t level, rust_str *str) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-06-28 12:15:41 -07:00
|
|
|
if (task->sched->log_lvl >= level) {
|
2011-04-19 12:21:57 +02:00
|
|
|
const char *c = str_buf(task, str);
|
2011-06-28 12:15:41 -07:00
|
|
|
task->sched->log(task, level, "rust: %s", c);
|
2011-04-19 12:21:57 +02:00
|
|
|
}
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-07-15 18:37:57 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_log_istr(rust_task *task, uint32_t level, rust_ivec *str) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
if (task->sched->log_lvl < level)
|
|
|
|
return;
|
|
|
|
const char *buf = (const char *)
|
|
|
|
(str->fill ? str->payload.data : str->payload.ptr->data);
|
|
|
|
task->sched->log(task, level, "rust: %s", buf);
|
|
|
|
}
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_trace_word(rust_task *task, uintptr_t i) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-06-28 12:15:41 -07:00
|
|
|
task->sched->log(task, 2, "trace: 0x%" PRIxPTR "", i, i, (char) i);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_trace_str(rust_task *task, char const *c) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-06-28 12:15:41 -07:00
|
|
|
task->sched->log(task, 2, "trace: %s", c);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-07-29 17:53:02 -07:00
|
|
|
extern "C" CDECL rust_port*
|
|
|
|
new_port(rust_task *task, size_t unit_sz);
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL rust_port*
|
2010-07-19 14:05:18 -07:00
|
|
|
upcall_new_port(rust_task *task, size_t unit_sz) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, comm, "upcall_new_port(task=0x%" PRIxPTR " (%s), unit_sz=%d)",
|
|
|
|
(uintptr_t) task, task->name, unit_sz);
|
2011-07-29 17:53:02 -07:00
|
|
|
return new_port(task, unit_sz);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-07-29 17:53:02 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
del_port(rust_task *task, rust_port *port);
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_del_port(rust_task *task, rust_port *port) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-29 17:53:02 -07:00
|
|
|
return del_port(task, port);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
2010-07-28 12:36:59 -07:00
|
|
|
* Creates a new channel pointing to a given port.
|
2010-07-19 14:05:18 -07:00
|
|
|
*/
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL rust_chan*
|
2011-07-29 17:53:02 -07:00
|
|
|
new_chan(rust_task *task, rust_port *port);
|
|
|
|
extern "C" CDECL rust_chan*
|
2010-07-19 14:05:18 -07:00
|
|
|
upcall_new_chan(rust_task *task, rust_port *port) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-29 17:53:02 -07:00
|
|
|
return new_chan(task, port);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-08-09 08:15:34 -07:00
|
|
|
/**
|
|
|
|
* Called whenever this channel needs to be flushed. This can happen due to a
|
|
|
|
* flush statement, or automatically whenever a channel's ref count is
|
|
|
|
* about to drop to zero.
|
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_flush_chan(rust_task *task, rust_chan *chan) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
|
|
|
* Called whenever the channel's ref count drops to zero.
|
2010-08-09 08:15:34 -07:00
|
|
|
*
|
|
|
|
* Cannot Yield: If the task were to unwind, the dropped ref would still
|
|
|
|
* appear to be live, causing modify-after-free errors.
|
2010-07-19 14:05:18 -07:00
|
|
|
*/
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL
|
2011-07-29 17:53:02 -07:00
|
|
|
void del_chan(rust_task *task, rust_chan *chan);
|
|
|
|
extern "C" CDECL
|
2010-08-31 14:36:51 -07:00
|
|
|
void upcall_del_chan(rust_task *task, rust_chan *chan) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-29 17:53:02 -07:00
|
|
|
del_chan(task, chan);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
|
|
|
* Clones a channel and stores it in the spawnee's domain. Each spawned task
|
2010-09-07 18:39:07 -07:00
|
|
|
* has its own copy of the channel.
|
2010-07-19 14:05:18 -07:00
|
|
|
*/
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL rust_chan *
|
2011-08-08 13:38:20 -07:00
|
|
|
upcall_clone_chan(rust_task *task, rust_task_id tid,
|
2010-07-19 14:05:18 -07:00
|
|
|
rust_chan *chan) {
|
2011-08-08 13:38:20 -07:00
|
|
|
// FIXME: This should be removed.
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *target = task->kernel->get_task_by_id(tid);
|
2011-06-29 20:54:03 -07:00
|
|
|
return chan->clone(target);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-07-18 12:02:26 -07:00
|
|
|
extern "C" CDECL rust_task *
|
|
|
|
upcall_chan_target_task(rust_task *task, rust_chan *chan) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-29 11:00:44 -07:00
|
|
|
return chan->port->task;
|
2011-07-18 12:02:26 -07:00
|
|
|
}
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_yield(rust_task *task) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, comm, "upcall yield()");
|
2010-06-23 21:03:09 -07:00
|
|
|
task->yield(1);
|
|
|
|
}
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_sleep(rust_task *task, size_t time_in_us) {
|
2010-08-11 21:23:34 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-13 12:25:36 -07:00
|
|
|
LOG(task, task, "elapsed %" PRIu64 " us",
|
|
|
|
task->yield_timer.elapsed_us());
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, task, "sleep %d us", time_in_us);
|
2011-07-13 13:43:35 -07:00
|
|
|
task->yield(time_in_us);
|
2010-08-11 21:23:34 -07:00
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
2010-07-28 16:46:13 -07:00
|
|
|
* Buffers a chunk of data in the specified channel.
|
2010-07-19 14:05:18 -07:00
|
|
|
*
|
2010-07-28 16:46:13 -07:00
|
|
|
* sptr: pointer to a chunk of data to buffer
|
2010-07-19 14:05:18 -07:00
|
|
|
*/
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL void
|
2010-07-19 14:05:18 -07:00
|
|
|
upcall_send(rust_task *task, rust_chan *chan, void *sptr) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2010-08-09 08:15:34 -07:00
|
|
|
chan->send(sptr);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, comm, "=== sent data ===>");
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
2010-07-19 14:05:18 -07:00
|
|
|
upcall_recv(rust_task *task, uintptr_t *dptr, rust_port *port) {
|
2011-07-29 11:00:44 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-08-01 14:57:17 -07:00
|
|
|
port_recv(task, dptr, port);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_fail(rust_task *task,
|
|
|
|
char const *expr,
|
|
|
|
char const *file,
|
|
|
|
size_t line) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG_ERR(task, upcall, "upcall fail '%s', %s:%" PRIdPTR, expr, file, line);
|
2011-07-13 13:43:35 -07:00
|
|
|
task->fail();
|
2011-07-14 18:49:18 -07:00
|
|
|
task->die();
|
|
|
|
task->notify_tasks_waiting_to_join();
|
|
|
|
task->yield(4);
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
|
|
|
* Called whenever a task's ref count drops to zero.
|
|
|
|
*/
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL void
|
2011-08-08 13:38:20 -07:00
|
|
|
upcall_kill(rust_task *task, rust_task_id tid) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *target = task->kernel->get_task_by_id(tid);
|
2011-07-27 14:51:25 -07:00
|
|
|
target->kill();
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
|
|
|
* Called by the exit glue when the task terminates.
|
|
|
|
*/
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL void
|
2010-07-19 14:05:18 -07:00
|
|
|
upcall_exit(rust_task *task) {
|
2011-07-06 12:48:43 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
task->die();
|
|
|
|
task->notify_tasks_waiting_to_join();
|
2010-06-23 21:03:09 -07:00
|
|
|
task->yield(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL uintptr_t
|
2010-08-31 14:36:51 -07:00
|
|
|
upcall_malloc(rust_task *task, size_t nbytes, type_desc *td) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2011-07-06 12:48:43 -07:00
|
|
|
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ")"
|
|
|
|
" with gc-chain head = 0x%" PRIxPTR,
|
|
|
|
nbytes, td, task->gc_alloc_chain);
|
|
|
|
|
2011-07-18 12:02:26 -07:00
|
|
|
// TODO: Maybe use dladdr here to find a more useful name for the
|
|
|
|
// type_desc.
|
|
|
|
|
|
|
|
void *p = task->malloc(nbytes, "tdesc", td);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2011-07-06 12:48:43 -07:00
|
|
|
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR
|
|
|
|
") = 0x%" PRIxPTR
|
|
|
|
" with gc-chain head = 0x%" PRIxPTR,
|
|
|
|
nbytes, td, (uintptr_t)p, task->gc_alloc_chain);
|
2010-06-23 21:03:09 -07:00
|
|
|
return (uintptr_t) p;
|
|
|
|
}
|
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
/**
|
|
|
|
* Called whenever an object's ref count drops to zero.
|
|
|
|
*/
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL void
|
2010-08-31 14:36:51 -07:00
|
|
|
upcall_free(rust_task *task, void* ptr, uintptr_t is_gc) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-06-28 12:15:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
|
|
|
DLOG(sched, mem,
|
2010-09-29 17:22:07 -07:00
|
|
|
"upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")",
|
|
|
|
(uintptr_t)ptr, is_gc);
|
2010-06-28 18:53:16 -07:00
|
|
|
task->free(ptr, (bool) is_gc);
|
|
|
|
}
|
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
extern "C" CDECL uintptr_t
|
|
|
|
upcall_shared_malloc(rust_task *task, size_t nbytes, type_desc *td) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
|
|
|
LOG(task, mem,
|
|
|
|
"upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR ")",
|
|
|
|
nbytes, td);
|
2011-07-18 12:02:26 -07:00
|
|
|
void *p = task->kernel->malloc(nbytes, "shared malloc");
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG(task, mem,
|
|
|
|
"upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR
|
|
|
|
") = 0x%" PRIxPTR,
|
|
|
|
nbytes, td, (uintptr_t)p);
|
|
|
|
return (uintptr_t) p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called whenever an object's ref count drops to zero.
|
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_shared_free(rust_task *task, void* ptr) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-12 11:53:45 -07:00
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
|
|
|
DLOG(sched, mem,
|
|
|
|
"upcall shared_free(0x%" PRIxPTR")",
|
|
|
|
(uintptr_t)ptr);
|
|
|
|
task->kernel->free(ptr);
|
|
|
|
}
|
|
|
|
|
2010-06-28 18:53:16 -07:00
|
|
|
extern "C" CDECL uintptr_t
|
2010-08-31 14:36:51 -07:00
|
|
|
upcall_mark(rust_task *task, void* ptr) {
|
2010-06-28 18:53:16 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
2011-06-28 12:15:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
2010-06-28 18:53:16 -07:00
|
|
|
if (ptr) {
|
|
|
|
gc_alloc *gcm = (gc_alloc*) (((char*)ptr) - sizeof(gc_alloc));
|
|
|
|
uintptr_t marked = (uintptr_t) gcm->mark();
|
2011-06-28 12:15:41 -07:00
|
|
|
DLOG(sched, gc, "upcall mark(0x%" PRIxPTR ") = %" PRIdPTR,
|
2010-06-28 18:53:16 -07:00
|
|
|
(uintptr_t)gcm, marked);
|
|
|
|
return marked;
|
|
|
|
}
|
|
|
|
return 0;
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-06-20 13:46:44 -07:00
|
|
|
rust_str *make_str(rust_task *task, char const *s, size_t fill) {
|
2010-06-23 21:03:09 -07:00
|
|
|
size_t alloc = next_power_of_two(sizeof(rust_str) + fill);
|
2011-07-18 12:02:26 -07:00
|
|
|
void *mem = task->malloc(alloc, "rust_str (make_str)");
|
2010-06-23 21:03:09 -07:00
|
|
|
if (!mem) {
|
2011-07-13 13:43:35 -07:00
|
|
|
task->fail();
|
2010-06-23 21:03:09 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-07-18 12:02:26 -07:00
|
|
|
rust_str *st = new (mem) rust_str(alloc, fill,
|
2011-06-29 15:11:20 -07:00
|
|
|
(uint8_t const *) s);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
|
|
|
"upcall new_str('%s', %" PRIdPTR ") = 0x%" PRIxPTR,
|
|
|
|
s, fill, st);
|
2010-06-23 21:03:09 -07:00
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
2011-06-20 13:46:44 -07:00
|
|
|
extern "C" CDECL rust_str *
|
|
|
|
upcall_new_str(rust_task *task, char const *s, size_t fill) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
return make_str(task, s, fill);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL rust_str *
|
2011-08-08 13:38:20 -07:00
|
|
|
upcall_dup_str(rust_task *task, rust_task_id tid, rust_str *str) {
|
2011-06-20 13:46:44 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *target = task->kernel->get_task_by_id(tid);
|
2011-06-28 14:21:31 -07:00
|
|
|
return make_str(target, (char const *)str->data, str->fill);
|
2011-06-20 13:46:44 -07:00
|
|
|
}
|
|
|
|
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL rust_vec *
|
2010-08-31 14:36:51 -07:00
|
|
|
upcall_new_vec(rust_task *task, size_t fill, type_desc *td) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-06-28 12:15:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
|
|
|
DLOG(sched, mem, "upcall new_vec(%" PRIdPTR ")", fill);
|
2010-06-23 21:03:09 -07:00
|
|
|
size_t alloc = next_power_of_two(sizeof(rust_vec) + fill);
|
2011-07-18 12:02:26 -07:00
|
|
|
void *mem = task->malloc(alloc, "rust_vec (upcall_new_vec)", td);
|
2010-06-23 21:03:09 -07:00
|
|
|
if (!mem) {
|
2011-07-13 13:43:35 -07:00
|
|
|
task->fail();
|
2010-06-23 21:03:09 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-07-18 12:02:26 -07:00
|
|
|
rust_vec *v = new (mem) rust_vec(alloc, 0, NULL);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2010-07-19 14:05:18 -07:00
|
|
|
"upcall new_vec(%" PRIdPTR ") = 0x%" PRIxPTR, fill, v);
|
2010-06-23 21:03:09 -07:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2011-06-15 18:03:15 -07:00
|
|
|
static rust_vec *
|
|
|
|
vec_grow(rust_task *task,
|
|
|
|
rust_vec *v,
|
|
|
|
size_t n_bytes,
|
|
|
|
uintptr_t *need_copy,
|
|
|
|
type_desc *td)
|
2010-09-03 16:18:32 -07:00
|
|
|
{
|
2011-06-28 12:15:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2011-06-15 18:03:15 -07:00
|
|
|
"vec_grow(0x%" PRIxPTR ", %" PRIdPTR
|
2011-04-28 13:14:25 -07:00
|
|
|
"), rc=%" PRIdPTR " alloc=%" PRIdPTR ", fill=%" PRIdPTR
|
|
|
|
", need_copy=0x%" PRIxPTR,
|
|
|
|
v, n_bytes, v->ref_count, v->alloc, v->fill, need_copy);
|
2010-09-03 16:18:32 -07:00
|
|
|
|
|
|
|
*need_copy = 0;
|
2010-06-23 21:03:09 -07:00
|
|
|
size_t alloc = next_power_of_two(sizeof(rust_vec) + v->fill + n_bytes);
|
2010-09-03 16:18:32 -07:00
|
|
|
|
2010-07-19 14:05:18 -07:00
|
|
|
if (v->ref_count == 1) {
|
2010-06-23 21:03:09 -07:00
|
|
|
|
|
|
|
// Fastest path: already large enough.
|
|
|
|
if (v->alloc >= alloc) {
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem, "no-growth path");
|
2010-06-23 21:03:09 -07:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Second-fastest path: can at least realloc.
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem, "realloc path");
|
2010-09-29 17:22:07 -07:00
|
|
|
v = (rust_vec*) task->realloc(v, alloc, td->is_stateful);
|
2010-06-23 21:03:09 -07:00
|
|
|
if (!v) {
|
2011-07-13 13:43:35 -07:00
|
|
|
task->fail();
|
2010-06-23 21:03:09 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
v->alloc = alloc;
|
|
|
|
|
|
|
|
} else {
|
2010-09-03 16:18:32 -07:00
|
|
|
/**
|
|
|
|
* Slowest path: make a new vec.
|
|
|
|
*
|
|
|
|
* 1. Allocate a new rust_vec with desired additional space.
|
|
|
|
* 2. Down-ref the shared rust_vec, point to the new one instead.
|
|
|
|
* 3. Copy existing elements into the new rust_vec.
|
|
|
|
*
|
|
|
|
* Step 3 is a bit tricky. We don't know how to properly copy the
|
|
|
|
* elements in the runtime (all we have are bits in a buffer; no
|
2011-06-10 14:14:00 -07:00
|
|
|
* type information and no copy glue). What we do instead is set the
|
2010-09-03 16:18:32 -07:00
|
|
|
* need_copy outparam flag to indicate to our caller (vec-copy glue)
|
|
|
|
* that we need the copies performed for us.
|
|
|
|
*/
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem, "new vec path");
|
2011-07-18 12:02:26 -07:00
|
|
|
void *mem = task->malloc(alloc, "rust_vec (vec_grow)", td);
|
2010-06-23 21:03:09 -07:00
|
|
|
if (!mem) {
|
2011-07-13 13:43:35 -07:00
|
|
|
task->fail();
|
2010-06-23 21:03:09 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-09 14:15:07 -08:00
|
|
|
|
|
|
|
if (v->ref_count != CONST_REFCOUNT)
|
|
|
|
v->deref();
|
|
|
|
|
2011-07-18 12:02:26 -07:00
|
|
|
v = new (mem) rust_vec(alloc, 0, NULL);
|
2010-09-03 16:18:32 -07:00
|
|
|
*need_copy = 1;
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
2011-06-28 12:15:41 -07:00
|
|
|
I(sched, sizeof(rust_vec) + v->fill <= v->alloc);
|
2010-06-23 21:03:09 -07:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2011-06-10 14:14:00 -07:00
|
|
|
// Copy elements from one vector to another,
|
|
|
|
// dealing with reference counts
|
|
|
|
static inline void
|
|
|
|
copy_elements(rust_task *task, type_desc *elem_t,
|
|
|
|
void *pdst, void *psrc, size_t n)
|
|
|
|
{
|
|
|
|
char *dst = (char *)pdst, *src = (char *)psrc;
|
2011-06-28 17:58:45 -07:00
|
|
|
memmove(dst, src, n);
|
2011-06-10 14:14:00 -07:00
|
|
|
|
|
|
|
// increment the refcount of each element of the vector
|
2011-06-28 16:52:29 -07:00
|
|
|
if (elem_t->copy_glue) {
|
|
|
|
glue_fn *copy_glue = elem_t->copy_glue;
|
2011-06-10 14:14:00 -07:00
|
|
|
size_t elem_size = elem_t->size;
|
|
|
|
const type_desc **tydescs = elem_t->first_param;
|
2011-06-28 17:58:45 -07:00
|
|
|
for (char *p = dst; p < dst+n; p += elem_size) {
|
2011-06-28 16:52:29 -07:00
|
|
|
copy_glue(NULL, task, NULL, tydescs, p);
|
2011-06-10 14:14:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_vec_append(rust_task *task, type_desc *t, type_desc *elem_t,
|
|
|
|
rust_vec **dst_ptr, rust_vec *src, bool skip_null)
|
|
|
|
{
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
rust_vec *dst = *dst_ptr;
|
|
|
|
uintptr_t need_copy;
|
|
|
|
size_t n_src_bytes = skip_null ? src->fill - 1 : src->fill;
|
|
|
|
size_t n_dst_bytes = skip_null ? dst->fill - 1 : dst->fill;
|
2011-06-15 18:03:15 -07:00
|
|
|
rust_vec *new_vec = vec_grow(task, dst, n_src_bytes, &need_copy, t);
|
2011-06-10 14:14:00 -07:00
|
|
|
|
2011-06-24 16:22:39 -07:00
|
|
|
// If src and dst are the same (due to "v += v"), then dst getting
|
|
|
|
// resized causes src to move as well.
|
2011-06-27 11:27:43 -07:00
|
|
|
if (dst == src && !need_copy) {
|
2011-06-24 16:22:39 -07:00
|
|
|
src = new_vec;
|
|
|
|
}
|
|
|
|
|
2011-06-10 14:14:00 -07:00
|
|
|
if (need_copy) {
|
|
|
|
// Copy any dst elements in, omitting null if doing str.
|
|
|
|
copy_elements(task, elem_t, &new_vec->data, &dst->data, n_dst_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy any src elements in, carrying along null if doing str.
|
|
|
|
void *new_end = (void *)((char *)new_vec->data + n_dst_bytes);
|
|
|
|
copy_elements(task, elem_t, new_end, &src->data, src->fill);
|
|
|
|
new_vec->fill = n_dst_bytes + src->fill;
|
|
|
|
|
|
|
|
// Write new_vec back through the alias we were given.
|
|
|
|
*dst_ptr = new_vec;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL type_desc *
|
2010-07-28 14:00:44 -07:00
|
|
|
upcall_get_type_desc(rust_task *task,
|
2011-05-26 18:20:48 -07:00
|
|
|
void *curr_crate, // ignored, legacy compat.
|
2010-07-28 14:00:44 -07:00
|
|
|
size_t size,
|
|
|
|
size_t align,
|
|
|
|
size_t n_descs,
|
2010-08-31 14:36:51 -07:00
|
|
|
type_desc const **descs) {
|
2011-07-06 15:06:30 -07:00
|
|
|
check_stack(task);
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, cache, "upcall get_type_desc with size=%" PRIdPTR
|
|
|
|
", align=%" PRIdPTR ", %" PRIdPTR " descs", size, align,
|
|
|
|
n_descs);
|
2011-05-26 18:20:48 -07:00
|
|
|
rust_crate_cache *cache = task->get_crate_cache();
|
2010-06-23 21:03:09 -07:00
|
|
|
type_desc *td = cache->get_type_desc(size, align, n_descs, descs);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, cache, "returning tydesc 0x%" PRIxPTR, td);
|
2010-06-23 21:03:09 -07:00
|
|
|
return td;
|
|
|
|
}
|
|
|
|
|
2011-08-08 13:38:20 -07:00
|
|
|
extern "C" CDECL rust_task_id
|
2011-05-20 14:29:26 -07:00
|
|
|
upcall_new_task(rust_task *spawner, rust_vec *name) {
|
|
|
|
// name is a rust string structure.
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(spawner);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task_id tid =
|
2011-07-23 19:03:02 -07:00
|
|
|
spawner->kernel->create_task(spawner, (const char *)name->data);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *task = spawner->kernel->get_task_by_id(tid);
|
2011-07-27 14:51:25 -07:00
|
|
|
task->ref();
|
2011-08-08 13:38:20 -07:00
|
|
|
return tid;
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-07-27 12:29:38 -07:00
|
|
|
extern "C" CDECL void
|
2011-08-08 13:38:20 -07:00
|
|
|
upcall_take_task(rust_task *task, rust_task_id tid) {
|
2011-07-27 12:29:38 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *target = task->kernel->get_task_by_id(tid);
|
2011-07-27 12:29:38 -07:00
|
|
|
if(target) {
|
|
|
|
target->ref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
2011-08-08 13:38:20 -07:00
|
|
|
upcall_drop_task(rust_task *task, rust_task_id tid) {
|
2011-07-27 12:29:38 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *target = task->kernel->get_task_by_id(tid);
|
2011-07-27 12:29:38 -07:00
|
|
|
if(target) {
|
2011-07-27 14:51:25 -07:00
|
|
|
target->deref();
|
2011-07-27 12:29:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-05 15:16:48 -07:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_take_chan(rust_task *task, rust_chan *target) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
if(target) {
|
|
|
|
target->ref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_drop_chan(rust_task *task, rust_chan *target) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
if(target) {
|
|
|
|
target->deref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL rust_task *
|
2010-08-31 14:36:51 -07:00
|
|
|
upcall_start_task(rust_task *spawner,
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task_id tid,
|
2010-08-31 14:36:51 -07:00
|
|
|
uintptr_t spawnee_fn,
|
2011-05-31 17:44:54 -07:00
|
|
|
uintptr_t args,
|
|
|
|
size_t args_sz) {
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(spawner);
|
|
|
|
|
2011-06-28 12:15:41 -07:00
|
|
|
rust_scheduler *sched = spawner->sched;
|
2011-08-08 13:38:20 -07:00
|
|
|
rust_task *task = spawner->kernel->get_task_by_id(tid);
|
2011-06-28 12:15:41 -07:00
|
|
|
DLOG(sched, task,
|
2011-05-26 18:00:33 -07:00
|
|
|
"upcall start_task(task %s @0x%" PRIxPTR
|
2011-07-13 15:44:09 -07:00
|
|
|
", spawnee 0x%" PRIxPTR ")",
|
2011-05-26 18:00:33 -07:00
|
|
|
task->name, task,
|
|
|
|
spawnee_fn);
|
|
|
|
|
|
|
|
// we used to be generating this tuple in rustc, but it's easier to do it
|
|
|
|
// here.
|
2011-05-31 17:44:54 -07:00
|
|
|
//
|
|
|
|
// The args tuple is stack-allocated. We need to move it over to the new
|
|
|
|
// stack.
|
|
|
|
task->rust_sp -= args_sz;
|
2011-06-15 18:16:17 -07:00
|
|
|
uintptr_t child_arg = (uintptr_t)task->rust_sp;
|
|
|
|
|
2011-05-31 17:44:54 -07:00
|
|
|
memcpy((void*)task->rust_sp, (void*)args, args_sz);
|
2011-06-15 18:16:17 -07:00
|
|
|
|
|
|
|
task->start(spawnee_fn, child_arg);
|
2010-06-23 21:03:09 -07:00
|
|
|
return task;
|
|
|
|
}
|
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
/**
|
|
|
|
* Resizes an interior vector that has been spilled to the heap.
|
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_ivec_resize_shared(rust_task *task,
|
|
|
|
rust_ivec *v,
|
|
|
|
size_t newsz) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-23 19:03:02 -07:00
|
|
|
scoped_lock with(task->sched->lock);
|
2011-07-05 22:55:41 -07:00
|
|
|
I(task->sched, !v->fill);
|
|
|
|
|
|
|
|
size_t new_alloc = next_power_of_two(newsz);
|
|
|
|
rust_ivec_heap *new_heap_part = (rust_ivec_heap *)
|
|
|
|
task->kernel->realloc(v->payload.ptr, new_alloc + sizeof(size_t));
|
|
|
|
|
|
|
|
new_heap_part->fill = newsz;
|
|
|
|
v->alloc = new_alloc;
|
|
|
|
v->payload.ptr = new_heap_part;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Spills an interior vector to the heap.
|
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_ivec_spill_shared(rust_task *task,
|
|
|
|
rust_ivec *v,
|
|
|
|
size_t newsz) {
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-23 19:03:02 -07:00
|
|
|
scoped_lock with(task->sched->lock);
|
2011-07-05 22:55:41 -07:00
|
|
|
size_t new_alloc = next_power_of_two(newsz);
|
|
|
|
|
|
|
|
rust_ivec_heap *heap_part = (rust_ivec_heap *)
|
2011-07-18 12:02:26 -07:00
|
|
|
task->kernel->malloc(new_alloc + sizeof(size_t),
|
|
|
|
"ivec spill shared");
|
2011-07-05 22:55:41 -07:00
|
|
|
heap_part->fill = newsz;
|
|
|
|
memcpy(&heap_part->data, v->payload.data, v->fill);
|
|
|
|
|
|
|
|
v->fill = 0;
|
|
|
|
v->alloc = new_alloc;
|
|
|
|
v->payload.ptr = heap_part;
|
|
|
|
}
|
2010-06-23 21:03:09 -07:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: C++
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
2011-07-13 13:51:20 -07:00
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
2010-06-23 21:03:09 -07:00
|
|
|
// End:
|
|
|
|
//
|