[kernel] Allow blocking on empty channels

This commit adds a new flag, j6_channel_block, and a new flags param to
the channel_receive syscall. When the block flag is specified, the
caller will block waiting for data on the channel if the channel is
empty.
This commit is contained in:
Justin C. Miller
2022-02-28 20:10:56 -08:00
parent 446025fb65
commit b8684777e0
5 changed files with 38 additions and 30 deletions

View File

@@ -3,6 +3,7 @@
#include "assert.h"
#include "memory.h"
#include "objects/channel.h"
#include "objects/thread.h"
#include "objects/vm_area.h"
extern obj::vm_area_guarded g_kernel_buffers;
@@ -12,10 +13,11 @@ namespace obj {
constexpr size_t buffer_bytes = mem::kernel_buffer_pages * mem::frame_size;
channel::channel() :
m_len(0),
m_data(g_kernel_buffers.get_section()),
m_buffer(reinterpret_cast<uint8_t*>(m_data), buffer_bytes),
kobject(kobject::type::channel)
m_len {0},
m_data {g_kernel_buffers.get_section()},
m_closed {false},
m_buffer {reinterpret_cast<uint8_t*>(m_data), buffer_bytes},
kobject {kobject::type::channel}
{
}
@@ -33,24 +35,23 @@ channel::enqueue(const util::buffer &data)
size_t len = data.count;
void *buffer = nullptr;
size_t avail = m_buffer.reserve(len, &buffer);
len = len > avail ? avail : len;
len = m_buffer.reserve(len, &buffer);
memcpy(buffer, data.pointer, len);
m_buffer.commit(len);
if (len)
m_can_recv = true;
if (len) {
thread *t = m_queue.pop_next();
if (m_buffer.free_space() == 0)
m_can_send = false;
lock.release();
if (t) t->wake();
}
return len;
}
size_t
channel::dequeue(util::buffer buffer)
channel::dequeue(util::buffer buffer, bool block)
{
util::scoped_lock lock {m_close_lock};
@@ -58,17 +59,21 @@ channel::dequeue(util::buffer buffer)
void *data = nullptr;
size_t avail = m_buffer.get_block(&data);
if (!avail && block) {
thread &cur = thread::current();
m_queue.add_thread(&cur);
lock.release();
cur.block();
lock.reacquire();
avail = m_buffer.get_block(&data);
}
size_t len = buffer.count > avail ? avail : buffer.count;
memcpy(data, buffer.pointer, len);
memcpy(buffer.pointer, data, len);
m_buffer.consume(len);
if (len)
m_can_send = true;
if (m_buffer.size() == 0)
m_can_recv = false;
return len;
}