From f7ae2e2220ca5ca20e2a99986e3b1bb61115f77d Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 21 Feb 2022 19:16:20 -0800 Subject: [PATCH] [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. --- definitions/objects/event.def | 12 +-- definitions/objects/object.def | 16 ---- definitions/objects/system.def | 3 +- definitions/objects/thread.def | 1 - src/kernel/device_manager.cpp | 26 +++--- src/kernel/device_manager.h | 14 +++- src/kernel/kernel.module | 2 + src/kernel/logger.cpp | 6 +- src/kernel/logger.h | 4 + src/kernel/main.cpp | 1 - src/kernel/objects/channel.cpp | 20 ++--- src/kernel/objects/channel.h | 14 ++-- src/kernel/objects/event.cpp | 48 ++++++++++++ src/kernel/objects/event.h | 37 +++++++-- src/kernel/objects/kobject.cpp | 83 +------------------- src/kernel/objects/kobject.h | 55 ++----------- src/kernel/objects/process.cpp | 1 - src/kernel/objects/process.h | 5 ++ src/kernel/objects/thread.cpp | 135 +++----------------------------- src/kernel/objects/thread.h | 87 +++++++------------- src/kernel/objects/vm_area.cpp | 4 +- src/kernel/objects/vm_area.h | 4 +- src/kernel/scheduler.cpp | 6 +- src/kernel/syscalls/event.cpp | 19 +++-- src/kernel/syscalls/object.cpp | 78 ------------------ src/kernel/syscalls/system.cpp | 9 +-- src/kernel/syscalls/thread.cpp | 11 +-- src/kernel/wait_queue.cpp | 50 ++++++++++++ src/kernel/wait_queue.h | 48 ++++++++++++ src/libraries/j6/init.cpp | 53 ++++++------- src/libraries/j6/j6.module | 1 - src/libraries/j6/j6/init.h | 39 +++------ src/libraries/j6/j6/signals.h | 22 ------ src/libraries/util/util/deque.h | 14 +++- src/libraries/util/util/map.h | 36 ++++++--- src/user/drv.uart/main.cpp | 52 +++++------- src/user/drv.uefi_fb/main.cpp | 1 - src/user/srv.init/loader.cpp | 3 +- src/user/srv.init/main.cpp | 26 ++++-- src/user/testapp/main.cpp | 1 - 40 files changed, 419 insertions(+), 628 deletions(-) create mode 100644 src/kernel/objects/event.cpp create mode 100644 src/kernel/wait_queue.cpp create mode 100644 src/kernel/wait_queue.h delete mode 100644 src/libraries/j6/j6/signals.h diff --git a/definitions/objects/event.def b/definitions/objects/event.def index 02b1cc8..85e5f5c 100644 --- a/definitions/objects/event.def +++ b/definitions/objects/event.def @@ -3,18 +3,20 @@ object event : object { capabilities [ signal + wait ] method create [constructor] - # Assert signals on the event from the given bitset + # Signal events on this object method signal [cap:signal] { - param signals uint64 + param signals uint64 # A bitset of which events to signal } - # De-assert signals on the event from the given bitset - method clear [cap:signal] { - param mask uint64 + # Wait for signaled events on this object + method wait [cap:wait] { + param signals uint64 [out] # A bitset of which events were signaled + param timeout uint64 # Wait timeout in nanoseconds } } diff --git a/definitions/objects/object.def b/definitions/objects/object.def index 923f3d9..7b8eb3c 100644 --- a/definitions/objects/object.def +++ b/definitions/objects/object.def @@ -11,20 +11,4 @@ object object [virtual] { method koid { param koid uint64 [out] } - - # Block the current thread waiting for an object to assert - # one of a set of signals - method wait { - param mask uint64 # Bitmap of which signals to wait for - param signals uint64 [out] # Returns the state of the signals - } - - # Block the current thread waiting for an one of multiple - # objects to assert one of a set of signals - method wait_many [static] { - param handles ref object [list] # The objects to wait on - param mask uint64 # Bitmap of which signals to wait for - param handle ref object [out] # Returns the object that signalled - param signals uint64 [out] # Returns the state of the signals - } } diff --git a/definitions/objects/system.def b/definitions/objects/system.def index 33f716b..88fb9e3 100644 --- a/definitions/objects/system.def +++ b/definitions/objects/system.def @@ -21,8 +21,9 @@ object system : object { # Ask the kernel to send this process messages whenever # the given IRQ fires method bind_irq [cap:bind_irq] { - param dest ref endpoint # Endpoint that will receive messages + param dest ref event # Event object that will receive messages param irq uint # IRQ number to bind + param signal uint # Signal number on the event to bind to } # Create a VMA and map an area of physical memory into it, diff --git a/definitions/objects/thread.def b/definitions/objects/thread.def index 418fb25..4e30a60 100644 --- a/definitions/objects/thread.def +++ b/definitions/objects/thread.def @@ -17,7 +17,6 @@ object thread : object { param status int32 } - method pause [static] method sleep [static] { param until uint64 } diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index ae52711..a0a35da 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -12,10 +12,10 @@ #include "interrupts.h" #include "logger.h" #include "memory.h" -#include "objects/endpoint.h" +#include "objects/event.h" -static obj::endpoint * const ignore_endpoint = reinterpret_cast(-1ull); +static obj::event * const ignore_event = reinterpret_cast(-1ull); static const char expected_signature[] = "RSD PTR "; @@ -58,9 +58,9 @@ device_manager::device_manager() : m_irqs.ensure_capacity(32); m_irqs.set_size(16); for (int i = 0; i < 16; ++i) - m_irqs[i] = nullptr; + m_irqs[i] = {nullptr, 0}; - m_irqs[2] = ignore_endpoint; + m_irqs[2] = {ignore_event, 0}; } template static const T * @@ -381,32 +381,32 @@ device_manager::dispatch_irq(unsigned irq) if (irq >= m_irqs.count()) return false; - obj::endpoint *e = m_irqs[irq]; - if (!e || e == ignore_endpoint) - return e == ignore_endpoint; + irq_binding &binding = m_irqs[irq]; + if (!binding.target || binding.target == ignore_event) + return binding.target == ignore_event; - e->signal_irq(irq); + binding.target->signal(1 << binding.signal); return true; } bool -device_manager::bind_irq(unsigned irq, obj::endpoint *target) +device_manager::bind_irq(unsigned irq, obj::event *target, unsigned signal) { // TODO: grow if under max size if (irq >= m_irqs.count()) return false; - m_irqs[irq]= target; + m_irqs[irq] = {target, signal}; return true; } void -device_manager::unbind_irqs(obj::endpoint *target) +device_manager::unbind_irqs(obj::event *target) { const size_t count = m_irqs.count(); for (size_t i = 0; i < count; ++i) { - if (m_irqs[i] == target) - m_irqs[i] = nullptr; + if (m_irqs[i].target == target) + m_irqs[i] = {nullptr, 0}; } } diff --git a/src/kernel/device_manager.h b/src/kernel/device_manager.h index c6c6778..b960a52 100644 --- a/src/kernel/device_manager.h +++ b/src/kernel/device_manager.h @@ -12,7 +12,7 @@ struct acpi_table_header; class block_device; namespace obj { - class endpoint; + class event; } using irq_callback = void (*)(void *); @@ -45,12 +45,13 @@ public: /// Bind an IRQ to an endpoint /// \arg irq The IRQ number to bind /// \arg target The endpoint to recieve messages when the IRQ is signalled + /// \arg signal The event's signal number to bind to /// \returns True on success - bool bind_irq(unsigned irq, obj::endpoint *target); + bool bind_irq(unsigned irq, obj::event *target, unsigned signal); /// Remove IRQ bindings for an endpoint /// \arg target The endpoint to remove - void unbind_irqs(obj::endpoint *target); + void unbind_irqs(obj::event *target); /// Allocate an MSI IRQ for a device /// \arg name Name of the interrupt, for display to user @@ -164,7 +165,12 @@ private: util::vector m_pci; util::vector m_devices; - util::vector m_irqs; + struct irq_binding + { + obj::event *target = nullptr; + unsigned signal = 0; + }; + util::vector m_irqs; util::vector m_blockdevs; diff --git a/src/kernel/kernel.module b/src/kernel/kernel.module index d02f113..b6cb680 100644 --- a/src/kernel/kernel.module +++ b/src/kernel/kernel.module @@ -33,6 +33,7 @@ kernel = module("kernel", "msr.cpp", "objects/channel.cpp", "objects/endpoint.cpp", + "objects/event.cpp", "objects/kobject.cpp", "objects/thread.cpp", "objects/process.cpp", @@ -64,6 +65,7 @@ kernel = module("kernel", "task.s", "tss.cpp", "vm_space.cpp", + "wait_queue.cpp", ]) from glob import glob diff --git a/src/kernel/logger.cpp b/src/kernel/logger.cpp index 1b3d916..9c6bc70 100644 --- a/src/kernel/logger.cpp +++ b/src/kernel/logger.cpp @@ -7,6 +7,7 @@ #include "logger.h" #include "memory.h" #include "objects/system.h" +#include "objects/thread.h" #include "printf/printf.h" static uint8_t log_buffer[128 * 1024]; @@ -87,13 +88,14 @@ logger::output(level severity, logs area, const char *fmt, va_list args) memcpy(out, buffer, n); m_buffer.commit(n); - obj::system &sys = obj::system::get(); - sys.assert_signal(j6_signal_system_has_log); + m_event.signal(1); } size_t logger::get_entry(void *buffer, size_t size) { + m_event.wait(); + util::scoped_lock lock {m_lock}; void *out; diff --git a/src/kernel/logger.h b/src/kernel/logger.h index f7466f5..4f22c70 100644 --- a/src/kernel/logger.h +++ b/src/kernel/logger.h @@ -8,6 +8,8 @@ #include #include +#include "objects/event.h" + enum class logs : uint8_t { #define LOG(name, lvl) name, #include @@ -107,6 +109,8 @@ private: return m_levels[static_cast(area)]; } + obj::event m_event; + level m_levels[areas_count]; immediate_cb m_immediate; diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 7755d1b..23a108f 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include "assert.h" diff --git a/src/kernel/objects/channel.cpp b/src/kernel/objects/channel.cpp index 1cb2613..71b3bc4 100644 --- a/src/kernel/objects/channel.cpp +++ b/src/kernel/objects/channel.cpp @@ -15,7 +15,7 @@ channel::channel() : m_len(0), m_data(g_kernel_buffers.get_section()), m_buffer(reinterpret_cast(m_data), buffer_bytes), - kobject(kobject::type::channel, j6_signal_channel_can_send) + kobject(kobject::type::channel) { } @@ -41,10 +41,10 @@ channel::enqueue(const util::buffer &data) m_buffer.commit(len); if (len) - assert_signal(j6_signal_channel_can_recv); + m_can_recv = true; if (m_buffer.free_space() == 0) - deassert_signal(j6_signal_channel_can_send); + m_can_send = false; return len; } @@ -64,10 +64,10 @@ channel::dequeue(util::buffer buffer) m_buffer.consume(len); if (len) - assert_signal(j6_signal_channel_can_send); + m_can_send = true; if (m_buffer.size() == 0) - deassert_signal(j6_signal_channel_can_recv); + m_can_recv = false; return len; } @@ -76,16 +76,8 @@ void channel::close() { util::scoped_lock lock {m_close_lock}; - - kobject::close(); g_kernel_buffers.return_section(m_data); -} - -void -channel::on_no_handles() -{ - kobject::on_no_handles(); - delete this; + m_closed = true; } } // namespace obj diff --git a/src/kernel/objects/channel.h b/src/kernel/objects/channel.h index 09d70a2..8d286f7 100644 --- a/src/kernel/objects/channel.h +++ b/src/kernel/objects/channel.h @@ -3,7 +3,6 @@ /// Definition of channel objects and related functions #include -#include #include #include #include @@ -26,10 +25,10 @@ public: 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 check_signal(j6_signal_channel_can_send); } + inline bool can_send() const { return m_can_send; } /// Check if the channel has a message wiating already - inline bool can_receive() const { return check_signal(j6_signal_channel_can_recv); } + inline bool can_receive() const { return m_can_recv; } /// Put a message into the channel /// \arg data Buffer of data to write @@ -43,14 +42,17 @@ public: /// Mark this channel as closed, all future calls to enqueue or /// dequeue messages will fail with j6_status_closed. - virtual void close() override; + void close(); -protected: - virtual void on_no_handles() override; + /// 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; }; diff --git a/src/kernel/objects/event.cpp b/src/kernel/objects/event.cpp new file mode 100644 index 0000000..6a975b9 --- /dev/null +++ b/src/kernel/objects/event.cpp @@ -0,0 +1,48 @@ +#include "objects/event.h" +#include "objects/thread.h" + +namespace obj { + +event::event() : + kobject {type::event}, + m_signals {0} +{} + +event::~event() {} + +void +event::signal(uint64_t s) +{ + uint64_t after = __atomic_or_fetch(&m_signals, s, __ATOMIC_SEQ_CST); + if (after) wake_observer(); +} + +uint64_t +event::wait() +{ + // If events are pending, grab those and return immediately + uint64_t value = read(); + if (value) + return value; + + // Wait for event::signal() to wake us with a value + thread ¤t = thread::current(); + m_queue.add_thread(¤t); + return current.block(); +} + +void +event::wake_observer() +{ + util::scoped_lock lock {m_queue.get_lock()}; + thread *t = m_queue.get_next_unlocked(); + if (!t) return; + + uint64_t value = read(); + if (value) { + m_queue.pop_next_unlocked(); + t->wake(value); + } +} + +} // namespace obj diff --git a/src/kernel/objects/event.h b/src/kernel/objects/event.h index 584e3cc..26becad 100644 --- a/src/kernel/objects/event.h +++ b/src/kernel/objects/event.h @@ -2,21 +2,48 @@ /// \file event.h /// Definition of event kobject types +#include +#include + #include "objects/kobject.h" +#include "wait_queue.h" namespace obj { +class thread; + class event : public kobject { public: /// Capabilities on a newly constructed event handle - constexpr static j6_cap_t creation_caps = 0; - - event() : - kobject(type::event) {} - + constexpr static j6_cap_t creation_caps = j6_cap_event_all; static constexpr kobject::type type = kobject::type::event; + + event(); + ~event(); + + /// Signal the given event(s). + /// \arg s The events to signal, as a bitset + void signal(uint64_t s); + + /// Wait for events to be signalled. If events have already + /// been signaled since the last call to wait, return them + /// immediately. + /// \returns The events which have been signalled, as a bitset + uint64_t wait(); + +private: + /// Read and consume the current signaled events + inline uint64_t read() { + return __atomic_exchange_n(&m_signals, 0, __ATOMIC_SEQ_CST); + } + + /// Wake an observer to handle an incoming event + void wake_observer(); + + uint64_t m_signals; + wait_queue m_queue; }; } // namespace obj diff --git a/src/kernel/objects/kobject.cpp b/src/kernel/objects/kobject.cpp index fe7970a..8b2adb5 100644 --- a/src/kernel/objects/kobject.cpp +++ b/src/kernel/objects/kobject.cpp @@ -1,5 +1,4 @@ #include -#include #include #include "assert.h" @@ -10,17 +9,12 @@ namespace obj { static j6_koid_t next_koids [static_cast(kobject::type::max)] = { 0 }; -kobject::kobject(type t, j6_signal_t signals) : +kobject::kobject(type t) : m_koid(koid_generate(t)), - m_signals(signals), m_handle_count(0) {} -kobject::~kobject() -{ - for (auto *t : m_blocked_threads) - t->wake_on_result(this, j6_status_destroyed); -} +kobject::~kobject() {} j6_koid_t kobject::koid_generate(type t) @@ -37,81 +31,10 @@ kobject::koid_type(j6_koid_t koid) return static_cast((koid >> 48) & 0xffffull); } -j6_signal_t -kobject::assert_signal(j6_signal_t s) -{ - j6_signal_t old = - __atomic_fetch_or(&m_signals, s, __ATOMIC_SEQ_CST); - notify_signal_observers(); - return old; -} - -j6_signal_t -kobject::deassert_signal(j6_signal_t s) -{ - return __atomic_fetch_and(&m_signals, ~s, __ATOMIC_SEQ_CST); -} - -void -kobject::compact_blocked_threads() -{ - // Clean up what we can of the list - while (!m_blocked_threads.empty() && !m_blocked_threads.first()) - m_blocked_threads.pop_front(); - while (!m_blocked_threads.empty() && !m_blocked_threads.last()) - m_blocked_threads.pop_back(); -} - -void -kobject::notify_signal_observers() -{ - for (auto &entry : m_blocked_threads) { - if (entry == nullptr) continue; - if (entry->wake_on_signals(this, m_signals)) - entry = nullptr; - } - compact_blocked_threads(); -} - -void -kobject::notify_object_observers(size_t count) -{ - if (!count) return; - - for (auto &entry : m_blocked_threads) { - if (entry == nullptr) continue; - if (entry->wake_on_object(this)) { - entry = nullptr; - if (--count) break; - } - } - compact_blocked_threads(); -} - -void -kobject::remove_blocked_thread(thread *t) -{ - // Can't really remove from a deque, so just - // null out removed entries. - for (auto &entry : m_blocked_threads) { - if (entry == t) { - entry = nullptr; - break; - } - } - compact_blocked_threads(); -} - -void -kobject::close() -{ - assert_signal(j6_signal_closed); -} - void kobject::on_no_handles() { - assert_signal(j6_signal_no_handles); + delete this; } } // namespace obj diff --git a/src/kernel/objects/kobject.h b/src/kernel/objects/kobject.h index b719619..58fa239 100644 --- a/src/kernel/objects/kobject.h +++ b/src/kernel/objects/kobject.h @@ -3,9 +3,7 @@ /// Definition of base type for user-interactable kernel objects #include -#include #include -#include namespace obj { @@ -25,7 +23,7 @@ public: max }; - kobject(type t, j6_signal_t signals = 0ull); + kobject(type t); virtual ~kobject(); /// Generate a new koid for a given type @@ -44,23 +42,6 @@ public: /// Get this object's koid inline j6_koid_t koid() const { return m_koid; } - /// Set the given signals active on this object - /// \arg s The set of signals to assert - /// \returns The previous state of the signals - j6_signal_t assert_signal(j6_signal_t s); - - /// Clear the given signals on this object - /// \arg s The set of signals to deassert - /// \returns The previous state of the signals - j6_signal_t deassert_signal(j6_signal_t s); - - /// Check if the given signals are set on this object - /// \arg s The set of signals to check - inline bool check_signal(j6_signal_t s) const { return (m_signals & s) == s; } - - /// Get the current object signal state - inline j6_signal_t signals() const { return m_signals; } - /// Increment the handle refcount inline void handle_retain() { ++m_handle_count; } @@ -69,45 +50,21 @@ public: if (--m_handle_count == 0) on_no_handles(); } - /// Add the given thread to the list of threads waiting on this object. - inline void add_blocked_thread(thread *t) { m_blocked_threads.push_back(t); } - - /// Remove the given thread from the list of threads waiting on this object. - void remove_blocked_thread(thread *t); - - /// Perform any cleanup actions necessary to mark this object closed - virtual void close(); - - /// Check if this object has been closed - inline bool closed() const { return check_signal(j6_signal_closed); } - protected: - /// Interface for subclasses to handle when all handles are closed. Subclasses - /// should either call the base version, or assert j6_signal_no_handles. + /// Interface for subclasses to handle when all handles are closed. + /// Default implementation deletes the object. virtual void on_no_handles(); + /// Get the current number of handles to this object + inline uint16_t handle_count() const { return m_handle_count; } + private: kobject() = delete; kobject(const kobject &other) = delete; kobject(const kobject &&other) = delete; - /// Notifiy observers of this object - /// \arg result The result to pass to the observers - void notify_signal_observers(); - - /// Compact the blocked threads deque - void compact_blocked_threads(); - j6_koid_t m_koid; - j6_signal_t m_signals; uint16_t m_handle_count; - -protected: - /// Notify threads waiting on this object - /// \arg count Number of observers to wake, or -1ull for all - void notify_object_observers(size_t count = -1ull); - - util::deque m_blocked_threads; }; } // namespace obj diff --git a/src/kernel/objects/process.cpp b/src/kernel/objects/process.cpp index 3f55842..31aa45a 100644 --- a/src/kernel/objects/process.cpp +++ b/src/kernel/objects/process.cpp @@ -53,7 +53,6 @@ process::exit(int32_t code) // TODO: make this thread-safe m_state = state::exited; m_return_code = code; - close(); for (auto *thread : m_threads) { thread->exit(code); diff --git a/src/kernel/objects/process.h b/src/kernel/objects/process.h index 89ad87e..2bae4da 100644 --- a/src/kernel/objects/process.h +++ b/src/kernel/objects/process.h @@ -103,6 +103,11 @@ public: /// \returns The kernel process object static process * create_kernel_process(page_table *pml4); +protected: + /// Don't delete a process on no handles, the scheduler takes + /// care of that. + virtual void on_no_handles() override {} + private: // This constructor is called by create_kernel_process process(page_table *kpml4); diff --git a/src/kernel/objects/thread.cpp b/src/kernel/objects/thread.cpp index d65acd3..7cf7161 100644 --- a/src/kernel/objects/thread.cpp +++ b/src/kernel/objects/thread.cpp @@ -1,4 +1,3 @@ -#include #include #include "cpu.h" @@ -15,15 +14,12 @@ extern obj::vm_area_guarded &g_kernel_stacks; namespace obj { -static constexpr j6_signal_t thread_default_signals = 0; - thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) : - kobject(kobject::type::thread, thread_default_signals), - m_parent(parent), - m_state(state::none), - m_wait_type(wait_type::none), - m_wait_data(0), - m_wait_obj(0) + kobject {kobject::type::thread}, + m_parent {parent}, + m_state {state::none}, + m_wake_value {0}, + m_wake_timeout {0} { parent.space().initialize_tcb(m_tcb); m_tcb.priority = pri; @@ -45,129 +41,20 @@ thread::~thread() thread & thread::current() { return *current_cpu().thread; } -j6_status_t -thread::wait_on_signals(j6_signal_t signals) -{ - util::scoped_lock lock {m_wait_lock}; - - m_wait_type = wait_type::signal; - m_wait_data = signals; - - lock.release(); - block(); - - return m_wait_result; -} - -j6_status_t -thread::wait_on_time(uint64_t t) -{ - util::scoped_lock lock {m_wait_lock}; - - m_wait_type = wait_type::time; - m_wait_time = t; - - lock.release(); - block(); - - return m_wait_result; -} - -j6_status_t -thread::wait_on_object(void *o, uint64_t t) -{ - util::scoped_lock lock {m_wait_lock}; - - m_wait_type = wait_type::object; - m_wait_data = reinterpret_cast(o); - - if (t) { - m_wait_type |= wait_type::time; - m_wait_time = t; - } - - lock.release(); - block(); - return m_wait_result; -} - -bool -thread::wake_on_signals(kobject *obj, j6_signal_t signals) -{ - util::scoped_lock lock {m_wait_lock}; - - if (!(m_wait_type & wait_type::signal) || - (signals & m_wait_data) == 0) - return false; - - m_wait_type = wait_type::none; - m_wait_result = j6_status_ok; - m_wait_data = signals; - m_wait_obj = obj->koid(); - set_state(state::ready); - return true; -} - -bool -thread::wake_on_time(uint64_t now) -{ - util::scoped_lock lock {m_wait_lock}; - - if (!(m_wait_type & wait_type::time) || - now < m_wait_time) - return false; - - if (!(m_wait_type & ~wait_type::none)) - m_wait_result = j6_status_ok; - else - m_wait_result = j6_err_timed_out; - - m_wait_type = wait_type::none; - m_wait_data = now; - m_wait_obj = 0; - set_state(state::ready); - return true; -} - -bool -thread::wake_on_object(void *o, uint64_t id) -{ - util::scoped_lock lock {m_wait_lock}; - - if (!(m_wait_type & wait_type::object) || - reinterpret_cast(o) != m_wait_data) - return false; - - m_wait_type = wait_type::none; - m_wait_result = j6_status_ok; - m_wait_obj = id; - set_state(state::ready); - return true; -} - -void -thread::wake_on_result(kobject *obj, j6_status_t result) -{ - util::scoped_lock lock {m_wait_lock}; - - m_wait_type = wait_type::none; - m_wait_result = result; - m_wait_data = 0; - m_wait_obj = obj->koid(); - set_state(state::ready); -} - -void +uint64_t thread::block() { clear_state(state::ready); if (current_cpu().thread == this) scheduler::get().schedule(); + return m_wake_value; } void -thread::wake() +thread::wake(uint64_t value) { + m_wake_value = value; + m_wake_timeout = 0; set_state(state::ready); } @@ -175,8 +62,8 @@ void thread::exit(int32_t code) { m_return_code = code; + m_wake_timeout = 0; set_state(state::exited); - close(); block(); } diff --git a/src/kernel/objects/thread.h b/src/kernel/objects/thread.h index c0c3578..98b22df 100644 --- a/src/kernel/objects/thread.h +++ b/src/kernel/objects/thread.h @@ -29,14 +29,14 @@ struct TCB obj::thread* thread; uint8_t priority; + // note: 3 bytes padding - // TODO: move state into TCB? - uintptr_t kernel_stack; - uint32_t time_left; uint64_t last_ran; + + uintptr_t kernel_stack; }; using tcb_list = util::linked_list; @@ -90,6 +90,10 @@ public: /// \returns True if the thread has constant priority. inline bool constant() const { return has_state(state::constant); } + /// Get the `exited` state of the thread. + /// \returns True if the thread has exited. + inline bool exited() const { return has_state(state::exited); } + /// Get the thread priority. inline uint8_t priority() const { return m_tcb.priority; } @@ -97,58 +101,21 @@ public: /// \arg p The new thread priority inline void set_priority(uint8_t p) { if (!constant()) m_tcb.priority = p; } - /// Block the thread, waiting an object's signals. - /// \arg signals Mask of signals to wait for - /// \returns j6_status_ok on success - j6_status_t wait_on_signals(j6_signal_t signals); + /// Block this thread, waiting for a value + /// \returns The value passed to wake() + uint64_t block(); - /// Block the thread, waiting for a given clock value - /// \arg t Clock value to wait for - /// \returns j6_status_ok on success - j6_status_t wait_on_time(uint64_t t); + /// Wake this thread, giving it a value + /// \arg value The value that block() should return + void wake(uint64_t value = 0); - /// Block the thread, waiting on the given object - /// \arg o The object that should wake this thread - /// \arg t The timeout clock value to wait for - /// \returns j6_status_ok on success - j6_status_t wait_on_object(void *o, uint64_t t = 0); + /// Set a timeout to unblock this thread + /// \arg time The clock time at which to wake. 0 for no timeout. + inline void set_wake_timeout(uint64_t time) { m_wake_timeout = time; } - /// Wake the thread if it is waiting on signals. - /// \arg obj Object that changed signals - /// \arg signals Signal state of the object - /// \returns True if this action unblocked the thread - bool wake_on_signals(kobject *obj, j6_signal_t signals); - - /// Wake the thread if it is waiting on the clock. - /// \arg now Current clock value - /// \returns True if this action unblocked the thread - bool wake_on_time(uint64_t now); - - /// Wake the thread if it is waiting on the given object. - /// \arg o Object trying to wake the thread - /// \arg id Id of the object trying to wake the thread - /// \returns True if this action unblocked the thread - bool wake_on_object(void *o, uint64_t id = 0); - - /// Wake the thread with a given result code. - /// \arg obj Object that changed signals - /// \arg result Result code to return to the thread - void wake_on_result(kobject *obj, j6_status_t result); - - /// Get the result status code from the last blocking operation - j6_status_t get_wait_result() const { return m_wait_result; } - - /// Get the current blocking opreation's wait data - uint64_t get_wait_data() const { return m_wait_data; } - - /// Get the current blocking operation's wait ojbect (as a handle) - j6_koid_t get_wait_object() const { return m_wait_obj; } - - /// Primitive thread blocking, instead of using wait framework - void block(); - - /// Primitive thread unblocking, instead of using wait framework - void wake(); + /// Get the timeout at which to unblock this thread + /// \returns The clock time at which to wake. 0 for no timeout. + inline uint64_t wake_timeout() const { return m_wake_timeout; } inline bool has_state(state s) const { return static_cast(m_state) & static_cast(s); @@ -189,6 +156,11 @@ public: /// \arg rsp The existing stack for the idle thread static thread * create_idle_thread(process &kernel, uint8_t pri, uintptr_t rsp); +protected: + /// Don't delete a thread on no handles, the scheduler takes + /// care of that. + virtual void on_no_handles() override {} + private: thread() = delete; thread(const thread &other) = delete; @@ -210,16 +182,13 @@ private: thread *m_creator; state m_state; - wait_type m_wait_type; - // There should be 1 byte of padding here + + // There should be 3 bytes of padding here int32_t m_return_code; - uint64_t m_wait_data; - uint64_t m_wait_time; - j6_status_t m_wait_result; - uint64_t m_wait_obj; - util::spinlock m_wait_lock; + uint64_t m_wake_value; + uint64_t m_wake_timeout; j6_handle_t m_self_handle; }; diff --git a/src/kernel/objects/vm_area.cpp b/src/kernel/objects/vm_area.cpp index dfe48ec..85318fd 100644 --- a/src/kernel/objects/vm_area.cpp +++ b/src/kernel/objects/vm_area.cpp @@ -35,15 +35,13 @@ void vm_area::remove_from(vm_space *space) { m_spaces.remove_swap(space); - if (!m_spaces.count() && - check_signal(j6_signal_no_handles)) + if (!m_spaces.count() && !handle_count()) delete this; } void vm_area::on_no_handles() { - kobject::on_no_handles(); if (!m_spaces.count()) delete this; } diff --git a/src/kernel/objects/vm_area.h b/src/kernel/objects/vm_area.h index 585d746..12f4ee7 100644 --- a/src/kernel/objects/vm_area.h +++ b/src/kernel/objects/vm_area.h @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -76,7 +75,10 @@ public: virtual bool get_page(uintptr_t offset, uintptr_t &phys) = 0; protected: + /// A VMA is not deleted until both no handles remain AND it's not + /// mapped by any VM space. virtual void on_no_handles() override; + bool can_resize(size_t size); size_t m_size; diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index b7f1101..ea80db5 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -126,13 +126,15 @@ scheduler::prune(run_queue &queue, uint64_t now) thread *th = tcb->thread; uint8_t priority = tcb->priority; + uint64_t timeout = th->wake_timeout(); + if (timeout && timeout <= now) + th->wake(); + bool ready = th->has_state(thread::state::ready); bool exited = th->has_state(thread::state::exited); bool constant = th->has_state(thread::state::constant); bool current = tcb == queue.current; - ready |= th->wake_on_time(now); - auto *remove = tcb; tcb = tcb->next(); if (!exited && !ready) diff --git a/src/kernel/syscalls/event.cpp b/src/kernel/syscalls/event.cpp index 9a386b7..5a3b4d1 100644 --- a/src/kernel/syscalls/event.cpp +++ b/src/kernel/syscalls/event.cpp @@ -1,7 +1,8 @@ #include -#include +#include "clock.h" #include "objects/event.h" +#include "objects/thread.h" #include "syscalls/helpers.h" using namespace obj; @@ -18,17 +19,21 @@ event_create(j6_handle_t *self) j6_status_t event_signal(event *self, j6_signal_t signals) { - if (signals & j6_signal_global_mask) - return j6_err_invalid_arg; - - self->assert_signal(signals); + self->signal(signals); return j6_status_ok; } j6_status_t -event_clear(event *self, j6_signal_t mask) +event_wait(event *self, j6_signal_t *signals, uint64_t timeout) { - self->deassert_signal(~mask); + thread& t = thread::current(); + + if (timeout) { + timeout += clock::get().value(); + t.set_wake_timeout(timeout); + } + + *signals = self->wait(); return j6_status_ok; } diff --git a/src/kernel/syscalls/object.cpp b/src/kernel/syscalls/object.cpp index d4179ea..f838497 100644 --- a/src/kernel/syscalls/object.cpp +++ b/src/kernel/syscalls/object.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -19,81 +18,4 @@ object_koid(kobject *self, j6_koid_t *koid) return j6_status_ok; } -j6_status_t -object_wait(kobject *self, j6_signal_t mask, j6_signal_t *sigs) -{ - j6_signal_t current = self->signals(); - if ((current & mask) != 0) { - *sigs = current; - return j6_status_ok; - } - - thread &th = thread::current(); - self->add_blocked_thread(&th); - th.wait_on_signals(mask); - - j6_status_t result = th.get_wait_result(); - if (result == j6_status_ok) { - *sigs = th.get_wait_data(); - } - return result; -} - -j6_status_t -object_wait_many(j6_handle_t * handles, size_t handles_count, uint64_t mask, j6_handle_t * woken, uint64_t * signals) -{ - util::vector objects {uint32_t(handles_count)}; - - for (unsigned i = 0; i < handles_count; ++i) { - j6_handle_t hid = handles[i]; - if (hid == j6_handle_invalid) - continue; - - handle *h = get_handle(hid); - if (!h || !h->object) - return j6_err_invalid_arg; - kobject *obj = h->object; - - j6_signal_t current = obj->signals(); - if ((current & mask) != 0) { - *signals = current; - *woken = hid; - return j6_status_ok; - } - - objects.append(obj); - } - - thread &th = thread::current(); - for (auto *obj : objects) - obj->add_blocked_thread(&th); - - th.wait_on_signals(mask); - - j6_status_t result = th.get_wait_result(); - if (result != j6_status_ok) - return result; - - *woken = j6_handle_invalid; - *signals = th.get_wait_data(); - j6_koid_t koid = th.get_wait_object(); - for (unsigned i = 0; i < handles_count; ++i) { - if (koid == objects[i]->koid()) - *woken = handles[i]; - else - objects[i]->remove_blocked_thread(&th); - } - - kassert(*woken != j6_handle_invalid, - "Somehow woke on a handle that was not waited on"); - return j6_status_ok; -} - -j6_status_t -object_close(kobject *self) -{ - self->close(); - return j6_status_ok; -} - } // namespace syscalls diff --git a/src/kernel/syscalls/system.cpp b/src/kernel/syscalls/system.cpp index 47a7060..2e9d0fa 100644 --- a/src/kernel/syscalls/system.cpp +++ b/src/kernel/syscalls/system.cpp @@ -6,7 +6,7 @@ #include "frame_allocator.h" #include "logger.h" #include "memory.h" -#include "objects/endpoint.h" +#include "objects/event.h" #include "objects/thread.h" #include "objects/system.h" #include "objects/vm_area.h" @@ -49,16 +49,13 @@ system_get_log(system *self, void *buffer, size_t *buffer_len) { size_t orig_size = *buffer_len; *buffer_len = g_logger.get_entry(buffer, *buffer_len); - if (!g_logger.has_log()) - self->deassert_signal(j6_signal_system_has_log); - return (*buffer_len > orig_size) ? j6_err_insufficient : j6_status_ok; } j6_status_t -system_bind_irq(system *self, endpoint *endp, unsigned irq) +system_bind_irq(system *self, event *dest, unsigned irq, unsigned signal) { - if (device_manager::get().bind_irq(irq, endp)) + if (device_manager::get().bind_irq(irq, dest, signal)) return j6_status_ok; return j6_err_invalid_arg; diff --git a/src/kernel/syscalls/thread.cpp b/src/kernel/syscalls/thread.cpp index 4debc09..0d3c01e 100644 --- a/src/kernel/syscalls/thread.cpp +++ b/src/kernel/syscalls/thread.cpp @@ -46,21 +46,14 @@ thread_kill(thread *self) return j6_status_ok; } -j6_status_t -thread_pause() -{ - thread &th = thread::current(); - th.wait_on_signals(-1ull); - return j6_status_ok; -} - j6_status_t thread_sleep(uint64_t til) { thread &th = thread::current(); log::debug(logs::task, "Thread %llx sleeping until %llu", th.koid(), til); - th.wait_on_time(til); + th.set_wake_timeout(til); + th.block(); return j6_status_ok; } diff --git a/src/kernel/wait_queue.cpp b/src/kernel/wait_queue.cpp new file mode 100644 index 0000000..9920830 --- /dev/null +++ b/src/kernel/wait_queue.cpp @@ -0,0 +1,50 @@ +#include "objects/thread.h" +#include "wait_queue.h" + +wait_queue::~wait_queue() +{ + util::scoped_lock lock {m_lock}; + for (auto *t : m_threads) { + if (!t->exited()) t->wake(); + t->handle_release(); + } +} + +void +wait_queue::add_thread(obj::thread *t) +{ + util::scoped_lock lock {m_lock}; + t->handle_retain(); + m_threads.push_back(t); +} + +void +wait_queue::pop_exited() +{ + while (!m_threads.empty()) { + obj::thread *t = m_threads.first(); + if (!t->exited()) + break; + + m_threads.pop_front(); + t->handle_release(); + } +} + +obj::thread * +wait_queue::get_next_unlocked() +{ + pop_exited(); + if (m_threads.empty()) + return nullptr; + return m_threads.first(); +} + +obj::thread * +wait_queue::pop_next_unlocked() +{ + pop_exited(); + if (m_threads.empty()) + return nullptr; + return m_threads.pop_front(); +} diff --git a/src/kernel/wait_queue.h b/src/kernel/wait_queue.h new file mode 100644 index 0000000..a440f83 --- /dev/null +++ b/src/kernel/wait_queue.h @@ -0,0 +1,48 @@ +#pragma once +/// \file wait_queue.h +/// Class and related defintions for keeping a queue of waiting threads + +#include +#include + +namespace obj { + class thread; +} + +class wait_queue +{ +public: + /// Wake all threads when destructing + ~wait_queue(); + + /// Add the given thread to the queue. Locks the + /// queue lock. + void add_thread(obj::thread *t); + + /// Pops the next waiting thread off the queue. + /// Locks the queue lock. + inline obj::thread * pop_next() { + util::scoped_lock lock {m_lock}; + return pop_next_unlocked(); + } + + /// Get the next waiting thread. Does not lock the + /// queue lock. + obj::thread * get_next_unlocked(); + + /// Pop the next thread off the queue. Does not + /// lock the queue lock. + obj::thread * pop_next_unlocked(); + + /// Get the spinlock to lock this queue + util::spinlock & get_lock() { return m_lock; } + +private: + /// Get rid of any exited threads that are next + /// in the queue. Caller must hold the queue lock. + void pop_exited(); + + util::spinlock m_lock; + util::deque m_threads; +}; + diff --git a/src/libraries/j6/init.cpp b/src/libraries/j6/init.cpp index cc24b19..65e671e 100644 --- a/src/libraries/j6/init.cpp +++ b/src/libraries/j6/init.cpp @@ -9,43 +9,38 @@ #include #include -j6_handle_t __handle_sys; j6_handle_t __handle_self; namespace { - constexpr size_t __static_arr_size = 4; - j6_handle_t __handle_array[__static_arr_size]; - - static j6_status_t - load_handles() - { - size_t count = __static_arr_size; - j6_handle_t *handles = __handle_array; - j6_status_t s = j6_handle_list(handles, &count); - - if (s != j6_err_insufficient && s != j6_status_ok) - return s; - - if (count > __static_arr_size) - count = __static_arr_size; - - for (size_t i = 0; i < count; ++i) { - uint8_t type = (handles[i] >> 56); - if (type == j6_object_type_system && __handle_sys == j6_handle_invalid) - __handle_sys = handles[i]; - else if (type == j6_object_type_process && __handle_self == j6_handle_invalid) - __handle_self = handles[i]; - } - - return s; - } + constexpr size_t static_arr_size = 8; + j6_handle_t handle_array[static_arr_size]; } // namespace +j6_handle_t +j6_find_first_handle(j6_object_type obj_type) +{ + size_t count = static_arr_size; + j6_handle_t *handles = handle_array; + j6_status_t s = j6_handle_list(handles, &count); + + if (s != j6_err_insufficient && s != j6_status_ok) + return j6_handle_invalid; + + if (count > static_arr_size) + count = static_arr_size; + + for (size_t i = 0; i < count; ++i) { + uint8_t type = (handles[i] >> 56); + if (type == obj_type) return handles[i]; + } + + return j6_handle_invalid; +} + extern "C" void __init_libj6(uint64_t *rsp) { - __handle_sys = __handle_self = j6_handle_invalid; - load_handles(); + __handle_self = j6_find_first_handle(j6_object_type_process); } #endif // __j6kernel diff --git a/src/libraries/j6/j6.module b/src/libraries/j6/j6.module index 78e5c88..68e209d 100644 --- a/src/libraries/j6/j6.module +++ b/src/libraries/j6/j6.module @@ -12,7 +12,6 @@ j6 = module("j6", "j6/errors.h", "j6/flags.h", "j6/init.h", - "j6/signals.h", "j6/syscalls.h.cog", "j6/sysconf.h.cog", "j6/types.h", diff --git a/src/libraries/j6/j6/init.h b/src/libraries/j6/j6/init.h index c65827c..0fdec8f 100644 --- a/src/libraries/j6/j6/init.h +++ b/src/libraries/j6/j6/init.h @@ -1,37 +1,16 @@ #pragma once /// \file init.h -/// Types used in process and thread initialization +/// Process initialization utility functions -#include #include -enum j6_init_type { // `value` is a: - j6_init_handle_self, // Handle to the system - j6_init_handle_other, // Handle to this process - j6_init_desc_framebuffer // Pointer to a j6_init_framebuffer descriptor -}; +#ifdef __cplusplus +extern "C" { +#endif -struct j6_typed_handle { - enum j6_object_type type; - j6_handle_t handle; -}; +/// Find the first handle of the given type held by this process +j6_handle_t j6_find_first_handle(j6_object_type obj_type); -struct j6_init_value { - enum j6_init_type type; - union { - struct j6_typed_handle handle; - void *data; - }; -}; - -/// Structure defining a framebuffer. -/// `flags` has the following bits: -/// 0-3: Pixel layout. 0000: rgb8, 0001: bgr8 -struct j6_init_framebuffer { - uintptr_t addr; - size_t size; - uint32_t vertical; - uint32_t horizontal; - uint32_t scanline; - uint32_t flags; -}; +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/libraries/j6/j6/signals.h b/src/libraries/j6/j6/signals.h deleted file mode 100644 index 83c9711..0000000 --- a/src/libraries/j6/j6/signals.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -/// \file signals.h -/// Collection of constants for the j6_signal_t type - -// Signals 56-63 are common to all types -#define j6_signal_no_handles (1ull << 56) -#define j6_signal_closed (1ull << 57) -#define j6_signal_global_mask 0xff00000000000000 - -// Signals 0-55 are defined per object type - -// System signals -#define j6_signal_system_has_log (1ull << 0) - -// Channel signals -#define j6_signal_channel_can_send (1ull << 0) -#define j6_signal_channel_can_recv (1ull << 1) - -// Endpoint signals -#define j6_signal_endpoint_can_send (1ull << 0) -#define j6_signal_endpoint_can_recv (1ull << 1) - diff --git a/src/libraries/util/util/deque.h b/src/libraries/util/util/deque.h index 599e789..b4ad093 100644 --- a/src/libraries/util/util/deque.h +++ b/src/libraries/util/util/deque.h @@ -3,6 +3,7 @@ /// A generic templatized linked list. #include +#include #include namespace util { @@ -42,7 +43,9 @@ public: inline void push_front(const T& item) { if (!m_first) { // need a new block at the start - m_list.push_front(new node_type); + node_type *n = new node_type; + memset(n, 0, sizeof(node_type)); + m_list.push_front(n); m_first = N; } m_list.front()->items[--m_first] = item; @@ -50,7 +53,9 @@ public: inline void push_back(const T& item) { if (m_next == N) { // need a new block at the end - m_list.push_back(new node_type); + node_type *n = new node_type; + memset(n, 0, sizeof(node_type)); + m_list.push_back(n); m_next = 0; } m_list.back()->items[m_next++] = item; @@ -80,7 +85,10 @@ public: return value; } - inline bool empty() const { return m_list.empty(); } + inline bool empty() const { + return m_list.empty() || + m_list.length() == 1 && m_first == m_next; + } inline T& first() { assert(!empty() && "Calling first() on an empty deque"); diff --git a/src/libraries/util/util/map.h b/src/libraries/util/util/map.h index 8d49914..ca09ca0 100644 --- a/src/libraries/util/util/map.h +++ b/src/libraries/util/util/map.h @@ -119,7 +119,22 @@ public: { node *n = lookup(k); if (!n) return false; + erase(n); + return true; + } + inline size_t count() const { return m_count; } + inline size_t capacity() const { return m_capacity; } + inline size_t threshold() const { return (m_capacity * max_load) / 100; } + +protected: + inline size_t mod(uint64_t i) const { return i & (m_capacity - 1); } + inline size_t offset(uint64_t h, size_t i) const { + return mod(i + m_capacity - mod(h)); + } + + void erase(node *n) + { n->~node(); --m_count; @@ -132,18 +147,6 @@ public: m.~node(); i = mod(++i); } - - return true; - } - - inline size_t count() const { return m_count; } - inline size_t capacity() const { return m_capacity; } - inline size_t threshold() const { return (m_capacity * max_load) / 100; } - -protected: - inline size_t mod(uint64_t i) const { return i & (m_capacity - 1); } - inline size_t offset(uint64_t h, size_t i) const { - return mod(i + m_capacity - mod(h)); } void set_capacity(size_t capacity) { @@ -263,7 +266,8 @@ public: V * find(const K &k) { node *n = this->lookup(k); - return n ? &n->val : nullptr; + V *val = n ? &n->val : nullptr; + return val; } const V * find(const K &k) const { @@ -285,6 +289,12 @@ public: map(size_t capacity = 0) : base(capacity) {} + V * find(const K &k) { + node *n = this->lookup(k); + V *val = n ? n->val : nullptr; + return val; + } + V * find(const K &k) const { const node *n = this->lookup(k); return n ? n->val : nullptr; diff --git a/src/user/drv.uart/main.cpp b/src/user/drv.uart/main.cpp index 3ef1b23..782431c 100644 --- a/src/user/drv.uart/main.cpp +++ b/src/user/drv.uart/main.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include @@ -19,7 +19,7 @@ extern "C" { } extern j6_handle_t __handle_self; -extern j6_handle_t __handle_sys; +j6_handle_t g_handle_sys = j6_handle_invalid; struct entry { @@ -76,13 +76,13 @@ log_pump_proc() void *message_buffer = nullptr; char stringbuf[300]; - j6_status_t result = j6_system_request_iopl(__handle_sys, 3); + j6_status_t result = j6_system_request_iopl(g_handle_sys, 3); if (result != j6_status_ok) return; while (true) { size_t size = buffer_size; - j6_status_t s = j6_system_get_log(__handle_sys, message_buffer, &size); + j6_status_t s = j6_system_get_log(g_handle_sys, message_buffer, &size); if (s == j6_err_insufficient) { free(message_buffer); @@ -94,12 +94,6 @@ log_pump_proc() continue; } - if (size == 0) { - j6_signal_t sigs = 0; - j6_object_wait(__handle_sys, j6_signal_system_has_log, &sigs); - continue; - } - const entry *e = reinterpret_cast(message_buffer); const char *area_name = area_names[e->area]; @@ -118,22 +112,26 @@ main(int argc, const char **argv) { j6_log("uart driver starting"); - j6_handle_t endp = j6_handle_invalid; + j6_handle_t event = j6_handle_invalid; j6_status_t result = j6_status_ok; - result = j6_system_request_iopl(__handle_sys, 3); + g_handle_sys = j6_find_first_handle(j6_object_type_system); + if (g_handle_sys == j6_handle_invalid) + return 1; + + result = j6_system_request_iopl(g_handle_sys, 3); if (result != j6_status_ok) return result; - result = j6_endpoint_create(&endp); + result = j6_event_create(&event); if (result != j6_status_ok) return result; - result = j6_system_bind_irq(__handle_sys, endp, 3); + result = j6_system_bind_irq(g_handle_sys, event, 3, 0); if (result != j6_status_ok) return result; - result = j6_system_bind_irq(__handle_sys, endp, 4); + result = j6_system_bind_irq(g_handle_sys, event, 4, 1); if (result != j6_status_ok) return result; @@ -159,8 +157,8 @@ main(int argc, const char **argv) size_t len = 0; while (true) { - uint64_t tag = 0; - result = j6_endpoint_receive(endp, &tag, nullptr, &len, 10000); + uint64_t signals = 0; + result = j6_event_wait(event, &signals, 1000); if (result == j6_err_timed_out) { com1.handle_interrupt(); com2.handle_interrupt(); @@ -172,22 +170,10 @@ main(int argc, const char **argv) continue; } - if (!j6_tag_is_irq(tag)) { - j6_log("uart driver got non-irq waiting for irq"); - continue; - } - - unsigned irq = j6_tag_to_irq(tag); - switch (irq) { - case 3: - com2.handle_interrupt(); - break; - case 4: - com1.handle_interrupt(); - break; - default: - j6_log("uart driver got unknown irq waiting for irq"); - } + if (signals & (1<<0)) + com2.handle_interrupt(); + if (signals & (1<<1)) + com1.handle_interrupt(); } j6_log("uart driver somehow got to the end of main"); diff --git a/src/user/drv.uefi_fb/main.cpp b/src/user/drv.uefi_fb/main.cpp index d66bc8c..803153f 100644 --- a/src/user/drv.uefi_fb/main.cpp +++ b/src/user/drv.uefi_fb/main.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index fe544ba..ff48820 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -13,7 +13,6 @@ using bootproto::module_flags; using bootproto::module_program; extern j6_handle_t __handle_self; -extern j6_handle_t __handle_sys; constexpr uintptr_t load_addr = 0xf8000000; constexpr size_t stack_size = 0x10000; @@ -28,7 +27,7 @@ load_program(const module_program &prog, j6_handle_t sys, char *err_msg) } j6_handle_t elf_vma = j6_handle_invalid; - j6_status_t res = j6_system_map_phys(__handle_sys, &elf_vma, prog.base_address, prog.size, 0); + j6_status_t res = j6_system_map_phys(sys, &elf_vma, prog.base_address, prog.size, 0); if (res != j6_status_ok) { sprintf(err_msg, " ** error loading program '%s': creating physical vma: %lx", prog.filename, res); return false; diff --git a/src/user/srv.init/main.cpp b/src/user/srv.init/main.cpp index 616ae53..dd53591 100644 --- a/src/user/srv.init/main.cpp +++ b/src/user/srv.init/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -21,21 +22,34 @@ extern "C" { uintptr_t _arg_modules_phys; // This gets filled in in _start extern j6_handle_t __handle_self; -extern j6_handle_t __handle_sys; int main(int argc, const char **argv) { + j6_status_t s; + + j6_handle_t sys = j6_handle_invalid; + j6_handle_t sys_child = j6_handle_invalid; + j6_log("srv.init starting"); - modules mods = modules::load_modules(_arg_modules_phys, __handle_sys, __handle_self); + sys = j6_find_first_handle(j6_object_type_system); + if (sys == j6_handle_invalid) + return 1; - j6_handle_t drv_sys_handle = j6_handle_invalid; - j6_status_t s = j6_handle_clone(__handle_sys, &drv_sys_handle, - j6_cap_system_bind_irq | j6_cap_system_map_phys | j6_cap_system_change_iopl); + s = j6_handle_clone(sys, &sys_child, + j6_cap_system_bind_irq | + j6_cap_system_get_log | + j6_cap_system_map_phys | + j6_cap_system_change_iopl); if (s != j6_status_ok) return s; + if (s != j6_status_ok) + return s; + + modules mods = modules::load_modules(_arg_modules_phys, sys, __handle_self); + for (auto &mod : mods.of_type(module_type::program)) { auto &prog = static_cast(mod); @@ -43,7 +57,7 @@ main(int argc, const char **argv) sprintf(message, " loading program module '%s' at %lx", prog.filename, prog.base_address); j6_log(message); - if (!load_program(prog, __handle_sys, message)) { + if (!load_program(prog, sys_child, message)) { j6_log(message); return 1; } diff --git a/src/user/testapp/main.cpp b/src/user/testapp/main.cpp index 65a05c4..ce701bc 100644 --- a/src/user/testapp/main.cpp +++ b/src/user/testapp/main.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "io.h"