[kernel] Make channels stream based

Multiple changes regarding channels. Mainly channels are now stream
based and can handle partial reads or writes. Channels now use the
kernel buffers area with the related buffer_cache. Added a fake stdout
stream channel and kernel task to read its contents to the screen in
preparation for handing channels as stdin/stdout to processes.
This commit is contained in:
2020-08-30 18:04:19 -07:00
parent f27b133089
commit 724b846ee4
10 changed files with 117 additions and 78 deletions

View File

@@ -1,40 +1,49 @@
#include "kutil/assert.h"
#include "buffer_cache.h"
#include "kernel_memory.h"
#include "objects/channel.h"
using memory::frame_size;
using memory::kernel_buffer_pages;
static constexpr size_t buffer_bytes = kernel_buffer_pages * frame_size;
channel::channel() :
m_len(0),
m_capacity(0),
m_data(nullptr),
m_data(g_kbuffer_cache.get_buffer()),
m_buffer(reinterpret_cast<uint8_t*>(m_data), buffer_bytes),
kobject(kobject::type::channel, j6_signal_channel_can_send)
{
}
channel::~channel()
{
kutil::kfree(m_data);
if (!closed()) close();
}
j6_status_t
channel::enqueue(size_t len, void *data)
channel::enqueue(size_t *len, const void *data)
{
// TODO: Make this thread safe!
if (closed())
return j6_status_closed;
if (!can_send())
if (!len || !*len)
return j6_err_invalid_arg;
if (m_buffer.free_space() == 0)
return j6_err_not_ready;
if (m_capacity < len) {
kutil::kfree(m_data);
m_data = kutil::kalloc(len);
m_capacity = len;
kassert(m_data, "Failed to allocate memory to copy channel message");
}
void *buffer = nullptr;
size_t avail = m_buffer.reserve(*len, &buffer);
*len = *len > avail ? avail : *len;
kutil::memcpy(buffer, data, *len);
m_buffer.commit(*len);
m_len = len;
kutil::memcpy(m_data, data, len);
assert_signal(j6_signal_channel_can_recv);
if (m_buffer.free_space() == 0)
deassert_signal(j6_signal_channel_can_send);
return j6_status_ok;
}
@@ -46,22 +55,33 @@ channel::dequeue(size_t *len, void *data)
if (closed())
return j6_status_closed;
if (!can_receive())
return j6_err_not_ready;
if (!len)
if (!len || !*len)
return j6_err_invalid_arg;
if (*len < m_len)
return j6_err_insufficient;
if (m_buffer.size() == 0)
return j6_err_not_ready;
void *buffer = nullptr;
size_t avail = m_buffer.get_block(&buffer);
*len = *len > avail ? avail : *len;
kutil::memcpy(data, buffer, *len);
m_buffer.consume(*len);
kutil::memcpy(data, m_data, m_len);
*len = m_len;
assert_signal(j6_signal_channel_can_send);
if (m_buffer.size() == 0)
deassert_signal(j6_signal_channel_can_recv);
return j6_status_ok;
}
void
channel::close()
{
g_kbuffer_cache.return_buffer(m_data);
assert_signal(j6_signal_channel_closed);
}
void
channel::on_no_handles()
{

View File

@@ -3,6 +3,7 @@
/// Definition of channel objects and related functions
#include "j6/signals.h"
#include "kutil/bip_buffer.h"
#include "objects/kobject.h"
/// Channels are bi-directional means of sending messages
@@ -20,10 +21,10 @@ public:
inline bool can_receive() const { return check_signal(j6_signal_channel_can_recv); }
/// Put a message into the channel
/// \arg len Length of data, in bytes
/// \arg len [in] Bytes in data buffer [out] number of bytes written
/// \arg data Pointer to the message data
/// \returns j6_status_ok on success
j6_status_t enqueue(size_t len, void *data);
j6_status_t enqueue(size_t *len, const void *data);
/// Get a message from the channel, copied into a provided buffer
/// \arg len On input, the size of the provided buffer. On output,
@@ -34,7 +35,7 @@ public:
/// Mark this channel as closed, all future calls to enqueue or
/// dequeue messages will fail with j6_status_closed.
inline void close() { assert_signal(j6_signal_channel_closed); }
void close();
/// Check if this channel has been closed
inline bool closed() { return check_signal(j6_signal_channel_closed); }
@@ -44,6 +45,6 @@ protected:
private:
size_t m_len;
size_t m_capacity;
void *m_data;
uintptr_t m_data;
kutil::bip_buffer m_buffer;
};