diff --git a/include/kernel/channel.h b/include/kernel/channel.h index 38941f7..3c8a38e 100644 --- a/include/kernel/channel.h +++ b/include/kernel/channel.h @@ -9,7 +9,7 @@ struct msg; struct channel { struct object c_base; unsigned int c_id; - struct waitqueue c_wq; + unsigned int c_msg_waiting; struct btree c_msg; struct btree_node c_node; }; diff --git a/include/kernel/object.h b/include/kernel/object.h index 03bdc81..6672d8b 100644 --- a/include/kernel/object.h +++ b/include/kernel/object.h @@ -88,9 +88,11 @@ struct object { koid_t ob_id; struct object_type *ob_type; spin_lock_t ob_lock; + uint32_t ob_signals; unsigned int ob_refcount; unsigned int ob_handles; struct queue_entry ob_list; + struct waitqueue ob_wq; } __aligned(sizeof(long)); extern kern_status_t object_bootstrap(void); @@ -116,6 +118,13 @@ extern void object_unlock_pair_irqrestore( struct object *b, unsigned long flags); +extern void object_assert_signal(struct object *obj, uint32_t signals); +extern void object_clear_signal(struct object *obj, uint32_t signals); +extern void object_wait_signal( + struct object *obj, + uint32_t signals, + unsigned long *irq_flags); + #ifdef __cplusplus } #endif diff --git a/kernel/channel.c b/kernel/channel.c index dea8c80..f064558 100644 --- a/kernel/channel.c +++ b/kernel/channel.c @@ -5,6 +5,7 @@ #include #include #include +#include #define CHANNEL_CAST(p) OBJECT_C_CAST(struct channel, c_base, &channel_type, p) @@ -100,6 +101,7 @@ static struct msg *get_next_msg( if (msg->msg_status == KMSG_WAIT_RECEIVE) { msg->msg_status = KMSG_WAIT_REPLY; msg->msg_sender_port->p_status = PORT_REPLY_BLOCKED; + channel->c_msg_waiting--; return msg; } @@ -119,7 +121,8 @@ extern kern_status_t channel_enqueue_msg( msg->msg_id++; } - wakeup_one(&channel->c_wq); + channel->c_msg_waiting++; + object_assert_signal(&channel->c_base, CHANNEL_SIGNAL_MSG_RECEIVED); return KERN_OK; } @@ -129,11 +132,21 @@ extern kern_status_t channel_recv_msg( kern_msg_t *out_msg, unsigned long *irq_flags) { - struct wait_item waiter; struct thread *self = current_thread(); struct msg *msg = NULL; unsigned long msg_lock_flags; + msg = get_next_msg(channel, &msg_lock_flags); + if (!msg) { + return KERN_NO_ENTRY; + } + + if (channel->c_msg_waiting == 0) { + object_clear_signal( + &channel->c_base, + CHANNEL_SIGNAL_MSG_RECEIVED); + } +#if 0 wait_item_init(&waiter, self); for (;;) { thread_wait_begin(&waiter, &channel->c_wq); @@ -147,6 +160,7 @@ extern kern_status_t channel_recv_msg( object_lock_irqsave(&channel->c_base, irq_flags); } thread_wait_end(&waiter, &channel->c_wq); +#endif /* msg is now set to the next message to process */ diff --git a/kernel/object.c b/kernel/object.c index 3caa310..b763880 100644 --- a/kernel/object.c +++ b/kernel/object.c @@ -226,3 +226,35 @@ struct object *object_header(void *p) return obj; } + +void object_assert_signal(struct object *obj, uint32_t signals) +{ + obj->ob_signals |= signals; + wakeup_queue(&obj->ob_wq); +} + +void object_clear_signal(struct object *obj, uint32_t signals) +{ + obj->ob_signals &= ~signals; +} + +void object_wait_signal( + struct object *obj, + uint32_t signals, + unsigned long *irq_flags) +{ + struct thread *self = current_thread(); + struct wait_item waiter; + wait_item_init(&waiter, self); + for (;;) { + thread_wait_begin(&waiter, &obj->ob_wq); + if (obj->ob_signals & signals) { + break; + } + + object_unlock_irqrestore(obj, *irq_flags); + schedule(SCHED_NORMAL); + object_lock_irqsave(obj, irq_flags); + } + thread_wait_end(&waiter, &obj->ob_wq); +} diff --git a/libmango/include-user/mango/object.h b/libmango/include-user/mango/object.h new file mode 100644 index 0000000..98ff2aa --- /dev/null +++ b/libmango/include-user/mango/object.h @@ -0,0 +1,8 @@ +#ifndef MANGO_OBJECT_H_ +#define MANGO_OBJECT_H_ + +#include + +extern kern_status_t kern_object_wait(kern_wait_item_t *items, size_t nr_items); + +#endif diff --git a/libmango/include/mango/signal.h b/libmango/include/mango/signal.h new file mode 100644 index 0000000..87ab161 --- /dev/null +++ b/libmango/include/mango/signal.h @@ -0,0 +1,10 @@ +#ifndef MANGO_SIGNAL_H_ +#define MANGO_SIGNAL_H_ + +#define CHANNEL_SIGNAL_MSG_RECEIVED 0x01u + +#define VM_CONTROLLER_SIGNAL_REQUEST_RECEIVED 0x01u + +#define EQUEUE_SIGNAL_PACKET_RECEIVED 0x01u + +#endif diff --git a/syscall/object.c b/syscall/object.c new file mode 100644 index 0000000..23a07f8 --- /dev/null +++ b/syscall/object.c @@ -0,0 +1,75 @@ +#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; +}