syscall: fix some missed-signal bugs in kern_object_wait
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
#include <kernel/sched.h>
|
#include <kernel/sched.h>
|
||||||
#include <kernel/syscall.h>
|
#include <kernel/syscall.h>
|
||||||
#include <kernel/task.h>
|
#include <kernel/task.h>
|
||||||
|
#include <kernel/thread.h>
|
||||||
#include <kernel/wait.h>
|
#include <kernel/wait.h>
|
||||||
#include <mango/status.h>
|
#include <mango/status.h>
|
||||||
#include <mango/types.h>
|
#include <mango/types.h>
|
||||||
@@ -18,31 +19,36 @@ kern_status_t sys_kern_object_wait(kern_wait_item_t *items, size_t nr_items)
|
|||||||
return KERN_MEMORY_FAULT;
|
return KERN_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self_thread->tr_state = THREAD_SLEEPING;
|
||||||
|
|
||||||
kern_status_t status = KERN_OK;
|
kern_status_t status = KERN_OK;
|
||||||
struct object *objects[KERN_WAIT_MAX_ITEMS];
|
struct object *objects[KERN_WAIT_MAX_ITEMS];
|
||||||
struct wait_item waiters[KERN_WAIT_MAX_ITEMS];
|
struct wait_item waiters[KERN_WAIT_MAX_ITEMS];
|
||||||
unsigned long irq_flags = 0;
|
unsigned long irq_flags = 0;
|
||||||
|
|
||||||
size_t i = 0, to_release = 0;
|
size_t nr_retained = 0;
|
||||||
bool signals_observed = false;
|
bool signals_observed = false;
|
||||||
for (i = 0; i < nr_items; i++) {
|
for (nr_retained = 0; nr_retained < nr_items; nr_retained++) {
|
||||||
kern_handle_t handle = items[i].w_handle;
|
kern_handle_t handle = items[nr_retained].w_handle;
|
||||||
handle_flags_t flags;
|
handle_flags_t flags;
|
||||||
struct object *object = NULL;
|
struct object *object = NULL;
|
||||||
|
|
||||||
status = task_resolve_handle(self, handle, &object, &flags);
|
status = task_resolve_handle(self, handle, &object, &flags);
|
||||||
if (status != KERN_OK) {
|
if (status != KERN_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
objects[i] = object;
|
objects[nr_retained] = object;
|
||||||
|
|
||||||
object_lock_irqsave(object, &irq_flags);
|
object_lock_irqsave(object, &irq_flags);
|
||||||
wait_item_init(&waiters[i], self_thread);
|
wait_item_init(&waiters[nr_retained], self_thread);
|
||||||
thread_wait_begin(&waiters[i], &object->ob_wq);
|
thread_wait_begin_nosleep(
|
||||||
|
&waiters[nr_retained],
|
||||||
|
&object->ob_wq);
|
||||||
|
|
||||||
if (object->ob_signals & items[i].w_waitfor) {
|
if (object->ob_signals & items[nr_retained].w_waitfor) {
|
||||||
signals_observed = true;
|
signals_observed = true;
|
||||||
items[i].w_observed = object->ob_signals;
|
items[nr_retained].w_observed = object->ob_signals;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_unlock_irqrestore(object, irq_flags);
|
object_unlock_irqrestore(object, irq_flags);
|
||||||
@@ -54,22 +60,23 @@ kern_status_t sys_kern_object_wait(kern_wait_item_t *items, size_t nr_items)
|
|||||||
|
|
||||||
schedule(SCHED_NORMAL);
|
schedule(SCHED_NORMAL);
|
||||||
|
|
||||||
for (i = 0; i < nr_items; i++) {
|
for (size_t i = 0; i < nr_retained; i++) {
|
||||||
object_lock_irqsave(objects[i], &irq_flags);
|
object_lock_irqsave(objects[i], &irq_flags);
|
||||||
|
|
||||||
if (objects[i]->ob_signals & items[i].w_waitfor) {
|
if (objects[i]->ob_signals & items[i].w_waitfor) {
|
||||||
signals_observed = true;
|
signals_observed = true;
|
||||||
|
items[i].w_observed = objects[i]->ob_signals;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_unlock_irqrestore(objects[i], irq_flags);
|
object_unlock_irqrestore(objects[i], irq_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
to_release = i;
|
for (size_t i = 0; i < nr_retained; i++) {
|
||||||
for (i = 0; i < to_release; i++) {
|
thread_wait_end_nosleep(&waiters[i], &objects[i]->ob_wq);
|
||||||
thread_wait_end(&waiters[i], &objects[i]->ob_wq);
|
|
||||||
object_unref(objects[i]);
|
object_unref(objects[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self_thread->tr_state = THREAD_READY;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user