#include #include #include #include #include #include #include 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; }