#include #include #include #define PORT_CAST(p) OBJECT_C_CAST(struct port, p_base, &port_type, p) static struct object_type port_type = { .ob_name = "port", .ob_size = sizeof(struct port), .ob_header_offset = offsetof(struct port, p_base), }; kern_status_t port_type_init(void) { return object_type_register(&port_type); } struct port *port_cast(struct object *obj) { return PORT_CAST(obj); } static void wait_for_reply(struct msg *msg, unsigned long *lock_flags) { struct wait_item waiter; struct thread *self = current_thread(); wait_item_init(&waiter, self); for (;;) { self->tr_state = THREAD_SLEEPING; if (msg->msg_status == KMSG_REPLY_SENT) { break; } port_unlock_irqrestore(msg->msg_sender_port, *lock_flags); schedule(SCHED_NORMAL); port_lock_irqsave(msg->msg_sender_port, lock_flags); } self->tr_state = THREAD_READY; } struct port *port_create(void) { struct object *port_object = object_create(&port_type); if (!port_object) { return NULL; } struct port *port = PORT_CAST(port_object); port->p_status = PORT_OFFLINE; return port; } kern_status_t port_connect(struct port *port, struct channel *remote) { if (port->p_status != PORT_OFFLINE) { return KERN_BAD_STATE; } port->p_remote = remote; port->p_status = PORT_READY; return KERN_OK; } kern_status_t port_disconnect(struct port *port) { if (port->p_status != PORT_READY) { return KERN_BAD_STATE; } port->p_remote = NULL; port->p_status = PORT_OFFLINE; return KERN_OK; } kern_status_t port_send_msg( struct port *port, const kern_msg_t *in_msg, kern_msg_t *out_reply, unsigned long *lock_flags) { if (port->p_status != PORT_READY) { return KERN_BAD_STATE; } struct thread *self = current_thread(); struct msg *msg = &self->tr_msg; memset(msg, 0x0, sizeof *msg); msg->msg_status = KMSG_WAIT_RECEIVE; msg->msg_sender_thread = self; msg->msg_sender_port = port; memcpy(&msg->msg_req, in_msg, sizeof msg->msg_req); memcpy(&msg->msg_resp, out_reply, sizeof msg->msg_req); unsigned long flags; channel_lock_irqsave(port->p_remote, &flags); port->p_status = PORT_SEND_BLOCKED; channel_enqueue_msg(port->p_remote, msg); channel_unlock_irqrestore(port->p_remote, flags); wait_for_reply(msg, lock_flags); channel_lock_irqsave(port->p_remote, &flags); btree_delete(&port->p_remote->c_msg, &msg->msg_node); channel_unlock_irqrestore(port->p_remote, flags); return msg->msg_result; }