Files
mango/syscall/object.c

76 lines
1.8 KiB
C
Raw Normal View History

#include <kernel/object.h>
#include <kernel/sched.h>
#include <kernel/syscall.h>
#include <kernel/task.h>
#include <kernel/wait.h>
#include <mango/status.h>
#include <mango/types.h>
kern_status_t sys_kern_object_wait(kern_wait_item_t *items, size_t nr_items)
{
if (nr_items > KERN_WAIT_MAX_ITEMS) {
return KERN_INVALID_ARGUMENT;
}
struct task *self = current_task();
struct thread *self_thread = current_thread();
if (!validate_access_rw(self, items, nr_items * sizeof *items)) {
return KERN_MEMORY_FAULT;
}
kern_status_t status = KERN_OK;
struct object *objects[KERN_WAIT_MAX_ITEMS];
struct wait_item waiters[KERN_WAIT_MAX_ITEMS];
unsigned long irq_flags = 0;
size_t i = 0, to_release = 0;
bool signals_observed = false;
for (i = 0; i < nr_items; i++) {
kern_handle_t handle = items[i].w_handle;
handle_flags_t flags;
struct object *object = NULL;
status = task_resolve_handle(self, handle, &object, &flags);
if (status != KERN_OK) {
break;
}
objects[i] = object;
object_lock_irqsave(object, &irq_flags);
wait_item_init(&waiters[i], self_thread);
thread_wait_begin(&waiters[i], &object->ob_wq);
if (object->ob_signals & items[i].w_waitfor) {
signals_observed = true;
items[i].w_observed = object->ob_signals;
}
object_unlock_irqrestore(object, irq_flags);
}
if (signals_observed || status != KERN_OK) {
goto cleanup;
}
schedule(SCHED_NORMAL);
for (i = 0; i < nr_items; i++) {
object_lock_irqsave(objects[i], &irq_flags);
if (objects[i]->ob_signals & items[i].w_waitfor) {
signals_observed = true;
}
object_unlock_irqrestore(objects[i], irq_flags);
}
cleanup:
to_release = i;
for (i = 0; i < to_release; i++) {
thread_wait_end(&waiters[i], &objects[i]->ob_wq);
object_unref(objects[i]);
}
return status;
}