Files
jsix/src/kernel/objects/channel.h
Justin C. Miller f7ae2e2220 [kernel] Re-design thread blocking
In preparation for the new mailbox IPC model, blocking threads needed an
overhaul. The `wait_on_*` and `wake_on_*` methods are gone, and the
`block()` and `wake()` calls on threads now pass a value between the
waker and the blocked thread.

As part of this change, the concept of signals on the base kobject class
was removed, along with the queue of blocked threads waiting on any
given object. Signals are now exclusively the domain of the event object
type, and the new wait_queue utility class helps manage waiting threads
when an object does actually need this functionality. In some cases (eg,
logger) an event object is used instead of the lower-level wait_queue.

Since this change has a lot of ramifications, this large commit includes
the following additional changes:

- The j6_object_wait, j6_object_wait_many, and j6_thread_pause syscalls
  have been removed.
- The j6_event_clear syscall has been removed - events are "cleared" by
  reading them now. A new j6_event_wait syscall has been added to read
  events.
- The generic close() method on kobject has been removed.
- The on_no_handles() method on kobject now deletes the object by
  default, and needs to be overridden by classes that should not be.
- The j6_system_bind_irq syscall now takes an event handle, as well as a
  signal that the IRQ should set on the event. IRQs will cause a waiting
  thread to be woken with the appropriate bit set.
- Threads waking due to timeout is simplified to just having a
  wake_timeout() accessor that returns a timestamp.
- The new wait_queue uses util::deque, which caused the disovery of two
  bugs in the deque implementation: empty deques could still have a
  single array allocated and thus return true for empty(), and new
  arrays getting allocated were not being zeroed first.
- Exposed a new erase() method on util::map that takes a node pointer
  instead of a key, skipping lookup.
2022-02-22 00:00:15 -08:00

61 lines
1.6 KiB
C++

#pragma once
/// \file channel.h
/// Definition of channel objects and related functions
#include <j6/caps.h>
#include <util/bip_buffer.h>
#include <util/counted.h>
#include <util/spinlock.h>
#include "objects/kobject.h"
namespace obj {
/// Channels are uni-directional means of sending data
class channel :
public kobject
{
public:
/// Capabilities on a newly constructed channel handle
constexpr static j6_cap_t creation_caps = j6_cap_channel_all;
channel();
virtual ~channel();
static constexpr kobject::type type = kobject::type::channel;
/// Check if the channel has space for a message to be sent
inline bool can_send() const { return m_can_send; }
/// Check if the channel has a message wiating already
inline bool can_receive() const { return m_can_recv; }
/// Put a message into the channel
/// \arg data Buffer of data to write
/// \returns The number of bytes successfully written
size_t enqueue(const util::buffer &data);
/// Get a message from the channel, copied into a provided buffer
/// \arg buffer The buffer to copy data into
/// \returns The number of bytes copied into the provided buffer
size_t dequeue(util::buffer buffer);
/// Mark this channel as closed, all future calls to enqueue or
/// dequeue messages will fail with j6_status_closed.
void close();
/// Check if this channel has been closed.
inline bool closed() const { return m_closed; }
private:
size_t m_len;
uintptr_t m_data;
bool m_closed;
bool m_can_send;
bool m_can_recv;
util::bip_buffer m_buffer;
util::spinlock m_close_lock;
};
} // namespace obj