[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.
This commit is contained in:
Justin C. Miller
2022-02-21 19:16:20 -08:00
parent f93d80b8d2
commit f7ae2e2220
40 changed files with 419 additions and 628 deletions

View File

@@ -3,9 +3,7 @@
/// Definition of base type for user-interactable kernel objects
#include <j6/errors.h>
#include <j6/signals.h>
#include <j6/types.h>
#include <util/deque.h>
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<thread*, 8> m_blocked_threads;
};
} // namespace obj