Files
jsix/src/kernel/objects/mailbox.h
Justin C. Miller e725795a17 [6s] Add 6s shell, make channels full-duplex
This commit adds the 6s shell, and a bunch of supporting work for it.
Major changes include:

- New shell.yaml manifest to give 6s control of the TTY instead of
  srv.logger
- Changes to mailbox syscalls to add max handles array size separate
  from input size. Also reversed the meaning of the similar data size
  argument in those syscalls. (Using the second arg as the max array
  size and the first as the current valid size allows for the auto
  verify code to verify handles properly, and simplifies user-side
  code.)
- New util::unique_ptr smart pointer class similar to std::unique_ptr
- New ipc::message format that uses util::unique_ptr to manage ownership
  and lifetimes and avoid extra copying.
- The service locator protocol now supports multiple handles per entry
- Channels got a major overhaul. They are now split into two VMAs, each
  containing a mutex, a condition, and a util::bip_buffer. The order of
  the VMAs determines which end of the pipe you're on. (ie, the creator
  swaps them before handing them to the other thread.) Their API also
  changed to be similar to that of util::bip_buffer, to avoid extra
  copies.
- util::bip_buffer now keeps its state and its buffer together, so that
  there are no pointers. This allows multiple processes to share them in
  shared memory, like in channels.
- The UART driver changed from keeping buffers for the serial ports to
  just keeping a channel, and the serial port objects read/write
  directly from/to the channel.

Known issues:

- The shell doesn't actually do anything yet. It echos its input back to
  the serial line and injects a prompt on new lines.
- The shell is one character behind in printing back to the serial line.
2024-04-23 23:32:28 -07:00

83 lines
2.6 KiB
C++

#pragma once
/// \file mailbox.h
/// Definition of mailbox kobject types
#include <j6/cap_flags.h>
#include <util/counted.h>
#include <util/node_map.h>
#include <util/spinlock.h>
#include "heap_allocator.h"
#include "ipc_message.h"
#include "memory.h"
#include "objects/kobject.h"
#include "wait_queue.h"
namespace obj {
class thread;
/// mailboxs are objects that enable synchronous message-passing IPC
class mailbox :
public kobject
{
public:
using reply_tag_t = uint64_t;
/// Capabilities on a newly constructed mailbox handle
static constexpr j6_cap_t creation_caps = j6_cap_mailbox_all;
static constexpr kobject::type type = kobject::type::mailbox;
/// Max message handle count
constexpr static size_t max_handle_count = 5;
mailbox();
virtual ~mailbox();
/// Close the mailbox, waking all waiting processes with an error
void close();
/// Check if the mailbox has been closed
inline bool closed() const { return __atomic_load_n(&m_closed, __ATOMIC_ACQUIRE); }
/// Send a message to a thread waiting to receive on this mailbox, and block the
/// current thread awaiting a response. The message contents should be in the calling
/// thread's message data.
/// \returns j6_status_ok if a reply was received
j6_status_t call();
/// Receive the next available message, optionally blocking if no messages are available.
/// \arg data [out] the message
/// \arg reply_tag [out] the reply_tag to use when replying to this message
/// \arg block True if this call should block when no messages are available.
/// \returns j6_status_ok if a message was received
j6_status_t receive(ipc::message_ptr &data, reply_tag_t &reply_tag, bool block);
/// Find a given pending message to be responded to. Returns a replyer object, which will
/// wake the calling read upon destruction.
/// \arg reply_tag The reply tag in the original message
/// \arg data Message data to pass on to the caller
/// \returns j6_status_ok if the reply was successfully sent
j6_status_t reply(reply_tag_t reply_tag, ipc::message_ptr data);
private:
wait_queue m_callers;
wait_queue m_responders;
struct reply_to { reply_tag_t reply_tag; thread *thread; };
using reply_map =
util::node_map<uint64_t, reply_to, 0, heap_allocated>;
util::spinlock m_reply_lock;
reply_map m_reply_map;
bool m_closed;
reply_tag_t m_next_reply_tag;
friend reply_tag_t & get_map_key(reply_to &rt);
};
inline mailbox::reply_tag_t & get_map_key(mailbox::reply_to &rt) { return rt.reply_tag; }
} // namespace obj