Files
jsix/src/kernel/objects/mailbox.cpp
Justin C. Miller 1a04310f80 [kernel] Simplify mailbox code, and messages
A number of simplifications of mailboxes now that the interface is much
simpler, and synchronous.

* call and respond can now only transfer one handle at a time
* mailbox objects got rid of the message queue, and just have
  wait_queues of blocked threads, and a reply_to map.
* threads now have a message_data struct on them for use by mailboxes
2022-10-14 01:02:56 -07:00

100 lines
2.0 KiB
C++

#include <util/counted.h>
#include "objects/mailbox.h"
#include "objects/thread.h"
namespace obj {
mailbox::mailbox() :
kobject(kobject::type::mailbox),
m_closed {false},
m_next_reply_tag {0}
{
}
mailbox::~mailbox()
{
close();
}
void
mailbox::close()
{
// If this was previously closed, we're done
bool was_closed = __atomic_exchange_n(&m_closed, true, __ATOMIC_ACQ_REL);
if (was_closed) return;
m_callers.clear(j6_status_closed);
m_responders.clear(j6_status_closed);
}
j6_status_t
mailbox::call()
{
if (closed())
return j6_status_closed;
thread &current = thread::current();
m_callers.add_thread(&current);
thread *responder = m_responders.pop_next();
if (responder)
responder->wake(j6_status_ok);
return current.block();
}
j6_status_t
mailbox::receive(thread::message_data &data, reply_tag_t &reply_tag, bool block)
{
if (closed())
return j6_status_closed;
thread &current = thread::current();
thread *caller = nullptr;
while (true) {
caller = m_callers.pop_next();
if (caller)
break;
if (!block)
return j6_status_would_block;
m_responders.add_thread(&current);
j6_status_t s = current.block();
if (s != j6_status_ok)
return s;
}
util::scoped_lock lock {m_reply_lock};
reply_tag = ++m_next_reply_tag;
m_reply_map.insert({ reply_tag, caller });
lock.release();
data = caller->get_message_data();
return j6_status_ok;
}
j6_status_t
mailbox::reply(reply_tag_t reply_tag, const thread::message_data &data)
{
if (closed())
return j6_status_closed;
util::scoped_lock lock {m_reply_lock};
reply_to *rt = m_reply_map.find(reply_tag);
if (!rt)
return j6_err_invalid_arg;
thread *caller = rt->thread;
m_reply_map.erase(reply_tag);
lock.release();
caller->get_message_data() = data;
caller->wake(j6_status_ok);
return j6_status_ok;
}
} // namespace obj