diff --git a/src/drivers/nulldrv/main.cpp b/src/drivers/nulldrv/main.cpp index 812608a..e8edfef 100644 --- a/src/drivers/nulldrv/main.cpp +++ b/src/drivers/nulldrv/main.cpp @@ -52,7 +52,7 @@ thread_proc() int main(int argc, const char **argv) { - j6_handle_t child = j6_handle_invalid; + j6_handle_t children[2] = {j6_handle_invalid, j6_handle_invalid}; j6_signal_t out = 0; j6_system_log("main thread starting"); @@ -76,7 +76,7 @@ main(int argc, const char **argv) j6_system_log("main thread created endpoint"); - result = j6_thread_create(reinterpret_cast(&thread_proc), &child); + result = j6_thread_create(reinterpret_cast(&thread_proc), &children[1]); if (result != j6_status_ok) return result; @@ -98,17 +98,26 @@ main(int argc, const char **argv) j6_system_log(message); - j6_system_log("main thread waiting on child"); - result = j6_object_wait(child, -1ull, &out); + j6_system_log("main thread creating a new process"); + result = j6_process_create(&children[0]); if (result != j6_status_ok) return result; - j6_system_log("main thread creating a new process"); - j6_handle_t child_proc = j6_handle_invalid; - result = j6_process_create(&child_proc); + j6_system_log("main thread waiting on children"); + + j6_handle_t outhandle; + result = j6_object_wait_many(children, 2, -1ull, &outhandle, &out); if (result != j6_status_ok) return result; + if (outhandle == children[1]) { + j6_system_log(" ok from child thread"); + } else if (outhandle == children[0]) { + j6_system_log(" ok from child process"); + } else { + j6_system_log(" ... got unknown handle"); + } + j6_system_log("main testing irqs"); diff --git a/src/include/j6/tables/syscalls.inc b/src/include/j6/tables/syscalls.inc index fdd3351..69badcb 100644 --- a/src/include/j6/tables/syscalls.inc +++ b/src/include/j6/tables/syscalls.inc @@ -6,8 +6,9 @@ SYSCALL(0x04, system_map_mmio, j6_handle_t, j6_handle_t *, uintptr_t, size_t, SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *) SYSCALL(0x09, object_wait, j6_handle_t, j6_signal_t, j6_signal_t *) -SYSCALL(0x0a, object_signal, j6_handle_t, j6_signal_t) -SYSCALL(0x0b, object_close, j6_handle_t) +SYSCALL(0x0a, object_wait_many, j6_handle_t *, uint32_t, j6_signal_t, j6_handle_t *, j6_signal_t *) +SYSCALL(0x0b, object_signal, j6_handle_t, j6_signal_t) +SYSCALL(0x0c, object_close, j6_handle_t) SYSCALL(0x10, process_create, j6_handle_t *) SYSCALL(0x11, process_start, j6_handle_t, uintptr_t, j6_handle_t *, size_t) diff --git a/src/kernel/log.cpp b/src/kernel/log.cpp index 09191b6..3d1ff9c 100644 --- a/src/kernel/log.cpp +++ b/src/kernel/log.cpp @@ -75,7 +75,7 @@ logger_task() if (!g_logger.has_log()) { sys.deassert_signal(j6_signal_system_has_log); sys.add_blocked_thread(&self); - self.wait_on_signals(&sys, j6_signal_system_has_log); + self.wait_on_signals(j6_signal_system_has_log); } } } diff --git a/src/kernel/objects/kobject.cpp b/src/kernel/objects/kobject.cpp index 768ee18..6f3c254 100644 --- a/src/kernel/objects/kobject.cpp +++ b/src/kernel/objects/kobject.cpp @@ -50,13 +50,11 @@ void kobject::notify_signal_observers() { size_t i = 0; - bool readied = false; while (i < m_blocked_threads.count()) { thread *t = m_blocked_threads[i]; if (t->wake_on_signals(this, m_signals)) { m_blocked_threads.remove_swap_at(i); - readied = true; } else { ++i; } diff --git a/src/kernel/objects/thread.cpp b/src/kernel/objects/thread.cpp index 6bde889..6b03abc 100644 --- a/src/kernel/objects/thread.cpp +++ b/src/kernel/objects/thread.cpp @@ -48,7 +48,7 @@ thread & thread::current() { return *current_cpu().thread; } inline void schedule_if_current(thread *t) { if (t == current_cpu().thread) scheduler::get().schedule(); } void -thread::wait_on_signals(kobject *obj, j6_signal_t signals) +thread::wait_on_signals(j6_signal_t signals) { m_wait_type = wait_type::signal; m_wait_data = signals; diff --git a/src/kernel/objects/thread.h b/src/kernel/objects/thread.h index 4118f4d..b3fe11c 100644 --- a/src/kernel/objects/thread.h +++ b/src/kernel/objects/thread.h @@ -74,10 +74,9 @@ public: /// \arg p The new thread priority inline void set_priority(uint8_t p) { if (!constant()) m_tcb.priority = p; } - /// Block the thread, waiting on the given object's signals. - /// \arg obj Object to wait on + /// Block the thread, waiting an object's signals. /// \arg signals Mask of signals to wait for - void wait_on_signals(kobject *obj, j6_signal_t signals); + void wait_on_signals(j6_signal_t signals); /// Block the thread, waiting for a given clock value /// \arg t Clock value to wait for @@ -114,6 +113,9 @@ public: /// 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; } + inline bool has_state(state s) const { return static_cast(m_state) & static_cast(s); } diff --git a/src/kernel/syscalls/object.cpp b/src/kernel/syscalls/object.cpp index 4431302..895c953 100644 --- a/src/kernel/syscalls/object.cpp +++ b/src/kernel/syscalls/object.cpp @@ -37,7 +37,7 @@ object_wait(j6_handle_t handle, j6_signal_t mask, j6_signal_t *sigs) thread &th = thread::current(); obj->add_blocked_thread(&th); - th.wait_on_signals(obj, mask); + th.wait_on_signals(mask); j6_status_t result = th.get_wait_result(); if (result == j6_status_ok) { @@ -46,6 +46,55 @@ object_wait(j6_handle_t handle, j6_signal_t mask, j6_signal_t *sigs) return result; } +j6_status_t +object_wait_many(j6_handle_t *handles, uint32_t count, j6_signal_t mask, j6_handle_t *handle, j6_signal_t *sigs) +{ + kutil::vector objects {count}; + + for (unsigned i = 0; i < count; ++i) { + j6_handle_t h = handles[i]; + if (h == j6_handle_invalid) + continue; + + kobject *obj = get_handle(h); + if (!obj) + return j6_err_invalid_arg; + + j6_signal_t current = obj->signals(); + if ((current & mask) != 0) { + *sigs = current; + *handle = h; + 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; + + *handle = j6_handle_invalid; + *sigs = th.get_wait_data(); + j6_koid_t koid = th.get_wait_object(); + for (unsigned i = 0; i < count; ++i) { + if (koid == objects[i]->koid()) + *handle = handles[i]; + else + objects[i]->remove_blocked_thread(&th); + } + + kassert(*handle != j6_handle_invalid, + "Somehow woke on a handle that was not waited on"); + return j6_status_ok; +} + j6_status_t object_signal(j6_handle_t handle, j6_signal_t signals) { diff --git a/src/kernel/syscalls/thread.cpp b/src/kernel/syscalls/thread.cpp index a4a18f1..3dd460a 100644 --- a/src/kernel/syscalls/thread.cpp +++ b/src/kernel/syscalls/thread.cpp @@ -40,7 +40,7 @@ j6_status_t thread_pause() { thread &th = thread::current(); - th.wait_on_signals(&th, -1ull); + th.wait_on_signals(-1ull); return j6_status_ok; }