Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

144 lines (114 sloc) 3.863 kb
#include "rust_port.h"
#include "rust_task.h"
rust_port::rust_port(rust_task *task, size_t unit_sz)
: ref_count(1), kernel(task->kernel), task(task),
unit_sz(unit_sz), buffer(kernel, unit_sz) {
LOG(task, comm,
"new rust_port(task=0x%" PRIxPTR ", unit_sz=%d) -> port=0x%"
PRIxPTR, (uintptr_t)task, unit_sz, (uintptr_t)this);
id = kernel->register_port(this);
}
rust_port::~rust_port() {
LOG(task, comm, "~rust_port 0x%" PRIxPTR, (uintptr_t) this);
}
void rust_port::ref() {
scoped_lock with(ref_lock);
ref_count++;
}
void rust_port::deref() {
scoped_lock with(ref_lock);
ref_count--;
if (!ref_count) {
// The port owner is waiting for the port to be detached (if it
// hasn't already been killed)
scoped_lock with(task->lifecycle_lock);
if (task->blocked_on(&detach_cond)) {
task->wakeup_inner(&detach_cond);
}
}
}
void rust_port::begin_detach(uintptr_t *yield) {
*yield = false;
kernel->release_port_id(id);
scoped_lock with(ref_lock);
ref_count--;
if (ref_count != 0) {
task->block(&detach_cond, "waiting for port detach");
*yield = true;
}
}
void rust_port::end_detach() {
// Just take the lock to make sure that the thread that signaled
// the detach_cond isn't still holding it
scoped_lock with(ref_lock);
assert(ref_count == 0);
}
void rust_port::send(void *sptr) {
bool did_rendezvous = false;
{
scoped_lock with(lock);
buffer.enqueue(sptr);
assert(!buffer.is_empty() &&
"rust_chan::transmit with nothing to send.");
{
scoped_lock with(task->lifecycle_lock);
if (task->blocked_on(this)) {
KLOG(kernel, comm, "dequeued in rendezvous_ptr");
buffer.dequeue(task->rendezvous_ptr);
task->rendezvous_ptr = 0;
task->wakeup_inner(this);
did_rendezvous = true;
}
}
}
if (!did_rendezvous) {
// If the task wasn't waiting specifically on this port,
// it may be waiting on a group of ports
rust_port_selector *port_selector = task->get_port_selector();
// The port selector will check if the task is blocked, not us.
port_selector->msg_sent_on(this);
}
}
void rust_port::receive(void *dptr, uintptr_t *yield) {
LOG(task, comm, "port: 0x%" PRIxPTR ", dptr: 0x%" PRIxPTR
", size: 0x%" PRIxPTR,
(uintptr_t) this, (uintptr_t) dptr, unit_sz);
scoped_lock with(lock);
*yield = false;
if (buffer.is_empty() == false) {
buffer.dequeue(dptr);
LOG(task, comm, "<=== read data ===");
return;
}
memset(dptr, 0, buffer.unit_sz);
// No data was buffered on any incoming channel, so block this task on
// the port. Remember the rendezvous location so that any sender task
// can write to it before waking up this task.
LOG(task, comm, "<=== waiting for rendezvous data ===");
task->rendezvous_ptr = (uintptr_t*) dptr;
task->block(this, "waiting for rendezvous data");
// Blocking the task might fail if the task has already been killed, but
// in the event of both failure and success the task needs to yield. On
// success, it yields and waits to be unblocked. On failure it yields and
// is then fails the task.
*yield = true;
}
size_t rust_port::size() {
scoped_lock with(lock);
return buffer.size();
}
void rust_port::log_state() {
LOG(task, comm,
"port size: %d",
buffer.size());
}
//
// Local Variables:
// mode: C++
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
Jump to Line
Something went wrong with that request. Please try again.