kernel: implement a generic object signalling system
This commit is contained in:
@@ -9,7 +9,7 @@ struct msg;
|
|||||||
struct channel {
|
struct channel {
|
||||||
struct object c_base;
|
struct object c_base;
|
||||||
unsigned int c_id;
|
unsigned int c_id;
|
||||||
struct waitqueue c_wq;
|
unsigned int c_msg_waiting;
|
||||||
struct btree c_msg;
|
struct btree c_msg;
|
||||||
struct btree_node c_node;
|
struct btree_node c_node;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -88,9 +88,11 @@ struct object {
|
|||||||
koid_t ob_id;
|
koid_t ob_id;
|
||||||
struct object_type *ob_type;
|
struct object_type *ob_type;
|
||||||
spin_lock_t ob_lock;
|
spin_lock_t ob_lock;
|
||||||
|
uint32_t ob_signals;
|
||||||
unsigned int ob_refcount;
|
unsigned int ob_refcount;
|
||||||
unsigned int ob_handles;
|
unsigned int ob_handles;
|
||||||
struct queue_entry ob_list;
|
struct queue_entry ob_list;
|
||||||
|
struct waitqueue ob_wq;
|
||||||
} __aligned(sizeof(long));
|
} __aligned(sizeof(long));
|
||||||
|
|
||||||
extern kern_status_t object_bootstrap(void);
|
extern kern_status_t object_bootstrap(void);
|
||||||
@@ -116,6 +118,13 @@ extern void object_unlock_pair_irqrestore(
|
|||||||
struct object *b,
|
struct object *b,
|
||||||
unsigned long flags);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <kernel/thread.h>
|
#include <kernel/thread.h>
|
||||||
#include <kernel/util.h>
|
#include <kernel/util.h>
|
||||||
#include <kernel/vm-region.h>
|
#include <kernel/vm-region.h>
|
||||||
|
#include <mango/signal.h>
|
||||||
|
|
||||||
#define CHANNEL_CAST(p) OBJECT_C_CAST(struct channel, c_base, &channel_type, p)
|
#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) {
|
if (msg->msg_status == KMSG_WAIT_RECEIVE) {
|
||||||
msg->msg_status = KMSG_WAIT_REPLY;
|
msg->msg_status = KMSG_WAIT_REPLY;
|
||||||
msg->msg_sender_port->p_status = PORT_REPLY_BLOCKED;
|
msg->msg_sender_port->p_status = PORT_REPLY_BLOCKED;
|
||||||
|
channel->c_msg_waiting--;
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +121,8 @@ extern kern_status_t channel_enqueue_msg(
|
|||||||
msg->msg_id++;
|
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;
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
@@ -129,11 +132,21 @@ extern kern_status_t channel_recv_msg(
|
|||||||
kern_msg_t *out_msg,
|
kern_msg_t *out_msg,
|
||||||
unsigned long *irq_flags)
|
unsigned long *irq_flags)
|
||||||
{
|
{
|
||||||
struct wait_item waiter;
|
|
||||||
struct thread *self = current_thread();
|
struct thread *self = current_thread();
|
||||||
struct msg *msg = NULL;
|
struct msg *msg = NULL;
|
||||||
unsigned long msg_lock_flags;
|
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);
|
wait_item_init(&waiter, self);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
thread_wait_begin(&waiter, &channel->c_wq);
|
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);
|
object_lock_irqsave(&channel->c_base, irq_flags);
|
||||||
}
|
}
|
||||||
thread_wait_end(&waiter, &channel->c_wq);
|
thread_wait_end(&waiter, &channel->c_wq);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* msg is now set to the next message to process */
|
/* msg is now set to the next message to process */
|
||||||
|
|
||||||
|
|||||||
@@ -226,3 +226,35 @@ struct object *object_header(void *p)
|
|||||||
|
|
||||||
return obj;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
8
libmango/include-user/mango/object.h
Normal file
8
libmango/include-user/mango/object.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef MANGO_OBJECT_H_
|
||||||
|
#define MANGO_OBJECT_H_
|
||||||
|
|
||||||
|
#include <mango/types.h>
|
||||||
|
|
||||||
|
extern kern_status_t kern_object_wait(kern_wait_item_t *items, size_t nr_items);
|
||||||
|
|
||||||
|
#endif
|
||||||
10
libmango/include/mango/signal.h
Normal file
10
libmango/include/mango/signal.h
Normal file
@@ -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
|
||||||
75
syscall/object.c
Normal file
75
syscall/object.c
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user