Add initial pass of syscall API kobjects
This commit is contained in:
15
src/kernel/objects/event.h
Normal file
15
src/kernel/objects/event.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
/// \file event.h
|
||||
/// Definition of event kobject types
|
||||
|
||||
#include "objects/kobject.h"
|
||||
|
||||
class event :
|
||||
public kobject
|
||||
{
|
||||
public:
|
||||
static constexpr type type_id = type::event;
|
||||
|
||||
event() :
|
||||
kobject(type_id) {}
|
||||
};
|
||||
26
src/kernel/objects/handle.cpp
Normal file
26
src/kernel/objects/handle.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "objects/handle.h"
|
||||
|
||||
handle::handle(handle&& other) :
|
||||
m_owner(other.m_owner),
|
||||
m_object(other.m_object),
|
||||
m_rights(other.m_rights)
|
||||
{
|
||||
other.m_owner = 0;
|
||||
other.m_object = nullptr;
|
||||
other.m_rights = 0;
|
||||
}
|
||||
|
||||
handle::handle(j6_koid_t owner, j6_rights_t rights, kobject *obj) :
|
||||
m_owner(owner),
|
||||
m_object(obj),
|
||||
m_rights(rights)
|
||||
{
|
||||
if (m_object)
|
||||
m_object->handle_retain();
|
||||
}
|
||||
|
||||
handle::~handle()
|
||||
{
|
||||
if (m_object)
|
||||
m_object->handle_release();
|
||||
}
|
||||
30
src/kernel/objects/handle.h
Normal file
30
src/kernel/objects/handle.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
/// \file handle.h
|
||||
/// Defines types for user handles to kernel objects
|
||||
|
||||
#include "j6/types.h"
|
||||
#include "objects/kobject.h"
|
||||
|
||||
class handle
|
||||
{
|
||||
public:
|
||||
/// Move constructor. Takes ownership of the object from other.
|
||||
handle(handle&& other);
|
||||
|
||||
/// Constructor.
|
||||
/// \arg owner koid of the process that has this handle
|
||||
/// \arg rights access rights this handle has over the object
|
||||
/// \arg obj the object held
|
||||
handle(j6_koid_t owner, j6_rights_t rights, kobject *obj);
|
||||
|
||||
~handle();
|
||||
|
||||
handle() = delete;
|
||||
handle(const handle &other) = delete;
|
||||
handle & operator=(const handle& other) = delete;
|
||||
|
||||
private:
|
||||
j6_koid_t m_owner;
|
||||
kobject *m_object;
|
||||
j6_rights_t m_rights;
|
||||
};
|
||||
98
src/kernel/objects/kobject.cpp
Normal file
98
src/kernel/objects/kobject.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "j6/errors.h"
|
||||
#include "j6/signals.h"
|
||||
#include "j6/types.h"
|
||||
#include "kutil/heap_allocator.h"
|
||||
#include "objects/kobject.h"
|
||||
|
||||
extern kutil::heap_allocator g_kernel_heap;
|
||||
|
||||
// TODO: per-cpu this?
|
||||
static j6_koid_t next_koid;
|
||||
|
||||
kobject::kobject(type t, j6_signal_t signals) :
|
||||
m_koid(koid_generate(t)),
|
||||
m_signals(signals),
|
||||
m_observers(g_kernel_heap),
|
||||
m_handle_count(0)
|
||||
{}
|
||||
|
||||
kobject::~kobject()
|
||||
{
|
||||
notify_signal_observers(0, j6_status_destroyed);
|
||||
}
|
||||
|
||||
j6_koid_t
|
||||
kobject::koid_generate(type t)
|
||||
{
|
||||
return (static_cast<uint64_t>(t) << 48) | next_koid++;
|
||||
}
|
||||
|
||||
kobject::type
|
||||
kobject::koid_type(j6_koid_t koid)
|
||||
{
|
||||
return static_cast<type>((koid >> 48) & 0xffffull);
|
||||
}
|
||||
|
||||
void
|
||||
kobject::assert_signal(j6_signal_t s)
|
||||
{
|
||||
m_signals |= s;
|
||||
notify_signal_observers(s);
|
||||
}
|
||||
|
||||
void
|
||||
kobject::deassert_signal(j6_signal_t s)
|
||||
{
|
||||
m_signals &= ~s;
|
||||
notify_signal_observers(s);
|
||||
}
|
||||
|
||||
void
|
||||
kobject::register_signal_observer(observer *object, j6_signal_t s)
|
||||
{
|
||||
m_observers.emplace(object, s);
|
||||
}
|
||||
|
||||
void
|
||||
kobject::deregister_signal_observer(observer *object)
|
||||
{
|
||||
for (size_t i = 0; i < m_observers.count(); ++i) {
|
||||
auto ® = m_observers[i];
|
||||
if (reg.object != object) continue;
|
||||
|
||||
reg = m_observers[m_observers.count() - 1];
|
||||
m_observers.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kobject::notify_signal_observers(j6_signal_t mask, j6_status_t result)
|
||||
{
|
||||
for (auto ® : m_observers) {
|
||||
if (mask == 0 || (reg.signals & mask) != 0) {
|
||||
if (!reg.object->on_signals_changed(this, m_signals, mask, result))
|
||||
reg.object = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Compact the observer list
|
||||
long last = m_observers.count() - 1;
|
||||
while (m_observers[last].object == nullptr && last >= 0) last--;
|
||||
|
||||
for (long i = 0; i < long(m_observers.count()) && i < last; ++i) {
|
||||
auto ® = m_observers[i];
|
||||
if (reg.object != nullptr) continue;
|
||||
reg = m_observers[last--];
|
||||
|
||||
while (m_observers[last].object == nullptr && last >= i) last--;
|
||||
}
|
||||
|
||||
m_observers.set_size(last + 1);
|
||||
}
|
||||
|
||||
void
|
||||
kobject::on_no_handles()
|
||||
{
|
||||
assert_signal(j6_signal_no_handles);
|
||||
}
|
||||
110
src/kernel/objects/kobject.h
Normal file
110
src/kernel/objects/kobject.h
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
/// \file kobject.h
|
||||
/// Definition of base type for user-interactable kernel objects
|
||||
|
||||
#include "j6/errors.h"
|
||||
#include "j6/types.h"
|
||||
#include "kutil/vector.h"
|
||||
|
||||
/// Base type for all user-interactable kernel objects
|
||||
class kobject
|
||||
{
|
||||
public:
|
||||
/// Types of kernel objects.
|
||||
enum class type : uint16_t
|
||||
{
|
||||
none,
|
||||
|
||||
event,
|
||||
eventpair,
|
||||
|
||||
vms,
|
||||
vmo,
|
||||
|
||||
job,
|
||||
process,
|
||||
thread,
|
||||
};
|
||||
|
||||
kobject(type t, j6_signal_t signals = 0ull);
|
||||
virtual ~kobject();
|
||||
|
||||
/// Generate a new koid for a given type
|
||||
/// \arg t The object type
|
||||
/// \returns A new unique koid
|
||||
static j6_koid_t koid_generate(type t);
|
||||
|
||||
/// Get the kobject type from a given koid
|
||||
/// \arg koid An existing koid
|
||||
/// \returns The object type for the koid
|
||||
static type koid_type(j6_koid_t koid);
|
||||
|
||||
/// Set the given signals active on this object
|
||||
/// \arg s The set of signals to assert
|
||||
void assert_signal(j6_signal_t s);
|
||||
|
||||
/// Clear the given signals on this object
|
||||
/// \arg s The set of signals to deassert
|
||||
void deassert_signal(j6_signal_t s);
|
||||
|
||||
class observer
|
||||
{
|
||||
public:
|
||||
/// Callback for when signals change.
|
||||
/// \arg obj The object triggering the callback
|
||||
/// \arg s The current state of obj's signals
|
||||
/// \arg ds Which signals caused the callback
|
||||
/// \arg result Status code for this notification
|
||||
/// \returns True if this object wants to keep watching signals
|
||||
virtual bool on_signals_changed(
|
||||
kobject *obj,
|
||||
j6_signal_t s,
|
||||
j6_signal_t ds,
|
||||
j6_status_t result) = 0;
|
||||
};
|
||||
|
||||
/// Register a signal observer
|
||||
/// \arg object The observer
|
||||
/// \arg s The signals the object wants notifiations for
|
||||
void register_signal_observer(observer *object, j6_signal_t s);
|
||||
|
||||
/// Deegister a signal observer
|
||||
/// \arg object The observer
|
||||
void deregister_signal_observer(observer *object);
|
||||
|
||||
/// Increment the handle refcount
|
||||
inline void handle_retain() { ++m_handle_count; }
|
||||
|
||||
/// Decrement the handle refcount
|
||||
inline void handle_release() {
|
||||
if (--m_handle_count == 0) on_no_handles();
|
||||
}
|
||||
|
||||
protected:
|
||||
kobject() = delete;
|
||||
kobject(const kobject &other) = delete;
|
||||
kobject(const kobject &&other) = delete;
|
||||
|
||||
/// Notifiy observers of this object
|
||||
/// \arg mask The signals that triggered this call. If 0, notify all observers.
|
||||
/// \arg result The result to pass to the observers
|
||||
void notify_signal_observers(j6_signal_t mask, j6_status_t result = j6_status_ok);
|
||||
|
||||
/// Interface for subclasses to handle when all handles are closed. Subclasses
|
||||
/// should either call the base version, or assert j6_signal_no_handles.
|
||||
virtual void on_no_handles();
|
||||
|
||||
j6_koid_t m_koid;
|
||||
j6_signal_t m_signals;
|
||||
uint16_t m_handle_count;
|
||||
|
||||
struct observer_registration
|
||||
{
|
||||
observer_registration(observer* o = nullptr, j6_signal_t s = 0) :
|
||||
object(o), signals(s) {}
|
||||
|
||||
observer *object;
|
||||
j6_signal_t signals;
|
||||
};
|
||||
kutil::vector<observer_registration> m_observers;
|
||||
};
|
||||
Reference in New Issue
Block a user