[kernel] Add object_wait_many syscall

Add the object_wait_many syscall to allow programs to wait for signals
on multiple objects at once. Also removed the object argument to
thread::wait_on_signals, which does nothing with it. That information is
saved in the thread being in the object's blocked threads list.
This commit is contained in:
Justin C. Miller
2021-05-29 19:57:47 -07:00
parent 9fbbd8b954
commit c07c39f8ed
8 changed files with 77 additions and 18 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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<uint8_t>(m_state) & static_cast<uint8_t>(s);
}

View File

@@ -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<kobject*> 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<kobject>(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)
{

View File

@@ -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;
}