diff options
Diffstat (limited to 'viengoos')
-rw-r--r-- | viengoos/ChangeLog | 112 | ||||
-rw-r--r-- | viengoos/Makefile.am | 1 | ||||
-rw-r--r-- | viengoos/ager.c | 28 | ||||
-rw-r--r-- | viengoos/cap.c | 37 | ||||
-rw-r--r-- | viengoos/messenger.c | 347 | ||||
-rw-r--r-- | viengoos/messenger.h | 214 | ||||
-rw-r--r-- | viengoos/object.c | 318 | ||||
-rw-r--r-- | viengoos/object.h | 57 | ||||
-rw-r--r-- | viengoos/pager.c | 24 | ||||
-rw-r--r-- | viengoos/rm.h | 48 | ||||
-rw-r--r-- | viengoos/server.c | 1472 | ||||
-rw-r--r-- | viengoos/thread.c | 220 | ||||
-rw-r--r-- | viengoos/thread.h | 114 |
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); |