[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.
This commit is contained in:
@@ -8,27 +8,37 @@
|
||||
|
||||
namespace util {
|
||||
|
||||
bip_buffer::bip_buffer() :
|
||||
m_start_a(0),
|
||||
m_start_b(0),
|
||||
m_size_a(0),
|
||||
m_size_b(0),
|
||||
m_size_r(0),
|
||||
m_buffer_size(0),
|
||||
m_buffer(nullptr)
|
||||
{}
|
||||
bip_buffer::bip_buffer(size_t size) :
|
||||
m_start_a {0},
|
||||
m_start_b {0},
|
||||
m_size_a {0},
|
||||
m_size_b {0},
|
||||
m_size_r {0},
|
||||
m_buffer_size {size - sizeof(bip_buffer)}
|
||||
{}
|
||||
|
||||
bip_buffer::bip_buffer(uint8_t *buffer, size_t size) :
|
||||
m_start_a(0),
|
||||
m_start_b(0),
|
||||
m_size_a(0),
|
||||
m_size_b(0),
|
||||
m_size_r(0),
|
||||
m_buffer_size(size),
|
||||
m_buffer(buffer)
|
||||
{}
|
||||
size_t
|
||||
bip_buffer::write_available() const
|
||||
{
|
||||
scoped_lock lock {m_lock};
|
||||
|
||||
size_t bip_buffer::reserve(size_t size, void **area)
|
||||
if (m_size_r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_size_b) {
|
||||
// If B exists, we're appending there. Get space between
|
||||
// the end of B and start of A.
|
||||
return m_start_a - m_start_b - m_size_b;
|
||||
} else {
|
||||
// B doesn't exist, check the space both before and after A.
|
||||
size_t remaining = m_buffer_size - m_start_a - m_size_a;
|
||||
return (m_start_a > remaining) ? m_start_a : remaining;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
bip_buffer::reserve(size_t size, uint8_t **area)
|
||||
{
|
||||
scoped_lock lock {m_lock};
|
||||
|
||||
@@ -84,7 +94,7 @@ void bip_buffer::commit(size_t size)
|
||||
m_start_r = m_size_r = 0;
|
||||
}
|
||||
|
||||
size_t bip_buffer::get_block(void **area) const
|
||||
size_t bip_buffer::get_block(uint8_t const **area) const
|
||||
{
|
||||
scoped_lock lock {m_lock};
|
||||
|
||||
|
||||
@@ -14,17 +14,14 @@ namespace util {
|
||||
class API bip_buffer
|
||||
{
|
||||
public:
|
||||
/// Default constructor. Creates a zero-size buffer.
|
||||
bip_buffer();
|
||||
|
||||
/// Constructor.
|
||||
bip_buffer(uint8_t *buffer, size_t size);
|
||||
bip_buffer(size_t size);
|
||||
|
||||
/// Reserve an area of buffer for a write.
|
||||
/// \arg size Requested size, in bytes
|
||||
/// \arg area [out] Pointer to returned area
|
||||
/// \returns Size of returned area, in bytes, or 0 on failure
|
||||
size_t reserve(size_t size, void **area);
|
||||
size_t reserve(size_t size, uint8_t **area);
|
||||
|
||||
/// Commit a pending write started by reserve()
|
||||
/// \arg size Amount of data used, in bytes
|
||||
@@ -33,7 +30,7 @@ public:
|
||||
/// Get a pointer to a block of data in the buffer.
|
||||
/// \arg area [out] Pointer to the retuned area
|
||||
/// \returns Size of the returned area, in bytes
|
||||
size_t get_block(void **area) const;
|
||||
size_t get_block(uint8_t const **area) const;
|
||||
|
||||
/// Mark a number of bytes as consumed, freeing buffer space
|
||||
/// \arg size Number of bytes to consume
|
||||
@@ -47,6 +44,13 @@ public:
|
||||
/// \returns Number of bytes of buffer that are free
|
||||
inline size_t free_space() const { return m_buffer_size - size(); }
|
||||
|
||||
/// Get total size of the buffer
|
||||
/// \returns Number of bytes in the buffer
|
||||
inline size_t buffer_size() const { return m_buffer_size; }
|
||||
|
||||
/// Get the current size available for a contiguous write
|
||||
size_t write_available() const;
|
||||
|
||||
private:
|
||||
size_t m_start_a;
|
||||
size_t m_start_b;
|
||||
@@ -56,9 +60,10 @@ private:
|
||||
size_t m_size_r;
|
||||
|
||||
mutable spinlock m_lock;
|
||||
|
||||
const size_t m_buffer_size;
|
||||
uint8_t * const m_buffer;
|
||||
uint8_t m_buffer[0];
|
||||
|
||||
bip_buffer() = delete;
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <util/basic_types.h>
|
||||
|
||||
namespace util {
|
||||
|
||||
@@ -92,4 +93,45 @@ private:
|
||||
size_t m_off;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class unique_ptr
|
||||
{
|
||||
public:
|
||||
unique_ptr() : m_value {nullptr} {}
|
||||
unique_ptr(T *p) : m_value {p} {}
|
||||
unique_ptr(unique_ptr &&o) { *this = util::move(o); }
|
||||
|
||||
~unique_ptr() { delete m_value; }
|
||||
|
||||
unique_ptr & operator=(unique_ptr &&o) {
|
||||
if (o.m_value == m_value) return *this;
|
||||
delete m_value;
|
||||
|
||||
m_value = o.m_value;
|
||||
o.m_value = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr(const unique_ptr &) = delete;
|
||||
unique_ptr & operator=(const unique_ptr &) = delete;
|
||||
|
||||
T* get() { return m_value; }
|
||||
const T* get() const { return m_value; }
|
||||
operator bool() const { return m_value; }
|
||||
bool empty() const { return m_value = nullptr; }
|
||||
|
||||
T* operator->() { return m_value; }
|
||||
const T operator->() const { return m_value; }
|
||||
|
||||
T operator*() { return *m_value; }
|
||||
const T operator*() const { return *m_value; }
|
||||
|
||||
operator T*() { return m_value; }
|
||||
operator const T*() const { return m_value; }
|
||||
|
||||
private:
|
||||
T *m_value = nullptr;
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
|
||||
Reference in New Issue
Block a user