summaryrefslogtreecommitdiff
path: root/viengoos
diff options
context:
space:
mode:
Diffstat (limited to 'viengoos')
-rw-r--r--viengoos/ChangeLog112
-rw-r--r--viengoos/Makefile.am1
-rw-r--r--viengoos/ager.c28
-rw-r--r--viengoos/cap.c37
-rw-r--r--viengoos/messenger.c347
-rw-r--r--viengoos/messenger.h214
-rw-r--r--viengoos/object.c318
-rw-r--r--viengoos/object.h57
-rw-r--r--viengoos/pager.c24
-rw-r--r--viengoos/rm.h48
-rw-r--r--viengoos/server.c1472
-rw-r--r--viengoos/thread.c220
-rw-r--r--viengoos/thread.h114
13 files changed, 1997 insertions, 995 deletions
diff --git a/viengoos/ChangeLog b/viengoos/ChangeLog
index 0c9817b..783bbfe 100644
--- a/viengoos/ChangeLog
+++ b/viengoos/ChangeLog
@@ -1,3 +1,115 @@
+2008-12-12 Neal H. Walfield <neal@gnu.org>
+
+ Implement messengers and convert to new IPC semantics.
+ * messenger.h: New file.
+ * messenger.c: New file.
+ * Makefile.am (viengoos_SOURCES): Add messenger.h and messenger.c.
+ * ager.c: Include "messenger.h".
+ (update_stats): Update notifivation code to use messengers.
+ * cap.c: Include <hurd/messenger.h>.
+ (cap_shootdown): Follow thread and messenger objects.
+ * object.h (object_wait_queue_head): Use and return struct
+ messenger *'s, not struct thread *'s. Update users.
+ (object_wait_queue_tail): Likewise.
+ (object_wait_queue_next): Likewise.
+ (object_wait_queue_prev): Likewise.
+ (object_wait_queue_enqueue): Likewise.
+ (object_wait_queue_dequeue): Likewise. Rename from this...
+ (object_wait_queue_unlink): ... to this.
+ (object_wait_queue_push): New declaration.
+ (folio_object_wait_queue_for_each): Use and return struct
+ messenger *'s, not struct thread *'s. Update users.
+ (object_wait_queue_for_each): Likewise.
+ * object.c: Include <hurd/messenger.h> and "messenger.h".
+ (folio_object_alloc): When destroying a messenger, call
+ messenger_destroy.
+ (folio_object_alloc): Send notifications using messengers.
+ (object_wait_queue_head): Use and return struct messenger *'s, not
+ struct thread *'s.
+ (object_wait_queue_tail): Likewise.
+ (object_wait_queue_next): Likewise.
+ (object_wait_queue_prev): Likewise.
+ (object_wait_queue_check): Likewise.
+ (object_wait_queue_enqueue): Likewise. Add MESSENGER to end of
+ the queue, not the beginning.
+ (object_wait_queue_push): New function.
+ (object_wait_queue_dequeue): Use and return struct messenger *'s,
+ not struct thread *'s. Rename from this...
+ (object_wait_queue_unlink): ... to this.
+ * pager.c: Include "messenger.h".
+ * thread.h: Don't include "list.h". Include <hurd/cap.h> and
+ <hurd/thread.h>.
+ (struct folio): Remove declaration.
+ (THREAD_SLOTS): Don't define.
+ (THREAD_WAIT_FUTEX): Move from here...
+ * messenger.h (MESSENGER_WAIT_FUTEX): ... to here.
+ * thread.h (THREAD_WAIT_DESTROY): Move from here...
+ * messenger.h (MESSENGER_WAIT_DESTROY): ... to here.
+ * thread.h (THREAD_WAIT_ACTIVITY_INFO): Move from here...
+ * messenger.h (MESSENGER_WAIT_ACTIVITY_INFO): ... to here.
+ * thread.h (struct thread): Rename field exception_page to utcb.
+ Add field exception_messenger. Remove fields wait_queue_p,
+ wait_queue_head, wait_queue_tail, wait_reason, wait_reason_arg,
+ wait_reason_arg2, wait_queue and futex_waiter_node.
+ (futex_waiters): Don't declare.
+ (thread_exregs): Change input capabilities to not be pointers to
+ capabilities but just capability structures. Add argument
+ exception_messenger. Remove arguments aspace_out, activity_out
+ and exception_page_out. Update users.
+ (thread_activate): New declaration.
+ (thread_raise_exception): Change MSG's type to be struct
+ vg_message *. Update users.
+ (thread_deliver_pending): New declaration.
+ * thread.c (thread_deinit): Remove code to remove THREAD from a
+ wait queue.
+ (thread_exregs): Change input capabilities to not be pointers to
+ capabilities but just capability structures. Update code. Add
+ argument exception_messenger. Set THREAD's exception messenger
+ according to it and CONTROL. Remove arguments aspace_out,
+ activity_out and exception_page_out. Don't save the old
+ capabilities.
+ (thread_raise_exception): Move body of function...
+ (thread_activate): ... to this new function. Update to use
+ messengers.
+ (thread_raise_exception): Implement in terms of it.
+ (thread_deliver_pending): New function.
+ * server.c: Include <hurd/ipc.h> and "messenger.h".
+ (DEBUG): If label is the IPC label, use "IPC" as the function.
+ (OBJECT_): Take additional parameter WRITABLE. Save whether the
+ object is writable in *WRITABLE. Update users.
+ (OBJECT): Likewise.
+ (server_loop): Update to use messengers and the new IPC interface.
+ Update method implementations appropriately. Don't marshal faults
+ using exception_fault_send_marshal but the new
+ activation_fault_send_marshal. Remove implementations of
+ object_slot_copy_out, object_slot_copy_in and object_slot_read.
+ Reimplement object_discard. In the thread_exregs implementation,
+ handle the exception messenger. Implement thread_id. Remove
+ thread_wait_object_destroyed. Implement
+ object_reply_on_destruction. In activity_info and
+ activity_policy, don't operate on PRINCIPAL but the invoke
+ activity. Implement thread_activation_collect. When blocking on
+ a futex, don't enqueue the calling thread but the reply messenger.
+ Implement the messenger_id method.
+ (REPLY): Redefine before processing an object invocation to reply
+ using the reply messenger included in the request.
+
+ * rm.h: Include <l4/message.h>.
+ (rm_method_id_string): Don't handle object_slot_copy_out,
+ object_slot_copy_in, object_slot_read, exception_collect or
+ thread_wait_object_destroyed. Handle object_reply_on_destruction,
+ thread_id, thread_activation_collect.
+ (RPC_TARGET_NEED_ARG): Don't undefine.
+ (RPC_TARGET): Don't define.
+ (struct io_buffer): Redefine in terms of L4_NUM_BRS.
+ (write): Update interface specification according to new IDL
+ interface. Update users.
+ (read): Likewise.
+ (as_dump): Likewise.
+ (fault): Likewise.
+ (RPC_STUB_PREFIX): Don't undefine.
+ (RPC_ID_PREFIX): Likewise.
+
2008-12-11 Neal H. Walfield <neal@gnu.org>
* viengoos.c (bootstrap): Add code to configure the memory to
diff --git a/viengoos/Makefile.am b/viengoos/Makefile.am
index bb97920..c3d37df 100644
--- a/viengoos/Makefile.am
+++ b/viengoos/Makefile.am
@@ -49,6 +49,7 @@ viengoos_SOURCES = $(ARCH_SOURCES) \
cap.h cap.c \
activity.h activity.c \
thread.h thread.c \
+ messenger.h messenger.c \
ager.h ager.c \
bits.h \
server.h server.c \
diff --git a/viengoos/ager.c b/viengoos/ager.c
index afd2168..d078252 100644
--- a/viengoos/ager.c
+++ b/viengoos/ager.c
@@ -32,6 +32,7 @@
#include "zalloc.h"
#include "thread.h"
#include "pager.h"
+#include "messenger.h"
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
@@ -401,14 +402,14 @@ update_stats (void)
0, sizeof (*ACTIVITY_STATS (activity)));
/* Wake anyone waiting for this statistic. */
- struct thread *thread;
+ struct messenger *messenger;
object_wait_queue_for_each (activity, (struct object *) activity,
- thread)
- if (thread->wait_reason == THREAD_WAIT_ACTIVITY_INFO
- && (thread->wait_reason_arg & activity_info_stats)
- && thread->wait_reason_arg2 <= period / FREQ)
+ messenger)
+ if (messenger->wait_reason == MESSENGER_WAIT_ACTIVITY_INFO
+ && (messenger->wait_reason_arg & activity_info_stats)
+ && messenger->wait_reason_arg2 <= period / FREQ)
{
- object_wait_queue_dequeue (activity, thread);
+ object_wait_queue_unlink (activity, messenger);
/* XXX: Only return valid stat buffers. */
struct activity_info info;
@@ -426,20 +427,7 @@ update_stats (void)
info.stats.count = ACTIVITY_STATS_PERIODS;
- l4_msg_t msg;
- rm_activity_info_reply_marshal (&msg, info);
- l4_msg_tag_t msg_tag = l4_msg_msg_tag (msg);
- l4_set_propagation (&msg_tag);
- l4_msg_set_msg_tag (msg, msg_tag);
- l4_set_virtual_sender (viengoos_tid);
- l4_msg_load (msg);
- msg_tag = l4_reply (thread->tid);
-
- if (l4_ipc_failed (msg_tag))
- debug (0, "%s %x failed: %u",
- l4_error_code () & 1 ? "Receiving from" : "Sending to",
- l4_error_code () & 1 ? l4_myself () : thread->tid,
- (l4_error_code () >> 1) & 0x7);
+ rm_activity_info_reply (root_activity, messenger, info);
}
}
diff --git a/viengoos/cap.c b/viengoos/cap.c
index 3f020fe..2a9ae66 100644
--- a/viengoos/cap.c
+++ b/viengoos/cap.c
@@ -20,6 +20,7 @@
#include <assert.h>
#include <hurd/stddef.h>
+#include <hurd/messenger.h>
#include "cap.h"
#include "object.h"
@@ -142,6 +143,42 @@ cap_shootdown (struct activity *activity, struct cap *root)
return;
+ case cap_messenger:
+ case cap_rmessenger:
+ if (remaining < VG_MESSENGER_SLOTS_LOG2 + PAGESIZE_LOG2)
+ return;
+
+ object = cap_to_object (activity, cap);
+ if (! object)
+ return;
+
+ remaining -= VG_MESSENGER_SLOTS_LOG2;
+
+ for (i = 0; i < VG_MESSENGER_SLOTS_LOG2; i ++)
+ if (root->oid != object->caps[i].oid)
+ doit (&object->caps[i], remaining);
+
+ return;
+
+ case cap_thread:
+ if (remaining < THREAD_SLOTS_LOG2 + PAGESIZE_LOG2)
+ return;
+
+ object = cap_to_object (activity, cap);
+ if (! object)
+ return;
+
+ remaining -= THREAD_SLOTS_LOG2;
+
+ for (i = 0; i < THREAD_SLOTS_LOG2; i ++)
+ if (root->oid != object->caps[i].oid)
+ doit (&object->caps[i],
+ remaining
+ + (i == THREAD_ASPACE_SLOT ? THREAD_SLOTS_LOG2 : 0));
+
+ return;
+
+
case cap_folio:
if (remaining < FOLIO_OBJECTS_LOG2 + PAGESIZE_LOG2)
return;
diff --git a/viengoos/messenger.c b/viengoos/messenger.c
new file mode 100644
index 0000000..fbcd58f
--- /dev/null
+++ b/viengoos/messenger.c
@@ -0,0 +1,347 @@
+/* messenger.c - Messenger object implementation.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ Written by Neal H. Walfield <neal@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+#include <hurd/cap.h>
+#include <hurd/as.h>
+
+#include "messenger.h"
+#include "object.h"
+#include "thread.h"
+
+/* When the kernel formulates relies, it does so in this buffer. */
+static char reply_message_data[PAGESIZE] __attribute__ ((aligned (PAGESIZE)));
+struct vg_message *reply_buffer = (struct vg_message *) &reply_message_data[0];
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+#include <backtrace.h>
+
+static bool
+messenger_load_internal (struct activity *activity,
+ struct messenger *target,
+ struct messenger *source,
+ struct vg_message *smessage,
+ bool may_block)
+{
+ assert (object_type ((struct object *) target) == cap_messenger);
+ if (source)
+ assert (object_type ((struct object *) source) == cap_messenger);
+
+ if (source)
+ assert (! smessage);
+ else
+ assert (smessage);
+
+ /* SOURCE should not already be blocked on another messenger. */
+ if (source)
+ {
+ assert (! source->wait_queue.next);
+ assert (! source->wait_queue.prev);
+ }
+
+ if (unlikely (target->blocked))
+ /* TARGET is blocked. */
+ {
+ if (! may_block)
+ {
+ debug (0, "Not enqueuing messenger: "
+ "target blocked and delivery marked as non-blocking.");
+ backtrace_print ();
+ return false;
+ }
+
+ /* Enqueue SOURCE on TARGET's wait queue. */
+
+ debug (0, "Target blocked. Enqueuing sender.");
+
+ assert (source);
+ source->wait_reason = MESSENGER_WAIT_TRANSFER_MESSAGE;
+ object_wait_queue_enqueue (activity, (struct object *) target, source);
+
+ return true;
+ }
+
+ /* TARGET is not blocked. Deliver the message. */
+ debug (5, "Delivering sender's message to target.");
+
+ target->blocked = true;
+
+ /* There are four combinations: the source can either have inline
+ data or out-of-line data and the target can either have inline
+ data or out-of-line data. */
+
+ struct vg_message *tmessage = NULL;
+
+ void *sdata;
+ void *tdata;
+ int data_count;
+
+ addr_t *saddrs;
+ int saddr_count;
+ addr_t *taddrs;
+ int taddr_count;
+
+ if (! source || source->out_of_band)
+ /* Source data is in a buffer. */
+ {
+ if (source)
+ smessage = (struct vg_message *) cap_to_object (activity,
+ &source->buffer);
+ else
+ assert (smessage);
+
+ if (smessage)
+ {
+ sdata = vg_message_data (smessage);
+ data_count = vg_message_data_count (smessage);
+
+ saddrs = vg_message_caps (smessage);
+ saddr_count = vg_message_cap_count (smessage);
+ }
+ else
+ {
+ sdata = NULL;
+ data_count = 0;
+ saddrs = NULL;
+ saddr_count = 0;
+ }
+ }
+ else
+ /* Source data is inline. */
+ {
+ assert (source);
+
+ sdata = source->inline_words;
+ data_count
+ = sizeof (source->inline_words[0]) * source->inline_word_count;
+
+ saddrs = source->inline_caps;
+ saddr_count = source->inline_cap_count;
+ }
+
+ if (target->out_of_band)
+ /* Target data is in a buffer. */
+ {
+ tmessage = (struct vg_message *) cap_to_object (activity,
+ &target->buffer);
+ if (tmessage)
+ {
+ taddrs = vg_message_caps (tmessage);
+ taddr_count = vg_message_cap_count (tmessage);
+
+ /* Set the number of capabilities to the number in the
+ source message. */
+ tmessage->cap_count = saddr_count;
+ tdata = vg_message_data (tmessage);
+ tmessage->data_count = data_count;
+ }
+ else
+ {
+ tdata = NULL;
+ data_count = 0;
+
+ taddrs = NULL;
+ taddr_count = 0;
+ }
+ }
+ else
+ /* Target data is inline. */
+ {
+ tdata = target->inline_words;
+ data_count = MIN (data_count,
+ sizeof (uintptr_t) * VG_MESSENGER_INLINE_WORDS);
+ target->inline_word_count
+ = (data_count + sizeof (uintptr_t) - 1) / sizeof (uintptr_t);
+
+ taddrs = target->inline_caps;
+ taddr_count = target->inline_cap_count;
+ }
+
+ do_debug (5)
+ {
+ if (smessage)
+ {
+ debug (0, "Source: ");
+ vg_message_dump (smessage);
+ }
+ if (tmessage)
+ {
+ debug (0, "Target: ");
+ vg_message_dump (tmessage);
+ }
+ }
+
+ /* Copy the caps. */
+ int i;
+ for (i = 0; i < MIN (saddr_count, taddr_count); i ++)
+ {
+ /* First get the target capability slot. */
+ bool twritable = true;
+
+ struct cap *tcap = NULL;
+ if (! ADDR_IS_VOID (taddrs[i]))
+ {
+ as_slot_lookup_rel_use (activity, &target->as_root, taddrs[i],
+ ({
+ twritable = writable;
+ tcap = slot;
+ }));
+ if (! tcap || ! twritable)
+ debug (0, DEBUG_BOLD ("Target " ADDR_FMT " does not designate "
+ "a %svalid slot!"),
+ ADDR_PRINTF (taddrs[i]), twritable ? "writable " : "");
+ }
+
+ if (likely (tcap && twritable))
+ /* We have a slot and it is writable. Look up the source
+ capability. */
+ {
+ struct cap scap = CAP_VOID;
+ bool swritable = true;
+ if (source)
+ {
+ if (! ADDR_IS_VOID (saddrs[i]))
+ scap = as_cap_lookup_rel (activity,
+ &source->as_root, saddrs[i],
+ -1, &swritable);
+ }
+ else
+ /* This is a kernel provided buffer. In this case the
+ address is really a pointer to a capability. */
+ if ((uintptr_t) saddrs[i].raw)
+ scap = * (struct cap *) (uintptr_t) saddrs[i].raw;
+
+ if (! swritable)
+ scap.type = cap_type_weaken (scap.type);
+
+ /* Shoot down the capability. */
+ cap_shootdown (activity, tcap);
+
+ /* Preserve the address translator and policy. */
+ struct cap_properties props = CAP_PROPERTIES_GET (*tcap);
+ *tcap = scap;
+ CAP_PROPERTIES_SET (tcap, props);
+
+ debug (5, ADDR_FMT " <- " CAP_FMT,
+ ADDR_PRINTF (taddrs[i]), CAP_PRINTF (tcap));
+ }
+ else
+ taddrs[i] = ADDR_VOID;
+ }
+ if (i < MAX (taddr_count, saddr_count) && target->out_of_band && taddrs)
+ /* Set the address of any non-transferred caps in the target to
+ ADDR_VOID. */
+ memset (&taddrs[i], 0,
+ sizeof (taddrs[0]) * (MAX (taddr_count, saddr_count)) - i);
+
+ /* Copy the data. */
+ memcpy (tdata, sdata, data_count);
+
+ do_debug (5)
+ if (tmessage)
+ {
+ debug (0, "Delivery: ");
+ vg_message_dump (tmessage);
+ }
+
+ if (target->activate_on_receive)
+ messenger_message_deliver (activity, target);
+ else
+ debug (0, "Not activing target.");
+
+ if (source && source->activate_on_send)
+ messenger_message_deliver (activity, source);
+
+ return true;
+}
+
+bool
+messenger_message_transfer (struct activity *activity,
+ struct messenger *target,
+ struct messenger *source,
+ bool may_block)
+{
+ return messenger_load_internal (activity, target, source, NULL, may_block);
+}
+
+bool
+messenger_message_load (struct activity *activity,
+ struct messenger *target,
+ struct vg_message *message)
+{
+ return messenger_load_internal (activity, target, NULL, message, false);
+}
+
+bool
+messenger_message_deliver (struct activity *activity,
+ struct messenger *messenger)
+{
+ assert (messenger->blocked);
+ assert (! messenger->wait_queue_p);
+
+ struct thread *thread
+ = (struct thread *) cap_to_object (activity, &messenger->thread);
+ if (! thread)
+ {
+ debug (0, "Messenger has no thread to activate!");
+ return false;
+ }
+
+ if (object_type ((struct object *) thread) != cap_thread)
+ {
+ debug (0, "Messenger's thread cap does not designate a thread but a %s",
+ cap_type_string (object_type ((struct object *) thread)));
+ return false;
+ }
+
+ return thread_activate (activity, thread, messenger, true);
+}
+
+void
+messenger_unblock (struct activity *activity, struct messenger *messenger)
+{
+ if (! messenger->blocked)
+ return;
+
+ messenger->blocked = 0;
+
+ struct messenger *m;
+ object_wait_queue_for_each (activity, (struct object *) messenger, m)
+ if (m->wait_reason == MESSENGER_WAIT_TRANSFER_MESSAGE)
+ {
+ object_wait_queue_unlink (activity, m);
+ bool ret = messenger_message_transfer (activity, messenger, m, true);
+ assert (ret);
+
+ break;
+ }
+}
+
+void
+messenger_destroy (struct activity *activity, struct messenger *messenger)
+{
+ if (messenger->wait_queue_p)
+ /* MESSENGER is attached to a wait queue. Detach it. */
+ object_wait_queue_unlink (activity, messenger);
+}
diff --git a/viengoos/messenger.h b/viengoos/messenger.h
new file mode 100644
index 0000000..abbf8ff
--- /dev/null
+++ b/viengoos/messenger.h
@@ -0,0 +1,214 @@
+/* messenger.h - Messenger buffer definitions.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ Written by Neal H. Walfield <neal@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ GNU Hurd is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _MESSENGER_H
+#define _MESSENGER_H 1
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <hurd/cap.h>
+#include <hurd/messenger.h>
+#include <hurd/message.h>
+
+#ifndef NDEBUG
+#include "../viengoos/list.h"
+#endif
+
+/* Messenger may be enqueued on any object and for different reasons.
+ The reason an object is enqueued is stored in the WAIT_REASON.
+ These are the reasons. */
+enum
+ {
+ /* The messenger is blocked on an object wait for a futex.
+ WAIT_REASON_ARG holds the byte offset in the object on which it
+ is waiting. */
+ MESSENGER_WAIT_FUTEX,
+
+ /* The messenger is blocked on an object waiting for the object to
+ be destroyed. */
+ MESSENGER_WAIT_DESTROY,
+
+ /* The messenger is blocked on an activity waiting for
+ information. The type of information is stored in
+ wait_reason_arg. The period in wait_reason_arg2. */
+ MESSENGER_WAIT_ACTIVITY_INFO,
+
+ /* The messenger is trying to transfer a message to another
+ messenger or to a thread. */
+ MESSENGER_WAIT_TRANSFER_MESSAGE,
+ };
+
+/* Messenger object. */
+struct messenger
+{
+ /* When this messenger is activated (that is, its contents are
+ delivered or it receives a message), THREAD is activated. This
+ is settable from user space. */
+ struct cap thread;
+
+ /* The root of the address space in which capability addresses
+ referenced in the message are resolved. */
+ struct cap as_root;
+
+ /* The message buffer. */
+ struct cap buffer;
+
+ /* The activity supplied by the sender of the message. */
+ struct cap sender_activity;
+
+
+ /* Whether the data is inline or out of line. */
+ bool out_of_band;
+
+ /* The inline data. */
+ int inline_word_count;
+ int inline_cap_count;
+
+ /* Inline data. */
+ uintptr_t inline_words[VG_MESSENGER_INLINE_WORDS];
+ addr_t inline_caps[VG_MESSENGER_INLINE_CAPS];
+
+
+ /* The buffer's version. If USER_VERSION_MATCHING is true, a
+ message can only be delivered if the user version in the
+ capability used to designate the buffer matches the buffer's user
+ version. */
+ uint64_t user_version;
+
+ /* If the user version in the capability must match
+ USER_VERSION. */
+ bool user_version_matching;
+ bool user_version_increment_on_delivery;
+
+
+ /* If the buffer is blocked, no messages will be delivered.
+ When a message is deliveried to this buffer, this is set to
+ true. */
+ bool blocked;
+
+ /* Activate thread when this messenger receives a message. */
+ bool activate_on_receive;
+ /* Activate thread when this messenger sends a message. */
+ bool activate_on_send;
+
+ /* The payload in the capability that was used to delivery the
+ message. This is only valid if this buffer contains an
+ (undelivered) message. */
+ uint64_t protected_payload;
+
+ /* The messenger's identifier. */
+ uint64_t id;
+
+
+ /* The object the messenger is waiting on. Only meaningful if
+ WAIT_QUEUE_P is true.
+
+ The list node used to connect a messenger to its target's
+ sender's wait queue.
+
+ Senders are arranged in a doubly-linked list. The head points to
+ the second element and the last element. The last element points
+ to the root and the second to last object.
+
+
+ H ----> 1
+ ^ //\
+ | / ||
+ ||/_ \/
+ 3 <===> 2
+
+ Next pointers: H -> 1 -> 2 -> 3 -> H
+ Previous pointers: 1 -> 3 -> 2 -> 1
+ */
+ struct
+ {
+ /* We don't need versioning as we automatically collect on object
+ destruction. */
+ oid_t next;
+ oid_t prev;
+ } wait_queue;
+
+ /* Whether the object is attached to a wait queue. (This is
+ different from the value of folio_object_wait_queue_p which
+ specifies if there are objects on this thread's wait queue.) */
+ uint32_t wait_queue_p : 1;
+
+ /* Whether this messenger is the head of the wait queue. If so,
+ WAIT_QUEUE.PREV designates the object. */
+ uint32_t wait_queue_head : 1;
+
+ /* Whether this messenger is the tail of the wait queue. If so,
+ WAIT_QUEUE.NEXT designates the object. */
+ uint32_t wait_queue_tail : 1;
+
+
+ /* Why the messenger is on a wait queue. */
+ uint32_t wait_reason : 27;
+ /* Additional information about the reason. */
+ uint32_t wait_reason_arg;
+ uint32_t wait_reason_arg2;
+
+#ifndef NDEBUG
+ /* Used for debugging futexes. */
+ struct list_node futex_waiter_node;
+#endif
+};
+
+#ifndef NDEBUG
+LIST_CLASS(futex_waiter, struct messenger, futex_waiter_node, true)
+/* List of threads waiting on a futex. */
+extern struct futex_waiter_list futex_waiters;
+#endif
+
+/* When the kernel formulates relies, it does so in this buffer. */
+extern struct vg_message *reply_buffer;
+
+/* Transfer SOURCE's message contents to TARGET. If TARGET is blocked
+ and MAY_BLOCK is true, enqueue SOURCE on TARGET. Returns whether
+ the message was delivered or whether SOURCE was enqueued on
+ TARGET. */
+extern bool messenger_message_transfer (struct activity *activity,
+ struct messenger *target,
+ struct messenger *source,
+ bool may_block);
+
+/* If target is not blocked, load the message MESSAGE into TARGET.
+ Returns whether the message was loaded. NB: ANY CAPABILITY
+ ADDRESSES ARE INTERPRETTED AS POINTERS TO STRUCT CAP!!! */
+extern bool messenger_message_load (struct activity *activity,
+ struct messenger *target,
+ struct vg_message *message);
+
+/* Attempt to deliver the message stored in TARGET to its thread. If
+ THREAD is activated, enqueues TARGET on it. */
+extern bool messenger_message_deliver (struct activity *activity,
+ struct messenger *target);
+
+/* Unblock messenger MESSENGER. If any messengers are waiting to
+ deliver a message attempt delivery. */
+extern void messenger_unblock (struct activity *activity,
+ struct messenger *messenger);
+
+/* Destroy the messenger MESSENGER: it is about to be deallocated. */
+extern void messenger_destroy (struct activity *activity,
+ struct messenger *messenger);
+
+#endif
diff --git a/viengoos/object.c b/viengoos/object.c
index 9dbc663..c91ff45 100644
--- a/viengoos/object.c
+++ b/viengoos/object.c
@@ -24,6 +24,7 @@
#include <hurd/ihash.h>
#include <hurd/folio.h>
#include <hurd/thread.h>
+#include <hurd/messenger.h>
#include <bit-array.h>
#include <assert.h>
@@ -31,6 +32,7 @@
#include "activity.h"
#include "thread.h"
#include "zalloc.h"
+#include "messenger.h"
/* For lack of a better place. */
ss_mutex_t kernel_lock;
@@ -527,7 +529,8 @@ folio_object_alloc (struct activity *activity,
/* Deallocate any existing object. */
if (folio_object_type (folio, idx) == cap_activity_control
- || folio_object_type (folio, idx) == cap_thread)
+ || folio_object_type (folio, idx) == cap_thread
+ || folio_object_type (folio, idx) == cap_messenger)
/* These object types have state that needs to be explicitly
destroyed. */
{
@@ -547,6 +550,10 @@ folio_object_alloc (struct activity *activity,
debug (4, "Destroying thread object at %llx", oid);
thread_deinit (activity, (struct thread *) object);
break;
+ case cap_messenger:
+ debug (4, "Destroying messenger object at %llx", oid);
+ messenger_destroy (activity, (struct messenger *) object);
+ break;
default:
assert (!"Object desc type does not match folio type.");
break;
@@ -555,14 +562,15 @@ folio_object_alloc (struct activity *activity,
/* Wake any threads waiting on this object. We wake them even if
they are not waiting for this object's death. */
- struct thread *thread;
- folio_object_wait_queue_for_each (activity, folio, idx, thread)
+ struct messenger *messenger;
+ folio_object_wait_queue_for_each (activity, folio, idx, messenger)
{
- object_wait_queue_dequeue (activity, thread);
- if (thread->wait_reason == THREAD_WAIT_DESTROY)
- rm_thread_wait_object_destroyed_reply (thread->tid, return_code);
+ object_wait_queue_unlink (activity, messenger);
+ if (messenger->wait_reason == MESSENGER_WAIT_DESTROY)
+ rm_object_reply_on_destruction_reply (activity,
+ messenger, return_code);
else
- rpc_error_reply (thread->tid, EFAULT);
+ rpc_error_reply (activity, messenger, EFAULT);
}
struct object_desc *odesc;
@@ -959,7 +967,7 @@ object_desc_claim (struct activity *activity, struct object_desc *desc,
}
/* Return the first waiter queued on object OBJECT. */
-struct thread *
+struct messenger *
object_wait_queue_head (struct activity *activity, struct object *object)
{
struct folio *folio = objects_folio (activity, object);
@@ -971,18 +979,18 @@ object_wait_queue_head (struct activity *activity, struct object *object)
oid_t h = folio_object_wait_queue (folio, i);
struct object *head = object_find (activity, h, OBJECT_POLICY_DEFAULT);
assert (head);
- assert (object_type (head) == cap_thread);
- assert (((struct thread *) head)->wait_queue_p);
- assert (((struct thread *) head)->wait_queue_head);
+ assert (object_type (head) == cap_messenger);
+ assert (((struct messenger *) head)->wait_queue_p);
+ assert (((struct messenger *) head)->wait_queue_head);
- return (struct thread *) head;
+ return (struct messenger *) head;
}
/* Return the last waiter queued on object OBJECT. */
-struct thread *
+struct messenger *
object_wait_queue_tail (struct activity *activity, struct object *object)
{
- struct thread *head = object_wait_queue_head (activity, object);
+ struct messenger *head = object_wait_queue_head (activity, object);
if (! head)
return NULL;
@@ -990,47 +998,47 @@ object_wait_queue_tail (struct activity *activity, struct object *object)
/* HEAD is also the list's tail. */
return head;
- struct thread *tail;
- tail = (struct thread *) object_find (activity, head->wait_queue.prev,
- OBJECT_POLICY_DEFAULT);
+ struct messenger *tail;
+ tail = (struct messenger *) object_find (activity, head->wait_queue.prev,
+ OBJECT_POLICY_DEFAULT);
assert (tail);
- assert (object_type ((struct object *) tail) == cap_thread);
+ assert (object_type ((struct object *) tail) == cap_messenger);
assert (tail->wait_queue_p);
assert (tail->wait_queue_tail);
return tail;
}
-/* Return the waiter following THREAD. */
-struct thread *
-object_wait_queue_next (struct activity *activity, struct thread *t)
+/* Return the waiter following M. */
+struct messenger *
+object_wait_queue_next (struct activity *activity, struct messenger *m)
{
- if (t->wait_queue_tail)
+ if (m->wait_queue_tail)
return NULL;
- struct thread *next;
- next = (struct thread *) object_find (activity, t->wait_queue.next,
- OBJECT_POLICY_DEFAULT);
+ struct messenger *next;
+ next = (struct messenger *) object_find (activity, m->wait_queue.next,
+ OBJECT_POLICY_DEFAULT);
assert (next);
- assert (object_type ((struct object *) next) == cap_thread);
+ assert (object_type ((struct object *) next) == cap_messenger);
assert (next->wait_queue_p);
assert (! next->wait_queue_head);
return next;
}
-/* Return the waiter preceding THREAD. */
-struct thread *
-object_wait_queue_prev (struct activity *activity, struct thread *t)
+/* Return the waiter preceding M. */
+struct messenger *
+object_wait_queue_prev (struct activity *activity, struct messenger *m)
{
- if (t->wait_queue_head)
+ if (m->wait_queue_head)
return NULL;
- struct thread *prev;
- prev = (struct thread *) object_find (activity, t->wait_queue.prev,
- OBJECT_POLICY_DEFAULT);
+ struct messenger *prev;
+ prev = (struct messenger *) object_find (activity, m->wait_queue.prev,
+ OBJECT_POLICY_DEFAULT);
assert (prev);
- assert (object_type ((struct object *) prev) == cap_thread);
+ assert (object_type ((struct object *) prev) == cap_messenger);
assert (prev->wait_queue_p);
assert (! prev->wait_queue_tail);
@@ -1038,29 +1046,29 @@ object_wait_queue_prev (struct activity *activity, struct thread *t)
}
static void
-object_wait_queue_check (struct activity *activity, struct thread *thread)
+object_wait_queue_check (struct activity *activity, struct messenger *messenger)
{
#ifndef NDEBUG
- if (! thread->wait_queue_p)
+ if (! messenger->wait_queue_p)
return;
- struct thread *last = thread;
- struct thread *t;
+ struct messenger *last = messenger;
+ struct messenger *m;
for (;;)
{
if (last->wait_queue_tail)
break;
- t = (struct thread *) object_find (activity, last->wait_queue.next,
- OBJECT_POLICY_DEFAULT);
- assert (t);
- assert (t->wait_queue_p);
- assert (! t->wait_queue_head);
- struct object *p = object_find (activity, t->wait_queue.prev,
+ m = (struct messenger *) object_find (activity, last->wait_queue.next,
+ OBJECT_POLICY_DEFAULT);
+ assert (m);
+ assert (m->wait_queue_p);
+ assert (! m->wait_queue_head);
+ struct object *p = object_find (activity, m->wait_queue.prev,
OBJECT_POLICY_DEFAULT);
assert (p == (struct object *) last);
- last = t;
+ last = m;
}
assert (last->wait_queue_tail);
@@ -1071,68 +1079,67 @@ object_wait_queue_check (struct activity *activity, struct thread *thread)
assert (folio_object_wait_queue_p (objects_folio (activity, o),
objects_folio_offset (o)));
- struct thread *head = object_wait_queue_head (activity, o);
+ struct messenger *head = object_wait_queue_head (activity, o);
if (! head)
return;
assert (head->wait_queue_head);
- struct thread *tail;
- tail = (struct thread *) object_find (activity, head->wait_queue.prev,
- OBJECT_POLICY_DEFAULT);
+ struct messenger *tail;
+ tail = (struct messenger *) object_find (activity, head->wait_queue.prev,
+ OBJECT_POLICY_DEFAULT);
assert (tail);
assert (tail->wait_queue_tail);
assert (last == tail);
last = head;
- while (last != thread)
+ while (last != messenger)
{
assert (! last->wait_queue_tail);
- t = (struct thread *) object_find (activity, last->wait_queue.next,
- OBJECT_POLICY_DEFAULT);
- assert (t);
- assert (t->wait_queue_p);
- assert (! t->wait_queue_head);
+ m = (struct messenger *) object_find (activity, last->wait_queue.next,
+ OBJECT_POLICY_DEFAULT);
+ assert (m);
+ assert (m->wait_queue_p);
+ assert (! m->wait_queue_head);
- struct object *p = object_find (activity, t->wait_queue.prev,
+ struct object *p = object_find (activity, m->wait_queue.prev,
OBJECT_POLICY_DEFAULT);
assert (p == (struct object *) last);
- last = t;
+ last = m;
}
#endif /* !NDEBUG */
}
-/* Enqueue the thread THREAD on object OBJECT's wait queue. */
void
-object_wait_queue_enqueue (struct activity *activity,
- struct object *object, struct thread *thread)
+object_wait_queue_push (struct activity *activity,
+ struct object *object, struct messenger *messenger)
{
- debug (5, "Adding " OID_FMT " to %p",
- OID_PRINTF (object_to_object_desc ((struct object *) thread)->oid),
+ debug (5, "Pushing " OID_FMT " onto %p",
+ OID_PRINTF (object_to_object_desc ((struct object *) messenger)->oid),
object);
- object_wait_queue_check (activity, thread);
+ object_wait_queue_check (activity, messenger);
- assert (! thread->wait_queue_p);
+ assert (! messenger->wait_queue_p);
- struct thread *oldhead = object_wait_queue_head (activity, object);
+ struct messenger *oldhead = object_wait_queue_head (activity, object);
if (oldhead)
{
assert (oldhead->wait_queue_head);
- /* THREAD->PREV = TAIL. */
- thread->wait_queue.prev = oldhead->wait_queue.prev;
+ /* MESSENGER->PREV = TAIL. */
+ messenger->wait_queue.prev = oldhead->wait_queue.prev;
- /* OLDHEAD->PREV = THREAD. */
+ /* OLDHEAD->PREV = MESSENGER. */
oldhead->wait_queue_head = 0;
- oldhead->wait_queue.prev = object_oid ((struct object *) thread);
+ oldhead->wait_queue.prev = object_oid ((struct object *) messenger);
- /* THREAD->NEXT = OLDHEAD. */
- thread->wait_queue.next = object_oid ((struct object *) oldhead);
+ /* MESSENGER->NEXT = OLDHEAD. */
+ messenger->wait_queue.next = object_oid ((struct object *) oldhead);
- thread->wait_queue_tail = 0;
+ messenger->wait_queue_tail = 0;
}
else
/* Empty list. */
@@ -1141,133 +1148,194 @@ object_wait_queue_enqueue (struct activity *activity,
objects_folio_offset (object),
true);
- /* THREAD->PREV = THREAD. */
- thread->wait_queue.prev = object_oid ((struct object *) thread);
+ /* MESSENGER->PREV = MESSENGER. */
+ messenger->wait_queue.prev = object_oid ((struct object *) messenger);
- /* THREAD->NEXT = OBJECT. */
- thread->wait_queue_tail = 1;
- thread->wait_queue.next = object_oid (object);
+ /* MESSENGER->NEXT = OBJECT. */
+ messenger->wait_queue_tail = 1;
+ messenger->wait_queue.next = object_oid (object);
}
- thread->wait_queue_p = true;
+ messenger->wait_queue_p = true;
- /* WAIT_QUEUE = THREAD. */
- thread->wait_queue_head = 1;
+ /* WAIT_QUEUE = MESSENGER. */
+ messenger->wait_queue_head = 1;
folio_object_wait_queue_set (objects_folio (activity, object),
objects_folio_offset (object),
- object_oid ((struct object *) thread));
+ object_oid ((struct object *) messenger));
+
+ object_wait_queue_check (activity, messenger);
+}
+
+void
+object_wait_queue_enqueue (struct activity *activity,
+ struct object *object, struct messenger *messenger)
+{
+ debug (5, "Enqueueing " OID_FMT " on %p",
+ OID_PRINTF (object_to_object_desc ((struct object *) messenger)->oid),
+ object);
+
+ object_wait_queue_check (activity, messenger);
+
+ assert (! messenger->wait_queue_p);
+
+ struct messenger *oldtail = object_wait_queue_tail (activity, object);
+ if (oldtail)
+ {
+ /* HEAD->PREV = MESSENGER. */
+ struct messenger *head = object_wait_queue_head (activity, object);
+ head->wait_queue.prev = object_oid ((struct object *) messenger);
+
+ assert (oldtail->wait_queue_tail);
+
+ /* MESSENGER->PREV = OLDTAIL. */
+ messenger->wait_queue.prev = object_oid ((struct object *) oldtail);
+
+ /* OLDTAIL->NEXT = MESSENGER. */
+ oldtail->wait_queue_tail = 0;
+ oldtail->wait_queue.next = object_oid ((struct object *) messenger);
+
+ /* MESSENGER->NEXT = OBJECT. */
+ messenger->wait_queue.next = object_oid (object);
+
+ messenger->wait_queue_head = 0;
+ messenger->wait_queue_tail = 1;
+ }
+ else
+ /* Empty list. */
+ {
+ folio_object_wait_queue_p_set (objects_folio (activity, object),
+ objects_folio_offset (object),
+ true);
+
+ /* MESSENGER->PREV = MESSENGER. */
+ messenger->wait_queue.prev = object_oid ((struct object *) messenger);
+
+ /* MESSENGER->NEXT = OBJECT. */
+ messenger->wait_queue_tail = 1;
+ messenger->wait_queue.next = object_oid (object);
+
+ /* WAIT_QUEUE = MESSENGER. */
+ messenger->wait_queue_head = 1;
+ folio_object_wait_queue_set (objects_folio (activity, object),
+ objects_folio_offset (object),
+ object_oid ((struct object *) messenger));
+ }
+
+ messenger->wait_queue_p = true;
- object_wait_queue_check (activity, thread);
+ object_wait_queue_check (activity, messenger);
}
-/* Dequeue thread THREAD from its wait queue. */
+/* Unlink messenger MESSENGER from its wait queue. */
void
-object_wait_queue_dequeue (struct activity *activity, struct thread *thread)
+object_wait_queue_unlink (struct activity *activity,
+ struct messenger *messenger)
{
debug (5, "Removing " OID_FMT,
- OID_PRINTF (object_to_object_desc ((struct object *) thread)->oid));
+ OID_PRINTF (object_to_object_desc ((struct object *) messenger)->oid));
- assert (thread->wait_queue_p);
+ assert (messenger->wait_queue_p);
- object_wait_queue_check (activity, thread);
+ object_wait_queue_check (activity, messenger);
- if (thread->wait_queue_tail)
- /* THREAD is the tail. THREAD->NEXT must be the object on which
+ if (messenger->wait_queue_tail)
+ /* MESSENGER is the tail. MESSENGER->NEXT must be the object on which
we are queued. */
{
struct object *object;
- object = object_find (activity, thread->wait_queue.next,
+ object = object_find (activity, messenger->wait_queue.next,
OBJECT_POLICY_DEFAULT);
assert (object);
assert (folio_object_wait_queue_p (objects_folio (activity, object),
objects_folio_offset (object)));
- assert (object_wait_queue_tail (activity, object) == thread);
+ assert (object_wait_queue_tail (activity, object) == messenger);
- if (thread->wait_queue_head)
- /* THREAD is also the head and thus the only item on the
+ if (messenger->wait_queue_head)
+ /* MESSENGER is also the head and thus the only item on the
list. */
{
- assert (object_find (activity, thread->wait_queue.prev,
+ assert (object_find (activity, messenger->wait_queue.prev,
OBJECT_POLICY_DEFAULT)
- == (struct object *) thread);
+ == (struct object *) messenger);
folio_object_wait_queue_p_set (objects_folio (activity, object),
objects_folio_offset (object),
false);
}
else
- /* THREAD is not also the head. */
+ /* MESSENGER is not also the head. */
{
- struct thread *head = object_wait_queue_head (activity, object);
+ struct messenger *head = object_wait_queue_head (activity, object);
/* HEAD->PREV == TAIL. */
assert (object_find (activity, head->wait_queue.prev,
OBJECT_POLICY_DEFAULT)
- == (struct object *) thread);
+ == (struct object *) messenger);
/* HEAD->PREV = TAIL->PREV. */
- head->wait_queue.prev = thread->wait_queue.prev;
+ head->wait_queue.prev = messenger->wait_queue.prev;
/* TAIL->PREV->NEXT = OBJECT. */
- struct thread *prev;
- prev = (struct thread *) object_find (activity,
- thread->wait_queue.prev,
+ struct messenger *prev;
+ prev = (struct messenger *) object_find (activity,
+ messenger->wait_queue.prev,
OBJECT_POLICY_DEFAULT);
assert (prev);
- assert (object_type ((struct object *) prev) == cap_thread);
+ assert (object_type ((struct object *) prev) == cap_messenger);
prev->wait_queue_tail = 1;
- prev->wait_queue.next = thread->wait_queue.next;
+ prev->wait_queue.next = messenger->wait_queue.next;
}
}
else
- /* THREAD is not the tail. */
+ /* MESSENGER is not the tail. */
{
- struct thread *next = object_wait_queue_next (activity, thread);
+ struct messenger *next = object_wait_queue_next (activity, messenger);
assert (next);
- struct object *p = object_find (activity, thread->wait_queue.prev,
+ struct object *p = object_find (activity, messenger->wait_queue.prev,
OBJECT_POLICY_DEFAULT);
assert (p);
- assert (object_type (p) == cap_thread);
- struct thread *prev = (struct thread *) p;
+ assert (object_type (p) == cap_messenger);
+ struct messenger *prev = (struct messenger *) p;
- if (thread->wait_queue_head)
- /* THREAD is the head. */
+ if (messenger->wait_queue_head)
+ /* MESSENGER is the head. */
{
- /* THREAD->PREV is the tail, TAIL->NEXT the object. */
- struct thread *tail = prev;
+ /* MESSENGER->PREV is the tail, TAIL->NEXT the object. */
+ struct messenger *tail = prev;
struct object *object = object_find (activity, tail->wait_queue.next,
OBJECT_POLICY_DEFAULT);
assert (object);
- assert (object_wait_queue_head (activity, object) == thread);
+ assert (object_wait_queue_head (activity, object) == messenger);
- /* OBJECT->WAIT_QUEUE = THREAD->NEXT. */
+ /* OBJECT->WAIT_QUEUE = MESSENGER->NEXT. */
next->wait_queue_head = 1;
folio_object_wait_queue_set (objects_folio (activity, object),
objects_folio_offset (object),
- thread->wait_queue.next);
+ messenger->wait_queue.next);
}
else
- /* THREAD is neither the head nor the tail. */
+ /* MESSENGER is neither the head nor the tail. */
{
- /* THREAD->PREV->NEXT = THREAD->NEXT. */
- prev->wait_queue.next = thread->wait_queue.next;
+ /* MESSENGER->PREV->NEXT = MESSENGER->NEXT. */
+ prev->wait_queue.next = messenger->wait_queue.next;
}
- /* THREAD->NEXT->PREV = THREAD->PREV. */
- next->wait_queue.prev = thread->wait_queue.prev;
+ /* MESSENGER->NEXT->PREV = MESSENGER->PREV. */
+ next->wait_queue.prev = messenger->wait_queue.prev;
}
- thread->wait_queue_p = false;
+ messenger->wait_queue_p = false;
#ifndef NDEBUG
- if (thread->wait_reason == THREAD_WAIT_FUTEX)
- futex_waiter_list_unlink (&futex_waiters, thread);
+ if (messenger->wait_reason == MESSENGER_WAIT_FUTEX)
+ futex_waiter_list_unlink (&futex_waiters, messenger);
#endif
- object_wait_queue_check (activity, thread);
+ object_wait_queue_check (activity, messenger);
}
diff --git a/viengoos/object.h b/viengoos/object.h
index 077bd7e..47f36b2 100644
--- a/viengoos/object.h
+++ b/viengoos/object.h
@@ -536,56 +536,63 @@ extern void folio_policy (struct activity *activity,
struct folio_policy *out);
/* Return the first waiter queued on object OBJECT. */
-extern struct thread *object_wait_queue_head (struct activity *activity,
- struct object *object);
+extern struct messenger *object_wait_queue_head (struct activity *activity,
+ struct object *object);
/* Return the last waiter queued on object OBJECT. */
-extern struct thread *object_wait_queue_tail (struct activity *activity,
- struct object *object);
+extern struct messenger *object_wait_queue_tail (struct activity *activity,
+ struct object *object);
-/* Return the waiter following THREAD. */
-extern struct thread *object_wait_queue_next (struct activity *activity,
- struct thread *thread);
+/* Return the waiter following MESSENGER. */
+extern struct messenger *object_wait_queue_next (struct activity *activity,
+ struct messenger *messenger);
-/* Return the waiter preceding THREAD. */
-extern struct thread *object_wait_queue_prev (struct activity *activity,
- struct thread *thread);
+/* Return the waiter preceding MESSENGER. */
+extern struct messenger *object_wait_queue_prev (struct activity *activity,
+ struct messenger *messenger);
-/* Enqueue thread on object OBJECT's wait queue. */
+/* Push the messenger MESSENGER onto object OBJECT's wait queue (i.e.,
+ add it to the front of the wait queue). */
+extern void object_wait_queue_push (struct activity *activity,
+ struct object *object,
+ struct messenger *messenger);
+
+/* Enqueue the messenger MESSENGER on object OBJECT's wait queue
+ (i.e., add it to the end of the wait queue). */
extern void object_wait_queue_enqueue (struct activity *activity,
struct object *object,
- struct thread *thread);
+ struct messenger *messenger);
-/* Dequeue thread THREAD from its wait queue. */
-extern void object_wait_queue_dequeue (struct activity *activity,
- struct thread *thread);
+/* Unlink messenger MESSENGER from its wait queue. */
+extern void object_wait_queue_unlink (struct activity *activity,
+ struct messenger *messenger);
-/* Iterate over each thread waiting on the object at IDX in FOLIO. It
+/* Iterate over each messenger waiting on the object at IDX in FOLIO. It
is safe to call object_wait_queue_dequeue. */
#define folio_object_wait_queue_for_each(__owqfe_activity, \
__owqfe_folio, __owqfe_idx, \
- __owqfe_thread) \
- for (struct thread *__owqfe_next \
- = (struct thread *) \
+ __owqfe_messenger) \
+ for (struct messenger *__owqfe_next \
+ = (struct messenger *) \
(folio_object_wait_queue_p (__owqfe_folio, __owqfe_idx) \
? object_find (__owqfe_activity, \
folio_object_wait_queue (__owqfe_folio, \
__owqfe_idx), \
OBJECT_POLICY_VOID) \
: NULL); \
- (__owqfe_thread = __owqfe_next) \
+ (__owqfe_messenger = __owqfe_next) \
&& ((__owqfe_next = object_wait_queue_next (__owqfe_activity, \
- __owqfe_thread)) \
+ __owqfe_messenger)) \
|| 1); /* do nothing. */)
#define object_wait_queue_for_each(__owqfe_activity, __owqfe_object, \
- __owqfe_thread) \
- for (struct thread *__owqfe_next \
+ __owqfe_messenger) \
+ for (struct messenger *__owqfe_next \
= object_wait_queue_head (__owqfe_activity, __owqfe_object); \
- (__owqfe_thread = __owqfe_next) \
+ (__owqfe_messenger = __owqfe_next) \
&& ((__owqfe_next = object_wait_queue_next (__owqfe_activity, \
- __owqfe_thread)) \
+ __owqfe_messenger)) \
|| 1); /* do nothing. */)
#endif
diff --git a/viengoos/pager.c b/viengoos/pager.c
index 65ccb5f..8b3b038 100644
--- a/viengoos/pager.c
+++ b/viengoos/pager.c
@@ -23,8 +23,9 @@
#include "activity.h"
#include "object.h"
#include "pager.h"
-#include "thread.h"
#include "profile.h"
+#include "messenger.h"
+#include "thread.h"
int pager_min_alloc_before_next_collect;
@@ -484,14 +485,13 @@ pager_collect (int goal)
bool need_reclaim = true;
- struct thread *thread;
- object_wait_queue_for_each (victim, (struct object *) victim,
- thread)
- if (thread->wait_reason == THREAD_WAIT_ACTIVITY_INFO
- && (thread->wait_reason_arg & activity_info_pressure))
+ struct messenger *m;
+ object_wait_queue_for_each (victim, (struct object *) victim, m)
+ if (m->wait_reason == MESSENGER_WAIT_ACTIVITY_INFO
+ && (m->wait_reason_arg & activity_info_pressure))
break;
- if (thread)
+ if (m)
{
debug (5, DEBUG_BOLD ("Requesting that " OBJECT_NAME_FMT " free "
"%d pages.")
@@ -528,12 +528,12 @@ pager_collect (int goal)
object_wait_queue_for_each (victim,
(struct object *) victim,
- thread)
- if (thread->wait_reason == THREAD_WAIT_ACTIVITY_INFO
- && (thread->wait_reason_arg & activity_info_pressure))
+ m)
+ if (m->wait_reason == MESSENGER_WAIT_ACTIVITY_INFO
+ && (m->wait_reason_arg & activity_info_pressure))
{
- object_wait_queue_dequeue (victim, thread);
- rm_activity_info_reply (thread->tid, info);
+ object_wait_queue_unlink (victim, m);
+ rm_activity_info_reply (root_activity, m, info);
}
}
diff --git a/viengoos/rm.h b/viengoos/rm.h
index 03754e1..bef530e 100644
--- a/viengoos/rm.h
+++ b/viengoos/rm.h
@@ -27,6 +27,7 @@
#include <hurd/thread.h>
#include <hurd/activity.h>
#include <hurd/futex.h>
+#include <l4/message.h>
enum rm_method_id
{
@@ -55,32 +56,30 @@ rm_method_id_string (int id)
return "folio_free";
case RM_folio_object_alloc:
return "folio_object_alloc";
+ case RM_folio_policy:
+ return "folio_policy";
case RM_cap_copy:
return "cap_copy";
case RM_cap_rubout:
return "cap_rubout";
case RM_cap_read:
return "cap_read";
- case RM_object_slot_copy_out:
- return "object_slot_copy_out";
- case RM_object_slot_copy_in:
- return "object_slot_copy_in";
- case RM_object_slot_read:
- return "object_slot_read";
case RM_object_discarded_clear:
return "object_discarded_clear";
case RM_object_discard:
return "object_discard";
case RM_object_status:
return "object_status";
+ case RM_object_reply_on_destruction:
+ return "object_reply_on_destruction";
case RM_object_name:
return "object_name";
- case RM_exception_collect:
- return "exception_collect";
case RM_thread_exregs:
return "thread_exregs";
- case RM_thread_wait_object_destroyed:
- return "thread_wait_object_destroyed";
+ case RM_thread_id:
+ return "thread_id";
+ case RM_thread_activation_collect:
+ return "thread_activation_collect";
case RM_activity_policy:
return "activity_policy";
case RM_activity_info:
@@ -94,12 +93,6 @@ rm_method_id_string (int id)
#define RPC_STUB_PREFIX rm
#define RPC_ID_PREFIX RM
-#undef RPC_TARGET_NEED_ARG
-#define RPC_TARGET \
- ({ \
- extern struct hurd_startup_data *__hurd_startup_data; \
- __hurd_startup_data->rm; \
- })
#include <hurd/rpc.h>
@@ -107,20 +100,29 @@ struct io_buffer
{
/* The length. */
unsigned char len;
- char data[127];
+ char data[(L4_NUM_BRS - 2) * sizeof (uintptr_t)];
};
/* Echo the character CHR on the manager console. */
-RPC_SIMPLE(write, 1, 0, struct io_buffer, io)
+RPC(write, 1, 0, 0, struct io_buffer, io)
/* Read up to MAX characters from the console's input device. */
-RPC(read, 1, 1, int, max, struct io_buffer, io)
+RPC(read, 1, 1, 0,
+ int, max, struct io_buffer, io)
/* Dump the address space rooted at ROOT. */
-RPC(as_dump, 2, 0, addr_t, principal, addr_t, root)
-
-/* Fault up to the MIN (15, COUNT) pages starting at START. */
-RPC(fault, 3, 1, addr_t, principal, uintptr_t, start, int, count,
+RPC(as_dump, 0, 0, 0,
+ /* cap_t, principal, cap_t, object */)
+
+/* Fault up to COUNT pages starting at START. Returns the number
+ actually faulted in OCOUNT. */
+RPC(fault, 2, 1, 0,
+ /* cap_t, principal, cap_t thread, */
+ uintptr_t, start, int, count,
+ /* Out: */
int, ocount)
+#undef RPC_STUB_PREFIX
+#undef RPC_ID_PREFIX
+
#endif
diff --git a/viengoos/server.c b/viengoos/server.c
index 530577a..544a6c4 100644
--- a/viengoos/server.c
+++ b/viengoos/server.c
@@ -28,6 +28,7 @@
#include <hurd/futex.h>
#include <hurd/trace.h>
#include <hurd/as.h>
+#include <hurd/ipc.h>
#include "server.h"
@@ -38,6 +39,7 @@
#include "object.h"
#include "thread.h"
#include "activity.h"
+#include "messenger.h"
#include "viengoos.h"
#include "profile.h"
@@ -48,7 +50,7 @@ struct futex_waiter_list futex_waiters;
#ifndef NDEBUG
struct trace_buffer rpc_trace = TRACE_BUFFER_INIT ("rpcs", 0,
- false, false, false);
+ true, false, false);
/* Like debug but also prints the method id and saves to the trace
buffer if level is less than or equal to 4. */
@@ -59,11 +61,14 @@ struct trace_buffer rpc_trace = TRACE_BUFFER_INIT ("rpcs", 0,
trace_buffer_add (&rpc_trace, "(%x %s %d) " format, \
thread->tid, \
l4_is_pagefault (msg_tag) ? "pagefault" \
- : rm_method_id_string (label), label, \
+ : label == 8194 ? "IPC" \
+ : rm_method_id_string (label), \
+ label, \
##args); \
debug (level, "(%x %s:%d %d) " format, \
thread->tid, l4_is_pagefault (msg_tag) ? "pagefault" \
- : rm_method_id_string (label), __LINE__, label, \
+ : label == 8194 ? "IPC" : rm_method_id_string (label), \
+ __LINE__, label, \
##args); \
} \
while (0)
@@ -72,7 +77,8 @@ struct trace_buffer rpc_trace = TRACE_BUFFER_INIT ("rpcs", 0,
# define DEBUG(level, format, args...) \
debug (level, "(%x %s:%d %d) " format, \
thread->tid, l4_is_pagefault (msg_tag) ? "pagefault" \
- : rm_method_id_string (label), __LINE__, label, \
+ : label == 8194 ? "IPC" : rm_method_id_string (label), \
+ __LINE__, label, \
##args)
#endif
@@ -140,11 +146,11 @@ server_loop (void)
{
debug (0, "No IPCs for some time. Deadlock?");
- struct thread *thread;
- while ((thread = futex_waiter_list_head (&futex_waiters)))
+ struct messenger *messenger;
+ while ((messenger = futex_waiter_list_head (&futex_waiters)))
{
- object_wait_queue_dequeue (root_activity, thread);
- rpc_error_reply (thread->tid, EDEADLK);
+ object_wait_queue_unlink (root_activity, messenger);
+ rpc_error_reply (root_activity, messenger, EDEADLK);
}
trace_buffer_dump (&rpc_trace, 0);
@@ -166,7 +172,7 @@ server_loop (void)
#endif
l4_msg_store (msg_tag, msg);
- l4_word_t label;
+ uintptr_t label;
label = l4_label (msg_tag);
/* By default we reply to the sender. */
@@ -233,15 +239,15 @@ server_loop (void)
Thus, it is difficult to incorporate it into the case
switch below. */
{
- l4_word_t access;
- l4_word_t ip;
- l4_word_t fault = l4_pagefault (msg_tag, &access, &ip);
+ uintptr_t access;
+ uintptr_t ip;
+ uintptr_t fault = l4_pagefault (msg_tag, &access, &ip);
bool write_fault = !! (access & L4_FPAGE_WRITABLE);
- DEBUG (4, "%s fault at %x (ip = %x)",
+ DEBUG (4, "%s fault at %x (ip: %x)",
write_fault ? "Write" : "Read", fault, ip);
- l4_word_t page_addr = fault & ~(PAGESIZE - 1);
+ uintptr_t page_addr = fault & ~(PAGESIZE - 1);
struct cap cap;
bool writable;
@@ -264,7 +270,7 @@ server_loop (void)
if (! writable && cap.discardable)
{
- debug (5, "Ignoring discardable predicate for cap designating "
+ DEBUG (4, "Ignoring discardable predicate for cap designating "
OID_FMT " (%s)",
OID_PRINTF (cap.oid), cap_type_string (cap.type));
cap.discardable = false;
@@ -287,7 +293,7 @@ server_loop (void)
{
if (folio_object_discarded (folio, object))
{
- debug (5, OID_FMT " (%s) was discarded",
+ DEBUG (4, OID_FMT " (%s) was discarded",
OID_PRINTF (cap.oid),
cap_type_string (folio_object_type (folio,
object)));
@@ -296,7 +302,7 @@ server_loop (void)
discarded = true;
- debug (5, "Raising discarded fault at %x", page_addr);
+ DEBUG (5, "Raising discarded fault at %x", page_addr);
}
}
}
@@ -308,30 +314,29 @@ server_loop (void)
ip, fault, write_fault ? 'w' : 'r',
discarded ? " discarded" : "");
- l4_word_t c = _L4_XCHG_REGS_DELIVER;
+ uintptr_t c = _L4_XCHG_REGS_DELIVER;
l4_thread_id_t targ = thread->tid;
- l4_word_t sp = 0;
- l4_word_t dummy = 0;
+ uintptr_t sp = 0;
+ uintptr_t dummy = 0;
_L4_exchange_registers (&targ, &c,
&sp, &dummy, &dummy, &dummy, &dummy);
- struct exception_info info;
+ struct activation_fault_info info;
info.access = access;
info.type = write_fault ? cap_page : cap_rpage;
info.discarded = discarded;
- l4_msg_t msg;
- exception_fault_send_marshal (&msg, PTR_TO_ADDR (fault),
- sp, ip, info);
-
- thread_raise_exception (activity, thread, &msg);
+ activation_fault_send_marshal (reply_buffer, PTR_TO_ADDR (fault),
+ sp, ip, info, ADDR_VOID);
+ thread_raise_exception (activity, thread, reply_buffer);
continue;
}
- DEBUG (4, "%s fault at " DEBUG_BOLD ("%x") " (ip=%x), replying with %p(r%s)",
- write_fault ? "Write" : "Read", page_addr, ip, page,
+ DEBUG (4, "%s fault at " DEBUG_BOLD ("%x") " (ip=%x), "
+ "replying with %p(r%s)",
+ write_fault ? "Write" : "Read", fault, ip, page,
writable ? "w" : "");
object_to_object_desc (page)->mapped = true;
@@ -405,19 +410,18 @@ server_loop (void)
struct activity *principal;
- /* If ERR_ is not 0, create a message indicating an error with the
- error code ERR_. Go to the start of the server loop. */
+ /* Create a message indicating an error with the error code ERR_.
+ Go to the start of the server loop. */
#define REPLY(err_) \
do \
{ \
if (err_) \
- { \
- DEBUG (1, DEBUG_BOLD ("Returning error %d"), err_); \
- l4_msg_clear (msg); \
- l4_msg_put_word (msg, 0, (err_)); \
- l4_msg_set_untyped_words (msg, 1); \
- do_reply = 1; \
- } \
+ DEBUG (1, DEBUG_BOLD ("Returning error %d to %x"), \
+ err_, from); \
+ l4_msg_clear (msg); \
+ l4_msg_put_word (msg, 0, (err_)); \
+ l4_msg_set_untyped_words (msg, 1); \
+ do_reply = 1; \
goto out; \
} \
while (0)
@@ -498,24 +502,26 @@ server_loop (void)
error_t OBJECT_ (struct cap *root,
addr_t addr, int type, bool require_writable,
- struct object **objectp)
+ struct object **objectp, bool *writable)
{
- bool writable = true;
+ bool w = true;
struct cap cap;
- cap = as_object_lookup_rel (principal, root, addr, type,
- require_writable ? &writable : NULL);
+ cap = as_object_lookup_rel (principal, root, addr, type, &w);
if (type != -1 && ! cap_types_compatible (cap.type, type))
{
- DEBUG (4, "Addr 0x%llx/%d does not reference object of "
+ DEBUG (0, "Addr 0x%llx/%d does not reference object of "
"type %s but %s",
addr_prefix (addr), addr_depth (addr),
cap_type_string (type), cap_type_string (cap.type));
return ENOENT;
}
- if (require_writable && ! writable)
+ if (writable)
+ *writable = w;
+
+ if (require_writable && ! w)
{
- DEBUG (4, "Addr " ADDR_FMT " not writable",
+ DEBUG (0, "Addr " ADDR_FMT " not writable",
ADDR_PRINTF (addr));
return EPERM;
}
@@ -523,19 +529,20 @@ server_loop (void)
*objectp = cap_to_object (principal, &cap);
if (! *objectp)
{
- DEBUG (4, "Addr " ADDR_FMT " contains a dangling pointer: "
- CAP_FMT,
- ADDR_PRINTF (addr), CAP_PRINTF (&cap));
+ do_debug (4)
+ DEBUG (0, "Addr " ADDR_FMT " contains a dangling pointer: "
+ CAP_FMT,
+ ADDR_PRINTF (addr), CAP_PRINTF (&cap));
return ENOENT;
}
return 0;
}
-#define OBJECT(root_, addr_, type_, require_writable_) \
+#define OBJECT(root_, addr_, type_, require_writable_, writablep_) \
({ \
struct object *OBJECT_ret; \
error_t err = OBJECT_ (root_, addr_, type_, require_writable_, \
- &OBJECT_ret); \
+ &OBJECT_ret, writablep_); \
if (err) \
REPLY (err); \
OBJECT_ret; \
@@ -557,7 +564,7 @@ server_loop (void)
thread if it matches the guard exactly. */ \
struct object *t_; \
error_t err = OBJECT_ (&thread->aspace, root_addr_, \
- cap_thread, true, &t_); \
+ cap_thread, true, &t_, NULL); \
if (! err) \
root_ = &((struct thread *) t_)->aspace; \
else \
@@ -568,46 +575,6 @@ server_loop (void)
root_; \
})
- if (label == RM_write)
- {
- struct io_buffer buffer;
- err = rm_write_send_unmarshal (&msg, &buffer);
- if (! err)
- {
- int i;
- for (i = 0; i < buffer.len; i ++)
- putchar (buffer.data[i]);
- }
-
- /* No reply needed. */
- do_reply = 0;
- continue;
- }
- else if (label == RM_read)
- {
- int max;
- err = rm_read_send_unmarshal (&msg, &max);
- if (err)
- {
- DEBUG (0, "Read error!");
- REPLY (EINVAL);
- }
-
- struct io_buffer buffer;
- buffer.len = 0;
-
- if (max > 0)
- {
- buffer.len = 1;
- buffer.data[0] = getchar ();
- }
-
- rm_read_reply_marshal (&msg, buffer);
- continue;
- }
-
- do_reply = 1;
-
/* Return the next word. */
#define ARG(word_) l4_msg_word (msg, word_);
@@ -628,19 +595,224 @@ server_loop (void)
#define ARG_ADDR(word_) ((addr_t) { ARG64(word_) })
+ if (label == 2132)
+ /* write. */
+ {
+ int len = msg[1];
+ char *buffer = (char *) &msg[2];
+ buffer[len] = 0;
+ s_printf ("%s", buffer);
+ continue;
+ }
+
+ if (label != 8194)
+ {
+ DEBUG (0, "Invalid label: %d", label);
+ continue;
+ }
+
+ int i = 0;
+ uintptr_t flags = ARG (i);
+ i ++;
+ addr_t recv_activity = ARG_ADDR (i);
+ i += ARG64_WORDS;
+ addr_t recv_messenger = ARG_ADDR (i);
+ i += ARG64_WORDS;
+ addr_t recv_buf = ARG_ADDR (i);
+ i += ARG64_WORDS;
+ addr_t recv_inline_cap = ARG_ADDR (i);
+ i += ARG64_WORDS;
+
+ addr_t send_activity = ARG_ADDR (i);
+ i += ARG64_WORDS;
+ addr_t target_messenger = ARG_ADDR (i);
+ i += ARG64_WORDS;
+
+ addr_t send_messenger = ARG_ADDR (i);
+ i += ARG64_WORDS;
+ addr_t send_buf = ARG_ADDR (i);
+ i += ARG64_WORDS;
+
+ uintptr_t inline_word1 = ARG (i);
+ i ++;
+ uintptr_t inline_word2 = ARG (i);
+ i ++;
+ addr_t inline_cap = ARG_ADDR (i);
+
+#ifndef NDEBUG
+ /* Get the label early to improve debugging output in case the
+ target is invalid. */
+ if ((flags & VG_IPC_SEND))
+ {
+ if ((flags & VG_IPC_SEND_INLINE))
+ label = inline_word1;
+ else
+ {
+ principal = activity;
+
+ struct cap cap = CAP_VOID;
+ if (! ADDR_IS_VOID (send_buf))
+ /* Caller provided a send buffer. */
+ CAP_ (&thread->aspace, send_buf, cap_page, true, &cap);
+ else
+ {
+ struct object *object = NULL;
+ OBJECT_ (&thread->aspace, send_messenger,
+ cap_messenger, true, &object, NULL);
+ if (object)
+ cap = ((struct messenger *) object)->buffer;
+ }
+
+ struct vg_message *message;
+ message = (struct vg_message *) cap_to_object (principal,
+ &cap);
+ if (message)
+ label = vg_message_word (message, 0);
+ }
+ }
+#endif
+
+ DEBUG (4, "flags: %s%s%s%s%s%s %s%s%s%s%s%s %s %s%s%s%s(%x),"
+ "recv (" ADDR_FMT ", " ADDR_FMT ", " ADDR_FMT "), "
+ "send (" ADDR_FMT ", " ADDR_FMT ", " ADDR_FMT ", " ADDR_FMT "), "
+ "inline (" ADDR_FMT "; %x, %x, " ADDR_FMT ")",
+ (flags & VG_IPC_RECEIVE) ? "R" : "-",
+ (flags & VG_IPC_RECEIVE_NONBLOCKING) ? "N" : "B",
+ (flags & VG_IPC_RECEIVE_ACTIVATE) ? "A" : "-",
+ (flags & VG_IPC_RECEIVE_SET_THREAD_TO_CALLER) ? "T" : "-",
+ (flags & VG_IPC_RECEIVE_SET_ASROOT_TO_CALLERS) ? "A" : "-",
+ (flags & VG_IPC_RECEIVE_INLINE) ? "I" : "-",
+ (flags & VG_IPC_SEND) ? "S" : "-",
+ (flags & VG_IPC_SEND_NONBLOCKING) ? "N" : "B",
+ (flags & VG_IPC_SEND_ACTIVATE) ? "A" : "-",
+ (flags & VG_IPC_SEND_SET_THREAD_TO_CALLER) ? "T" : "-",
+ (flags & VG_IPC_SEND_SET_ASROOT_TO_CALLERS) ? "A" : "-",
+ (flags & VG_IPC_SEND_INLINE) ? "I" : "-",
+ (flags & VG_IPC_RETURN) ? "R" : "-",
+ (flags & VG_IPC_RECEIVE_INLINE_CAP1) ? "C" : "-",
+ (flags & VG_IPC_SEND_INLINE_WORD1) ? "1" : "-",
+ (flags & VG_IPC_SEND_INLINE_WORD2) ? "2" : "-",
+ (flags & VG_IPC_SEND_INLINE_CAP1) ? "C" : "-",
+ flags,
+ ADDR_PRINTF (recv_activity), ADDR_PRINTF (recv_messenger),
+ ADDR_PRINTF (recv_buf),
+ ADDR_PRINTF (send_activity), ADDR_PRINTF (target_messenger),
+ ADDR_PRINTF (send_messenger), ADDR_PRINTF (send_buf),
+ ADDR_PRINTF (recv_inline_cap),
+ inline_word1, inline_word2, ADDR_PRINTF (inline_cap));
+
+ if ((flags & VG_IPC_RECEIVE))
+ /* IPC includes a receive phase. */
+ {
+ principal = activity;
+ if (! ADDR_IS_VOID (recv_activity))
+ {
+ principal = (struct activity *) OBJECT (&thread->aspace,
+ recv_activity,
+ cap_activity, false,
+ NULL);
+ if (! principal)
+ {
+ DEBUG (0, "Invalid receive activity.");
+ REPLY (ENOENT);
+ }
+ }
+
+ struct messenger *messenger
+ = (struct messenger *) OBJECT (&thread->aspace,
+ recv_messenger, cap_messenger,
+ true, NULL);
+ if (! messenger)
+ {
+ DEBUG (0, "IPC includes receive phase, however, "
+ "no receive messenger provided.");
+ REPLY (EINVAL);
+ }
+
+ if ((flags & VG_IPC_RECEIVE_INLINE))
+ {
+ messenger->out_of_band = false;
+ if ((flags & VG_IPC_RECEIVE_INLINE_CAP1))
+ messenger->inline_caps[0] = recv_inline_cap;
+ }
+ else
+ {
+ messenger->out_of_band = true;
+ if (unlikely (! ADDR_IS_VOID (recv_buf)))
+ /* Associate RECV_BUF with RECV_MESSENGER. */
+ messenger->buffer = CAP (&thread->aspace, recv_buf,
+ cap_page, true);
+ }
+
+ if (unlikely ((flags & VG_IPC_RECEIVE_SET_THREAD_TO_CALLER)))
+ messenger->thread = object_to_cap ((struct object *) thread);
+
+ if (unlikely ((flags & VG_IPC_RECEIVE_SET_ASROOT_TO_CALLERS)))
+ messenger->as_root = thread->aspace;
+
+ messenger->activate_on_receive = (flags & VG_IPC_RECEIVE_ACTIVATE);
+
+ /* See if there is a messenger trying to send to
+ MESSENGER. */
+ struct messenger *sender;
+ object_wait_queue_for_each (principal,
+ (struct object *) messenger, sender)
+ if (sender->wait_reason == MESSENGER_WAIT_TRANSFER_MESSAGE)
+ /* There is. Transfer SENDER's message to MESSENGER. */
+ {
+ object_wait_queue_unlink (principal, sender);
+
+ assert (messenger->blocked);
+ messenger->blocked = 0;
+ bool ret = messenger_message_transfer (principal,
+ messenger, sender,
+ true);
+ assert (ret);
+
+ break;
+ }
+
+ if (! sender)
+ /* There was no sender waiting. */
+ {
+ if ((flags & VG_IPC_RECEIVE_NONBLOCKING))
+ /* The receive phase is non-blocking. */
+ REPLY (EWOULDBLOCK);
+ else
+ /* Unblock MESSENGER. */
+ messenger->blocked = 0;
+ }
+ }
+
+ if (! (flags & VG_IPC_SEND))
+ /* No send phase. */
+ {
+ if ((flags & VG_IPC_RETURN))
+ /* But a return phase. */
+ REPLY (0);
+
+ continue;
+ }
+
+ /* Send phase. */
+
+ if ((flags & VG_IPC_SEND_INLINE))
+ label = inline_word1;
+
principal = activity;
- addr_t principal_addr = ARG_ADDR (0);
struct cap principal_cap;
- if (! ADDR_IS_VOID (principal_addr))
+ if (! ADDR_IS_VOID (send_activity))
{
+ /* We need the cap below, otherwise, we could just use
+ OBJECT. */
principal_cap = CAP (&thread->aspace,
- principal_addr, cap_activity, false);
+ send_activity, cap_activity, false);
principal = (struct activity *) cap_to_object (principal,
&principal_cap);
if (! principal)
{
DEBUG (4, "Dangling pointer at " ADDR_FMT,
- ADDR_PRINTF (principal_addr));
+ ADDR_PRINTF (send_activity));
REPLY (ENOENT);
}
}
@@ -650,26 +822,243 @@ server_loop (void)
principal = activity;
}
+ struct messenger *source
+ = (struct messenger *) OBJECT (&thread->aspace,
+ send_messenger, cap_messenger,
+ true, NULL);
+ if (unlikely (! source))
+ {
+ DEBUG (0, "Source not valid.");
+ REPLY (ENOENT);
+ }
+
+ if (unlikely (! ADDR_IS_VOID (send_buf)))
+ source->buffer = CAP (&thread->aspace, send_buf, cap_page, true);
+
+ if (unlikely ((flags & VG_IPC_SEND_SET_THREAD_TO_CALLER)))
+ source->thread = object_to_cap ((struct object *) thread);
+
+ if (unlikely ((flags & VG_IPC_SEND_SET_ASROOT_TO_CALLERS)))
+ source->as_root = thread->aspace;
+
+ source->activate_on_send = (flags & VG_IPC_SEND_ACTIVATE);
+
+ bool target_writable = true;
+ struct object *target;
+ /* We special case VOID to mean the current thread. */
+ if (ADDR_IS_VOID (target_messenger))
+ target = (struct object *) thread;
+ else
+ target = OBJECT (&thread->aspace, target_messenger, -1, false,
+ &target_writable);
+ if (! target)
+ {
+ DEBUG (0, "Target not valid.");
+ REPLY (ENOENT);
+ }
+
+ if (object_type (target) == cap_messenger && ! target_writable)
+ /* TARGET is a weak reference to a messenger. Forward the
+ message. */
+ {
+ DEBUG (5, "IPC: " OID_FMT " -> " OID_FMT,
+ OID_PRINTF (object_oid ((struct object *) source)),
+ OID_PRINTF (object_oid ((struct object *) target)));
+
+ if ((flags & VG_IPC_SEND_INLINE))
+ {
+ source->out_of_band = false;
+ source->inline_words[0] = inline_word1;
+ source->inline_words[1] = inline_word2;
+ source->inline_caps[0] = inline_cap;
+
+ if ((flags & VG_IPC_SEND_INLINE_WORD1)
+ && (flags & VG_IPC_SEND_INLINE_WORD2))
+ source->inline_word_count = 2;
+ else if ((flags & VG_IPC_SEND_INLINE_WORD1))
+ source->inline_word_count = 1;
+ else
+ source->inline_word_count = 0;
+
+ if ((flags & VG_IPC_SEND_INLINE_CAP1))
+ source->inline_cap_count = 1;
+ else
+ source->inline_cap_count = 0;
+ }
+ else
+ source->out_of_band = true;
+
+ if (messenger_message_transfer (principal,
+ (struct messenger *) target,
+ source,
+ ! (flags & VG_IPC_SEND_NONBLOCKING)))
+ /* The messenger has been enqueued. */
+ {
+ if ((flags & VG_IPC_RETURN))
+ REPLY (0);
+ continue;
+ }
+ else
+ REPLY (ETIMEDOUT);
+ }
+
+ /* TARGET designates a kernel implemented object. Implement
+ it. */
+
+ /* The reply messenger (if any). */
+ struct messenger *reply = NULL;
+
+ /* We are now so far that we should not reply to the caller but
+ to TARGET. Set up our handy REPLY macro to do so. */
+#undef REPLY
+ /* Send a reply indicating that an error with the error code ERR_.
+ Go to the start of the server loop. */
+#define REPLY(err_) \
+ do \
+ { \
+ if (err_) \
+ DEBUG (0, DEBUG_BOLD ("Returning error %d"), err_); \
+ if (reply) \
+ if (rpc_error_reply (principal, reply, err_)) \
+ DEBUG (0, DEBUG_BOLD ("Failed to send reply")); \
+ goto out; \
+ } \
+ while (0)
+
+
+ struct vg_message *message;
+ if ((flags & VG_IPC_SEND_INLINE))
+ {
+ message = reply_buffer;
+ vg_message_clear (message);
+ if ((flags & VG_IPC_SEND_INLINE_WORD1))
+ vg_message_append_word (message, inline_word1);
+ if ((flags & VG_IPC_SEND_INLINE_WORD2))
+ vg_message_append_word (message, inline_word2);
+ if ((flags & VG_IPC_SEND_INLINE_CAP1))
+ vg_message_append_cap (message, inline_cap);
+ }
+ else
+ {
+ if (source->buffer.type != cap_page)
+ {
+ DEBUG (0, "Sender user-buffer has wrong type: %s",
+ cap_type_string (source->buffer.type));
+ REPLY (EINVAL);
+ }
+ message = (struct vg_message *) cap_to_object (principal,
+ &source->buffer);
+ if (! message)
+ {
+ DEBUG (0, "Sender user-buffer has wrong type: %s",
+ cap_type_string (source->buffer.type));
+ REPLY (EINVAL);
+ }
+ }
+
+ label = vg_message_word (message, 0);
+
+ do_debug (5)
+ {
+ DEBUG (0, "");
+ vg_message_dump (message);
+ }
+
+ /* Extract the reply messenger (if any). */
+ if (vg_message_cap_count (message) > 0)
+ /* We only look for a messenger here. We know that any reply
+ that a kernel object generates that is sent to a kernel
+ object will just result in a discarded EINVAL. */
+ reply = (struct messenger *)
+ OBJECT (&thread->aspace,
+ vg_message_cap (message,
+ vg_message_cap_count (message) - 1),
+ cap_rmessenger, false, NULL);
+
+ /* There are a number of methods that look up an object relative
+ to the invoked object. Generate an appropriate root for
+ them. */
+ struct cap target_root_cap;
+ struct cap *target_root;
+ if (likely (target == (struct object *) thread))
+ target_root = &thread->aspace;
+ else if (object_type (target) == cap_thread)
+ target_root = &((struct thread *) target)->aspace;
+ else
+ {
+ target_root_cap = object_to_cap (target);
+ target_root = &target_root_cap;
+ }
+
+ DEBUG (4, OID_FMT " %s(%llx) -> " OID_FMT " %s(%llx)",
+ OID_PRINTF (object_oid ((struct object *) source)),
+ cap_type_string (object_type ((struct object *) source)),
+ source->id,
+ OID_PRINTF (object_oid ((struct object *) target)),
+ cap_type_string (object_type (target)),
+ object_type (target) == cap_messenger
+ ? ((struct messenger *) target)->id : 0);
+ if (reply)
+ DEBUG (4, "reply to: " OID_FMT "(%llx)",
+ OID_PRINTF (object_oid ((struct object *) reply)),
+ reply->id);
+
switch (label)
{
+ case RM_write:
+ {
+ struct io_buffer buffer;
+ err = rm_write_send_unmarshal (message, &buffer, NULL);
+ if (! err)
+ {
+ int i;
+ for (i = 0; i < buffer.len; i ++)
+ putchar (buffer.data[i]);
+ }
+
+ rm_write_reply (activity, reply);
+ break;
+ }
+ case RM_read:
+ {
+ int max;
+ err = rm_read_send_unmarshal (message, &max, NULL);
+ if (err)
+ {
+ DEBUG (0, "Read error!");
+ REPLY (EINVAL);
+ }
+
+ struct io_buffer buffer;
+ buffer.len = 0;
+
+ if (max > 0)
+ {
+ buffer.len = 1;
+ buffer.data[0] = getchar ();
+ }
+
+ rm_read_reply (activity, reply, buffer);
+ break;
+ }
+
case RM_fault:
{
uintptr_t start;
int max;
- err = rm_fault_send_unmarshal (&msg, &principal_addr,
- &start, &max);
+ err = rm_fault_send_unmarshal (message, &start, &max, NULL);
if (err)
REPLY (err);
- DEBUG (4, "(%p, %d)", start, max);
+ DEBUG (4, "(%p, %d)", (void *) start, max);
start &= ~(PAGESIZE - 1);
- rm_fault_reply_marshal (&msg, 0);
+ rm_fault_reply (activity, reply, 0);
int limit = (L4_NUM_MRS - 1
- l4_untyped_words (l4_msg_msg_tag (msg)))
- * sizeof (l4_word_t) / sizeof (l4_map_item_t);
+ * sizeof (uintptr_t) / sizeof (l4_map_item_t);
if (max > limit)
max = limit;
@@ -716,7 +1105,7 @@ server_loop (void)
l4_untyped_words (l4_msg_msg_tag (msg)),
l4_typed_words (l4_msg_msg_tag (msg)));
- rm_fault_reply_marshal (&msg, count);
+ rm_fault_reply (activity, reply, count);
int i;
for (i = 0; i < count; i ++)
l4_msg_append_map_item (msg, map_items[i]);
@@ -726,82 +1115,80 @@ server_loop (void)
case RM_folio_alloc:
{
- addr_t folio_addr;
- struct folio_policy policy;
+ if (object_type (target) != cap_activity_control)
+ {
+ DEBUG (0, "target " ADDR_FMT " not an activity but a %s",
+ ADDR_PRINTF (target_messenger),
+ cap_type_string (object_type (target)));
+ REPLY (EINVAL);
+ }
+
+ struct activity *activity = (struct activity *) target;
- err = rm_folio_alloc_send_unmarshal (&msg, &principal_addr,
- &folio_addr, &policy);
+ struct folio_policy policy;
+ err = rm_folio_alloc_send_unmarshal (message, &policy, NULL);
if (err)
REPLY (err);
- DEBUG (4, "(" ADDR_FMT ")", ADDR_PRINTF (folio_addr));
-
- struct cap *folio_slot = SLOT (&thread->aspace, folio_addr);
+ DEBUG (4, "(" ADDR_FMT ")", ADDR_PRINTF (target_messenger));
- struct folio *folio = folio_alloc (principal, policy);
+ struct folio *folio = folio_alloc (activity, policy);
if (! folio)
REPLY (ENOMEM);
- bool r = cap_set (principal, folio_slot,
- object_to_cap ((struct object *) folio));
- assert (r);
-
- rm_folio_alloc_reply_marshal (&msg);
+ rm_folio_alloc_reply (principal, reply,
+ object_to_cap ((struct object *) folio));
break;
}
case RM_folio_free:
{
- addr_t folio_addr;
+ if (object_type (target) != cap_folio)
+ REPLY (EINVAL);
+
+ struct folio *folio = (struct folio *) target;
- err = rm_folio_free_send_unmarshal (&msg, &principal_addr,
- &folio_addr);
+ err = rm_folio_free_send_unmarshal (message, NULL);
if (err)
REPLY (err);
- DEBUG (4, "(" ADDR_FMT ")", ADDR_PRINTF (folio_addr));
+ DEBUG (4, "(" ADDR_FMT ")", ADDR_PRINTF (target_messenger));
- struct folio *folio = (struct folio *) OBJECT (&thread->aspace,
- folio_addr,
- cap_folio, true);
folio_free (principal, folio);
- rm_folio_free_reply_marshal (&msg);
+ rm_folio_free_reply (activity, reply);
break;
}
case RM_folio_object_alloc:
{
- addr_t folio_addr;
+ if (object_type (target) != cap_folio)
+ REPLY (EINVAL);
+
+ struct folio *folio = (struct folio *) target;
+
uint32_t idx;
uint32_t type;
struct object_policy policy;
uintptr_t return_code;
- addr_t object_addr;
- addr_t object_weak_addr;
-
- err = rm_folio_object_alloc_send_unmarshal (&msg, &principal_addr,
- &folio_addr, &idx,
- &type, &policy,
- &return_code,
- &object_addr,
- &object_weak_addr);
+
+ err = rm_folio_object_alloc_send_unmarshal (message,
+ &idx, &type, &policy,
+ &return_code, NULL);
if (err)
REPLY (err);
- DEBUG (4, "(" ADDR_FMT ", %d, %s, (%s, %d), %d, "
- ADDR_FMT", "ADDR_FMT")",
-
- ADDR_PRINTF (folio_addr), idx, cap_type_string (type),
+ DEBUG (4, "(" ADDR_FMT ", %d (" ADDR_FMT "), %s, (%s, %d), %d)",
+ ADDR_PRINTF (target_messenger), idx,
+ addr_depth (target_messenger) + FOLIO_OBJECTS_LOG2
+ <= ADDR_BITS
+ ? ADDR_PRINTF (addr_extend (target_messenger,
+ idx, FOLIO_OBJECTS_LOG2))
+ : ADDR_PRINTF (ADDR_VOID),
+ cap_type_string (type),
policy.discardable ? "discardable" : "precious",
policy.priority,
- return_code,
- ADDR_PRINTF (object_addr),
- ADDR_PRINTF (object_weak_addr));
-
- struct folio *folio = (struct folio *) OBJECT (&thread->aspace,
- folio_addr,
- cap_folio, true);
+ return_code);
if (idx >= FOLIO_OBJECTS)
REPLY (EINVAL);
@@ -809,202 +1196,61 @@ server_loop (void)
if (! (CAP_TYPE_MIN <= type && type <= CAP_TYPE_MAX))
REPLY (EINVAL);
- struct cap *object_slot = NULL;
- if (! ADDR_IS_VOID (object_addr))
- object_slot = SLOT (&thread->aspace, object_addr);
-
- struct cap *object_weak_slot = NULL;
- if (! ADDR_IS_VOID (object_weak_addr))
- object_weak_slot = SLOT (&thread->aspace, object_weak_addr);
-
struct cap cap;
cap = folio_object_alloc (principal,
folio, idx, type, policy, return_code);
- if (type != cap_void)
- {
- if (object_slot)
- {
- bool r = cap_set (principal, object_slot, cap);
- assert (r);
- }
- if (object_weak_slot)
- {
- bool r = cap_set (principal, object_weak_slot, cap);
- assert (r);
- object_weak_slot->type
- = cap_type_weaken (object_weak_slot->type);
- }
- }
+ struct cap weak = cap;
+ weak.type = cap_type_weaken (cap.type);
- rm_folio_object_alloc_reply_marshal (&msg);
+ rm_folio_object_alloc_reply (activity, reply, cap, weak);
break;
}
case RM_folio_policy:
{
- addr_t folio_addr;
- l4_word_t flags;
+ if (object_type (target) != cap_folio)
+ REPLY (EINVAL);
+
+ struct folio *folio = (struct folio *) target;
+
+ uintptr_t flags;
struct folio_policy in, out;
- err = rm_folio_policy_send_unmarshal (&msg, &principal_addr,
- &folio_addr,
- &flags, &in);
+ err = rm_folio_policy_send_unmarshal (message, &flags, &in, NULL);
if (err)
REPLY (err);
DEBUG (4, "(" ADDR_FMT ", %d)",
- ADDR_PRINTF (folio_addr), flags);
-
- struct folio *folio = (struct folio *) OBJECT (&thread->aspace,
- folio_addr,
- cap_folio, true);
+ ADDR_PRINTF (target_messenger), flags);
folio_policy (principal, folio, flags, in, &out);
- rm_folio_policy_reply_marshal (&msg, out);
+ rm_folio_policy_reply (activity, reply, out);
break;
}
- case RM_object_slot_copy_out:
+ case RM_cap_copy:
{
addr_t source_as_addr;
addr_t source_addr;
struct cap source;
addr_t target_as_addr;
addr_t target_addr;
- struct cap *target;
- uint32_t idx;
uint32_t flags;
struct cap_properties properties;
- struct cap object_cap;
- struct object *object;
-
- err = rm_object_slot_copy_out_send_unmarshal
- (&msg, &principal_addr, &source_as_addr, &source_addr, &idx,
- &target_as_addr, &target_addr, &flags, &properties);
- if (err)
- REPLY (err);
-
- DEBUG (4, "(" ADDR_FMT "@" ADDR_FMT "+%d -> "
- ADDR_FMT "@" ADDR_FMT ", %s%s%s%s%s%s, %s/%d %lld/%d %d/%d",
-
- ADDR_PRINTF (source_as_addr), ADDR_PRINTF (source_addr),
- idx,
- ADDR_PRINTF (target_as_addr), ADDR_PRINTF (target_addr),
-
- CAP_COPY_COPY_ADDR_TRANS_SUBPAGE & flags
- ? "copy subpage/" : "",
- CAP_COPY_COPY_ADDR_TRANS_GUARD & flags
- ? "copy trans guard/" : "",
- CAP_COPY_COPY_SOURCE_GUARD & flags
- ? "copy src guard/" : "",
- CAP_COPY_WEAKEN & flags ? "weak/" : "",
- CAP_COPY_DISCARDABLE_SET & flags ? "discardable/" : "",
- CAP_COPY_PRIORITY_SET & flags ? "priority" : "",
-
- properties.policy.discardable ? "discardable" : "precious",
- properties.policy.priority,
- CAP_ADDR_TRANS_GUARD (properties.addr_trans),
- CAP_ADDR_TRANS_GUARD_BITS (properties.addr_trans),
- CAP_ADDR_TRANS_SUBPAGE (properties.addr_trans),
- CAP_ADDR_TRANS_SUBPAGES (properties.addr_trans));
-
- struct cap *root = ROOT (source_as_addr);
- object_cap = CAP (root, source_addr, -1, false);
-
- root = ROOT (target_as_addr);
-
- goto get_slot;
-
- case RM_object_slot_copy_in:
- err = rm_object_slot_copy_in_send_unmarshal
- (&msg, &principal_addr, &target_as_addr, &target_addr, &idx,
- &source_as_addr, &source_addr, &flags, &properties);
- if (err)
- REPLY (err);
-
- DEBUG (4, "(" ADDR_FMT "@" ADDR_FMT "+%d <- "
- ADDR_FMT "@" ADDR_FMT ", %s%s%s%s%s%s, %s/%d %lld/%d %d/%d",
-
- ADDR_PRINTF (target_as_addr), ADDR_PRINTF (target_addr),
- idx,
- ADDR_PRINTF (source_as_addr), ADDR_PRINTF (source_addr),
-
- CAP_COPY_COPY_ADDR_TRANS_SUBPAGE & flags
- ? "copy subpage/" : "",
- CAP_COPY_COPY_ADDR_TRANS_GUARD & flags
- ? "copy trans guard/" : "",
- CAP_COPY_COPY_SOURCE_GUARD & flags
- ? "copy src guard/" : "",
- CAP_COPY_WEAKEN & flags ? "weak/" : "",
- CAP_COPY_DISCARDABLE_SET & flags ? "discardable/" : "",
- CAP_COPY_PRIORITY_SET & flags ? "priority" : "",
-
- properties.policy.discardable ? "discardable" : "precious",
- properties.policy.priority,
- CAP_ADDR_TRANS_GUARD (properties.addr_trans),
- CAP_ADDR_TRANS_GUARD_BITS (properties.addr_trans),
- CAP_ADDR_TRANS_SUBPAGE (properties.addr_trans),
- CAP_ADDR_TRANS_SUBPAGES (properties.addr_trans));
-
- root = ROOT (target_as_addr);
- object_cap = CAP (root, target_addr, -1, true);
-
- root = ROOT (source_as_addr);
-
- get_slot:
- if (idx >= cap_type_num_slots[object_cap.type])
- REPLY (EINVAL);
-
- if (object_cap.type == cap_cappage
- || object_cap.type == cap_rcappage)
- /* Ensure that IDX falls within the subpage. */
- {
- if (idx >= CAP_SUBPAGE_SIZE (&object_cap))
- {
- DEBUG (1, "index (%d) >= subpage size (%d)",
- idx, CAP_SUBPAGE_SIZE (&object_cap));
- REPLY (EINVAL);
- }
-
- idx += CAP_SUBPAGE_OFFSET (&object_cap);
- }
-
- object = cap_to_object (principal, &object_cap);
- if (! object)
- {
- DEBUG (1, CAP_FMT " maps to void", CAP_PRINTF (&object_cap));
- REPLY (EINVAL);
- }
-
- if (label == RM_object_slot_copy_out)
- {
- source = ((struct cap *) object)[idx];
- target = SLOT (root, target_addr);
- }
- else
- {
- source = CAP (root, source_addr, -1, false);
- target = &((struct cap *) object)[idx];
- }
-
- goto cap_copy_body;
-
- case RM_cap_copy:
- err = rm_cap_copy_send_unmarshal (&msg,
- &principal_addr,
- &target_as_addr, &target_addr,
+ err = rm_cap_copy_send_unmarshal (message,
+ &target_addr,
&source_as_addr, &source_addr,
- &flags, &properties);
+ &flags, &properties, NULL);
if (err)
REPLY (err);
DEBUG (4, "(" ADDR_FMT "@" ADDR_FMT " <- "
ADDR_FMT "@" ADDR_FMT ", %s%s%s%s%s%s, %s/%d %lld/%d %d/%d",
- ADDR_PRINTF (target_as_addr), ADDR_PRINTF (target_addr),
+ ADDR_PRINTF (target_messenger), ADDR_PRINTF (target_addr),
ADDR_PRINTF (source_as_addr), ADDR_PRINTF (source_addr),
CAP_COPY_COPY_ADDR_TRANS_SUBPAGE & flags
@@ -1024,13 +1270,11 @@ server_loop (void)
CAP_ADDR_TRANS_SUBPAGE (properties.addr_trans),
CAP_ADDR_TRANS_SUBPAGES (properties.addr_trans));
- root = ROOT (target_as_addr);
- target = SLOT (root, target_addr);
-
- root = ROOT (source_as_addr);
- source = CAP (root, source_addr, -1, false);
+ struct cap *target;
+ target = SLOT (target_root, target_addr);
- cap_copy_body:;
+ target_root = ROOT (source_as_addr);
+ source = CAP (target_root, source_addr, -1, false);
if ((flags & ~(CAP_COPY_COPY_ADDR_TRANS_SUBPAGE
| CAP_COPY_COPY_ADDR_TRANS_GUARD
@@ -1091,165 +1335,98 @@ server_loop (void)
}
}
- switch (label)
- {
- case RM_object_slot_copy_out:
- rm_object_slot_copy_out_reply_marshal (&msg);
- break;
- case RM_object_slot_copy_in:
- rm_object_slot_copy_in_reply_marshal (&msg);
- break;
- case RM_cap_copy:
- rm_cap_copy_reply_marshal (&msg);
+ rm_cap_copy_reply (activity, reply);
#if 0
- /* XXX: Surprisingly, it appears that this may be
- more expensive than just faulting the pages
- normally. This needs more investivation. */
- if (ADDR_IS_VOID (target_as_addr)
- && cap_types_compatible (target->type, cap_page)
- && CAP_GUARD_BITS (target) == 0
- && addr_depth (target_addr) == ADDR_BITS - PAGESIZE_LOG2)
- /* The target address space is the caller's. The target
- object appears to be a page. It seems to be
- installed at a point where it would appear in the
- hardware address space. If this is really the case,
- then we can map it now and save a fault later. */
- {
- profile_region ("cap_copy-prefault");
-
- struct cap cap = *target;
- if (target->type == cap_rpage)
- cap.discardable = false;
+ /* XXX: Surprisingly, it appears that this may be
+ more expensive than just faulting the pages
+ normally. This needs more investivation. */
+ if (ADDR_IS_VOID (target_as_addr)
+ && cap_types_compatible (target->type, cap_page)
+ && CAP_GUARD_BITS (target) == 0
+ && addr_depth (target_addr) == ADDR_BITS - PAGESIZE_LOG2)
+ /* The target address space is the caller's. The target
+ object appears to be a page. It seems to be
+ installed at a point where it would appear in the
+ hardware address space. If this is really the case,
+ then we can map it now and save a fault later. */
+ {
+ profile_region ("cap_copy-prefault");
- struct object *page = cap_to_object_soft (principal, &cap);
- if (page)
- {
- object_to_object_desc (page)->mapped = true;
+ struct cap cap = *target;
+ if (target->type == cap_rpage)
+ cap.discardable = false;
- l4_fpage_t fpage
- = l4_fpage ((uintptr_t) page, PAGESIZE);
- fpage = l4_fpage_add_rights (fpage, L4_FPAGE_READABLE);
- if (cap.type == cap_page)
- fpage = l4_fpage_add_rights (fpage,
- L4_FPAGE_WRITABLE);
+ struct object *page = cap_to_object_soft (principal, &cap);
+ if (page)
+ {
+ object_to_object_desc (page)->mapped = true;
- l4_word_t page_addr = addr_prefix (target_addr);
+ l4_fpage_t fpage
+ = l4_fpage ((uintptr_t) page, PAGESIZE);
+ fpage = l4_fpage_add_rights (fpage, L4_FPAGE_READABLE);
+ if (cap.type == cap_page)
+ fpage = l4_fpage_add_rights (fpage,
+ L4_FPAGE_WRITABLE);
- l4_map_item_t map_item = l4_map_item (fpage, page_addr);
+ uintptr_t page_addr = addr_prefix (target_addr);
- l4_msg_append_map_item (msg, map_item);
- }
+ l4_map_item_t map_item = l4_map_item (fpage, page_addr);
- profile_region_end ();
+ l4_msg_append_map_item (msg, map_item);
}
-#endif
- break;
+ profile_region_end ();
}
+#endif
+
break;
}
case RM_cap_rubout:
{
- addr_t target_as_addr;
- addr_t target_addr;
+ addr_t addr;
- err = rm_cap_rubout_send_unmarshal (&msg,
- &principal_addr,
- &target_as_addr,
- &target_addr);
+ err = rm_cap_rubout_send_unmarshal (message, &addr, NULL);
if (err)
REPLY (err);
DEBUG (4, ADDR_FMT "@" ADDR_FMT,
- ADDR_PRINTF (target_as_addr),
- ADDR_PRINTF (target_addr));
-
- struct cap *root = ROOT (target_as_addr);
-
- /* We don't look up the argument directly as we need to
- respect any subpag specification for cappages. */
- struct cap *target = SLOT (root, target_addr);
-
- cap_shootdown (principal, target);
-
- memset (target, 0, sizeof (*target));
-
- rm_cap_rubout_reply_marshal (&msg);
- break;
- }
-
- case RM_object_slot_read:
- {
- addr_t root_addr;
- addr_t source_addr;
- uint32_t idx;
-
- err = rm_object_slot_read_send_unmarshal (&msg,
- &principal_addr,
- &root_addr,
- &source_addr, &idx);
- if (err)
- REPLY (err);
-
- DEBUG (4, ADDR_FMT "@" ADDR_FMT "+%d",
- ADDR_PRINTF (root_addr), ADDR_PRINTF (source_addr), idx);
-
- struct cap *root = ROOT (root_addr);
+ ADDR_PRINTF (target_messenger),
+ ADDR_PRINTF (addr));
/* We don't look up the argument directly as we need to
- respect any subpag specification for cappages. */
- struct cap source = CAP (root, source_addr, -1, false);
+ respect any subpage specification for cappages. */
+ struct cap *slot = SLOT (target_root, addr);
- struct object *object = cap_to_object (principal, &source);
- if (! object)
- REPLY (EINVAL);
+ cap_shootdown (principal, slot);
- if (idx >= cap_type_num_slots[source.type])
- REPLY (EINVAL);
+ memset (target, 0, sizeof (*slot));
- if (source.type == cap_cappage || source.type == cap_rcappage)
- /* Ensure that idx falls within the subpage. */
- {
- if (idx >= CAP_SUBPAGE_SIZE (&source))
- REPLY (EINVAL);
-
- idx += CAP_SUBPAGE_OFFSET (&source);
- }
-
- source = ((struct cap *) object)[idx];
-
- rm_object_slot_read_reply_marshal (&msg, source.type,
- CAP_PROPERTIES_GET (source));
+ rm_cap_rubout_reply (activity, reply);
break;
}
case RM_cap_read:
{
- addr_t root_addr;
addr_t cap_addr;
- err = rm_cap_read_send_unmarshal (&msg, &principal_addr,
- &root_addr,
- &cap_addr);
+ err = rm_cap_read_send_unmarshal (message, &cap_addr, NULL);
if (err)
REPLY (err);
DEBUG (4, ADDR_FMT "@" ADDR_FMT,
- ADDR_PRINTF (root_addr), ADDR_PRINTF (cap_addr));
+ ADDR_PRINTF (target_messenger), ADDR_PRINTF (cap_addr));
- struct cap *root = ROOT (root_addr);
-
- struct cap cap = CAP (root, cap_addr, -1, false);
+ struct cap cap = CAP (target_root, cap_addr, -1, false);
/* Even if CAP.TYPE is not void, the cap may not designate
an object. Looking up the object will set CAP.TYPE to
cap_void if this is the case. */
if (cap.type != cap_void)
cap_to_object (principal, &cap);
- rm_cap_read_reply_marshal (&msg, cap.type,
- CAP_PROPERTIES_GET (cap));
+ rm_cap_read_reply (activity, reply, cap.type,
+ CAP_PROPERTIES_GET (cap));
break;
}
@@ -1258,15 +1435,16 @@ server_loop (void)
addr_t object_addr;
err = rm_object_discarded_clear_send_unmarshal
- (&msg, &principal_addr, &object_addr);
+ (message, &object_addr, NULL);
if (err)
REPLY (err);
DEBUG (4, ADDR_FMT, ADDR_PRINTF (object_addr));
- /* We can't look up the object here as object_lookup
- returns NULL if the object's discardable bit is
- set! Instead, we lookup the capability. */
+ /* We can't look up the object use OBJECT as object_lookup
+ returns NULL if the object's discardable bit is set!
+ Instead, we lookup the capability, find the object's
+ folio and then clear its discarded bit. */
struct cap cap = CAP (&thread->aspace, object_addr, -1, true);
if (cap.type == cap_void)
REPLY (ENOENT);
@@ -1285,7 +1463,7 @@ server_loop (void)
bool was_discarded = folio_object_discarded (folio, idx);
folio_object_discarded_set (folio, idx, false);
- rm_object_discarded_clear_reply_marshal (&msg);
+ rm_object_discarded_clear_reply (activity, reply);
#if 0
/* XXX: Surprisingly, it appears that this may be more
@@ -1313,7 +1491,7 @@ server_loop (void)
L4_FPAGE_READABLE
| L4_FPAGE_WRITABLE);
- l4_word_t page_addr = addr_prefix (object_addr);
+ uintptr_t page_addr = addr_prefix (object_addr);
l4_map_item_t map_item = l4_map_item (fpage, page_addr);
@@ -1334,87 +1512,32 @@ server_loop (void)
case RM_object_discard:
{
- addr_t object_addr;
-
- err = rm_object_discard_send_unmarshal
- (&msg, &principal_addr, &object_addr);
+ err = rm_object_discard_send_unmarshal (message, NULL);
if (err)
REPLY (err);
- DEBUG (4, ADDR_FMT, ADDR_PRINTF (object_addr));
+ DEBUG (4, ADDR_FMT, ADDR_PRINTF (target_messenger));
- /* We can't look up the object here as object_lookup
- returns NULL if the object's discardable bit is
- set! Instead, we lookup the capability. */
- struct cap cap = CAP (&thread->aspace, object_addr, -1, true);
- if (cap.type == cap_void)
- REPLY (ENOENT);
- if (cap_type_weak_p (cap.type))
- REPLY (EPERM);
-
- struct folio *folio;
- int offset;
-
- struct object *object = cap_to_object_soft (principal, &cap);
- if (object)
- {
- struct object_desc *desc = object_to_object_desc (object);
-
- folio = objects_folio (principal, object);
- offset = objects_folio_offset (object);
-
- ACTIVITY_STATS (desc->activity)->discarded ++;
-
- memory_object_destroy (principal, object);
- memory_frame_free ((uintptr_t) object);
-
- /* Consistent with the API, we do NOT set the discarded
- bit. */
-
- folio_object_content_set (folio, offset, false);
-
- assertx (! cap_to_object_soft (principal, &cap),
- ADDR_FMT ": " CAP_FMT,
- ADDR_PRINTF (object_addr), CAP_PRINTF (&cap));
- }
- else
- /* The object is not in memory, however, we can still
- clear it's content bit. */
- {
- offset = (cap.oid % (1 + FOLIO_OBJECTS)) - 1;
- oid_t foid = cap.oid - offset - 1;
-
- folio = (struct folio *)
- object_find (activity, foid, OBJECT_POLICY_VOID);
-
- if (folio_object_version (folio, offset) != cap.version)
- /* Or not, seems the object is gone! */
- REPLY (ENOENT);
- }
+ struct folio *folio = objects_folio (principal, target);
- folio_object_content_set (folio, offset, false);
+ folio_object_content_set (folio,
+ objects_folio_offset (target), false);
- rm_object_discard_reply_marshal (&msg);
+ rm_object_discard_reply (activity, reply);
break;
}
case RM_object_status:
{
- addr_t object_addr;
bool clear;
-
- err = rm_object_status_send_unmarshal
- (&msg, &principal_addr, &object_addr, &clear);
+ err = rm_object_status_send_unmarshal (message, &clear, NULL);
if (err)
REPLY (err);
DEBUG (4, ADDR_FMT ", %sclear",
- ADDR_PRINTF (object_addr), clear ? "" : "no ");
+ ADDR_PRINTF (target_messenger), clear ? "" : "no ");
- struct object *object = OBJECT (&thread->aspace,
- object_addr, -1, true);
-
- struct object_desc *desc = object_to_object_desc (object);
+ struct object_desc *desc = object_to_object_desc (target);
uintptr_t status = (desc->user_referenced ? object_referenced : 0)
| (desc->user_dirty ? object_dirty : 0);
@@ -1424,103 +1547,120 @@ server_loop (void)
desc->user_dirty = 0;
}
- rm_object_status_reply_marshal (&msg, status);
+ rm_object_status_reply (activity, reply, status);
break;
}
case RM_object_name:
{
- addr_t object_addr;
struct object_name name;
+ err = rm_object_name_send_unmarshal (message, &name, NULL);
- err = rm_object_name_send_unmarshal
- (&msg, &principal_addr, &object_addr, &name);
-
- struct object *object = OBJECT (&thread->aspace,
- object_addr, -1, false);
-
- if (object_type (object) == cap_activity_control)
+ if (object_type (target) == cap_activity_control)
{
- struct activity *a = (struct activity *) object;
+ struct activity *a = (struct activity *) target;
memcpy (a->name.name, name.name, sizeof (name));
a->name.name[sizeof (a->name.name) - 1] = 0;
}
- else if (object_type (object) == cap_thread)
+ else if (object_type (target) == cap_thread)
{
- struct thread *t = (struct thread *) object;
+ struct thread *t = (struct thread *) target;
memcpy (t->name.name, name.name, sizeof (name));
t->name.name[sizeof (t->name.name) - 1] = 0;
}
- rm_object_name_reply_marshal (&msg);
+ rm_object_name_reply (activity, reply);
break;
}
case RM_thread_exregs:
{
+ if (object_type (target) != cap_thread)
+ REPLY (EINVAL);
+ struct thread *t = (struct thread *) target;
+
struct hurd_thread_exregs_in in;
- addr_t target;
- l4_word_t control;
- err = rm_thread_exregs_send_unmarshal (&msg,
- &principal_addr, &target,
- &control, &in);
+ uintptr_t control;
+ addr_t aspace_addr;
+ addr_t activity_addr;
+ addr_t utcb_addr;
+ addr_t exception_messenger_addr;
+ err = rm_thread_exregs_send_unmarshal
+ (message, &control, &in,
+ &aspace_addr, &activity_addr, &utcb_addr,
+ &exception_messenger_addr,
+ NULL);
if (err)
REPLY (err);
- DEBUG (4, ADDR_FMT, ADDR_PRINTF (target));
-
- struct thread *t
- = (struct thread *) OBJECT (&thread->aspace,
- target, cap_thread, true);
-
- struct cap *aspace = NULL;
- struct cap aspace_cap;
+ int d = 4;
+ DEBUG (d, "%s%s" ADDR_FMT "(%x): %s%s%s%s %s%s%s%s %s%s%s %s%s",
+ t->name.name[0] ? t->name.name : "",
+ t->name.name[0] ? ": " : "",
+ ADDR_PRINTF (target_messenger), t->tid,
+ (control & HURD_EXREGS_SET_UTCB) ? "U" : "-",
+ (control & HURD_EXREGS_SET_EXCEPTION_MESSENGER) ? "E" : "-",
+ (control & HURD_EXREGS_SET_ASPACE) ? "R" : "-",
+ (control & HURD_EXREGS_SET_ACTIVITY) ? "A" : "-",
+ (control & HURD_EXREGS_SET_SP) ? "S" : "-",
+ (control & HURD_EXREGS_SET_IP) ? "I" : "-",
+ (control & HURD_EXREGS_SET_EFLAGS) ? "F" : "-",
+ (control & HURD_EXREGS_SET_USER_HANDLE) ? "U" : "-",
+ (control & _L4_XCHG_REGS_CANCEL_RECV) ? "R" : "-",
+ (control & _L4_XCHG_REGS_CANCEL_SEND) ? "S" : "-",
+ (control & _L4_XCHG_REGS_CANCEL_IPC) ? "I" : "-",
+ (control & _L4_XCHG_REGS_HALT) ? "H" : "-",
+ (control & _L4_XCHG_REGS_SET_HALT) ? "Y" : "N");
+
+ if ((control & HURD_EXREGS_SET_UTCB))
+ DEBUG (d, "utcb: " ADDR_FMT, ADDR_PRINTF (utcb_addr));
+ if ((control & HURD_EXREGS_SET_EXCEPTION_MESSENGER))
+ DEBUG (d, "exception messenger: " ADDR_FMT,
+ ADDR_PRINTF (exception_messenger_addr));
+ if ((control & HURD_EXREGS_SET_ASPACE))
+ DEBUG (d, "aspace: " ADDR_FMT, ADDR_PRINTF (aspace_addr));
+ if ((control & HURD_EXREGS_SET_ACTIVITY))
+ DEBUG (d, "activity: " ADDR_FMT, ADDR_PRINTF (activity_addr));
+ if ((control & HURD_EXREGS_SET_SP))
+ DEBUG (d, "sp: %p", (void *) in.sp);
+ if ((control & HURD_EXREGS_SET_IP))
+ DEBUG (d, "ip: %p", (void *) in.ip);
+ if ((control & HURD_EXREGS_SET_EFLAGS))
+ DEBUG (d, "eflags: %p", (void *) in.eflags);
+ if ((control & HURD_EXREGS_SET_USER_HANDLE))
+ DEBUG (d, "user_handle: %p", (void *) in.user_handle);
+
+ struct cap aspace = CAP_VOID;
if ((HURD_EXREGS_SET_ASPACE & control))
- {
- aspace_cap = CAP (&thread->aspace, in.aspace, -1, false);
- aspace = &aspace_cap;
- }
+ aspace = CAP (&thread->aspace, aspace_addr, -1, false);
- struct cap *a = NULL;
- struct cap a_cap;
+ struct cap a = CAP_VOID;
if ((HURD_EXREGS_SET_ACTIVITY & control))
{
- if (ADDR_IS_VOID (in.activity))
- a = &thread->activity;
+ /* XXX: Remove this hack... */
+ if (ADDR_IS_VOID (activity_addr))
+ a = thread->activity;
else
- {
- a_cap = CAP (&thread->aspace,
- in.activity, cap_activity, false);
- a = &a_cap;
- }
- }
-
- struct cap *exception_page = NULL;
- struct cap exception_page_cap;
- if ((HURD_EXREGS_SET_EXCEPTION_PAGE & control))
- {
- exception_page_cap = CAP (&thread->aspace,
- in.exception_page, cap_page, true);
- exception_page = &exception_page_cap;
+ a = CAP (&thread->aspace,
+ activity_addr, cap_activity, false);
}
- struct cap *aspace_out = NULL;
- if ((HURD_EXREGS_GET_REGS & control)
- && ! ADDR_IS_VOID (in.aspace_out))
- aspace_out = SLOT (&thread->aspace, in.aspace_out);
+ struct cap utcb = CAP_VOID;
+ if ((HURD_EXREGS_SET_UTCB & control))
+ utcb = CAP (&thread->aspace, utcb_addr, cap_page, true);
- struct cap *activity_out = NULL;
- if ((HURD_EXREGS_GET_REGS & control)
- && ! ADDR_IS_VOID (in.activity_out))
- activity_out = SLOT (&thread->aspace, in.activity_out);
+ struct cap exception_messenger = CAP_VOID;
+ if ((HURD_EXREGS_SET_EXCEPTION_MESSENGER & control))
+ exception_messenger
+ = CAP (&thread->aspace, exception_messenger_addr,
+ cap_rmessenger, false);
- struct cap *exception_page_out = NULL;
- if ((HURD_EXREGS_GET_REGS & control)
- && ! ADDR_IS_VOID (in.exception_page_out))
- exception_page_out = SLOT (&thread->aspace,
- in.exception_page_out);
+ struct cap aspace_out = thread->aspace;
+ struct cap activity_out = thread->activity;
+ struct cap utcb_out = thread->utcb;
+ struct cap exception_messenger_out = thread->exception_messenger;
struct hurd_thread_exregs_out out;
out.sp = in.sp;
@@ -1530,56 +1670,94 @@ server_loop (void)
err = thread_exregs (principal, t, control,
aspace, in.aspace_cap_properties_flags,
- in.aspace_cap_properties, a, exception_page,
+ in.aspace_cap_properties,
+ a, utcb, exception_messenger,
&out.sp, &out.ip,
- &out.eflags, &out.user_handle,
- aspace_out, activity_out,
- exception_page_out);
+ &out.eflags, &out.user_handle);
if (err)
REPLY (err);
- rm_thread_exregs_reply_marshal (&msg, out);
+ rm_thread_exregs_reply (activity, reply, out,
+ aspace_out, activity_out,
+ utcb_out, exception_messenger_out);
break;
}
- case RM_thread_wait_object_destroyed:
+ case RM_thread_id:
{
- addr_t addr;
- err = rm_thread_wait_object_destroyed_send_unmarshal
- (&msg, &principal_addr, &addr);
+ if (object_type (target) != cap_thread)
+ REPLY (EINVAL);
+ struct thread *t = (struct thread *) target;
+
+ err = rm_thread_id_send_unmarshal (message, NULL);
if (err)
REPLY (err);
- DEBUG (4, ADDR_FMT, ADDR_PRINTF (addr));
+ rm_thread_id_reply (activity, reply, t->tid);
+ break;
+ }
+
+ case RM_object_reply_on_destruction:
+ {
+ err = rm_object_reply_on_destruction_send_unmarshal (message,
+ NULL);
+ if (err)
+ REPLY (err);
- struct object *object = OBJECT (&thread->aspace, addr, -1, true);
+ DEBUG (4, ADDR_FMT, ADDR_PRINTF (target_messenger));
- thread->wait_reason = THREAD_WAIT_DESTROY;
- object_wait_queue_enqueue (principal, object, thread);
+ reply->wait_reason = MESSENGER_WAIT_DESTROY;
+ object_wait_queue_enqueue (principal, target, reply);
- do_reply = 0;
break;
}
case RM_activity_policy:
{
+ if (object_type (target) != cap_activity_control)
+ {
+ DEBUG (0, "expects an activity, not a %s",
+ cap_type_string (object_type (target)));
+ REPLY (EINVAL);
+ }
+ struct activity *activity = (struct activity *) target;
+
uintptr_t flags;
struct activity_policy in;
- err = rm_activity_policy_send_unmarshal (&msg, &principal_addr,
- &flags, &in);
+ err = rm_activity_policy_send_unmarshal (message, &flags, &in,
+ NULL);
if (err)
REPLY (err);
- DEBUG (4, "");
-
- if (principal_cap.type != cap_activity_control
+ int d = 4;
+ DEBUG (d, "(%s) child: %s%s; sibling: %s%s; storage: %s",
+ target_writable ? "strong" : "weak",
+ (flags & ACTIVITY_POLICY_CHILD_REL_PRIORITY_SET) ? "P" : "-",
+ (flags & ACTIVITY_POLICY_CHILD_REL_WEIGHT_SET) ? "W" : "-",
+ (flags & ACTIVITY_POLICY_SIBLING_REL_PRIORITY_SET)
+ ? "P" : "-",
+ (flags & ACTIVITY_POLICY_SIBLING_REL_WEIGHT_SET) ? "W" : "-",
+ (flags & ACTIVITY_POLICY_STORAGE_SET) ? "P" : "-");
+
+ if ((flags & ACTIVITY_POLICY_CHILD_REL_PRIORITY_SET))
+ DEBUG (d, "Child priority: %d", in.child_rel.priority);
+ if ((flags & ACTIVITY_POLICY_CHILD_REL_WEIGHT_SET))
+ DEBUG (d, "Child weight: %d", in.child_rel.weight);
+ if ((flags & ACTIVITY_POLICY_SIBLING_REL_PRIORITY_SET))
+ DEBUG (d, "Sibling priority: %d", in.sibling_rel.priority);
+ if ((flags & ACTIVITY_POLICY_SIBLING_REL_WEIGHT_SET))
+ DEBUG (d, "Sibling weight: %d", in.sibling_rel.weight);
+ if ((flags & ACTIVITY_POLICY_STORAGE_SET))
+ DEBUG (d, "Storage: %d", in.folios);
+
+ if (! target_writable
&& (flags & (ACTIVITY_POLICY_STORAGE_SET
| ACTIVITY_POLICY_CHILD_REL_SET)))
REPLY (EPERM);
- rm_activity_policy_reply_marshal (&msg, principal->policy);
+ rm_activity_policy_reply (principal, reply, activity->policy);
if ((flags & (ACTIVITY_POLICY_CHILD_REL_PRIORITY_SET
| ACTIVITY_POLICY_CHILD_REL_WEIGHT_SET
@@ -1602,7 +1780,7 @@ server_loop (void)
if ((flags & ACTIVITY_POLICY_STORAGE_SET))
p.folios = in.folios;
- activity_policy_update (principal, p);
+ activity_policy_update (activity, p);
}
break;
@@ -1610,32 +1788,36 @@ server_loop (void)
case RM_activity_info:
{
+ if (object_type (target) != cap_activity_control)
+ REPLY (EINVAL);
+ struct activity *activity = (struct activity *) target;
+
uintptr_t flags;
uintptr_t until_period;
- err = rm_activity_info_send_unmarshal (&msg, &principal_addr,
- &flags,
- &until_period);
+ err = rm_activity_info_send_unmarshal (message,
+ &flags, &until_period,
+ NULL);
if (err)
REPLY (err);
- int period = principal->current_period - 1;
+ int period = activity->current_period - 1;
if (period < 0)
period = (ACTIVITY_STATS_PERIODS + 1) + period;
DEBUG (4, OBJECT_NAME_FMT ": %s%s%s(%d), "
"period: %d (current: %d)",
- OBJECT_NAME_PRINTF ((struct object *) principal),
+ OBJECT_NAME_PRINTF ((struct object *) activity),
flags & activity_info_stats ? "stats" : "",
(flags == (activity_info_pressure|activity_info_stats))
? ", " : "",
flags & activity_info_pressure ? "pressure" : "",
flags,
- until_period, principal->stats[period].period);
+ until_period, activity->stats[period].period);
if ((flags & activity_info_stats)
- && principal->stats[period].period > 0
- && principal->stats[period].period >= until_period)
+ && activity->stats[period].period > 0
+ && activity->stats[period].period >= until_period)
/* Return the available statistics. */
{
/* XXX: Only return valid stat buffers. */
@@ -1645,29 +1827,25 @@ server_loop (void)
int i;
for (i = 0; i < ACTIVITY_STATS_PERIODS; i ++)
{
- period = principal->current_period - 1 - i;
+ period = activity->current_period - 1 - i;
if (period < 0)
period = (ACTIVITY_STATS_PERIODS + 1) + period;
- info.stats.stats[i] = principal->stats[period];
+ info.stats.stats[i] = activity->stats[period];
}
info.stats.count = ACTIVITY_STATS_PERIODS;
- rm_activity_info_reply_marshal (&msg, info);
+ rm_activity_info_reply (principal, reply, info);
}
else if (flags)
/* Queue thread on the activity. */
{
- thread->wait_reason = THREAD_WAIT_ACTIVITY_INFO;
- thread->wait_reason_arg = flags;
- thread->wait_reason_arg2 = until_period;
+ reply->wait_reason = MESSENGER_WAIT_ACTIVITY_INFO;
+ reply->wait_reason_arg = flags;
+ reply->wait_reason_arg2 = until_period;
- object_wait_queue_enqueue (principal,
- (struct object *) principal,
- thread);
-
- do_reply = 0;
+ object_wait_queue_enqueue (principal, target, reply);
}
else
REPLY (EINVAL);
@@ -1675,36 +1853,30 @@ server_loop (void)
break;
}
- case RM_exception_collect:
+ case RM_thread_activation_collect:
{
- /* We don't expect a principal. */
- err = rm_exception_collect_send_unmarshal (&msg, &principal_addr);
+ if (object_type (target) != cap_thread)
+ REPLY (EINVAL);
+
+ err = rm_thread_activation_collect_send_unmarshal (message, NULL);
if (err)
REPLY (err);
- panic ("Collecting exception: %x", from);
-#warning exception_collect not implemented
-
- /* XXX: Implement me. */
+ thread_deliver_pending (principal, (struct thread *) target);
+ rm_thread_activation_collect_reply (principal, reply);
break;
}
case RM_as_dump:
{
- addr_t root_addr;
- err = rm_as_dump_send_unmarshal (&msg, &principal_addr,
- &root_addr);
+ err = rm_as_dump_send_unmarshal (message, NULL);
if (err)
REPLY (err);
- DEBUG (4, "");
-
- struct cap *root = ROOT (root_addr);
-
- as_dump_from (principal, root, "");
+ as_dump_from (principal, target_root, "");
- rm_as_dump_reply_marshal (&msg);
+ rm_as_dump_reply (activity, reply);
break;
}
@@ -1716,22 +1888,22 @@ server_loop (void)
int to_requeue, struct object *object2, int offset2)
{
int count = 0;
- struct thread *t;
+ struct messenger *m;
- object_wait_queue_for_each (principal, object1, t)
- if (t->wait_reason == THREAD_WAIT_FUTEX
- && t->wait_reason_arg == offset1)
+ object_wait_queue_for_each (principal, object1, m)
+ if (m->wait_reason == MESSENGER_WAIT_FUTEX
+ && m->wait_reason_arg == offset1)
/* Got a match. */
{
if (count < to_wake)
{
- object_wait_queue_dequeue (principal, t);
+ object_wait_queue_unlink (principal, m);
- debug (5, "Waking thread %x", t->tid);
+ debug (5, "Waking messenger");
- err = rm_futex_reply (t->tid, 0);
+ err = rm_futex_reply (principal, m, 0);
if (err)
- panic ("Error futex waking %x: %d", t->tid, err);
+ panic ("Error futex waking: %d", err);
count ++;
@@ -1740,10 +1912,10 @@ server_loop (void)
}
else
{
- object_wait_queue_dequeue (principal, t);
+ object_wait_queue_unlink (principal, m);
- t->wait_reason_arg = offset2;
- object_wait_queue_enqueue (principal, object2, t);
+ m->wait_reason_arg = offset2;
+ object_wait_queue_enqueue (principal, object2, m);
count ++;
@@ -1763,10 +1935,10 @@ server_loop (void)
void *addr2;
union futex_val3 val3;
- err = rm_futex_send_unmarshal (&msg, &principal_addr,
+ err = rm_futex_send_unmarshal (message,
&addr1, &op, &val1,
&timeout, &val2,
- &addr2, &val3);
+ &addr2, &val3, NULL);
if (err)
REPLY (err);
@@ -1790,14 +1962,12 @@ server_loop (void)
char *mode = "unknown";
- struct object *page = cap_to_object (principal,
- &thread->exception_page);
+ struct object *page = cap_to_object (principal, &thread->utcb);
if (page && object_type (page) == cap_page)
{
- struct exception_page *exception_page
- = (struct exception_page *) page;
+ struct vg_utcb *utcb = (struct vg_utcb *) page;
- if (exception_page->activated_mode)
+ if (utcb->activated_mode)
mode = "activated";
else
mode = "normal";
@@ -1821,7 +1991,7 @@ server_loop (void)
addr_t addr = addr_chop (PTR_TO_ADDR (addr1), PAGESIZE_LOG2);
struct object *object1 = OBJECT (&thread->aspace,
- addr, cap_page, true);
+ addr, cap_page, true, NULL);
int offset1 = (uintptr_t) addr1 & (PAGESIZE - 1);
int *vaddr1 = (void *) object1 + offset1;
@@ -1834,17 +2004,15 @@ server_loop (void)
if (timeout)
panic ("Timeouts not yet supported");
- thread->wait_reason = THREAD_WAIT_FUTEX;
- thread->wait_reason_arg = offset1;
+ reply->wait_reason = MESSENGER_WAIT_FUTEX;
+ reply->wait_reason_arg = offset1;
- object_wait_queue_enqueue (principal, object1, thread);
+ object_wait_queue_enqueue (principal, object1, reply);
#ifndef NDEBUG
- futex_waiter_list_enqueue (&futex_waiters, thread);
+ futex_waiter_list_enqueue (&futex_waiters, reply);
#endif
- /* Don't reply. */
- do_reply = 0;
break;
case FUTEX_WAKE:
@@ -1856,13 +2024,13 @@ server_loop (void)
REPLY (EINVAL);
int count = wake (val1, object1, offset1, 0, 0, 0);
- rm_futex_reply_marshal (&msg, count);
+ rm_futex_reply (activity, reply, count);
break;
case FUTEX_WAKE_OP:
addr = addr_chop (PTR_TO_ADDR (addr2), PAGESIZE_LOG2);
struct object *object2 = OBJECT (&thread->aspace,
- addr, cap_page, true);
+ addr, cap_page, true, NULL);
int offset2 = (uintptr_t) addr2 & (PAGESIZE - 1);
int *vaddr2 = (void *) object2 + offset2;
@@ -1914,7 +2082,7 @@ server_loop (void)
if (comparison)
count += wake (val2.value, object2, offset2, 0, 0, 0);
- rm_futex_reply_marshal (&msg, 0);
+ rm_futex_reply (activity, reply, 0);
break;
case FUTEX_CMP_REQUEUE:
@@ -1929,23 +2097,51 @@ server_loop (void)
/* Get the second object. */
addr = addr_chop (PTR_TO_ADDR (addr2), PAGESIZE_LOG2);
- object2 = OBJECT (&thread->aspace, addr, cap_page, true);
+ object2 = OBJECT (&thread->aspace, addr, cap_page, true, NULL);
offset2 = (uintptr_t) addr2 & (PAGESIZE - 1);
count = wake (val1, object1, offset1,
val2.value, object2, offset2);
- rm_futex_reply_marshal (&msg, count);
+ rm_futex_reply (activity, reply, count);
break;
}
break;
}
+ case VG_messenger_id:
+ {
+ if (object_type (target) != cap_messenger || ! target_writable)
+ REPLY (EINVAL);
+ struct messenger *m = (struct messenger *) target;
+
+ uint64_t id;
+ err = vg_messenger_id_send_unmarshal (message, &id, NULL);
+ if (err)
+ REPLY (EINVAL);
+
+ uint64_t old = m->id;
+ m->id = id;
+
+ vg_messenger_id_reply (principal, reply, old);
+
+ break;
+ }
+
default:
/* XXX: Don't panic when running production code. */
DEBUG (1, "Didn't handle message from %x.%x with label %d",
l4_thread_no (from), l4_version (from), label);
}
+
+ if ((flags & VG_IPC_RETURN))
+ {
+ l4_msg_clear (msg);
+ l4_msg_put_word (msg, 0, 0);
+ l4_msg_set_untyped_words (msg, 1);
+ do_reply = 1;
+ }
+
out:;
}
diff --git a/viengoos/thread.c b/viengoos/thread.c
index 6ce0197..bdba441 100644
--- a/viengoos/thread.c
+++ b/viengoos/thread.c
@@ -26,12 +26,14 @@
#include <hurd/exceptions.h>
#include <hurd/thread.h>
#include <bit-array.h>
+#include <backtrace.h>
#include "cap.h"
#include "object.h"
#include "thread.h"
#include "activity.h"
#include "zalloc.h"
+#include "messenger.h"
#include <hurd/trace.h>
#define THREAD_VERSION 2
@@ -89,7 +91,7 @@ thread_init (struct thread *thread)
size_t size = PAGESIZE * 10;
void *buffer = (void *) zalloc (size);
if (! buffer)
- panic ("Failed to allocate memory for thread has.");
+ panic ("Failed to allocate memory for thread hash.");
hurd_ihash_init_with_buffer (&tid_to_thread, false, HURD_IHASH_NO_LOCP,
buffer, size);
@@ -132,10 +134,6 @@ thread_deinit (struct activity *activity, struct thread *thread)
if (thread->commissioned)
thread_decommission (thread);
- if (thread->wait_queue_p)
- /* THREAD is attached to a wait queue. Detach it. */
- object_wait_queue_dequeue (activity, thread);
-
/* Free the thread id. */
bit_dealloc (thread_ids,
l4_thread_no (thread->tid) - THREAD_ID_BASE);
@@ -254,15 +252,14 @@ control_to_string (l4_word_t control, char string[33])
error_t
thread_exregs (struct activity *principal,
- struct thread *thread, l4_word_t control,
- struct cap *aspace,
- l4_word_t flags, struct cap_properties properties,
- struct cap *activity,
- struct cap *exception_page,
- l4_word_t *sp, l4_word_t *ip,
- l4_word_t *eflags, l4_word_t *user_handle,
- struct cap *aspace_out, struct cap *activity_out,
- struct cap *exception_page_out)
+ struct thread *thread, uintptr_t control,
+ struct cap aspace,
+ uintptr_t flags, struct cap_properties properties,
+ struct cap activity,
+ struct cap utcb,
+ struct cap exception_messenger,
+ uintptr_t *sp, uintptr_t *ip,
+ uintptr_t *eflags, uintptr_t *user_handle)
{
if ((control & ~(HURD_EXREGS_SET_REGS
| HURD_EXREGS_GET_REGS
@@ -274,36 +271,26 @@ thread_exregs (struct activity *principal,
return EINVAL;
}
- if ((control & HURD_EXREGS_GET_REGS) && aspace_out)
- cap_copy (principal,
- ADDR_VOID, aspace_out, ADDR_VOID,
- ADDR_VOID, thread->aspace, ADDR_VOID);
-
if ((control & HURD_EXREGS_SET_ASPACE))
cap_copy_x (principal,
ADDR_VOID, &thread->aspace, ADDR_VOID,
- ADDR_VOID, *aspace, ADDR_VOID,
+ ADDR_VOID, aspace, ADDR_VOID,
flags, properties);
- if ((control & HURD_EXREGS_GET_REGS) && activity_out)
- cap_copy (principal,
- ADDR_VOID, activity_out, ADDR_VOID,
- ADDR_VOID, thread->activity, ADDR_VOID);
-
if ((control & HURD_EXREGS_SET_ACTIVITY))
cap_copy (principal,
ADDR_VOID, &thread->activity, ADDR_VOID,
- ADDR_VOID, *activity, ADDR_VOID);
+ ADDR_VOID, activity, ADDR_VOID);
- if ((control & HURD_EXREGS_GET_REGS) && exception_page_out)
+ if ((control & HURD_EXREGS_SET_UTCB))
cap_copy (principal,
- ADDR_VOID, exception_page_out, ADDR_VOID,
- ADDR_VOID, thread->exception_page, ADDR_VOID);
+ ADDR_VOID, &thread->utcb, ADDR_VOID,
+ ADDR_VOID, utcb, ADDR_VOID);
- if ((control & HURD_EXREGS_SET_EXCEPTION_PAGE))
+ if ((control & HURD_EXREGS_SET_EXCEPTION_MESSENGER))
cap_copy (principal,
- ADDR_VOID, &thread->exception_page, ADDR_VOID,
- ADDR_VOID, *exception_page, ADDR_VOID);
+ ADDR_VOID, &thread->exception_messenger, ADDR_VOID,
+ ADDR_VOID, exception_messenger, ADDR_VOID);
if (thread->commissioned)
{
@@ -443,23 +430,29 @@ thread_exregs (struct activity *principal,
return 0;
}
-void
-thread_raise_exception (struct activity *activity,
- struct thread *thread,
- l4_msg_t *msg)
+bool
+thread_activate (struct activity *activity,
+ struct thread *thread,
+ struct messenger *messenger,
+ bool may_block)
{
- l4_word_t ip = 0;
- l4_word_t sp = 0;
+ assert (messenger);
+ assert (object_type ((struct object *) messenger) == cap_messenger);
+
+
+ uintptr_t ip = 0;
+ uintptr_t sp = 0;
{
- l4_word_t c = _L4_XCHG_REGS_DELIVER;
+ uintptr_t c = _L4_XCHG_REGS_DELIVER;
l4_thread_id_t targ = thread->tid;
- l4_word_t dummy = 0;
+ uintptr_t dummy = 0;
_L4_exchange_registers (&targ, &c,
&sp, &ip, &dummy, &dummy, &dummy);
}
- struct object *page = cap_to_object (activity, &thread->exception_page);
- if (! page)
+ struct vg_utcb *utcb
+ = (struct vg_utcb *) cap_to_object (activity, &thread->utcb);
+ if (! utcb)
{
#ifndef NDEBUG
extern struct trace_buffer rpc_trace;
@@ -468,36 +461,50 @@ thread_raise_exception (struct activity *activity,
do_debug (4)
as_dump_from (activity, &thread->aspace, "");
- debug (0, "Malformed thread (%x): no exception page (ip: %x, sp: %x)",
+ debug (0, "Malformed thread (%x): no utcb (ip: %x, sp: %x)",
thread->tid, ip, sp);
- return;
+ return false;
}
- if (object_type (page) != cap_page)
+ if (object_type ((struct object *) utcb) != cap_page)
{
- debug (0, "Malformed thread: exception page slot contains a %s, "
- "not a cap_page",
- cap_type_string (object_type (page)));
- return;
+ debug (0, "Malformed thread: utcb slot contains a %s, not a page",
+ cap_type_string (object_type ((struct object *) utcb)));
+ return false;
}
- struct exception_page *exception_page = (struct exception_page *) page;
-
- if (exception_page->activated_mode)
+ if (utcb->activated_mode)
{
debug (0, "Deferring exception delivery: thread in activated mode!"
"(sp: %x, ip: %x)", sp, ip);
- /* XXX: Sure, we could note that an exception is pending but we
- need to queue the event. */
- // exception_page->pending_message = 1;
+ if (! may_block)
+ return false;
- return;
+ object_wait_queue_enqueue (activity,
+ (struct object *) thread, messenger);
+ messenger->wait_reason = MESSENGER_WAIT_TRANSFER_MESSAGE;
+
+ utcb->pending_message = 1;
+
+ return true;
}
- /* Copy the message. */
- memcpy (&exception_page->exception, msg,
- (1 + l4_untyped_words (l4_msg_msg_tag (*msg))) * sizeof (l4_word_t));
+ debug (5, "Activating %x (ip: %p; sp: %p)",
+ thread->tid, ip, sp);
+
+ utcb->protected_payload = messenger->protected_payload;
+ utcb->messenger_id = messenger->id;
+
+ if (! messenger->out_of_band)
+ {
+ memcpy (utcb->inline_words, messenger->inline_words,
+ messenger->inline_word_count * sizeof (uintptr_t));
+ memcpy (utcb->inline_caps, messenger->inline_caps,
+ messenger->inline_cap_count * sizeof (addr_t));
+ utcb->inline_word_count = messenger->inline_word_count;
+ utcb->inline_cap_count = messenger->inline_cap_count;
+ }
l4_word_t c = HURD_EXREGS_STOP | _L4_XCHG_REGS_DELIVER
| _L4_XCHG_REGS_CANCEL_SEND | _L4_XCHG_REGS_CANCEL_RECV;
@@ -521,7 +528,7 @@ thread_raise_exception (struct activity *activity,
int err = l4_error_code ();
debug (0, "Failed to exregs %x: %s (%d)",
thread->tid, l4_strerror (err), err);
- return;
+ return false;
}
do_debug (4)
{
@@ -531,28 +538,28 @@ thread_raise_exception (struct activity *activity,
thread->tid, string, c);
}
- exception_page->saved_thread_state = c;
+ utcb->saved_thread_state = c;
- exception_page->activated_mode = 1;
+ utcb->activated_mode = 1;
- if (exception_page->exception_handler_ip <= ip
- && ip < exception_page->exception_handler_end)
+ if (utcb->activation_handler_ip <= ip
+ && ip < utcb->activation_handler_end)
/* Thread is transitioning. Don't save sp and ip. */
{
- debug (4, "Fault while interrupt in transition (ip: %x)!",
+ debug (0, "Fault while interrupt in transition (ip: %x)!",
ip);
- exception_page->interrupt_in_transition = 1;
+ utcb->interrupt_in_transition = 1;
}
else
{
- exception_page->interrupt_in_transition = 0;
- exception_page->saved_sp = sp;
- exception_page->saved_ip = ip;
+ utcb->interrupt_in_transition = 0;
+ utcb->saved_sp = sp;
+ utcb->saved_ip = ip;
}
c = HURD_EXREGS_START | _L4_XCHG_REGS_SET_SP | _L4_XCHG_REGS_SET_IP;
- sp = exception_page->exception_handler_sp;
- ip = exception_page->exception_handler_ip;
+ sp = utcb->activation_handler_sp;
+ ip = utcb->activation_handler_ip;
targ = thread->tid;
do_debug (4)
{
@@ -571,7 +578,7 @@ thread_raise_exception (struct activity *activity,
int err = l4_error_code ();
debug (0, "Failed to exregs %x: %s (%d)",
thread->tid, l4_strerror (err), err);
- return;
+ return false;
}
do_debug (4)
{
@@ -580,4 +587,73 @@ thread_raise_exception (struct activity *activity,
debug (0, "exregs on %x returned control: %s (%x)",
thread->tid, string, c);
}
+
+ return true;
+}
+
+void
+thread_raise_exception (struct activity *activity,
+ struct thread *thread,
+ struct vg_message *message)
+{
+ struct messenger *handler
+ = (struct messenger *) cap_to_object (activity,
+ &thread->exception_messenger);
+ if (! handler)
+ {
+ backtrace_print ();
+ debug (0, "Thread %x has no exception handler.", thread->tid);
+ }
+ else if (object_type ((struct object *) handler) != cap_messenger)
+ debug (0, "%s is not a valid exception handler.",
+ cap_type_string (object_type ((struct object *) handler)));
+ else
+ {
+ if (! messenger_message_load (activity, handler, message))
+ debug (0, "Failed to deliver exception to thread's exception handler.");
+ return;
+ }
+}
+
+void
+thread_deliver_pending (struct activity *activity,
+ struct thread *thread)
+{
+ struct vg_utcb *utcb
+ = (struct vg_utcb *) cap_to_object (activity, &thread->utcb);
+ if (! utcb)
+ {
+ debug (0, "Malformed thread (%x): no utcb",
+ thread->tid);
+ return;
+ }
+
+ if (object_type ((struct object *) utcb) != cap_page)
+ {
+ debug (0, "Malformed thread: utcb slot contains a %s, not a page",
+ cap_type_string (object_type ((struct object *) utcb)));
+ return;
+ }
+
+ if (utcb->activated_mode)
+ {
+ debug (0, "Deferring exception delivery: thread in activated mode!");
+ return;
+ }
+
+
+ struct messenger *m;
+ object_wait_queue_for_each (activity, (struct object *) thread, m)
+ if (m->wait_reason == MESSENGER_WAIT_TRANSFER_MESSAGE)
+ {
+ object_wait_queue_unlink (activity, m);
+ m->wait_reason = MESSENGER_WAIT_TRANSFER_MESSAGE;
+
+ bool ret = thread_activate (activity, thread, m, false);
+ assert (ret);
+
+ return;
+ }
+
+ utcb->pending_message = 0;
}
diff --git a/viengoos/thread.h b/viengoos/thread.h
index 728bf7b..3bcb91d 100644
--- a/viengoos/thread.h
+++ b/viengoos/thread.h
@@ -23,35 +23,12 @@
#include <l4.h>
#include <errno.h>
-
-#include "list.h"
+#include <hurd/cap.h>
+#include <hurd/thread.h>
/* Forward. */
-struct folio;
struct activity;
-/* Number of capability slots at the start of the thread
- structure. */
-enum
- {
- THREAD_SLOTS = 3,
- };
-
-enum
- {
- /* THREAD is blocked on an object wait for a futex.
- WAIT_REASON_ARG holds the byte offset in the object on which it
- is waiting. */
- THREAD_WAIT_FUTEX,
- /* THREAD is blocked on an object waiting for the object to be
- destroyed. */
- THREAD_WAIT_DESTROY,
- /* THREAD is blocked on an activity waiting for information. The
- type of information is stored in wait_reason_arg. The period
- in wait_reason_arg2. */
- THREAD_WAIT_ACTIVITY_INFO,
- };
-
struct thread
{
/* User accessible fields. */
@@ -63,10 +40,14 @@ struct thread
this thread's storage is allocated!) */
struct cap activity;
- /* Capability identifying a page to use to store exceptions. */
- struct cap exception_page;
+ /* A capability designating a messenger to which to deliver
+ exceptions. */
+ struct cap exception_messenger;
- /* Non-user accessible fields. */
+ /* A capability the page that contains the thread's UTCB. */
+ struct cap utcb;
+
+ /* Non-user-accessible fields. */
/* Allocated thread id. */
l4_thread_id_t tid;
@@ -82,48 +63,9 @@ struct thread
/* Whether the thread has been commissioned (a tid allocated). */
uint32_t commissioned : 1;
- /* Whether the object is attached to a wait queue. (This is
- different from the value of folio_object_wait_queue_p which
- specifies if there are objects on this thread's wait queue.) */
- bool wait_queue_p;
-
- /* Whether this thread is the head of the wait queue. If so,
- WAIT_QUEUE.PREV designates the object. */
- uint32_t wait_queue_head : 1;
-
- /* Whether this thread is the tail of the wait queue. If so,
- WAIT_QUEUE.NEXT designates the object. */
- uint32_t wait_queue_tail : 1;
-
- /* The event the thread is interested in. */
- uint32_t wait_reason : 28;
- /* More information about the reason. */
- uint32_t wait_reason_arg;
- uint32_t wait_reason_arg2;
-
- /* The object the thread is waiting on. Only meaningful if
- WAIT_QUEUE_P is true. */
- struct
- {
- /* We don't need versioning as we automatically collect on object
- destruction. */
- oid_t next;
- oid_t prev;
- } wait_queue;
-
-#ifndef NDEBUG
- struct list_node futex_waiter_node;
-#endif
-
struct object_name name;
};
-#ifndef NDEBUG
-LIST_CLASS(futex_waiter, struct thread, futex_waiter_node, true)
-/* List of threads waiting on a futex. */
-extern struct futex_waiter_list futex_waiters;
-#endif
-
/* The hardwired base of the UTCB (2.5GB). */
#define UTCB_AREA_BASE (0xA0000000)
/* The size of the UTCB. */
@@ -152,21 +94,33 @@ extern void thread_decommission (struct thread *thread);
USER_HANDLER are as per l4_exchange_regs, however, the caller may
not set the pager. */
extern error_t thread_exregs (struct activity *principal,
- struct thread *thread, l4_word_t control,
- struct cap *aspace,
- l4_word_t flags, struct cap_properties properties,
- struct cap *activity,
- struct cap *exception_page,
- l4_word_t *sp, l4_word_t *ip,
- l4_word_t *eflags, l4_word_t *user_handle,
- struct cap *aspace_out,
- struct cap *activity_out,
- struct cap *exception_page_out);
-
-/* Send thread THREAD an exception. */
+ struct thread *thread, uintptr_t control,
+ struct cap aspace,
+ uintptr_t flags, struct cap_properties properties,
+ struct cap activity,
+ struct cap utcb,
+ struct cap exception_messenger,
+ uintptr_t *sp, uintptr_t *ip,
+ uintptr_t *eflags, uintptr_t *user_handle);
+
+/* Deliver the message carried by messenger MESSENGER to thread
+ thread. If thread is not activated, activate the thread. Returns
+ whether the message was delivered or the messenger was enqueued on
+ the thread. */
+extern bool thread_activate (struct activity *activity,
+ struct thread *thread,
+ struct messenger *messenger,
+ bool may_block);
+
+/* Send thread THREAD's exception messenger the exception described by
+ MESSAGE. If this would block, silently discards MESSAGE. */
extern void thread_raise_exception (struct activity *activity,
struct thread *thread,
- l4_msg_t *msg);
+ struct vg_message *message);
+
+/* Deliver a pending message, if any and if possible. */
+extern void thread_deliver_pending (struct activity *activity,
+ struct thread *thread);
/* Given the L4 thread id THREADID, find the associated thread. */
extern struct thread *thread_lookup (l4_thread_id_t threadid);