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