#include #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; } self_thread->tr_state = THREAD_SLEEPING; 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 nr_retained = 0; bool signals_observed = false; for (nr_retained = 0; nr_retained < nr_items; nr_retained++) { kern_handle_t handle = items[nr_retained].w_handle; handle_flags_t flags; struct object *object = NULL; status = task_resolve_handle(self, handle, &object, &flags); if (status != KERN_OK) { break; } objects[nr_retained] = object; object_lock_irqsave(object, &irq_flags); wait_item_init(&waiters[nr_retained], self_thread); thread_wait_begin_nosleep( &waiters[nr_retained], &object->ob_wq); if (object->ob_signals & items[nr_retained].w_waitfor) { signals_observed = true; items[nr_retained].w_observed = object->ob_signals; } object_unlock_irqrestore(object, irq_flags); } if (signals_observed || status != KERN_OK) { goto cleanup; } schedule(SCHED_NORMAL); for (size_t i = 0; i < nr_retained; i++) { object_lock_irqsave(objects[i], &irq_flags); if (objects[i]->ob_signals & items[i].w_waitfor) { signals_observed = true; items[i].w_observed = objects[i]->ob_signals; } object_unlock_irqrestore(objects[i], irq_flags); } cleanup: for (size_t i = 0; i < nr_retained; i++) { thread_wait_end_nosleep(&waiters[i], &objects[i]->ob_wq); object_unref(objects[i]); } self_thread->tr_state = THREAD_READY; return status; }