summaryrefslogtreecommitdiff
path: root/hurd
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 /hurd
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 'hurd')
-rw-r--r--hurd/ChangeLog236
-rw-r--r--hurd/RPC7
-rw-r--r--hurd/activity.h12
-rw-r--r--hurd/cap.h134
-rw-r--r--hurd/exceptions.h181
-rw-r--r--hurd/folio.h42
-rw-r--r--hurd/futex.h81
-rw-r--r--hurd/headers.m43
-rw-r--r--hurd/ipc.h296
-rw-r--r--hurd/message.h229
-rw-r--r--hurd/messenger.h87
-rw-r--r--hurd/rpc.h1041
-rw-r--r--hurd/startup.h21
-rw-r--r--hurd/t-rpc.c123
-rw-r--r--hurd/thread.h346
15 files changed, 2099 insertions, 740 deletions
diff --git a/hurd/ChangeLog b/hurd/ChangeLog
index 7d15920..3c74c1c 100644
--- a/hurd/ChangeLog
+++ b/hurd/ChangeLog
@@ -1,3 +1,239 @@
+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.
+
2008-12-10 Neal H. Walfield <neal@gnu.org>
* stddef.h: When checking if compiling for i386, check if i386 is
diff --git a/hurd/RPC b/hurd/RPC
index 61969c5..2268bda 100644
--- a/hurd/RPC
+++ b/hurd/RPC
@@ -4,8 +4,9 @@ RPC Method id Assignments
100: miscellaneous (putchar, etc.)
200: folio
300: cap
-400: object
-500: exceptions
+400: generic object
+500: activation
600: thread
700: activity
-800: futex \ No newline at end of file
+800: futex
+900: messenger
diff --git a/hurd/activity.h b/hurd/activity.h
index 8a4902d..dc77fc0 100644
--- a/hurd/activity.h
+++ b/hurd/activity.h
@@ -169,12 +169,6 @@ struct activity_stats
#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>
@@ -194,7 +188,8 @@ enum
};
/* Get ACTIVITY's policy and set according to FLAGS and IN. */
-RPC (activity_policy, 3, 1, addr_t, activity,
+RPC (activity_policy, 2, 1, 0,
+ /* cap_t principal, cap_t activity */
uintptr_t, flags, struct activity_policy, in,
/* Out: */
struct activity_policy, out);
@@ -248,7 +243,8 @@ struct activity_info
indicating that the activity must free some memory or will be such
subject to paging. In this case, the activity should try to free
at least the indicated number of pages as quickly as possible. */
-RPC (activity_info, 3, 1, addr_t, activity,
+RPC (activity_info, 2, 1, 0,
+ /* cap_t principal, cap_t activity, */
uintptr_t, flags, uintptr_t, until_period,
/* Out: */
struct activity_info, info)
diff --git a/hurd/cap.h b/hurd/cap.h
index eae17db..0dd3e82 100644
--- a/hurd/cap.h
+++ b/hurd/cap.h
@@ -23,10 +23,12 @@
#include <hurd/types.h>
#include <hurd/stddef.h>
+#include <hurd/addr.h>
#include <hurd/addr-trans.h>
#include <hurd/startup.h>
#include <hurd/error.h>
#include <stdint.h>
+#include <stdbool.h>
/* Capabilities.
@@ -47,7 +49,10 @@ enum cap_type
cap_activity,
cap_activity_control,
cap_thread,
-#define CAP_TYPE_MAX cap_thread
+ cap_messenger,
+ cap_rmessenger,
+ cap_type_count,
+#define CAP_TYPE_MAX (cap_type_count - 1)
};
static inline const char *
@@ -73,6 +78,10 @@ cap_type_string (enum cap_type type)
return "activity_control";
case cap_thread:
return "thread";
+ case cap_messenger:
+ return "messenger";
+ case cap_rmessenger:
+ return "rmessenger";
default:
return "unknown cap type";
};
@@ -101,6 +110,11 @@ cap_types_compatible (enum cap_type a, enum cap_type b)
if (a == cap_activity_control && b == cap_activity)
return true;
+ if (a == cap_messenger && b == cap_rmessenger)
+ return true;
+ if (a == cap_rmessenger && b == cap_messenger)
+ return true;
+
return false;
}
@@ -113,6 +127,7 @@ cap_type_weak_p (enum cap_type type)
case cap_rpage:
case cap_rcappage:
case cap_activity:
+ case cap_rmessenger:
return true;
default:
@@ -139,6 +154,10 @@ cap_type_weaken (enum cap_type type)
case cap_activity:
return cap_activity;
+ case cap_messenger:
+ case cap_rmessenger:
+ return cap_rmessenger;
+
default:
return cap_void;
}
@@ -163,6 +182,10 @@ cap_type_strengthen (enum cap_type type)
case cap_activity:
return cap_activity_control;
+ case cap_messenger:
+ case cap_rmessenger:
+ return cap_messenger;
+
default:
return type;
}
@@ -229,7 +252,7 @@ struct cap_properties
#ifdef RM_INTERN
/* An OID corresponds to a page on a volume. Only the least 54 bits
are significant. */
-typedef l4_uint64_t oid_t;
+typedef uint64_t oid_t;
#define OID_FMT "0x%llx"
#define OID_PRINTF(__op_oid) ((oid_t) (__op_oid))
#endif
@@ -273,6 +296,8 @@ struct cap
#endif
};
+#define CAP_VOID ((struct cap) { .type = cap_void })
+
/* Return CAP's policy. */
#define CAP_POLICY_GET(__cpg_cap) \
OBJECT_POLICY ((__cpg_cap).discardable, (__cpg_cap).priority)
@@ -356,12 +381,6 @@ struct cap
#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>
@@ -371,12 +390,10 @@ enum
RM_cap_rubout,
RM_cap_read,
- RM_object_slot_copy_out = 400,
- RM_object_slot_copy_in,
- RM_object_slot_read,
- RM_object_discarded_clear,
+ RM_object_discarded_clear = 400,
RM_object_discard,
RM_object_status,
+ RM_object_reply_on_destruction,
RM_object_name,
};
@@ -400,14 +417,9 @@ enum
CAP_COPY_PRIORITY_SET = 1 << 5,
};
-/* Copy the capability in capability slot SOURCE in the address space
- rooted at SOURCE_ADDRESS_SPACE to the slot TARGET in the address
- space rooted at TARGET_ADDRESS_SPACE. The address space is
- resolved in the context of the caller. If the address space
- identifies a thread, its address space root is used. If it is
- ADDR_VOID, then the calling thread's address space route is used.
- (PRINCIPAL and the address spaces are looked up in the context of
- the caller.)
+/* Copy the capability in capability slot SOURCE to the slot at ADDR
+ in the object OBJECT. If OBJECT is ADDR_VOID, then the calling
+ thread's address space root is used.
By default, preserves SOURCE's subpage specification and copies
TARGET's guard and policy.
@@ -419,9 +431,8 @@ enum
If CAP_COPY_COPY_SOURCE_GUARD is set, uses the guard description in
source. Otherwise, preserves the guard in TARGET.
- If CAP_COPY_WEAKEN is set, saves a weakened version of SOURCE in
- *TARGET (e.g., if SOURCE's type is cap_page, *TARGET's type is set
- to cap_rpage).
+ If CAP_COPY_WEAKEN is set, saves a weakened version of SOURCE
+ (e.g., if SOURCE's type is cap_page, a cap_rpage is saved).
If CAP_COPY_DISCARDABLE_SET is set, then sets the discardable bit
based on the value in PROPERTIES. Otherwise, copies SOURCE's
@@ -429,55 +440,33 @@ enum
If CAP_COPY_PRIORITY_SET is set, then sets the priority based on
the value in properties. Otherwise, copies SOURCE's value. */
-RPC(cap_copy, 7, 0, addr_t, principal,
- addr_t, target_address_space, addr_t, target,
- addr_t, source_address_space, addr_t, source,
- l4_word_t, flags, struct cap_properties, properties)
-
-/* Overwrite the capability slot TARGET in address space
- TARGET_ADDRESS_SPACE with a void capability. */
-RPC(cap_rubout, 3, 0, addr_t, principal,
- addr_t, target_address_space, addr_t, target)
-
-/* Returns the public bits of the capability CAP in TYPE and
- CAP_PROPERTIES. */
-RPC(cap_read, 3, 2, addr_t, principal, addr_t, address_space, addr_t, cap,
- /* Out: */
- l4_word_t, type, struct cap_properties, properties)
-
-/* Copy the capability from slot SLOT of the object OBJECT (relative
- to the start of the object's subpage) to slot TARGET. PROPERTIES
- are interpreted as per cap_copy. */
-RPC(object_slot_copy_out, 8, 0, addr_t, principal,
- addr_t, object_address_space, addr_t, object, l4_word_t, slot,
- addr_t, target_address_space, addr_t, target,
- l4_word_t, flags, struct cap_properties, properties)
-
-/* Copy the capability from slot SOURCE to slot INDEX of the object
- OBJECT (relative to the start of the object's subpage). PROPERTIES
- are interpreted as per cap_copy. */
-RPC(object_slot_copy_in, 8, 0, addr_t, principal,
- addr_t, object_address_space, addr_t, object, l4_word_t, index,
- addr_t, source_address_space, addr_t, source,
- l4_word_t, flags, struct cap_properties, properties)
-
-/* Store the public bits of the capability slot SLOT of object OBJECT
+RPC(cap_copy, 5, 0, 0,
+ /* cap_t activity, cap_t object, */ addr_t, addr,
+ cap_t, source_object, addr_t, source_addr,
+ uintptr_t, flags, struct cap_properties, properties)
+
+/* Overwrite the capability slot at ADDR in the object OBJECT with a
+ void capability. */
+RPC(cap_rubout, 1, 0, 0,
+ /* cap_t activity, cap_t object, */ addr_t, addr)
+
+/* Returns the public bits of the capability at address ADDR in OBJECT
in TYPE and CAP_PROPERTIES. */
-RPC(object_slot_read, 4, 2, addr_t, principal, addr_t, address_space,
- addr_t, object, l4_word_t, slot,
+RPC(cap_read, 1, 2, 0,
+ /* cap_t activity, cap_t object, */ addr_t, addr,
/* Out: */
- l4_word_t, type, struct cap_properties, properties)
+ uintptr_t, type, struct cap_properties, properties)
-/* Clear the discarded bit. */
-RPC(object_discarded_clear, 2, 0,
- addr_t, principal, addr_t, object)
+/* Clear the discarded bit of the object at ADDR in object OBJECT. */
+RPC(object_discarded_clear, 1, 0, 0,
+ /* cap_t activity, cap_t object, */ addr_t, addr)
/* If the object designated by OBJECT is in memory, discard it.
OBJECT must have write authority. This does not set the object's
discarded bit and thus does not result in a fault. Instead, the
- next access will see zero-filled memory. */
-RPC(object_discard, 2, 0,
- addr_t, principal, addr_t, object)
+ next access will see, e.g., zero-filled memory. */
+RPC(object_discard, 0, 0, 0
+ /* cap_t activity, cap_t object, */)
enum
{
@@ -490,9 +479,17 @@ enum
(Note: this is not the state of a frame but an indication of
whether the object has been modified since the last time it the
dirty bit was cleared.) */
-RPC (object_status, 3, 1, addr_t, principal, addr_t, object, bool, clear,
+RPC (object_status, 1, 1, 0,
+ /* addr_t activity, addr_t object, */ bool, clear,
uintptr_t, status)
+/* Returns the object's return code in RETURN_CODE on object
+ destruction. */
+RPC (object_reply_on_destruction, 0, 1, 0,
+ /* cap_t principal, cap_t object, */
+ /* Out: */
+ uintptr_t, return_code);
+
struct object_name
{
char name[12];
@@ -501,13 +498,12 @@ struct object_name
/* Give object OBJECT a name. This is only used for debugging
purposes and is only supported by some objects, in particular,
activities and threads. */
-RPC (object_name, 3, 0, addr_t, principal,
- addr_t, object, struct object_name, name);
+RPC (object_name, 1, 0, 0,
+ /* cap_t activity, cap_t object, */ struct object_name, name);
#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
-#undef RPC_TARGET
/* An object. */
diff --git a/hurd/exceptions.h b/hurd/exceptions.h
index 5771210..765fc5f 100644
--- a/hurd/exceptions.h
+++ b/hurd/exceptions.h
@@ -1,26 +1,25 @@
-/* exceptions.h - Exception handling definitions.
+/* activations.h - Activation handling definitions.
Copyright (C) 2007, 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 Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ 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.
- The GNU Hurd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 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 the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
-#ifndef _HURD_EXCEPTIONS_H
-#define _HURD_EXCEPTIONS_H 1
+#ifndef _HURD_ACTIVATIONS_H
+#define _HURD_ACTIVATIONS_H 1
#include <hurd/stddef.h>
@@ -29,36 +28,33 @@
#include <stdint.h>
#include <hurd/cap.h>
#include <hurd/thread.h>
-#include <l4/thread.h>
#include <hurd/error.h>
+#include <l4/space.h>
-#define RPC_STUB_PREFIX exception
-#define RPC_ID_PREFIX EXCEPTION
-#define RPC_TARGET_NEED_ARG
-#define RPC_TARGET_ARG_TYPE l4_thread_id_t
-#define RPC_TARGET(x) (x)
+#define RPC_STUB_PREFIX activation
+#define RPC_ID_PREFIX ACTIVATION
#include <hurd/rpc.h>
-/* Exception message ids. */
+/* Activation message ids. */
enum
{
- EXCEPTION_fault = 10,
+ ACTIVATION_fault = 10,
};
/* Return a string corresponding to a message id. */
static inline const char *
-exception_method_id_string (l4_word_t id)
+activation_method_id_string (uintptr_t id)
{
switch (id)
{
- case EXCEPTION_fault:
+ case ACTIVATION_fault:
return "fault";
default:
return "unknown";
}
}
-struct exception_info
+struct activation_fault_info
{
union
{
@@ -75,93 +71,98 @@ struct exception_info
};
};
-#define EXCEPTION_INFO_FMT "%c%c%c %s%s"
-#define EXCEPTION_INFO_PRINTF(info) \
+#define ACTIVATION_FAULT_INFO_FMT "%c%c%c %s%s"
+#define ACTIVATION_FAULT_INFO_PRINTF(info) \
((info).access & L4_FPAGE_READABLE ? 'r' : '~'), \
- ((info).access & L4_FPAGE_WRITABLE ? 'w' : '~'), \
- ((info).access & L4_FPAGE_EXECUTABLE ? 'x' : '~'), \
- cap_type_string ((info).type), \
- (info.discarded) ? " discarded" : ""
+ ((info).access & L4_FPAGE_WRITABLE ? 'w' : '~'), \
+ ((info).access & L4_FPAGE_EXECUTABLE ? 'x' : '~'), \
+ cap_type_string ((info).type), \
+ (info.discarded) ? " discarded" : ""
/* Raise a fault at address FAULT_ADDRESS. If IP is not 0, then IP is
the value of the IP of the faulting thread at the time of the fault
and SP the value of the stack pointer at the time of the fault. */
-RPC (fault, 4, 0, addr_t, fault_address, uintptr_t, sp, uintptr_t, ip,
- struct exception_info, exception_info)
+RPC (fault, 4, 0, 0,
+ addr_t, fault_address, uintptr_t, sp, uintptr_t, ip,
+ struct activation_fault_info, activation_fault_info)
#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
-#undef RPC_TARGET_NEED_ARG
-#undef RPC_TARGET_ARG_TYPE
-#undef RPC_TARGET
-#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; \
- })
+/* Initializes the activation handler to allow receiving IPCs (but
+ does not handle other faults). This must be called exactly once
+ before any IPCs are sent. */
+extern void hurd_activation_handler_init_early (void);
-#include <hurd/rpc.h>
+/* Initialize the activation handler. This must be called after the
+ storage sub-system has been initialized. At this point, the
+ activation handler is able to handle exceptions. */
+extern void hurd_activation_handler_init (void);
-/* Exception message ids. */
-enum
- {
- RM_exception_collect = 500,
- };
-/* Cause the delivery of a pending event, if any. */
-RPC(exception_collect, 1, 0, addr_t, principal)
+/* Return the calling thread's UTCB. Threading libraries should set
+ this to their own implementation once they are up and running. */
+extern struct vg_utcb *(*hurd_utcb) (void);
-#undef RPC_STUB_PREFIX
-#undef RPC_ID_PREFIX
-#undef RPC_TARGET
-#endif /* !ASM */
-
-/* The exception stack is 4 pages large. The word beyond the base of
- the stack is a pointer to the exception page, which is usually the
- last page of the stack. */
-#define EXCEPTION_STACK_SIZE_LOG2 (PAGESIZE_LOG2 + 2)
-#define EXCEPTION_STACK_SIZE (1 << EXCEPTION_STACK_SIZE_LOG2)
+/* Allocate a utcb buffer and associated data structures (including an
+ exception messenger) for the thread THEAD (which must already exist
+ but should not be running). Installs the UTCB and exception
+ messenger in the thread object. Returns the new UTCB in *UTCB.
+ Returns 0 on success, otherwise an error code. */
+extern error_t hurd_activation_state_alloc (addr_t thread,
+ struct vg_utcb **utcb);
-#ifndef ASM
-
-/* Initialize the exception handler. */
-extern void exception_handler_init (void);
+/* Release the state allocated by hurd_activation_state_alloc. May
+ not be called by a thread on its own UTCB! */
+extern void hurd_activation_state_free (struct vg_utcb *utcb);
-/* When a thread causes an exception, the kernel invokes the thread's
- exception handler. This points to the low-level exception handler,
- which invokes exception_handler_activated. (It is passed a pointer
- to the exception page.)
+/* When a thread causes an activation, the kernel invokes the thread's
+ activation handler. This points to the low-level activation handler,
+ which invokes activation_handler_activated. (It is passed a pointer
+ to the utcb.)
This function must determine how to continue. It may, but need
- not, immediately handle the fault. The problem with handling the
- fault immediately is that this function runs on the exception
- handler's tiny stack (~3kb) and it runs in activated mode. The
+ not, immediately handle the activation. The problem with handling
+ an activation immediately is that this function runs on the
+ activation handler's tiny stack and it runs in activated mode. The
latter means that it may not fault (which generally precludes
- accessing any dynamically allocated storage). To allow an easy
- transition to another function in normal-mode, if the function
- returns an exception_frame, then the exception handler will call
- exception_handler_normal passing it that argument. This function
- runs in normal mode and on the normal stack. When this function
- returns, the interrupted state is restored. */
-extern struct exception_frame *
- exception_handler_activated (struct exception_page *exception_page);
-
-extern void exception_handler_normal (struct exception_frame *exception_frame);
-
-/* Should be called before destroyed the exception page associated
- with a thread. */
-extern void exception_page_cleanup (struct exception_page *exception_page);
-
-/* The first instruction of exception handler dispatcher. */
-extern char exception_handler_entry;
+ accessing any dynamically allocated storage) or even properly send
+ IPC (as it has no easy way to determine when the IPC has been
+ received and when a reply is available--this information is
+ delivered by activations!).
+
+ To allow an easy transition to another function in normal-mode, if
+ the function returns an activation_frame, then the activation
+ handler will call hurd_activation_handler_normal passing it that
+ argument. This function runs in normal mode and on the normal
+ stack. When this function returns, the interrupted state is
+ restored. */
+extern struct activation_frame *hurd_activation_handler_activated
+ (struct vg_utcb *utcb);
+
+extern void hurd_activation_handler_normal
+ (struct activation_frame *activation_frame, struct vg_utcb *utcb);
+
+
+/* The first instruction of activation handler dispatcher. */
+extern char hurd_activation_handler_entry;
/* The instruction immediately following the last instruction of the
- exception handler dispatcher. */
-extern char exception_handler_end;
+ activation handler dispatcher. */
+extern char hurd_activation_handler_end;
+
+
+/* Register the current extant IPC. */
+extern void hurd_activation_message_register (struct hurd_message_buffer *mb);
+
+/* Unregister the current extant IPC. This is normally done
+ automatically when a reply is receive. However, if the IPC is
+ aborted, then this function must be called before the next IPC may
+ be sent. */
+extern void hurd_activation_message_unregister (struct hurd_message_buffer *mb);
+
+/* Dump the activation stack to stdout. */
+extern void hurd_activation_stack_dump (void);
#endif /* !ASM */
diff --git a/hurd/folio.h b/hurd/folio.h
index 9245ef6..9ad36c3 100644
--- a/hurd/folio.h
+++ b/hurd/folio.h
@@ -373,12 +373,6 @@ folio_object_cap (struct folio *folio, int object)
#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>
@@ -390,14 +384,16 @@ enum
RM_folio_policy
};
-/* Allocate a folio against PRINCIPAL. Store a capability in the
+/* Allocate a folio against ACTIVITY. Return a capability in the
caller's cspace in slot FOLIO. POLICY specifies the storage
policy. */
-RPC(folio_alloc, 3, 0, addr_t, principal, addr_t, folio,
- struct folio_policy, policy)
+RPC(folio_alloc, 1, 0, 1,
+ /* cap_t, principal, cap_t, activity, */
+ struct folio_policy, policy, cap_t, folio)
-/* Free the folio designated by FOLIO. PRINCIPAL pays. */
-RPC(folio_free, 2, 0, addr_t, principal, addr_t, folio)
+/* Free the folio designated by FOLIO. */
+RPC(folio_free, 0, 0, 0
+ /* cap_t, principal, cap_t, folio */)
/* Destroys the INDEXth object in folio FOLIO and allocate in its
place an object of tye TYPE. If TYPE is CAP_VOID, any existing
@@ -406,15 +402,14 @@ RPC(folio_free, 2, 0, addr_t, principal, addr_t, folio)
folio. If an object is destroyed and there are waiters, they are
passed the return code RETURN_CODE.
- If OBJECT_SLOT is not ADDR_VOID, then stores a capability to the
- allocated object in OBJECT_SLOT. If OBJECT_WEAK_SLOT is not
- ADDR_VOID, stores a weaken reference to the created object. If an
- object is destroyed and there are waiters, they are passed the
- return code RETURN_CODE. */
-RPC(folio_object_alloc, 8, 0, addr_t, principal,
- addr_t, folio, uintptr_t, index, uintptr_t, type,
+ Returns a capability to the allocated object in OBJECT. Returns a
+ weak capability to the object in OBJECT_WEAK. */
+RPC(folio_object_alloc, 4, 0, 2,
+ /* cap_t, principal, cap_t, folio, */
+ uintptr_t, index, uintptr_t, type,
struct object_policy, policy, uintptr_t, return_code,
- addr_t, object_slot, addr_t, object_weak_slot)
+ /* Out: */
+ cap_t, object, cap_t, object_weak)
/* Flags for folio_policy. */
enum
@@ -433,16 +428,15 @@ enum
/* Get and set the management policy for folio FOLIO.
If FOLIO_POLICY_DELIVER is set in FLAGS, then return FOLIO's
- current paging policy in VALUE. Then, if any of the set flags are
+ current paging policy in OLD. Then, if any of the set flags are
set, set the corresponding values based on the value of POLICY. */
-RPC(folio_policy, 4, 1,
- addr_t, principal, addr_t, folio,
+RPC(folio_policy, 2, 1, 0,
+ /* cap_t, principal, cap_t, folio, */
uintptr_t, flags, struct folio_policy, policy,
/* Out: */
- struct folio_policy, value)
+ struct folio_policy, old)
#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
-#undef RPC_TARGET
#endif
diff --git a/hurd/futex.h b/hurd/futex.h
index 8c4507c..e1e71a3 100644
--- a/hurd/futex.h
+++ b/hurd/futex.h
@@ -3,17 +3,17 @@
Written by Neal H. Walfield <neal@gnu.org>.
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.
+ 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.
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.
+ 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
+ You should have received a copy of the GNU General Public License
+ along with GNU Hurd. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef _HURD_FUTEX_H
@@ -38,12 +38,6 @@ enum
#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>
@@ -103,8 +97,8 @@ union futex_val3
#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE \
(union futex_val3) { { 1, 0, FUTEX_OP_CMP_GT, FUTEX_OP_SET } }
-RPC (futex, 8, 1,
- addr_t, principal,
+RPC (futex, 7, 1, 0,
+ /* cap_t principal, cap_t thread, */
void *, addr1, int, op, int, val1,
bool, timeout, union futex_val2, val2,
void *, addr2, union futex_val3, val3,
@@ -113,7 +107,6 @@ RPC (futex, 8, 1,
#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
-#undef RPC_TARGET
#ifndef RM_INTERN
#include <errno.h>
@@ -124,11 +117,11 @@ struct futex_return
long ret;
};
-/* Standard futex signatures. See futex documentation, e.g., Futexes
- are Tricky by Ulrich Drepper. */
static inline struct futex_return
-futex (void *addr1, int op, int val1, struct timespec *timespec,
- void *addr2, int val3)
+__attribute__((always_inline))
+futex_using (struct hurd_message_buffer *mb,
+ void *addr1, int op, int val1, struct timespec *timespec,
+ void *addr2, int val3)
{
union futex_val2 val2;
if (timespec)
@@ -138,18 +131,36 @@ futex (void *addr1, int op, int val1, struct timespec *timespec,
error_t err;
long ret = 0; /* Elide gcc warning. */
- err = rm_futex (ADDR_VOID,
- addr1, op, val1, !! timespec, val2, addr2,
- (union futex_val3) val3, &ret);
+ if (mb)
+ err = rm_futex_using (mb,
+ ADDR_VOID, ADDR_VOID,
+ addr1, op, val1, !! timespec, val2, addr2,
+ (union futex_val3) val3, &ret);
+ else
+ err = rm_futex (ADDR_VOID, ADDR_VOID,
+ addr1, op, val1, !! timespec, val2, addr2,
+ (union futex_val3) val3, &ret);
return (struct futex_return) { err, ret };
}
+/* Standard futex signatures. See futex documentation, e.g., Futexes
+ are Tricky by Ulrich Drepper. */
+static inline struct futex_return
+__attribute__((always_inline))
+futex (void *addr1, int op, int val1, struct timespec *timespec,
+ void *addr2, int val3)
+{
+ return futex_using (NULL, addr1, op, val1, timespec, addr2, val3);
+}
+
+
/* If *F is VAL, wait until woken. */
static inline long
-futex_wait (int *f, int val)
+__attribute__((always_inline))
+futex_wait_using (struct hurd_message_buffer *mb, int *f, int val)
{
struct futex_return ret;
- ret = futex (f, FUTEX_WAIT, val, NULL, 0, 0);
+ ret = futex_using (mb, f, FUTEX_WAIT, val, NULL, 0, 0);
if (ret.err)
{
errno = ret.err;
@@ -158,8 +169,17 @@ futex_wait (int *f, int val)
return ret.ret;
}
+static inline long
+__attribute__((always_inline))
+futex_wait (int *f, int val)
+{
+ return futex_wait_using (NULL, f, val);
+}
+
+
/* If *F is VAL, wait until woken. */
static inline long
+__attribute__((always_inline))
futex_timed_wait (int *f, int val, struct timespec *timespec)
{
struct futex_return ret;
@@ -172,12 +192,14 @@ futex_timed_wait (int *f, int val, struct timespec *timespec)
return ret.ret;
}
+
/* Signal NWAKE waiters waiting on futex F. */
static inline long
-futex_wake (int *f, int nwake)
+__attribute__((always_inline))
+futex_wake_using (struct hurd_message_buffer *mb, int *f, int nwake)
{
struct futex_return ret;
- ret = futex (f, FUTEX_WAKE, nwake, NULL, 0, 0);
+ ret = futex_using (mb, f, FUTEX_WAKE, nwake, NULL, 0, 0);
if (ret.err)
{
errno = ret.err;
@@ -185,6 +207,13 @@ futex_wake (int *f, int nwake)
}
return ret.ret;
}
+
+static inline long
+__attribute__((always_inline))
+futex_wake (int *f, int nwake)
+{
+ return futex_wake_using (NULL, f, nwake);
+}
#endif /* !RM_INTERN */
#endif
diff --git a/hurd/headers.m4 b/hurd/headers.m4
index 7708aea..51b19fd 100644
--- a/hurd/headers.m4
+++ b/hurd/headers.m4
@@ -27,6 +27,9 @@ AC_CONFIG_LINKS([sysroot/include/hurd/stddef.h:hurd/stddef.h
sysroot/include/hurd/rmutex.h:hurd/rmutex.h
sysroot/include/hurd/futex.h:hurd/futex.h
sysroot/include/hurd/error.h:hurd/error.h
+ sysroot/include/hurd/message.h:hurd/message.h
+ sysroot/include/hurd/messenger.h:hurd/messenger.h
+ sysroot/include/hurd/ipc.h:hurd/ipc.h
sysroot/include/hurd/math.h:hurd/math.h
sysroot/include/hurd/bits/math.h:hurd/bits/${arch}/math.h
])
diff --git a/hurd/ipc.h b/hurd/ipc.h
new file mode 100644
index 0000000..95588a0
--- /dev/null
+++ b/hurd/ipc.h
@@ -0,0 +1,296 @@
+/* ipc.h - Interprocess communication interface.
+ 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 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VIENGOOS_IPC_H
+#define _VIENGOOS_IPC_H 1
+
+#include <stdint.h>
+#include <errno.h>
+#include <hurd/addr.h>
+#include <hurd/stddef.h>
+#include <hurd/message.h>
+#include <assert.h>
+
+#ifdef USE_L4
+#include <l4.h>
+#endif
+
+/* IPC flags. */
+enum
+ {
+ /* IPC includes a receive phase. */
+ VG_IPC_RECEIVE = 1 << 0,
+ /* Don't unblock the receive buffer if there is no message queued
+ for delivery. */
+ VG_IPC_RECEIVE_NONBLOCKING = 1 << 1,
+ /* Activate the thread on message receipt. */
+ VG_IPC_RECEIVE_ACTIVATE = 1 << 2,
+ /* Set the receive messenger's thread to the caller. */
+ VG_IPC_RECEIVE_SET_THREAD_TO_CALLER = 1 << 3,
+ /* Set the receive messener's address space root to the
+ caller's. */
+ VG_IPC_RECEIVE_SET_ASROOT_TO_CALLERS = 1 << 4,
+ /* Whether to receive the message inline. */
+ VG_IPC_RECEIVE_INLINE = 1 << 5,
+ /* Whether to receive any capabilities inline when receiving a
+ message inline (i.e., when VG_IPC_RECEIVE_INLINE is set). */
+ VG_IPC_RECEIVE_INLINE_CAP1 = 1 << 6,
+
+ /* IPC includes a send phase. */
+ VG_IPC_SEND = 1 << 7,
+ /* If the object is blocked, return EWOULDBLOCK. */
+ VG_IPC_SEND_NONBLOCKING = 1 << 8,
+ /* Activate the thread on message transfer. */
+ VG_IPC_SEND_ACTIVATE = 1 << 9,
+ /* Set the send messenger's thread to the caller. */
+ VG_IPC_SEND_SET_THREAD_TO_CALLER = 1 << 10,
+ /* Set the sender messener's address space root to the
+ caller's. */
+ VG_IPC_SEND_SET_ASROOT_TO_CALLERS = 1 << 11,
+ /* Whether to send the message inline. */
+ VG_IPC_SEND_INLINE = 1 << 12,
+
+ /* Which inline data to transfer when sending a message. Inline
+ data is ignored if the send buffer is not ADDR_VOID. */
+ VG_IPC_SEND_INLINE_WORD1 = 1 << 13,
+ VG_IPC_SEND_INLINE_WORD2 = 1 << 14,
+ VG_IPC_SEND_INLINE_CAP1 = 1 << 15,
+
+
+ /* The IPC includes a return phase. */
+ VG_IPC_RETURN = 1 << 16,
+
+ };
+
+#ifndef RM_INTERN
+/* An IPC consists of three phases: the receive phase, the send phase
+ and the return phase. All three phases are optional. Each phase
+ is executed after the previous phase has completed. If a phase
+ does not complete successfully, the phase is aborted and the
+ remaining phases are not executed.
+
+
+ RECEIVE PHASE
+
+ If FLAGS contains VG_IPC_RECEIVE, the IPC includes a receive phase.
+
+ If RECV_BUF is not ADDR_VOID, associates RECV_BUF with
+ RECV_MESSENGER.
+
+ If FLAGS contains VG_IPC_RECEIVE_NONBLOCKING:
+
+ Unblocks RECV_MESSENGER if RECV_MESSENGER has a messenger waiting
+ to deliver a message. Otherwise, returns EWOUDBLOCK.
+
+ Otherwise:
+
+ Unblocks RECV_MESSENGER.
+
+ Resources are charged to RECV_ACTIVITY.
+
+ If VG_IPC_RECEIVE_ACTIVATE is set, an activation is sent to the
+ thread associated with RECV_MESSENGER when RECV_MESSENGER receives
+ a message.
+
+
+ SEND PHASE
+
+ If FLAGS contains VG_IPC_SEND, the IPC includes a send phase.
+
+ If SEND_MESSENGER is ADDR_VOID, an implicit messenger is allocated
+ and VG_IPC_SEND_NONBLOCKING is assumed to be on.
+
+ If SEND_BUF is not ADDR_VOID, assocaiates SEND_BUF with
+ SEND_MESSENGER. Otherwise, associates inline data (INLINE_WORD1,
+ INLINE_WORD2 and INLINE_CAP) according to the inline flags with
+ SEND_MESSENGER.
+
+ If FLAGS contains VG_IPC_SEND_NONBLOCKING:
+
+ If TARGET_MESSENGER is blocked, returns ETIMEDOUT.
+
+ Otherwise:
+
+ Blocks SEND_MESSENGER and enqueues it on TARGET_MESSENGER.
+
+ When TARGET_MESSENGER becomes unblocked, SEND_MESSENGER delivers
+ its message to TARGET_MESSENGER.
+
+ Resources are charged to SEND_ACTIVITY.
+
+ If VG_IPC_SEND_ACTIVATE is set, an activation is sent to the thread
+ associated with SEND_MESSENGER when SEND_MESSENGER's message is
+ transferred to TARGET_MESSENGER (or, when TARGET_MESSENGER is
+ destroyed).
+
+
+ RETURN PHASE
+
+ If FLAGS contains VG_IPC_RETURN, the IPC returns. Otherwise, the
+ calling thread is suspended until it is next activated. */
+static inline error_t
+vg_ipc_full (uintptr_t flags,
+ addr_t recv_activity, addr_t recv_messenger, addr_t recv_buf,
+ addr_t recv_inline_cap,
+ addr_t send_activity, addr_t target_messenger,
+ addr_t send_messenger, addr_t send_buf,
+ uintptr_t send_inline_word1, uintptr_t send_inline_word2,
+ addr_t send_inline_cap)
+{
+ error_t err = 0;
+
+#ifdef USE_L4
+ l4_msg_tag_t tag = l4_niltag;
+ l4_msg_tag_set_label (&tag, 8194);
+
+ l4_msg_t msg;
+ l4_msg_clear (msg);
+ l4_msg_set_msg_tag (msg, tag);
+
+ void msg_append_addr (addr_t addr)
+ {
+ int i;
+ for (i = 0; i < sizeof (addr_t) / sizeof (uintptr_t); i ++)
+ l4_msg_append_word (msg, ((uintptr_t *) &addr)[i]);
+ }
+
+ l4_msg_append_word (msg, flags);
+
+ msg_append_addr (recv_activity);
+ msg_append_addr (recv_messenger);
+ msg_append_addr (recv_buf);
+ msg_append_addr (recv_inline_cap);
+
+ msg_append_addr (send_activity);
+ msg_append_addr (target_messenger);
+
+ msg_append_addr (send_messenger);
+ msg_append_addr (send_buf);
+
+ l4_msg_append_word (msg, send_inline_word1);
+ l4_msg_append_word (msg, send_inline_word2);
+ msg_append_addr (send_inline_cap);
+
+ l4_msg_load (msg);
+ l4_accept (l4_map_grant_items (L4_COMPLETE_ADDRESS_SPACE));
+
+ bool call = true;
+
+ while (1)
+ {
+ extern struct hurd_startup_data *__hurd_startup_data;
+
+ if (call)
+ tag = l4_call (__hurd_startup_data->rm);
+ else
+ tag = l4_receive (__hurd_startup_data->rm);
+
+ if (likely (l4_ipc_failed (tag)))
+ {
+ if (((l4_error_code () >> 1) & 0x7) == 3)
+ {
+ if (l4_error_code () & 1)
+ /* IPC was interrupted in the receive phase, i.e., we
+ got a response. */
+ break;
+ else
+ call = false;
+ }
+ else
+ return EHOSTDOWN;
+ }
+ else
+ {
+ assert (l4_untyped_words (tag) == 1);
+ l4_msg_store (tag, msg);
+ /* Potential error performing IPC (or VG_RETURN specified). */
+ err = l4_msg_word (msg, 1);
+ break;
+ }
+ }
+#else
+# warning vg_ipc not ported to this architecture.
+#endif
+
+ return err;
+}
+
+static inline error_t
+vg_ipc (uintptr_t flags,
+ addr_t recv_activity, addr_t recv_messenger, addr_t recv_buf,
+ addr_t send_activity, addr_t target_messenger,
+ addr_t send_messenger, addr_t send_buf)
+{
+ return vg_ipc_full (flags,
+ recv_activity, recv_messenger, recv_buf, ADDR_VOID,
+ send_activity, target_messenger,
+ send_messenger, send_buf,
+ 0, 0, ADDR_VOID);
+}
+
+static inline error_t
+vg_ipc_short (uintptr_t flags,
+ addr_t recv_activity, addr_t recv_messenger, addr_t recv_cap,
+ addr_t send_activity, addr_t target_messenger,
+ addr_t send_messenger,
+ uintptr_t inline_word1, uintptr_t inline_word2,
+ addr_t inline_cap)
+{
+ return vg_ipc_full (flags,
+ recv_activity, recv_messenger, ADDR_VOID, recv_cap,
+ send_activity, target_messenger,
+ send_messenger, ADDR_VOID,
+ inline_word1, inline_word2, inline_cap);
+}
+
+static inline error_t
+vg_send (uintptr_t flags, addr_t send_activity, addr_t target_messenger,
+ addr_t send_messenger, addr_t send_buf)
+{
+ return vg_ipc_full (flags | VG_IPC_SEND | VG_IPC_SEND_ACTIVATE,
+ ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ send_activity, target_messenger,
+ send_messenger, send_buf,
+ 0, 0, ADDR_VOID);
+}
+
+static inline error_t
+vg_reply (uintptr_t flags, addr_t send_activity, addr_t target_messenger,
+ addr_t send_messenger, addr_t send_buf)
+{
+ return vg_ipc_full (flags | VG_IPC_SEND | VG_IPC_SEND_NONBLOCKING,
+ ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ send_activity, target_messenger, send_messenger, send_buf,
+ 0, 0, ADDR_VOID);
+}
+
+/* Suspend the caller until the next activation. */
+static inline error_t
+vg_suspend (void)
+{
+ return vg_ipc_full (0,
+ ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ 0, 0, ADDR_VOID);
+}
+
+#endif
+
+#endif
diff --git a/hurd/message.h b/hurd/message.h
new file mode 100644
index 0000000..d59e41d
--- /dev/null
+++ b/hurd/message.h
@@ -0,0 +1,229 @@
+/* message.h - Message 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 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VIENGOOS_MESSAGE_H
+#define _VIENGOOS_MESSAGE_H 1
+
+#include <stdint.h>
+#include <assert.h>
+#include <hurd/addr.h>
+#include <hurd/stddef.h>
+
+/* A message.
+
+ When handing a message structure to a messenger, it must start at
+ the beginning of a page and it cannot extend past the end of that
+ page. */
+struct vg_message
+{
+ union
+ {
+ struct
+ {
+ /* The number of capability addresses in the message. */
+ uint16_t cap_count;
+ /* The number of bytes of data transferred in this message. */
+ uint16_t data_count;
+
+ addr_t caps[/* cap_count */];
+ // char data[data_count];
+ };
+
+ char raw[PAGESIZE];
+ };
+};
+
+
+/* Clear the msg so that it references no capabilities and
+ contains no data. */
+static inline void
+vg_message_clear (struct vg_message *msg)
+{
+ msg->cap_count = 0;
+ msg->data_count = 0;
+}
+
+
+/* Return the number of capabilities referenced by MSG. */
+static inline int
+vg_message_cap_count (struct vg_message *msg)
+{
+ int max = (PAGESIZE - __builtin_offsetof (struct vg_message, caps))
+ / sizeof (addr_t);
+
+ int count = msg->cap_count;
+ if (count > max)
+ count = max;
+
+ return count;
+}
+
+/* Return the number of bytes of data in MSG. */
+static inline int
+vg_message_data_count (struct vg_message *msg)
+{
+ int max = PAGESIZE
+ - vg_message_cap_count (msg) * sizeof (addr_t)
+ - __builtin_offsetof (struct vg_message, caps);
+
+ int count = msg->data_count;
+ if (count > max)
+ count = max;
+
+ return count;
+}
+
+
+/* Return the start of the capability address array in msg MSG. */
+static inline addr_t *
+vg_message_caps (struct vg_message *msg)
+{
+ return msg->caps;
+}
+
+/* Return capability IDX in msg MSG. */
+static inline addr_t
+vg_message_cap (struct vg_message *msg, int idx)
+{
+ assert (idx < msg->cap_count);
+
+ return msg->caps[idx];
+}
+
+
+/* Return the start of the data in msg MSG. */
+static inline char *
+vg_message_data (struct vg_message *msg)
+{
+ return (void *) msg
+ + __builtin_offsetof (struct vg_message, caps)
+ + msg->cap_count * sizeof (addr_t);
+}
+
+/* Return data word WORD in msg MSG. */
+static inline uintptr_t
+vg_message_word (struct vg_message *msg, int word)
+{
+ assert (word < msg->data_count / sizeof (uintptr_t));
+
+ return ((uintptr_t *) vg_message_data (msg))[word];
+}
+
+
+/* Append the array of capability addresses CAPS to the msg MSG.
+ There must be sufficient room in the message buffer. */
+static inline void
+vg_message_append_caps (struct vg_message *msg, int cap_count, addr_t *caps)
+{
+ assert ((void *) vg_message_data (msg) - (void *) msg
+ + vg_message_data_count (msg) + cap_count * sizeof (*caps)
+ <= PAGESIZE);
+
+ __builtin_memmove (&msg->caps[msg->cap_count + cap_count],
+ &msg->caps[msg->cap_count],
+ msg->data_count);
+
+ __builtin_memcpy (&msg->caps[msg->cap_count],
+ caps,
+ cap_count * sizeof (addr_t));
+
+ msg->cap_count += cap_count;
+}
+
+/* Append the capability address CAP to the msg MSG. There must be
+ sufficient room in the message buffer. */
+static inline void
+vg_message_append_cap (struct vg_message *msg, addr_t cap)
+{
+ vg_message_append_caps (msg, 1, &cap);
+}
+
+
+/* Append DATA to the msg MSG. There must be sufficient room in the
+ message buffer. */
+static inline void
+vg_message_append_data (struct vg_message *msg, int bytes, char *data)
+{
+ int dstart = __builtin_offsetof (struct vg_message, caps)
+ + msg->cap_count * sizeof (addr_t);
+ int dend = dstart + msg->data_count;
+
+ int new_dend = dend + bytes;
+ assert (new_dend <= PAGESIZE);
+
+ msg->data_count += bytes;
+ __builtin_memcpy ((void *) msg + dend, data, bytes);
+}
+
+/* Append the word WORD to the msg MSG. There must be
+ sufficient room in the message buffer. */
+static inline void
+vg_message_append_word (struct vg_message *msg, uintptr_t word)
+{
+ vg_message_append_data (msg, sizeof (word), (char *) &word);
+}
+
+/* Return data word WORD in msg MSG. */
+static inline void
+vg_message_word_set (struct vg_message *msg, int pos, uintptr_t word)
+{
+ if (msg->data_count < pos * sizeof (uintptr_t))
+ msg->data_count = pos * sizeof (uintptr_t);
+
+ ((uintptr_t *) vg_message_data (msg))[pos] = word;
+}
+
+#include <s-printf.h>
+
+static inline void
+vg_message_dump (struct vg_message *message)
+{
+ s_printf ("%d bytes, %d caps\n",
+ vg_message_data_count (message),
+ vg_message_cap_count (message));
+
+ char d2h[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F' };
+ unsigned char *data = vg_message_data (message);
+
+ int i = 0;
+ while (i < vg_message_data_count (message))
+ {
+ s_printf ("%d: ", i);
+
+ int j, k;
+ for (j = 0, k = 0;
+ i < vg_message_data_count (message) && j < 4 * 8;
+ j ++, i ++)
+ {
+ s_printf ("%c%c", d2h[data[i] >> 4], d2h[data[i] & 0xf]);
+ if (j % 4 == 3)
+ s_printf (" ");
+ }
+ s_printf ("\n");
+ }
+
+ for (i = 0; i < vg_message_cap_count (message); i ++)
+ s_printf ("cap %d: " ADDR_FMT "\n",
+ i, ADDR_PRINTF (vg_message_cap (message, i)));
+}
+
+
+#endif /* _VIENGOOS_MESSAGE_H */
diff --git a/hurd/messenger.h b/hurd/messenger.h
new file mode 100644
index 0000000..78d42f1
--- /dev/null
+++ b/hurd/messenger.h
@@ -0,0 +1,87 @@
+/* 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 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VIENGOOS_MESSENGER_H
+#define _VIENGOOS_MESSENGER_H 1
+
+#include <stdint.h>
+#include <hurd/addr.h>
+
+/* A messenger references a message buffer. It can transfer a message
+ (contained in its message buffer) to another messenger. It can
+ also receive a message from another messenger. A messenger can
+ block waiting to deliver a message to or receive a message from
+ another messenger.
+
+ To send a message, a payload is loaded into a message buffer and
+ associated with a messenger. The messenger is then enqueued on
+ another messenger. When the latter messenger is unblocked, the
+ message is delivered.
+
+ To avoid messages from being overwritten, messengers are blocked on
+ message delivery and must be explicitly unblocked before another
+ message is sent. */
+#ifdef RM_INTERN
+struct messenger;
+typedef struct messenger *vg_messenger_t;
+#else
+typedef addr_t vg_messenger_t;
+#endif
+
+#define VG_MESSENGER_INLINE_WORDS 2
+#define VG_MESSENGER_INLINE_CAPS 1
+
+/* Number of user-settable capability slots at the start of the
+ messenger structure. */
+enum
+ {
+ /* The thread to activate. */
+ VG_MESSENGER_THREAD_SLOT = 0,
+ /* The address space root relative to which all capability
+ addresses in the message buffer will be resolved. */
+ VG_MESSENGER_ASROOT_SLOT,
+ /* The assocaited message buffer. */
+ VG_MESSENGER_BUFFER_SLOT,
+ /* The activity that was delivered with the last message. */
+ VG_MESSENGER_ACTIVITY_SLOT,
+
+ VG_MESSENGER_SLOTS = 4,
+ };
+#define VG_MESSENGER_SLOTS_LOG2 2
+
+enum
+ {
+ VG_messenger_id = 900,
+ };
+
+#define RPC_STUB_PREFIX vg
+#define RPC_ID_PREFIX VG
+
+#include <hurd/rpc.h>
+
+/* Set MESSENGER's ID to ID and return the old ID in OLD. */
+RPC(messenger_id, 1, 1, 0,
+ /* cap_t activity, cap_t messenger, */
+ uint64_t, id, uint64_t, old)
+
+#undef RPC_STUB_PREFIX vg
+#undef RPC_ID_PREFIX VG
+
+#endif /* _VIENGOOS_MESSENGER_H */
diff --git a/hurd/rpc.h b/hurd/rpc.h
index e363509..55fe8be 100644
--- a/hurd/rpc.h
+++ b/hurd/rpc.h
@@ -4,20 +4,19 @@
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 Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ 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.
- The GNU Hurd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 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 the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
#define RPC_CONCAT2(a,b) a##b
#define RPC_CONCAT(a,b) RPC_CONCAT2(a,b)
@@ -41,107 +40,66 @@
#else
#define RPC_ID_PREFIX_(name) RPC_CONCAT(RPC_ID_PREFIX,_##name)
#endif
-
-/* We need to know where to send the IPC. Either the caller can
- supply it or it can be implicit.
-
- If the caller should supply the target, then define
- RPC_TARGET_NEED_ARG, RPC_TARGET_ARG_TYPE to the type of the
- argument, and RPC_TARGET to a be a macro that takes a single
- argument and returns an l4_thread_id_t.
-
- #define RPC_STUB_PREFIX prefix
- #define RPC_ID_PREFIX PREFIX
- #define RPC_TARGET_NEED_ARG
- #define RPC_TARGET_ARG_TYPE object_t
- #define RPC_TARGET(x) ((x)->thread_id)
-
- If the caller need not supply the argument, then the includer
- should not define RPC_TARGET_NEED_ARG and should define RPC_TARGET
- to be a macro that takes no arguments and returns an
- l4_thread_id_t.
-
- #define RPC_STUB_PREFIX prefix
- #define RPC_ID_PREFIX PREFIX
- #undef RPC_TARGET_NEED_ARG
- #define RPC_TARGET ({ extern l4_thread_id_t foo_server; foo_server; })
-
- At the end of the include file, be sure to #undef the used
- preprocessor variables to avoid problems when multiple headers
- make use of this file.
-
- #undef RPC_STUB_PREFIX
- #undef RPC_ID_PREFIX
- #undef RPC_TARGET_NEED_ARG
- #undef RPC_TARGET_ARG_TYPE
- #undef RPC_TARGET
- */
-#ifndef RPC_TARGET
-#error Did not define RPC_TARGET
-#endif
-
-#undef RPC_TARGET_ARG_
-#undef RPC_TARGET_
-
-#ifdef RPC_TARGET_NEED_ARG
-# ifndef RPC_TARGET_ARG_TYPE
-# error RPC_TARGET_NEED_ARG define but RPC_TARGET_ARG_TYPE not defined.
-# endif
-
-# define RPC_TARGET_ARG_ RPC_TARGET_ARG_TYPE arg_,
-# define RPC_TARGET_ RPC_TARGET(arg_)
-#else
-
-# define RPC_TARGET_ARG_
-# define RPC_TARGET_ RPC_TARGET
-#endif
-
-#undef RPC_TARGET_NEED_ARG
#ifndef _HURD_RPC_H
#define _HURD_RPC_H
#include <hurd/stddef.h>
-#include <l4/ipc.h>
-#include <l4/space.h>
+#include <hurd/message.h>
+#include <hurd/ipc.h>
#include <errno.h>
+
+#ifdef RM_INTERN
+extern struct vg_message *reply_buffer;
+
+/* We can't include messenger.h as it includes hurd/cap.h which in turn
+ includes this file. */
+struct messenger;
+struct activity;
+extern bool messenger_message_load (struct activity *activity,
+ struct messenger *target,
+ struct vg_message *message);
+#else
+# include <hurd/message-buffer.h>
+#endif
+typedef addr_t cap_t;
/* First we define some cpp help macros. */
-#define CPP_IFTHEN_0(when, whennot) whennot
-#define CPP_IFTHEN_1(when, whennot) when
-#define CPP_IFTHEN_2(when, whennot) when
-#define CPP_IFTHEN_3(when, whennot) when
-#define CPP_IFTHEN_4(when, whennot) when
-#define CPP_IFTHEN_5(when, whennot) when
-#define CPP_IFTHEN_6(when, whennot) when
-#define CPP_IFTHEN_7(when, whennot) when
-#define CPP_IFTHEN_8(when, whennot) when
-#define CPP_IFTHEN_9(when, whennot) when
-#define CPP_IFTHEN_10(when, whennot) when
-#define CPP_IFTHEN_11(when, whennot) when
-#define CPP_IFTHEN_12(when, whennot) when
-#define CPP_IFTHEN_13(when, whennot) when
-#define CPP_IFTHEN_14(when, whennot) when
-#define CPP_IFTHEN_15(when, whennot) when
-#define CPP_IFTHEN_16(when, whennot) when
-#define CPP_IFTHEN_17(when, whennot) when
-#define CPP_IFTHEN_18(when, whennot) when
-#define CPP_IFTHEN_19(when, whennot) when
-#define CPP_IFTHEN_20(when, whennot) when
-#define CPP_IFTHEN_21(when, whennot) when
-#define CPP_IFTHEN_22(when, whennot) when
-#define CPP_IFTHEN_23(when, whennot) when
-#define CPP_IFTHEN_24(when, whennot) when
-#define CPP_IFTHEN_25(when, whennot) when
-
-#define CPP_IFTHEN_(expr, when, whennot) \
- CPP_IFTHEN_##expr(when, whennot)
-#define CPP_IFTHEN(expr, when, whennot) \
- CPP_IFTHEN_(expr, when, whennot)
-#define CPP_IF(expr, when) \
- CPP_IFTHEN(expr, when,)
-#define CPP_IFNOT(expr, whennot) \
- CPP_IFTHEN(expr, , whennot)
+#define CPP_IFELSE_0(when, whennot) whennot
+#define CPP_IFELSE_1(when, whennot) when
+#define CPP_IFELSE_2(when, whennot) when
+#define CPP_IFELSE_3(when, whennot) when
+#define CPP_IFELSE_4(when, whennot) when
+#define CPP_IFELSE_5(when, whennot) when
+#define CPP_IFELSE_6(when, whennot) when
+#define CPP_IFELSE_7(when, whennot) when
+#define CPP_IFELSE_8(when, whennot) when
+#define CPP_IFELSE_9(when, whennot) when
+#define CPP_IFELSE_10(when, whennot) when
+#define CPP_IFELSE_11(when, whennot) when
+#define CPP_IFELSE_12(when, whennot) when
+#define CPP_IFELSE_13(when, whennot) when
+#define CPP_IFELSE_14(when, whennot) when
+#define CPP_IFELSE_15(when, whennot) when
+#define CPP_IFELSE_16(when, whennot) when
+#define CPP_IFELSE_17(when, whennot) when
+#define CPP_IFELSE_18(when, whennot) when
+#define CPP_IFELSE_19(when, whennot) when
+#define CPP_IFELSE_20(when, whennot) when
+#define CPP_IFELSE_21(when, whennot) when
+#define CPP_IFELSE_22(when, whennot) when
+#define CPP_IFELSE_23(when, whennot) when
+#define CPP_IFELSE_24(when, whennot) when
+#define CPP_IFELSE_25(when, whennot) when
+
+#define CPP_IFELSE_(expr, when, whennot) \
+ CPP_IFELSE_##expr(when, whennot)
+#define CPP_IFELSE(expr, when, whennot) \
+ CPP_IFELSE_(expr, when, whennot)
+#define CPP_IF(expr, when) \
+ CPP_IFELSE(expr, when,)
+#define CPP_IFNOT(expr, whennot) \
+ CPP_IFELSE(expr, , whennot)
#define CPP_SUCC_0 1
#define CPP_SUCC_1 2
@@ -176,11 +134,11 @@
/* We'd like to define CPP_ADD as:
#define CPP_ADD(x, y) \
- CPP_IFTHEN(y, CPP_ADD(SUCC(x), SUCC(y)), y)
+ CPP_IFELSE(y, CPP_ADD(SUCC(x), SUCC(y)), y)
This does not work as while a macro is being expanded, it becomes
ineligible for expansion. Thus, any references (including indirect
- references) are not expanded. Nested applications of a macro are,
+ references) are not expanded. Repeated applications of a macro are,
however, allowed, and this is what the CPP_APPLY macro does. */
#define CPP_APPLY1(x, y) x(y)
#define CPP_APPLY2(x, y) x(CPP_APPLY1(x, y))
@@ -209,13 +167,44 @@
#define CPP_APPLY25(x, y) x(CPP_APPLY24(x, y))
#define CPP_ADD(x, y) \
- CPP_IFTHEN(y, CPP_APPLY##y(CPP_SUCC, x), x)
+ CPP_IFELSE(y, CPP_APPLY##y(CPP_SUCC, x), x)
+
+/* Apply a function to each of the first n arguments.
+
+
+ CPP_FOREACH(2, CPP_SAFE_DEREF, NULL, a, b)
+
+ =>
+
+ ((a) ? *(a) : NULL), ((b) ? *(b) : NULL)
+ */
+#define CPP_FOREACH_0(func, cookie, ...)
+#define CPP_FOREACH_1(func, cookie, element, ...) func(cookie, element)
+#define CPP_FOREACH_2(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_1(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_3(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_2(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_4(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_3(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_5(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_4(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_6(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_5(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_7(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_6(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_8(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_7(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH_9(func, cookie, element, ...) func(cookie, element), CPP_FOREACH_8(func, cookie, __VA_ARGS__)
+
+#define CPP_FOREACH_(n, func, cookie, ...) \
+ CPP_FOREACH_##n(func, cookie, __VA_ARGS__)
+#define CPP_FOREACH(n, func, cookie, ...) \
+ CPP_FOREACH_(n, func, cookie, __VA_ARGS__)
+
+/* Used in conjunction with CPP_FOREACH. Generates C code that
+ dereferences ELEMENT if it is not NULL, otherwise, returns
+ COOKIE. */
+#define CPP_SAFE_DEREF(cookie, element) ((element) ? *(element) : (cookie))
+
/* CPP treats commas specially so we have to be smart about how we
insert them algorithmically. For instance, this won't work:
#define COMMA ,
- CPP_IFTHEN(x, COMMA, )
+ CPP_IFELSE(x, COMMA, )
To optional insert a comma, use this function instead. When the
result is need, invoke the result. For instance:
@@ -224,22 +213,36 @@
*/
#define RPC_COMMA() ,
#define RPC_NOCOMMA()
-#define RPC_IF_COMMA(x) CPP_IFTHEN(x, RPC_COMMA, RPC_NOCOMMA)
+#define RPC_IF_COMMA(x) CPP_IFELSE(x, RPC_COMMA, RPC_NOCOMMA)
-/* Load the argument ARG, which is of type TYPE into MR IDX. */
+/* Append the argument __RLA_ARG, whose type is __RLA_TYPE, to the
+ message buffer MSG. */
#define RPCLOADARG(__rla_type, __rla_arg) \
{ \
- union \
- { \
- __rla_type __rla_a; \
- l4_word_t __rla_raw[(sizeof (__rla_type) + sizeof (l4_word_t) - 1) \
- / sizeof (l4_word_t)]; \
- } __rla_arg2 = { (__rla_arg) }; \
- int __rla_i; \
- for (__rla_i = 0; \
- __rla_i < sizeof (__rla_arg2) / sizeof (l4_word_t); \
- __rla_i ++) \
- l4_msg_append_word (*msg, __rla_arg2.__rla_raw[__rla_i]); \
+ if (__builtin_strcmp (#__rla_type, "cap_t") == 0) \
+ { \
+ union \
+ { \
+ __rla_type __rla_a; \
+ RPC_GRAB2 (, 1, RPC_TYPE_SHIFT (1, struct cap *, cap_t, __rla_foo)); \
+ cap_t __rla_cap; \
+ } __rla_arg2 = { (__rla_arg) }; \
+ vg_message_append_cap (msg, __rla_arg2.__rla_cap); \
+ } \
+ else \
+ { \
+ union \
+ { \
+ __rla_type __rla_a; \
+ uintptr_t __rla_raw[(sizeof (__rla_type) + sizeof (uintptr_t) - 1) \
+ / sizeof (uintptr_t)]; \
+ } __rla_arg2 = { (__rla_arg) }; \
+ int __rla_i; \
+ for (__rla_i = 0; \
+ __rla_i < sizeof (__rla_arg2) / sizeof (uintptr_t); \
+ __rla_i ++) \
+ vg_message_append_word (msg, __rla_arg2.__rla_raw[__rla_i]); \
+ } \
}
#define RPCLOAD0(...)
@@ -271,23 +274,48 @@
#define RPCLOAD_(__rl_count, ...) RPCLOAD##__rl_count (__VA_ARGS__)
#define RPCLOAD(__rl_count, ...) RPCLOAD_ (__rl_count, __VA_ARGS__)
-/* Store the contents of MR __RSU_IDX+1 into *ARG, which is of type TYPE.
- NB: __RSU_IDX is thus the return parameter number, not the message
- register number; MR0 contains the error code. */
+/* Store the next argument in the message MSG whose type is __RSA_TYPE
+ in *__RSA_ARG. */
#define RPCSTOREARG(__rsa_type, __rsa_arg) \
{ \
- union \
- { \
- __rsa_type __rsa_a; \
- l4_word_t __rsa_raw[(sizeof (__rsa_type) + sizeof (l4_word_t) - 1) \
- / sizeof (l4_word_t)]; \
- } __rsa_arg2; \
- int __rsa_i; \
- for (__rsa_i = 0; \
- __rsa_i < sizeof (__rsa_arg2) / sizeof (l4_word_t); \
- __rsa_i ++) \
- __rsa_arg2.__rsa_raw[__rsa_i] = l4_msg_word (*msg, __rsu_idx ++); \
- *(__rsa_arg) = __rsa_arg2.__rsa_a; \
+ if (__builtin_strcmp (#__rsa_type, "cap_t") == 0) \
+ { \
+ union \
+ { \
+ __rsa_type *__rsa_a; \
+ cap_t *__rsa_cap; \
+ } __rsa_arg2; \
+ __rsa_arg2.__rsa_a = __rsa_arg; \
+ if (vg_message_cap_count (msg) > __rsu_cap_idx) \
+ { \
+ if (__rsa_arg) \
+ *__rsa_arg2.__rsa_cap = vg_message_cap (msg, __rsu_cap_idx); \
+ __rsu_cap_idx ++; \
+ } \
+ else \
+ __rsu_err = EINVAL; \
+ } \
+ else \
+ { \
+ union \
+ { \
+ __rsa_type __rsa_a; \
+ uintptr_t __rsa_raw[(sizeof (__rsa_type) + sizeof (uintptr_t) - 1) \
+ / sizeof (uintptr_t)]; \
+ } __rsa_arg2; \
+ int __rsa_i; \
+ for (__rsa_i = 0; \
+ __rsa_i < sizeof (__rsa_arg2) / sizeof (uintptr_t); \
+ __rsa_i ++) \
+ if (vg_message_data_count (msg) / sizeof (uintptr_t) \
+ > __rsu_data_idx) \
+ __rsa_arg2.__rsa_raw[__rsa_i] \
+ = vg_message_word (msg, __rsu_data_idx ++); \
+ else \
+ __rsu_err = EINVAL; \
+ if (! __rsu_err && __rsa_arg) \
+ *(__rsa_arg) = __rsa_arg2.__rsa_a; \
+ } \
}
#define RPCSTORE0(...)
@@ -345,35 +373,36 @@
#define RPCSTORE_(__rs_count, ...) RPCSTORE##__rs_count (__VA_ARGS__)
#define RPCSTORE(__rs_count, ...) RPCSTORE_ (__rs_count, __VA_ARGS__)
-/* Marshal the in-arguments into the provided message buffer. */
+/* Marshal a request. */
#define RPC_SEND_MARSHAL(id, icount, ...) \
static inline void \
+ __attribute__((always_inline)) \
RPC_CONCAT (RPC_STUB_PREFIX_(id), _send_marshal) \
- (l4_msg_t *msg RPC_IF_COMMA (icount) () \
- RPC_GRAB2 (, icount, ##__VA_ARGS__)) \
+ (struct vg_message *msg, \
+ RPC_GRAB2 (, icount, ##__VA_ARGS__) RPC_IF_COMMA(icount) () \
+ cap_t reply_messenger) \
{ \
- l4_msg_tag_t tag; \
- \
- tag = l4_niltag; \
- l4_msg_tag_set_label (&tag, RPC_ID_PREFIX_(id)); \
- \
- l4_msg_clear (*msg); \
- l4_msg_set_msg_tag (*msg, tag); \
- \
+ vg_message_clear (msg); \
+ /* Add the label. */ \
+ vg_message_append_word (msg, RPC_ID_PREFIX_(id)); \
+ /* Then load the arguments. */ \
RPCLOAD (icount, ##__VA_ARGS__); \
+ /* Finally, add the reply messenger. */ \
+ vg_message_append_cap (msg, reply_messenger); \
}
-/* Unmarshal the in-arguments from the provided message buffer. */
+/* Unmarshal a request. */
#define RPC_SEND_UNMARSHAL(id, icount, ...) \
static inline error_t \
+ __attribute__((always_inline)) \
RPC_CONCAT (RPC_STUB_PREFIX_(id), _send_unmarshal) \
- (l4_msg_t *msg RPC_IF_COMMA(icount) () \
- RPC_GRAB2 (*, icount, ##__VA_ARGS__)) \
+ (struct vg_message *msg, \
+ RPC_GRAB2 (*, icount, ##__VA_ARGS__) RPC_IF_COMMA(icount) () \
+ cap_t *reply_messenger) \
{ \
- l4_msg_tag_t tag = l4_msg_msg_tag (*msg); \
- \
- l4_word_t label; \
- label = l4_label (tag); \
+ uintptr_t label = 0; \
+ if (likely (vg_message_data_count (msg) >= sizeof (uintptr_t))) \
+ label = vg_message_word (msg, 0); \
if (label != RPC_ID_PREFIX_(id)) \
{ \
debug (1, #id " has bad method id, %d, excepted %d", \
@@ -381,130 +410,175 @@
return EINVAL; \
} \
\
- error_t err = 0; \
- int __rsu_idx __attribute__ ((unused)); \
- __rsu_idx = 0; \
+ int __rsu_data_idx __attribute__ ((unused)) = 1; \
+ int __rsu_cap_idx __attribute__ ((unused)) = 0; \
+ error_t __rsu_err = 0; \
RPCSTORE (icount, ##__VA_ARGS__); \
- if (err == 0 && __rsu_idx != l4_untyped_words (tag)) \
+ if (unlikely (__rsu_err \
+ || (__rsu_data_idx * sizeof (uintptr_t) \
+ != vg_message_data_count (msg) \
+ && __rsu_cap_idx + 1 != vg_message_cap_count (msg)))) \
{ \
- debug (1, #id " has wrong number of arguments: %d, expected %d words", \
- l4_untyped_words (tag), __rsu_idx); \
+ debug (1, #id " has wrong number of arguments: " \
+ "got %d bytes and %d caps; expected %d/%d", \
+ __rsu_data_idx * sizeof (uintptr_t), __rsu_cap_idx + 1, \
+ vg_message_data_count (msg), \
+ vg_message_cap_count (msg)); \
return EINVAL; \
} \
+ \
+ if (reply_messenger) \
+ *reply_messenger = vg_message_cap (msg, __rsu_cap_idx); \
return 0; \
}
-/* Marshal the reply. */
-#define RPC_REPLY_MARSHAL(id, ocount, ...) \
+/* Prepare a receive buffer. */
+#ifdef RM_INTERN
+#define RPC_RECEIVE_MARSHAL(id, ret_cap_count, ...)
+#else
+#define RPC_RECEIVE_MARSHAL(id, ret_cap_count, ...) \
+ static inline void \
+ __attribute__((always_inline)) \
+ RPC_CONCAT (RPC_STUB_PREFIX_(id), _receive_marshal) \
+ (struct vg_message *msg RPC_IF_COMMA(ret_cap_count) () \
+ RPC_GRAB2 (, ret_cap_count, ##__VA_ARGS__)) \
+ { \
+ vg_message_clear (msg); \
+ /* Load the arguments. */ \
+ RPCLOAD (ret_cap_count, ##__VA_ARGS__); \
+ assert (vg_message_data_count (msg) == 0); \
+ assert (vg_message_cap_count (msg) == ret_cap_count); \
+ }
+#endif
+
+/* Marshal a reply. */
+#define RPC_REPLY_MARSHAL(id, out_count, ret_cap_count, ...) \
static inline void \
+ __attribute__((always_inline)) \
RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply_marshal) \
- (l4_msg_t *msg RPC_IF_COMMA (ocount) () \
- RPC_GRAB2 (, ocount, ##__VA_ARGS__)) \
+ (struct vg_message *msg \
+ RPC_IF_COMMA (out_count) () \
+ RPC_GRAB2 (, out_count, ##__VA_ARGS__) \
+ RPC_IF_COMMA (ret_cap_count) () \
+ RPC_GRAB2 (, ret_cap_count, \
+ RPC_TYPE_SHIFT (ret_cap_count, struct cap *, \
+ RPC_CHOP2 (out_count, __VA_ARGS__)))) \
{ \
- l4_msg_tag_t tag; \
- \
- tag = l4_niltag; \
- l4_msg_tag_set_label (&tag, RPC_ID_PREFIX_(id)); \
+ vg_message_clear (msg); \
\
- l4_msg_clear (*msg); \
- l4_msg_set_msg_tag (*msg, tag); \
+ /* The error code. */ \
+ vg_message_append_word (msg, 0); \
+ RPCLOAD (CPP_ADD (out_count, ret_cap_count), ##__VA_ARGS__); \
\
- /* No error. */ \
- l4_msg_append_word (*msg, 0); \
- \
- RPCLOAD (ocount, ##__VA_ARGS__); \
+ assert (vg_message_cap_count (msg) == ret_cap_count); \
}
-/* Unmarshal the reply. */
-#define RPC_REPLY_UNMARSHAL(id, ocount, ...) \
+/* Unmarshal a reply. */
+#define RPC_REPLY_UNMARSHAL(id, out_count, ret_cap_count, ...) \
static inline error_t \
+ __attribute__((always_inline)) \
RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply_unmarshal) \
- (l4_msg_t *msg RPC_IF_COMMA (ocount) () \
- RPC_GRAB2(*, ocount, ##__VA_ARGS__)) \
+ (struct vg_message *msg \
+ RPC_IF_COMMA (CPP_ADD (out_count, ret_cap_count)) () \
+ RPC_GRAB2(*, CPP_ADD (out_count, ret_cap_count), ##__VA_ARGS__)) \
{ \
- l4_msg_tag_t tag = l4_msg_msg_tag (*msg); \
- l4_word_t err = l4_msg_word (*msg, 0); \
+ /* The server error code. */ \
+ error_t __rsu_err = EINVAL; \
+ if (likely (vg_message_data_count (msg) >= sizeof (uintptr_t))) \
+ __rsu_err = vg_message_word (msg, 0); \
+ if (unlikely (__rsu_err)) \
+ return __rsu_err; \
\
- int __rsu_idx __attribute__ ((unused)); \
- __rsu_idx = 1; \
- RPCSTORE (ocount, ##__VA_ARGS__); \
- if (err == 0) \
+ int __rsu_data_idx __attribute__ ((unused)) = 1; \
+ int __rsu_cap_idx __attribute__ ((unused)) = 0; \
+ RPCSTORE (CPP_ADD (out_count, ret_cap_count), ##__VA_ARGS__); \
+ if (unlikely (__rsu_err \
+ || (__rsu_data_idx * sizeof (uintptr_t) \
+ != vg_message_data_count (msg) \
+ || __rsu_cap_idx != vg_message_cap_count (msg)))) \
{ \
- if (__rsu_idx != l4_untyped_words (tag)) \
- { \
- debug (1, "Got %d words, expected %d words", \
- __rsu_idx, l4_untyped_words (tag)); \
- return EINVAL; \
- } \
+ debug (1, #id " has wrong number of arguments: " \
+ "got %d bytes and %d caps; expected %d/%d", \
+ __rsu_data_idx * sizeof (uintptr_t), __rsu_cap_idx, \
+ vg_message_data_count (msg), \
+ vg_message_cap_count (msg)); \
+ return EINVAL; \
} \
- return err; \
+ return 0; \
}
/* RPC_ARGUMENTS takes a list of types and arguments and returns the first
COUNT arguments. (NB: the list may contain more than COUNT
- arguments!). */
+ arguments!).
+
+ RPC_ARGUMENTS(2, &, int, i, int, j, double, d)
+
+ =>
+
+ &i, &j
+*/
#define RPC_ARGUMENTS0(...)
-#define RPC_ARGUMENTS1(__ra_type, __ra_arg, ...) __ra_arg RPC_ARGUMENTS0(__VA_ARGS__)
-#define RPC_ARGUMENTS2(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS1(__VA_ARGS__)
-#define RPC_ARGUMENTS3(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS2(__VA_ARGS__)
-#define RPC_ARGUMENTS4(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS3(__VA_ARGS__)
-#define RPC_ARGUMENTS5(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS4(__VA_ARGS__)
-#define RPC_ARGUMENTS6(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS5(__VA_ARGS__)
-#define RPC_ARGUMENTS7(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS6(__VA_ARGS__)
-#define RPC_ARGUMENTS8(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS7(__VA_ARGS__)
-#define RPC_ARGUMENTS9(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS8(__VA_ARGS__)
-#define RPC_ARGUMENTS10(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS9(__VA_ARGS__)
-#define RPC_ARGUMENTS11(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS10(__VA_ARGS__)
-#define RPC_ARGUMENTS12(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS11(__VA_ARGS__)
-#define RPC_ARGUMENTS13(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS12(__VA_ARGS__)
-#define RPC_ARGUMENTS14(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS13(__VA_ARGS__)
-#define RPC_ARGUMENTS15(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS14(__VA_ARGS__)
-#define RPC_ARGUMENTS16(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS15(__VA_ARGS__)
-#define RPC_ARGUMENTS17(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS16(__VA_ARGS__)
-#define RPC_ARGUMENTS18(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS17(__VA_ARGS__)
-#define RPC_ARGUMENTS19(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS18(__VA_ARGS__)
-#define RPC_ARGUMENTS20(__ra_type, __ra_arg, ...) __ra_arg, RPC_ARGUMENTS19(__VA_ARGS__)
-#define RPC_ARGUMENTS_(__ra_count, ...) RPC_ARGUMENTS##__ra_count(__VA_ARGS__)
-#define RPC_ARGUMENTS(__ra_count, ...) RPC_ARGUMENTS_(__ra_count, __VA_ARGS__)
+#define RPC_ARGUMENTS1(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg RPC_ARGUMENTS0(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS2(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS1(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS3(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS2(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS4(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS3(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS5(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS4(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS6(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS5(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS7(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS6(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS8(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS7(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS9(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS8(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS10(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS9(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS11(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS10(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS12(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS11(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS13(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS12(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS14(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS13(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS15(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS14(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS16(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS15(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS17(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS16(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS18(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS17(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS19(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS18(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS20(__ra_prefix, __ra_type, __ra_arg, ...) __ra_prefix __ra_arg, RPC_ARGUMENTS19(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS_(__ra_count, __ra_prefix, ...) RPC_ARGUMENTS##__ra_count(__ra_prefix, __VA_ARGS__)
+#define RPC_ARGUMENTS(__ra_count, __ra_prefix, ...) RPC_ARGUMENTS_(__ra_count, __ra_prefix, __VA_ARGS__)
/* Given a list of arguments, returns the arguments minus the first
COUNT **pairs** of arguments. For example:
- RPC_CHOP(1, int, i, int, j, double, d)
+ RPC_CHOP2(1, int, i, int, j, double, d)
=>
int, j, double, d
*/
-#define RPC_CHOP0(...) __VA_ARGS__
-#define RPC_CHOP1(__rc_a, __rc_b, ...) RPC_CHOP0(__VA_ARGS__)
-#define RPC_CHOP2(__rc_a, __rc_b, ...) RPC_CHOP1(__VA_ARGS__)
-#define RPC_CHOP3(__rc_a, __rc_b, ...) RPC_CHOP2(__VA_ARGS__)
-#define RPC_CHOP4(__rc_a, __rc_b, ...) RPC_CHOP3(__VA_ARGS__)
-#define RPC_CHOP5(__rc_a, __rc_b, ...) RPC_CHOP4(__VA_ARGS__)
-#define RPC_CHOP6(__rc_a, __rc_b, ...) RPC_CHOP5(__VA_ARGS__)
-#define RPC_CHOP7(__rc_a, __rc_b, ...) RPC_CHOP6(__VA_ARGS__)
-#define RPC_CHOP8(__rc_a, __rc_b, ...) RPC_CHOP7(__VA_ARGS__)
-#define RPC_CHOP9(__rc_a, __rc_b, ...) RPC_CHOP8(__VA_ARGS__)
-#define RPC_CHOP10(__rc_a, __rc_b, ...) RPC_CHOP9(__VA_ARGS__)
-#define RPC_CHOP11(__rc_a, __rc_b, ...) RPC_CHOP10(__VA_ARGS__)
-#define RPC_CHOP12(__rc_a, __rc_b, ...) RPC_CHOP11(__VA_ARGS__)
-#define RPC_CHOP13(__rc_a, __rc_b, ...) RPC_CHOP12(__VA_ARGS__)
-#define RPC_CHOP14(__rc_a, __rc_b, ...) RPC_CHOP13(__VA_ARGS__)
-#define RPC_CHOP15(__rc_a, __rc_b, ...) RPC_CHOP14(__VA_ARGS__)
-#define RPC_CHOP16(__rc_a, __rc_b, ...) RPC_CHOP15(__VA_ARGS__)
-#define RPC_CHOP17(__rc_a, __rc_b, ...) RPC_CHOP16(__VA_ARGS__)
-#define RPC_CHOP18(__rc_a, __rc_b, ...) RPC_CHOP17(__VA_ARGS__)
-#define RPC_CHOP19(__rc_a, __rc_b, ...) RPC_CHOP18(__VA_ARGS__)
-#define RPC_CHOP20(__rc_a, __rc_b, ...) RPC_CHOP19(__VA_ARGS__)
-#define RPC_CHOP21(__rc_a, __rc_b, ...) RPC_CHOP20(__VA_ARGS__)
-#define RPC_CHOP22(__rc_a, __rc_b, ...) RPC_CHOP21(__VA_ARGS__)
-#define RPC_CHOP23(__rc_a, __rc_b, ...) RPC_CHOP22(__VA_ARGS__)
-#define RPC_CHOP24(__rc_a, __rc_b, ...) RPC_CHOP23(__VA_ARGS__)
-#define RPC_CHOP25(__rc_a, __rc_b, ...) RPC_CHOP24(__VA_ARGS__)
-#define RPC_CHOP_(__rc_count, ...) RPC_CHOP##__rc_count (__VA_ARGS__)
-#define RPC_CHOP(__rc_count, ...) RPC_CHOP_(__rc_count, __VA_ARGS__)
+#define RPC_CHOP2_0(...) __VA_ARGS__
+#define RPC_CHOP2_1(__rc_a, __rc_b, ...) RPC_CHOP2_0(__VA_ARGS__)
+#define RPC_CHOP2_2(__rc_a, __rc_b, ...) RPC_CHOP2_1(__VA_ARGS__)
+#define RPC_CHOP2_3(__rc_a, __rc_b, ...) RPC_CHOP2_2(__VA_ARGS__)
+#define RPC_CHOP2_4(__rc_a, __rc_b, ...) RPC_CHOP2_3(__VA_ARGS__)
+#define RPC_CHOP2_5(__rc_a, __rc_b, ...) RPC_CHOP2_4(__VA_ARGS__)
+#define RPC_CHOP2_6(__rc_a, __rc_b, ...) RPC_CHOP2_5(__VA_ARGS__)
+#define RPC_CHOP2_7(__rc_a, __rc_b, ...) RPC_CHOP2_6(__VA_ARGS__)
+#define RPC_CHOP2_8(__rc_a, __rc_b, ...) RPC_CHOP2_7(__VA_ARGS__)
+#define RPC_CHOP2_9(__rc_a, __rc_b, ...) RPC_CHOP2_8(__VA_ARGS__)
+#define RPC_CHOP2_10(__rc_a, __rc_b, ...) RPC_CHOP2_9(__VA_ARGS__)
+#define RPC_CHOP2_11(__rc_a, __rc_b, ...) RPC_CHOP2_10(__VA_ARGS__)
+#define RPC_CHOP2_12(__rc_a, __rc_b, ...) RPC_CHOP2_11(__VA_ARGS__)
+#define RPC_CHOP2_13(__rc_a, __rc_b, ...) RPC_CHOP2_12(__VA_ARGS__)
+#define RPC_CHOP2_14(__rc_a, __rc_b, ...) RPC_CHOP2_13(__VA_ARGS__)
+#define RPC_CHOP2_15(__rc_a, __rc_b, ...) RPC_CHOP2_14(__VA_ARGS__)
+#define RPC_CHOP2_16(__rc_a, __rc_b, ...) RPC_CHOP2_15(__VA_ARGS__)
+#define RPC_CHOP2_17(__rc_a, __rc_b, ...) RPC_CHOP2_16(__VA_ARGS__)
+#define RPC_CHOP2_18(__rc_a, __rc_b, ...) RPC_CHOP2_17(__VA_ARGS__)
+#define RPC_CHOP2_19(__rc_a, __rc_b, ...) RPC_CHOP2_18(__VA_ARGS__)
+#define RPC_CHOP2_20(__rc_a, __rc_b, ...) RPC_CHOP2_19(__VA_ARGS__)
+#define RPC_CHOP2_21(__rc_a, __rc_b, ...) RPC_CHOP2_20(__VA_ARGS__)
+#define RPC_CHOP2_22(__rc_a, __rc_b, ...) RPC_CHOP2_21(__VA_ARGS__)
+#define RPC_CHOP2_23(__rc_a, __rc_b, ...) RPC_CHOP2_22(__VA_ARGS__)
+#define RPC_CHOP2_24(__rc_a, __rc_b, ...) RPC_CHOP2_23(__VA_ARGS__)
+#define RPC_CHOP2_25(__rc_a, __rc_b, ...) RPC_CHOP2_24(__VA_ARGS__)
+#define RPC_CHOP2_(__rc_count, ...) RPC_CHOP2_##__rc_count (__VA_ARGS__)
+#define RPC_CHOP2(__rc_count, ...) RPC_CHOP2_(__rc_count, __VA_ARGS__)
/* Given a list of arguments, returns the first COUNT **pairs** of
arguments, the elements of each pair separated by SEP and each pair
@@ -576,182 +650,405 @@
#define RPC_GRAB_(__rg_count, ...) RPC_GRAB_##__rg_count (__VA_ARGS__)
#define RPC_GRAB(__rg_count, ...) RPC_GRAB_(__rg_count, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_0(...)
+#define RPC_TYPE_SHIFT_1(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg RPC_TYPE_SHIFT_0(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_2(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_1(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_3(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_2(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_4(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_3(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_5(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_4(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_6(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_5(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_7(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_6(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_8(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_7(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_9(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_8(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_10(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_9(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_11(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_10(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_12(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_11(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_13(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_12(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_14(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_13(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_15(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_14(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_16(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_15(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_17(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_16(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_18(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_17(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_19(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_18(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_20(__ra_new_type, __ra_type, __ra_arg, ...) __ra_new_type, __ra_arg, RPC_TYPE_SHIFT_19(__ra_new_type, __VA_ARGS__)
+#define RPC_TYPE_SHIFT_(__ra_count, __ra_new_type, ...) RPC_TYPE_SHIFT_##__ra_count(__ra_new_type, __VA_ARGS__)
+#ifdef RM_INTERN
+# define RPC_TYPE_SHIFT(__ra_count, __ra_new_type, ...) RPC_TYPE_SHIFT_(__ra_count, __ra_new_type, __VA_ARGS__)
+#else
+# define RPC_TYPE_SHIFT(__ra_count, __ra_new_type, ...) __VA_ARGS__
+#endif
+
/* Ensure that there are X pairs of arguments. */
#define RPC_INVALID_NUMBER_OF_ARGUMENTS_
#define RPC_EMPTY_LIST_(x) RPC_INVALID_NUMBER_OF_ARGUMENTS_##x
#define RPC_EMPTY_LIST(x) RPC_EMPTY_LIST_(x)
#define RPC_ENSURE_ARGS(count, ...) \
- RPC_EMPTY_LIST (RPC_CHOP (count, __VA_ARGS__))
-
-#define RPC_MARSHAL_GEN_(id, icount, ocount, ...) \
- RPC_ENSURE_ARGS(CPP_ADD (icount, ocount), ##__VA_ARGS__) \
+ RPC_EMPTY_LIST (RPC_CHOP2 (count, __VA_ARGS__))
+
+#define RPC_SEND_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, ...) \
+ RPC_SEND_MARSHAL(id, in_count, ##__VA_ARGS__) \
+ RPC_SEND_UNMARSHAL(id, in_count, ##__VA_ARGS__)
+
+#define RPC_RECEIVE_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, ...) \
+ RPC_RECEIVE_MARSHAL(id, ret_cap_count, \
+ RPC_CHOP2 (CPP_ADD (in_count, out_count), \
+ ##__VA_ARGS__))
+
+#define RPC_REPLY_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, ...) \
+ RPC_REPLY_MARSHAL(id, out_count, ret_cap_count, \
+ RPC_CHOP2 (in_count, ##__VA_ARGS__)) \
+ RPC_REPLY_UNMARSHAL(id, out_count, ret_cap_count, \
+ RPC_CHOP2 (in_count, ##__VA_ARGS__))
+
+#define RPC_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, ...) \
+ RPC_ENSURE_ARGS(CPP_ADD (CPP_ADD (in_count, out_count), \
+ ret_cap_count), \
+ ##__VA_ARGS__) \
+ RPC_SEND_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, \
+ ##__VA_ARGS__) \
+ RPC_RECEIVE_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, \
+ ##__VA_ARGS__) \
+ RPC_REPLY_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, \
+ ##__VA_ARGS__)
+
+/* Send a message. __RPC_REPY_MESSENGER designates the messenger that
+ should receive the reply. (Its buffer should have already been
+ prepared using, e.g., the corresponding receive_marshal
+ function.) */
+#ifndef RM_INTERN
+#define RPC_SEND_(postfix, id, in_count, out_count, ret_cap_count, ...) \
+ static inline error_t \
+ __attribute__((always_inline)) \
+ RPC_CONCAT(RPC_STUB_PREFIX_(id), postfix) \
+ (cap_t __rpc_activity, cap_t __rpc_object \
+ RPC_IF_COMMA (in_count) () \
+ RPC_GRAB2 (, in_count, __VA_ARGS__), \
+ cap_t __rpc_reply_messenger) \
+ { \
+ struct hurd_message_buffer *mb = hurd_message_buffer_alloc (); \
+ mb->just_free = true; \
\
- RPC_SEND_MARSHAL(id, icount, ##__VA_ARGS__) \
- RPC_SEND_UNMARSHAL(id, icount, ##__VA_ARGS__) \
- RPC_REPLY_MARSHAL(id, ocount, RPC_CHOP (icount, ##__VA_ARGS__)) \
- RPC_REPLY_UNMARSHAL(id, ocount, RPC_CHOP (icount, ##__VA_ARGS__))
+ RPC_CONCAT (RPC_STUB_PREFIX_(id), _send_marshal) \
+ (mb->request \
+ RPC_IF_COMMA (in_count) () RPC_ARGUMENTS(in_count,, __VA_ARGS__), \
+ __rpc_reply_messenger); \
+ \
+ error_t err = vg_send (VG_IPC_SEND_SET_THREAD_TO_CALLER \
+ | VG_IPC_SEND_SET_ASROOT_TO_CALLERS, \
+ __rpc_activity, __rpc_object, \
+ mb->sender, ADDR_VOID); \
+ \
+ return err; \
+ }
+#else
+#define RPC_SEND_(postfix, id, in_count, out_count, ret_cap_count, ...)
+#endif
-#define RPC_SIMPLE_(postfix, id, icount, ocount, ...) \
- /* Send, but do not wait for a reply. */ \
+/* Send a message. Abort if the target is not ready. */
+#ifndef RM_INTERN
+#define RPC_SEND_NONBLOCKING_(postfix, id, in_count, out_count, ret_cap_count, ...) \
static inline error_t \
__attribute__((always_inline)) \
RPC_CONCAT(RPC_STUB_PREFIX_(id), postfix) \
- (RPC_TARGET_ARG_ RPC_GRAB2 (, icount, __VA_ARGS__)) \
+ (cap_t __rpc_activity, cap_t __rpc_object \
+ RPC_IF_COMMA (in_count) () \
+ RPC_GRAB2 (, in_count, __VA_ARGS__), \
+ cap_t __rpc_reply_messenger) \
{ \
- l4_msg_tag_t tag; \
- l4_msg_t msg; \
+ struct hurd_message_buffer *mb = hurd_message_buffer_alloc (); \
\
RPC_CONCAT (RPC_STUB_PREFIX_(id), _send_marshal) \
- CPP_IFTHEN (icount, \
- (&msg, RPC_ARGUMENTS(icount, __VA_ARGS__)), \
- (&msg)); \
+ (mb->request \
+ RPC_IF_COMMA (in_count) () RPC_ARGUMENTS(in_count,, __VA_ARGS__), \
+ __rpc_reply_messenger); \
\
- l4_msg_load (msg); \
- l4_accept (L4_UNTYPED_WORDS_ACCEPTOR); \
+ error_t err = vg_reply (VG_IPC_SEND_SET_THREAD_TO_CALLER \
+ | VG_IPC_SEND_SET_ASROOT_TO_CALLERS, \
+ __rpc_activity, __rpc_object, \
+ mb->sender, ADDR_VOID); \
\
- for (;;) \
- { \
- tag = l4_send (RPC_TARGET_); \
- if (unlikely (l4_ipc_failed (tag))) \
- { \
- if (((l4_error_code () >> 1) & 0x7) == 3) \
- /* IPC was interrupted. */ \
- /* XXX: We need to somehow consider the signal state and \
- return EINTR if appropriate. */ \
- continue; \
- return EHOSTDOWN; \
- } \
- break; \
- } \
+ hurd_message_buffer_free (mb); \
\
- return 0; \
+ return err; \
}
+#else
+#define RPC_SEND_NONBLOCKING_(postfix, id, in_count, out_count, ret_cap_count, ...)
+#endif
-#define RPC_(postfix, id, icount, ocount, ...) \
+/* Send a message and wait for a reply. */
+#ifndef RM_INTERN
+#define RPC_(postfix, id, in_count, out_count, ret_cap_count, ...) \
static inline error_t \
__attribute__((always_inline)) \
- RPC_CONCAT (RPC_STUB_PREFIX_(id), postfix) \
- (RPC_TARGET_ARG_ \
- RPC_GRAB (CPP_ADD(icount, ocount), \
- RPC_GRAB2 (, icount, __VA_ARGS__) RPC_IF_COMMA(icount) () \
- RPC_GRAB2 (*, ocount, RPC_CHOP (icount, __VA_ARGS__)))) \
+ RPC_CONCAT (RPC_CONCAT (RPC_STUB_PREFIX_(id), _using), postfix) \
+ (struct hurd_message_buffer *mb, \
+ addr_t __rpc_activity, \
+ addr_t __rpc_object \
+ /* In arguments. */ \
+ RPC_IF_COMMA (in_count) () \
+ RPC_GRAB2 (, in_count, __VA_ARGS__) \
+ /* Out arguments (data and caps). */ \
+ RPC_IF_COMMA (CPP_ADD (out_count, ret_cap_count)) () \
+ RPC_GRAB2 (*, CPP_ADD (out_count, ret_cap_count), \
+ RPC_CHOP2 (in_count, __VA_ARGS__))) \
{ \
- l4_msg_tag_t tag; \
- l4_msg_t msg; \
+ /* Prepare the reply buffer. */ \
+ RPC_CONCAT (RPC_STUB_PREFIX_(id), _receive_marshal) \
+ (mb->reply \
+ RPC_IF_COMMA (ret_cap_count) () \
+ CPP_FOREACH(ret_cap_count, CPP_SAFE_DEREF, ADDR_VOID, \
+ RPC_ARGUMENTS (ret_cap_count, , \
+ RPC_CHOP2 (CPP_ADD (in_count, out_count), \
+ __VA_ARGS__)))); \
\
+ /* Then the send buffer. */ \
RPC_CONCAT (RPC_STUB_PREFIX_(id), _send_marshal) \
- CPP_IFTHEN (icount, \
- (&msg, RPC_ARGUMENTS(icount, __VA_ARGS__)), \
- (&msg)); \
+ (mb->request \
+ RPC_IF_COMMA (in_count) () \
+ RPC_ARGUMENTS (in_count,, __VA_ARGS__), \
+ mb->receiver); \
\
- l4_msg_load (msg); \
- l4_accept (l4_map_grant_items (L4_COMPLETE_ADDRESS_SPACE)); \
+ hurd_activation_message_register (mb); \
\
- bool call = true; \
- for (;;) \
- { \
- if (call) \
- tag = l4_call (RPC_TARGET_); \
- else \
- tag = l4_receive (RPC_TARGET_); \
- if (unlikely (l4_ipc_failed (tag))) \
- { \
- if (((l4_error_code () >> 1) & 0x7) == 3) \
- /* IPC was interrupted. */ \
- /* XXX: We need to somehow consider the signal state and \
- return EINTR if appropriate. */ \
- { \
- if ((l4_error_code () & 1)) \
- /* Error occurred during receive phase. */ \
- call = false; \
+ /* We will be resumed via an activation. */ \
+ error_t err = vg_ipc (VG_IPC_RECEIVE | VG_IPC_SEND \
+ | VG_IPC_RECEIVE_ACTIVATE \
+ | VG_IPC_SEND_SET_THREAD_TO_CALLER \
+ | VG_IPC_SEND_SET_ASROOT_TO_CALLERS \
+ | VG_IPC_RECEIVE_SET_THREAD_TO_CALLER \
+ | VG_IPC_RECEIVE_SET_ASROOT_TO_CALLERS, \
+ __rpc_activity, \
+ mb->receiver_strong, ADDR_VOID, \
+ __rpc_activity, __rpc_object, \
+ mb->sender, ADDR_VOID); \
+ if (err) \
+ /* Error sending the IPC. */ \
+ hurd_activation_message_unregister (mb); \
+ else \
+ err = RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply_unmarshal) \
+ (mb->reply \
+ RPC_IF_COMMA (CPP_ADD (out_count, ret_cap_count)) () \
+ RPC_ARGUMENTS (CPP_ADD (out_count, ret_cap_count),, \
+ RPC_CHOP2 (in_count, ##__VA_ARGS__))); \
\
- continue; \
- } \
- return EHOSTDOWN; \
- } \
- break; \
- } \
- \
- l4_msg_store (tag, msg); \
- return RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply_unmarshal) \
- CPP_IFTHEN (ocount, \
- (&msg, RPC_ARGUMENTS (ocount, \
- RPC_CHOP (icount, ##__VA_ARGS__))), \
- (&msg)); \
+ return err; \
} \
+ \
+ static inline error_t \
+ __attribute__((always_inline)) \
+ RPC_CONCAT (RPC_STUB_PREFIX_(id), postfix) \
+ (addr_t __rpc_activity, \
+ addr_t __rpc_object \
+ /* In arguments. */ \
+ RPC_IF_COMMA (in_count) () \
+ RPC_GRAB2 (, in_count, __VA_ARGS__) \
+ /* Out arguments (data and caps). */ \
+ RPC_IF_COMMA (CPP_ADD (out_count, ret_cap_count)) () \
+ RPC_GRAB2 (*, CPP_ADD (out_count, ret_cap_count), \
+ RPC_CHOP2 (in_count, __VA_ARGS__))) \
+ { \
+ struct hurd_message_buffer *mb = hurd_message_buffer_alloc (); \
+ \
+ error_t err; \
+ err = RPC_CONCAT (RPC_CONCAT (RPC_STUB_PREFIX_(id), _using), postfix) \
+ (mb, __rpc_activity, __rpc_object \
+ RPC_IF_COMMA (CPP_ADD (CPP_ADD (in_count, out_count), \
+ ret_cap_count)) () \
+ RPC_ARGUMENTS (CPP_ADD (CPP_ADD (in_count, out_count), \
+ ret_cap_count),, __VA_ARGS__)); \
+ \
+ hurd_message_buffer_free (mb); \
+ \
+ return err; \
+ }
+#else
+# define RPC_(postfix, id, in_count, out_count, ret_cap_count, ...)
+#endif
-/* Generate stubs for marshalling a reply and sending it (without
- blocking). */
-#define RPC_REPLY_(id, icount, ocount, ...) \
+/* Send a reply to __RPC_TARGET. If __RPC_TARGET does not accept the
+ message immediately, abort sending. */
+#ifndef RM_INTERN
+#define RPC_REPLY_(id, in_count, out_count, ret_cap_count, ...) \
static inline error_t \
RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply) \
- (l4_thread_id_t tid RPC_IF_COMMA (ocount) () \
- RPC_GRAB2 (, ocount, RPC_CHOP (icount, ##__VA_ARGS__))) \
+ (addr_t __rpc_activity, \
+ addr_t __rpc_target \
+ /* Out data. */ \
+ RPC_IF_COMMA (out_count) () \
+ RPC_GRAB2 (, out_count, RPC_CHOP2 (in_count, ##__VA_ARGS__)) \
+ /* Return capabilities. */ \
+ RPC_IF_COMMA (ret_cap_count) () \
+ RPC_GRAB2 (, ret_cap_count, \
+ RPC_CHOP2 (CPP_ADD (in_count, out_count), \
+ ##__VA_ARGS__))) \
{ \
- l4_msg_tag_t tag; \
- l4_msg_t msg; \
+ struct hurd_message_buffer *mb = hurd_message_buffer_alloc (); \
\
RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply_marshal) \
- (&msg RPC_IF_COMMA (ocount) () \
- RPC_ARGUMENTS(ocount, RPC_CHOP (icount, __VA_ARGS__))); \
+ (mb->request \
+ /* Out data. */ \
+ RPC_IF_COMMA (out_count) () \
+ RPC_ARGUMENTS(out_count,, RPC_CHOP2 (in_count, __VA_ARGS__)) \
+ /* Out capabilities. */ \
+ RPC_IF_COMMA (ret_cap_count) () \
+ RPC_ARGUMENTS(ret_cap_count,, \
+ RPC_CHOP2 (CPP_ADD (in_count, out_count), \
+ __VA_ARGS__))); \
\
- l4_msg_load (msg); \
- l4_accept (L4_UNTYPED_WORDS_ACCEPTOR); \
+ error_t err = vg_reply (VG_IPC_SEND_SET_THREAD_TO_CALLER \
+ | VG_IPC_SEND_SET_ASROOT_TO_CALLERS, \
+ __rpc_activity, __rpc_target, \
+ mb->sender, ADDR_VOID); \
\
- tag = l4_reply (tid); \
- if (l4_ipc_failed (tag)) \
- return EHOSTDOWN; \
- return 0; \
+ hurd_message_buffer_free (mb); \
+ \
+ return err; \
}
+#else
+#define RPC_REPLY_(id, in_count, out_count, ret_cap_count, ...) \
+ static inline error_t \
+ __attribute__((always_inline)) \
+ RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply) \
+ (struct activity *__rpc_activity, \
+ struct messenger *__rpc_target \
+ /* Out data. */ \
+ RPC_IF_COMMA (out_count) () \
+ RPC_GRAB2 (, out_count, RPC_CHOP2 (in_count, ##__VA_ARGS__)) \
+ /* Return capabilities. */ \
+ RPC_IF_COMMA (ret_cap_count) () \
+ RPC_GRAB2 (, ret_cap_count, \
+ RPC_TYPE_SHIFT (ret_cap_count, struct cap, \
+ RPC_CHOP2 (CPP_ADD (in_count, out_count), \
+ ##__VA_ARGS__)))) \
+ { \
+ RPC_CONCAT (RPC_STUB_PREFIX_(id), _reply_marshal) \
+ (reply_buffer \
+ /* Out data. */ \
+ RPC_IF_COMMA (out_count) () \
+ RPC_ARGUMENTS(out_count,, RPC_CHOP2 (in_count, ##__VA_ARGS__)) \
+ /* Out capabilities. */ \
+ RPC_IF_COMMA (ret_cap_count) () \
+ RPC_ARGUMENTS (ret_cap_count, &, \
+ RPC_CHOP2 (CPP_ADD (in_count, out_count), \
+ ##__VA_ARGS__))); \
+ \
+ bool ret = messenger_message_load (__rpc_activity, \
+ __rpc_target, reply_buffer); \
+ \
+ return ret ? 0 : EWOULDBLOCK; \
+ }
+#endif
+
+/* RPC template. ID is the method name. IN_COUNT is the number of
+ arguments. OUT_COUNT is the number of out arguments.
+ RET_CAP_COUNT is the number of capabilities that are returned. The
+ remaining arguments correspond to pairs of types and argument
+ names.
+
+ Consider:
+
+ RPC(method, 2, 1, 1,
+ // In (data and capability) parameters
+ int, foo, cap_t, bar,
+ // Out data parameters
+ int bam,
+ // Out capabilities
+ cap_t xyzzy)
+
+ This will generate marshalling and unmarshalling functions as well
+ as send, reply and call functions. For instance, the signature for
+ the correspond send marshal function is:
+
+ error_t method_send_marshal (struct vg_message *message,
+ int foo, cap_t bar, cap_t reply)
+
+ that of the send unmarshal function is:
+
+ error_t method_send_unmarshal (struct vg_message *message,
+ int *foo, cap_t *bar, cap_t *reply)
+
+ that of the receive marshal function is:
+
+ error_t method_receive_marshal (struct vg_message *message,
+ cap_t xyzzy)
+
+
+ that of the reply marshal function is:
+
+ error_t method_reply_marshal (struct vg_message *message,
+ int bam, cap_t xyzzy)
-/* RPC template. ID is the method name, ARGS is the list of arguments
- as normally passed to a function, LOADER is code to load the in
- parameters, and STORER is code to load the out parameters. The
- code assumes that the first MR contains the error code and returns
- this as the function return value. If the IPC fails, EHOSTDOWN is
- returned. */
-
-#define RPC_SIMPLE(id, icount, ocount, ...) \
- RPC_MARSHAL_GEN_(id, icount, ocount, ##__VA_ARGS__) \
- \
- RPC_SIMPLE_(, id, icount, ocount, ##__VA_ARGS__) \
- RPC_SIMPLE_(_send, id, icount, ocount, ##__VA_ARGS__) \
- RPC_(_call, id, icount, ocount, ##__VA_ARGS__) \
- \
- RPC_REPLY_(id, icount, ocount, ##__VA_ARGS__)
-
-#define RPC(id, icount, ocount, ...) \
- RPC_MARSHAL_GEN_(id, icount, ocount, ##__VA_ARGS__) \
- \
- RPC_(, id, icount, ocount, ##__VA_ARGS__) \
- RPC_SIMPLE_(_send, id, icount, ocount, ##__VA_ARGS__) \
- RPC_(_call, id, icount, ocount, ##__VA_ARGS__) \
- \
- RPC_REPLY_(id, icount, ocount, ##__VA_ARGS__)
+ that of the reply unmarshal function is:
+
+ error_t method_reply_unmarshal (struct vg_message *message,
+ int *bam, cap_t *xyzzy)
+
+ Functions to send requests and replies as well as to produce calls
+ are also generated.
+
+ error_t method_call (cap_t activity, cap_t object,
+ int foo, cap_t bar, int *bam, cap_t *xyzzy)
+
+ Note that *XYZZY must be initialize with the location of a
+ capability slot to store the returned capability. *XYZZY is set to
+ ADDR_VOID if the sender did not provide a capability.
+
+ To send a message and not wait for a reply, a function with the
+ following prototype is generated:
+
+ error_t method_send (cap_t activity, cap_t object,
+ int foo, cap_t bar,
+ cap_t reply_messenger)
+
+ To reply to a request, a function with the following prototype is
+ generated:
+
+ error_t method_reply (cap_t activity, cap_t reply_messenger,
+ int bam, cap_t xyzzy)
+*/
+
+#define RPC(id, in_count, out_count, ret_cap_count, ...) \
+ RPC_MARSHAL_GEN_(id, in_count, out_count, ret_cap_count, ##__VA_ARGS__) \
+ \
+ RPC_(, id, in_count, out_count, ret_cap_count, ##__VA_ARGS__) \
+ RPC_SEND_(_send, id, in_count, out_count, ret_cap_count, \
+ ##__VA_ARGS__) \
+ RPC_SEND_NONBLOCKING_(_send_nonblocking, \
+ id, in_count, out_count, ret_cap_count, \
+ ##__VA_ARGS__) \
+ RPC_REPLY_(id, in_count, out_count, ret_cap_count, ##__VA_ARGS__)
/* Marshal a reply consisting of the error code ERR in *MSG. */
static inline void
-rpc_error_reply_marshal (l4_msg_t *msg, error_t err)
+__attribute__((always_inline))
+rpc_error_reply_marshal (struct vg_message *msg, error_t err)
{
- l4_msg_clear (*msg);
- l4_msg_put_word (*msg, 0, err);
- l4_msg_set_untyped_words (*msg, 1);
+ vg_message_clear (msg);
+ vg_message_append_word (msg, err);
}
-/* Reply to the thread THREAD with error code ERROR. */
+/* Reply to the target TARGET with error code ERROR. */
+#ifdef RM_INTERN
static inline error_t
-rpc_error_reply (l4_thread_id_t thread, error_t err)
+__attribute__((always_inline))
+rpc_error_reply (struct activity *activity, struct messenger *target,
+ error_t err)
{
- l4_msg_t msg;
-
- rpc_error_reply_marshal (&msg, err);
- l4_msg_load (msg);
-
- l4_msg_tag_t tag;
- tag = l4_reply (thread);
- if (l4_ipc_failed (tag))
- return EHOSTDOWN;
- return 0;
+ rpc_error_reply_marshal (reply_buffer, err);
+ bool ret = messenger_message_load (activity, target, reply_buffer);
+ return ret ? 0 : EWOULDBLOCK;
}
+#else
+static inline error_t
+__attribute__((always_inline))
+rpc_error_reply (cap_t activity, cap_t target, error_t err)
+{
+ return vg_ipc_short (VG_IPC_SEND_NONBLOCKING | VG_IPC_SEND_INLINE
+ | VG_IPC_SEND_INLINE_WORD1,
+ ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ ADDR_VOID, target,
+ ADDR_VOID, err, 0, ADDR_VOID);
+}
+#endif
#endif
diff --git a/hurd/startup.h b/hurd/startup.h
index 7883dfb..0c31d9f 100644
--- a/hurd/startup.h
+++ b/hurd/startup.h
@@ -23,10 +23,12 @@
#include <stdint.h>
#include <stddef.h>
-#include <l4/types.h>
-
#include <hurd/types.h>
#include <hurd/addr.h>
+
+#ifdef USE_L4
+# include <l4/types.h>
+#endif
/* The version of the startup data defined by this header file. */
#define HURD_STARTUP_VERSION_MAJOR UINT16_C (0)
@@ -59,11 +61,16 @@ struct hurd_startup_data
unsigned short version_minor;
/* Startup flags. */
- l4_word_t flags;
+ uintptr_t flags;
+#ifdef USE_L4
/* The UTCB area of this task. */
l4_fpage_t utcb_area;
+ /* Thread id of Viengoos. */
+ l4_thread_id_t rm;
+#endif
+
/* The argument vector. */
char *argz;
/* Absolute address in the data space. */
@@ -74,9 +81,6 @@ struct hurd_startup_data
/* Absolute address in the data space. */
size_t envz_len;
- /* Thread id of the resource manager. */
- l4_thread_id_t rm;
-
/* Slot in which a capability designating the task's primary
activity is stored. */
addr_t activity;
@@ -85,6 +89,11 @@ struct hurd_startup_data
stored. */
addr_t thread;
+ /* To allow a task to boot strap itself, it needs a couple of
+ messengers (one to send and another to receive). Here they
+ are. */
+ addr_t messengers[2];
+
struct hurd_object_desc *descs;
int desc_count;
diff --git a/hurd/t-rpc.c b/hurd/t-rpc.c
index 9483d39..b286296 100644
--- a/hurd/t-rpc.c
+++ b/hurd/t-rpc.c
@@ -7,20 +7,19 @@ int output_debug = 1;
#define RPC_STUB_PREFIX rpc
#define RPC_ID_PREFIX RPC
-#undef RPC_TARGET_NEED_ARG
-#define RPC_TARGET 1
#include <hurd/rpc.h>
/* Exception message ids. */
enum
{
- RPC_noargs = 500,
+ RPC_noargs = 0x1ABE100,
RPC_onein,
RPC_oneout,
RPC_onlyin,
RPC_onlyout,
RPC_mix,
+ RPC_caps,
};
struct foo
@@ -29,58 +28,81 @@ struct foo
char b;
};
-RPC(noargs, 0, 0)
-RPC(onein, 1, 0, uint32_t, arg)
-RPC(oneout, 0, 1, uint32_t, arg)
-RPC(onlyin, 4, 0, uint32_t, arg, uint32_t, idx, struct foo, foo, bool, p)
-RPC(onlyout, 0, 4, uint32_t, arg, uint32_t, idx, struct foo, foo, bool, p)
-RPC(mix, 2, 3, uint32_t, arg, uint32_t, idx,
+RPC(noargs, 0, 0, 0)
+RPC(onein, 1, 0, 0, uint32_t, arg)
+RPC(oneout, 0, 1, 0, uint32_t, arg)
+RPC(onlyin, 4, 0, 0, uint32_t, arg, uint32_t, idx, struct foo, foo, bool, p)
+RPC(onlyout, 0, 4, 0, uint32_t, arg, uint32_t, idx, struct foo, foo, bool, p)
+RPC(mix, 2, 3, 0, uint32_t, arg, uint32_t, idx,
struct foo, foo, bool, p, int, i)
+RPC(caps, 3, 2, 2,
+ /* In: */
+ int, i, cap_t, c, struct foo, foo,
+ /* Out: */
+ int, a, int, b, cap_t, x, cap_t, y)
#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
-#undef RPC_TARGET
int
main (int argc, char *argv[])
{
printf ("Checking RPC... ");
- l4_msg_t msg;
error_t err;
+ struct vg_message *msg;
- rpc_noargs_send_marshal (&msg);
- err = rpc_noargs_send_unmarshal (&msg);
+
+#define REPLY ADDR (0x1000, ADDR_BITS - 12)
+ addr_t reply = REPLY;
+
+ msg = malloc (sizeof (*msg));
+ rpc_noargs_send_marshal (msg, REPLY);
+ err = rpc_noargs_send_unmarshal (msg, &reply);
assert (! err);
+ assert (ADDR_EQ (reply, REPLY));
+ free (msg);
- rpc_noargs_reply_marshal (&msg);
- err = rpc_noargs_reply_unmarshal (&msg);
+ msg = malloc (sizeof (*msg));
+ rpc_noargs_reply_marshal (msg);
+ err = rpc_noargs_reply_unmarshal (msg);
assert (err == 0);
+ free (msg);
+ msg = malloc (sizeof (*msg));
#define VALUE 0xfde8963a
uint32_t arg = VALUE;
uint32_t arg_out;
- rpc_onein_send_marshal (&msg, arg);
- err = rpc_onein_send_unmarshal (&msg, &arg_out);
+ rpc_onein_send_marshal (msg, arg, REPLY);
+ err = rpc_onein_send_unmarshal (msg, &arg_out, &reply);
assert (! err);
assert (arg_out == VALUE);
+ assert (ADDR_EQ (reply, REPLY));
+ free (msg);
- rpc_onein_reply_marshal (&msg);
- err = rpc_onein_reply_unmarshal (&msg);
+ msg = malloc (sizeof (*msg));
+ rpc_onein_reply_marshal (msg);
+ err = rpc_onein_reply_unmarshal (msg);
assert (! err);
+ free (msg);
-
- rpc_oneout_send_marshal (&msg);
- err = rpc_oneout_send_unmarshal (&msg);
+ msg = malloc (sizeof (*msg));
+ rpc_oneout_send_marshal (msg, REPLY);
+ err = rpc_oneout_send_unmarshal (msg, &reply);
assert (! err);
+ assert (ADDR_EQ (reply, REPLY));
+ free (msg);
- rpc_oneout_reply_marshal (&msg, arg);
- err = rpc_oneout_reply_unmarshal (&msg, &arg_out);
+ msg = malloc (sizeof (*msg));
+ rpc_oneout_reply_marshal (msg, arg);
+ err = rpc_oneout_reply_unmarshal (msg, &arg_out);
assert (! err);
assert (arg_out == VALUE);
+ free (msg);
+ msg = malloc (sizeof (*msg));
struct foo foo;
foo.a = 1 << 31;
@@ -89,26 +111,34 @@ main (int argc, char *argv[])
struct foo foo_out;
bool p_out;
- rpc_onlyin_send_marshal (&msg, 0x1234567, 321, foo, true);
- err = rpc_onlyin_send_unmarshal (&msg, &arg_out, &idx_out, &foo_out, &p_out);
+ rpc_onlyin_send_marshal (msg, 0x1234567, 0xABC, foo, true, REPLY);
+ err = rpc_onlyin_send_unmarshal (msg, &arg_out, &idx_out, &foo_out, &p_out,
+ &reply);
assert (! err);
assert (arg_out == 0x1234567);
- assert (idx_out == 321);
+ assert (idx_out == 0xABC);
assert (foo_out.a == foo.a);
assert (foo_out.b == foo.b);
assert (p_out == true);
+ assert (ADDR_EQ (reply, REPLY));
+ free (msg);
- rpc_onlyin_reply_marshal (&msg);
- err = rpc_onlyin_reply_unmarshal (&msg);
+ msg = malloc (sizeof (*msg));
+ rpc_onlyin_reply_marshal (msg);
+ err = rpc_onlyin_reply_unmarshal (msg);
assert (! err);
+ free (msg);
-
- rpc_onlyout_send_marshal (&msg);
- err = rpc_onlyout_send_unmarshal (&msg);
+ msg = malloc (sizeof (*msg));
+ rpc_onlyout_send_marshal (msg, REPLY);
+ err = rpc_onlyout_send_unmarshal (msg, &reply);
assert (! err);
+ assert (ADDR_EQ (reply, REPLY));
+ free (msg);
- rpc_onlyout_reply_marshal (&msg, 0x1234567, 321, foo, true);
- err = rpc_onlyout_reply_unmarshal (&msg, &arg_out, &idx_out,
+ msg = malloc (sizeof (*msg));
+ rpc_onlyout_reply_marshal (msg, 0x1234567, 321, foo, true);
+ err = rpc_onlyout_reply_unmarshal (msg, &arg_out, &idx_out,
&foo_out, &p_out);
assert (! err);
assert (arg_out == 0x1234567);
@@ -116,22 +146,39 @@ main (int argc, char *argv[])
assert (foo_out.a == foo.a);
assert (foo_out.b == foo.b);
assert (p_out == true);
+ free (msg);
- rpc_mix_send_marshal (&msg, arg, 456789);
- err = rpc_mix_send_unmarshal (&msg, &arg_out, &idx_out);
+ msg = malloc (sizeof (*msg));
+ rpc_mix_send_marshal (msg, arg, 456789, REPLY);
+ err = rpc_mix_send_unmarshal (msg, &arg_out, &idx_out, &reply);
assert (! err);
assert (arg_out == arg);
assert (idx_out == 456789);
+ assert (ADDR_EQ (reply, REPLY));
+ free (msg);
+ msg = malloc (sizeof (*msg));
int i_out = 0;
- rpc_mix_reply_marshal (&msg, foo, false, 4200042);
- err = rpc_mix_reply_unmarshal (&msg, &foo_out, &p_out, &i_out);
+ rpc_mix_reply_marshal (msg, foo, false, 4200042);
+ err = rpc_mix_reply_unmarshal (msg, &foo_out, &p_out, &i_out);
assert (! err);
assert (foo_out.a == foo.a);
assert (foo_out.b == foo.b);
assert (p_out == false);
assert (i_out == 4200042);
+ free (msg);
+
+ msg = malloc (sizeof (*msg));
+ rpc_caps_send_marshal (msg, 54, ADDR (1, ADDR_BITS), foo, REPLY);
+ addr_t addr;
+ err = rpc_caps_send_unmarshal (msg, &i_out, &addr, &foo_out, &reply);
+ assert (! err);
+ assert (i_out == 54);
+ assert (ADDR_EQ (addr, ADDR (1, ADDR_BITS)));
+ assert (foo_out.a == foo.a);
+ assert (foo_out.b == foo.b);
+ free (msg);
printf ("ok\n");
return 0;
diff --git a/hurd/thread.h b/hurd/thread.h
index c583723..81a4925 100644
--- a/hurd/thread.h
+++ b/hurd/thread.h
@@ -16,42 +16,70 @@
License along with GNU Hurd. If not, see
<http://www.gnu.org/licenses/>. */
-#ifndef _HURD_THREAD_H
-#define _HURD_THREAD_H 1
+#ifndef __have_vg_thread_id_t
+# define __have_vg_thread_id_t
-#include <hurd/types.h>
-#include <hurd/addr-trans.h>
-#include <hurd/cap.h>
-#include <hurd/startup.h>
-#include <l4/syscall.h>
-#include <l4/ipc.h>
+# ifdef USE_L4
+# include <l4.h>
+typedef l4_thread_id_t vg_thread_id_t;
+# define vg_niltid l4_nilthread
+# define VG_THREAD_ID_FMT "%x"
+# else
+# include <stdint.h>
+typedef uint64_t vg_thread_id_t;
+# define vg_niltid -1
+# define VG_THREAD_ID_FMT "%llx"
+# endif
-enum
- {
- RM_thread_exregs = 600,
- RM_thread_wait_object_destroyed,
- RM_thread_raise_exception,
- };
+#endif /* !__have_vg_thread_id_t */
-#ifdef RM_INTERN
-struct thread;
-typedef struct thread *thread_t;
-#else
-typedef addr_t thread_t;
-#endif
+#ifndef __have_activation_frame
+# define __have_activation_frame
-struct exception_frame
+# include <stdint.h>
+
+# ifdef USE_L4
+# include <l4/ipc.h>
+# endif
+
+struct hurd_message_buffer;
+
+struct activation_frame
{
-#if i386
- /* eax, ecx, edx, eflags, eip, ebx, edi, esi. */
- l4_word_t regs[8];
+ /* **** ia32-exception-entry.S silently depends on the layout of
+ this structure up to and including the next field **** */
+#ifdef i386
+ union
+ {
+ uintptr_t regs[10];
+ struct
+ {
+ uintptr_t eax;
+ uintptr_t ecx;
+ uintptr_t edx;
+ uintptr_t eflags;
+ uintptr_t eip;
+ uintptr_t ebx;
+ uintptr_t edi;
+ uintptr_t esi;
+ uintptr_t ebp;
+ uintptr_t esp;
+ };
+ };
#else
# error Not ported to this architecture!
#endif
- struct exception_frame *next;
- struct exception_frame *prev;
- l4_msg_t exception;
+ /* The base of the stack to use when running
+ hurd_activation_handler_normal. If NULL, then the interrupted
+ stack is used. */
+ void *normal_mode_stack;
+
+ struct activation_frame *next;
+ struct activation_frame *prev;
+ struct hurd_message_buffer *message_buffer;
+
+#ifdef USE_L4
/* We need to save parts of the UTCB. */
l4_word_t saved_sender;
l4_word_t saved_receiver;
@@ -60,16 +88,69 @@ struct exception_frame
l4_word_t saved_flags;
l4_word_t saved_br0;
l4_msg_t saved_message;
+#endif
+
+#define ACTIVATION_FRAME_CANARY 0x10ADAB1E
+ uintptr_t canary;
+};
+#endif
+
+#if defined(__need_vg_thread_id_t) || defined (__need_activation_frame)
+# undef __need_vg_thread_id_t
+# undef __need_activation_frame
+#else
+
+#ifndef _HURD_THREAD_H
+#define _HURD_THREAD_H 1
+
+#include <stdint.h>
+#include <hurd/types.h>
+#include <hurd/addr.h>
+#include <hurd/addr-trans.h>
+#include <hurd/cap.h>
+#include <hurd/messenger.h>
+#include <setjmp.h>
+
+/* Cause the activation frame to assume the state of the long jump
+ buffer BUF. If SET_RET is true, the normal function return value
+ is set to RET. */
+extern void hurd_activation_frame_longjmp (struct activation_frame *af,
+ jmp_buf buf,
+ bool set_ret, int ret);
+
+struct hurd_fault_catcher
+{
+#define HURD_FAULT_CATCHER_MAGIC 0xb01dface
+ uintptr_t magic;
+
+ /* Start of the region to watch. */
+ uintptr_t start;
+ /* Length of the region in bytes. */
+ uintptr_t len;
+ /* The callback. Return true to continue execute. False to throw a
+ SIGSEGV. */
+ bool (*callback) (struct activation_frame *activation_frame,
+ uintptr_t fault);
+
+ struct hurd_fault_catcher *next;
+ struct hurd_fault_catcher **prevp;
};
-struct exception_page
+/* Register a fatch catch handler. */
+extern void hurd_fault_catcher_register (struct hurd_fault_catcher *catcher);
+
+/* Unregister a fault catch handler. */
+extern void hurd_fault_catcher_unregister (struct hurd_fault_catcher *catcher);
+
+/* The user thread control block. */
+struct vg_utcb
{
union
{
- /* Whether the thread is in activation mode or not. If so, no
- exception will be delivered.
+ /* The following structures are examined or modified by the
+ kernel. */
- **** ia32-exception-entry.S silently depends on the layout of
+ /* **** ia32-exception-entry.S silently depends on the layout of
this structure **** */
struct
{
@@ -77,56 +158,108 @@ struct exception_page
{
struct
{
- /* Whether the thread is in activated mode. */
- l4_word_t activated_mode : 1;
+ /* Whether the thread is in activated mode. If so, any
+ activations that arrive during this time will be queued
+ or dropped. */
+ uintptr_t activated_mode : 1;
/* Set by the kernel to indicated that there is a pending
message. */
- l4_word_t pending_message : 1;
+ uintptr_t pending_message : 1;
/* Set by the kernel to indicate whether the thread was
interrupted while the EIP is in the transition range. */
- l4_word_t interrupt_in_transition : 1;
+ uintptr_t interrupt_in_transition : 1;
};
- l4_word_t mode;
+ uintptr_t mode;
};
/* The value of the IP and SP when the thread was running. */
- l4_word_t saved_ip;
- l4_word_t saved_sp;
+ uintptr_t saved_ip;
+ uintptr_t saved_sp;
/* The state of the thread (as returned by _L4_exchange_regs) */
- l4_word_t saved_thread_state;
+ uintptr_t saved_thread_state;
+
+ /* Top of the activation frame stack (i.e., the active
+ activation). */
+ struct activation_frame *activation_stack;
+ /* The bottom of the activation stack. */
+ struct activation_frame *activation_stack_bottom;
+
+ uintptr_t activation_handler_sp;
+ uintptr_t activation_handler_ip;
+ uintptr_t activation_handler_end;
+
+ /* The protected payload of the capability that invoked the
+ messenger that caused this activation. */
+ uint64_t protected_payload;
+ /* The messenger's id. */
+ uint64_t messenger_id;
+
+ uintptr_t inline_words[VG_MESSENGER_INLINE_WORDS];
+ addr_t inline_caps[VG_MESSENGER_INLINE_CAPS];
+
+ union
+ {
+ struct
+ {
+ int inline_word_count : 2;
+ int inline_cap_count : 1;
+ };
+ int inline_data : 3;
+ };
+
+ /* The following fields are not examined or modified by the
+ kernel. */
+
+ /* The CRC protects the above fields by checking for
+ modification, which can happen if a call back function uses
+ too much stack. The fields following crc are not protected
+ by the crc as they are expected to be changed by the
+ activation handler. */
- /* Top of the exception frame stack. */
- struct exception_frame *exception_stack;
- /* Bottom of the exception frame stack. */
- struct exception_frame *exception_stack_bottom;
+ uintptr_t crc;
- l4_word_t exception_handler_sp;
- l4_word_t exception_handler_ip;
- l4_word_t exception_handler_end;
+ /* The exception buffer. */
+ struct hurd_message_buffer *exception_buffer;
+ /* The current extant IPC. */
+ struct hurd_message_buffer *extant_message;
- /* The exception. */
- l4_msg_t exception;
+ struct hurd_fault_catcher *catchers;
- l4_word_t crc;
+ /* The alternate activation stack. */
+ void *alternate_stack;
+ bool alternate_stack_inuse;
+
+#define UTCB_CANARY0 0xCA17A1
+#define UTCB_CANARY1 0xDEADB15D
+ uintptr_t canary0;
+ uintptr_t canary1;
};
char data[PAGESIZE];
};
};
+/* A thread object's user accessible capability slots. */
enum
{
/* Root of the address space. */
THREAD_ASPACE_SLOT = 0,
/* The activity the thread is bound to. */
THREAD_ACTIVITY_SLOT = 1,
- /* Where exceptions are saved. Must be a cap_page. */
- THREAD_EXCEPTION_PAGE_SLOT = 2,
+ /* The messenger to post exceptions to. */
+ THREAD_EXCEPTION_MESSENGER = 2,
+ /* The user thread control block. Must be a cap_page. */
+ THREAD_UTCB = 3,
+
+ /* Total number of capability slots in a thread object. This must
+ be a power of 2. */
+ THREAD_SLOTS = 4,
};
+#define THREAD_SLOTS_LOG2 2
enum
{
- HURD_EXREGS_SET_EXCEPTION_PAGE = 0x1000,
-
+ HURD_EXREGS_SET_UTCB = 0x2000,
+ HURD_EXREGS_SET_EXCEPTION_MESSENGER = 0x1000,
HURD_EXREGS_SET_ASPACE = 0x800,
HURD_EXREGS_SET_ACTIVITY = 0x400,
HURD_EXREGS_SET_SP = _L4_XCHG_REGS_SET_SP,
@@ -134,7 +267,8 @@ enum
HURD_EXREGS_SET_SP_IP = _L4_XCHG_REGS_SET_SP | _L4_XCHG_REGS_SET_IP,
HURD_EXREGS_SET_EFLAGS = _L4_XCHG_REGS_SET_FLAGS,
HURD_EXREGS_SET_USER_HANDLE = _L4_XCHG_REGS_SET_USER_HANDLE,
- HURD_EXREGS_SET_REGS = (HURD_EXREGS_SET_EXCEPTION_PAGE
+ HURD_EXREGS_SET_REGS = (HURD_EXREGS_SET_UTCB
+ | HURD_EXREGS_SET_EXCEPTION_MESSENGER
| HURD_EXREGS_SET_ASPACE
| HURD_EXREGS_SET_ACTIVITY
| HURD_EXREGS_SET_SP
@@ -152,53 +286,53 @@ enum
HURD_EXREGS_ABORT_IPC = HURD_EXREGS_ABORT_SEND | _L4_XCHG_REGS_CANCEL_RECV,
};
+enum
+ {
+ RM_thread_exregs = 600,
+ RM_thread_id,
+ RM_thread_activation_collect,
+ };
+
+#ifdef RM_INTERN
+struct thread;
+typedef struct thread *thread_t;
+#else
+typedef addr_t thread_t;
+#endif
+
#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>
struct hurd_thread_exregs_in
{
- addr_t aspace;
uintptr_t aspace_cap_properties_flags;
struct cap_properties aspace_cap_properties;
- addr_t activity;
-
- addr_t exception_page;
-
- l4_word_t sp;
- l4_word_t ip;
- l4_word_t eflags;
- l4_word_t user_handle;
-
- addr_t aspace_out;
- addr_t activity_out;
- addr_t exception_page_out;
+ uintptr_t sp;
+ uintptr_t ip;
+ uintptr_t eflags;
+ uintptr_t user_handle;
};
struct hurd_thread_exregs_out
{
- l4_word_t sp;
- l4_word_t ip;
- l4_word_t eflags;
- l4_word_t user_handle;
+ uintptr_t sp;
+ uintptr_t ip;
+ uintptr_t eflags;
+ uintptr_t user_handle;
};
/* l4_exregs wrapper. */
-RPC (thread_exregs, 4, 1,
- addr_t, principal,
- addr_t, thread,
- l4_word_t, control,
- struct hurd_thread_exregs_in, in,
+RPC (thread_exregs, 6, 1, 4,
+ /* cap_t principal, cap_t thread, */
+ uintptr_t, control, struct hurd_thread_exregs_in, in,
+ cap_t, aspace, cap_t, activity, cap_t, utcb, cap_t, exception_messenger,
/* Out: */
- struct hurd_thread_exregs_out, out)
+ struct hurd_thread_exregs_out, out,
+ cap_t, aspace_out, cap_t, activity_out, cap_t, utcb_out,
+ cap_t, exception_messenger_out)
static inline error_t
thread_start (addr_t thread)
@@ -208,7 +342,8 @@ thread_start (addr_t thread)
return rm_thread_exregs (ADDR_VOID, thread,
HURD_EXREGS_START | HURD_EXREGS_ABORT_IPC,
- in, &out);
+ in, ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ &out, NULL, NULL, NULL, NULL);
}
static inline error_t
@@ -223,7 +358,8 @@ thread_start_sp_ip (addr_t thread, uintptr_t sp, uintptr_t ip)
return rm_thread_exregs (ADDR_VOID, thread,
HURD_EXREGS_START | HURD_EXREGS_ABORT_IPC
| HURD_EXREGS_SET_SP_IP,
- in, &out);
+ in, ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ &out, NULL, NULL, NULL, NULL);
}
static inline error_t
@@ -234,29 +370,31 @@ thread_stop (addr_t thread)
return rm_thread_exregs (ADDR_VOID, thread,
HURD_EXREGS_STOP | HURD_EXREGS_ABORT_IPC,
- in, &out);
+ in, ADDR_VOID, ADDR_VOID, ADDR_VOID, ADDR_VOID,
+ &out, NULL, NULL, NULL, NULL);
}
-/* Cause the caller to wait until OBJECT is destroyed. Returns the
- object's return code in RETURN_CODE. */
-RPC(thread_wait_object_destroyed, 2, 1,
- addr_t, principal, addr_t, object,
- /* Out: */
- uintptr_t, return_code);
-
-/* The kernel interprets the payload as a short l4_msg_t buffer: that
- is one that does not exceed 128 bytes. */
-struct exception_buffer
-{
- char payload[128];
-};
+/* Return the unique integer associated with thread THREAD. */
+RPC(thread_id, 0, 1, 0,
+ /* cap_t, principal, cap_t, thread, */
+ vg_thread_id_t, tid)
-RPC(thread_raise_exception, 3, 0,
- addr_t, principal, addr_t, thread,
- struct exception_buffer, exception_buffer)
+/* Cause the delivery of a pending message, if any. */
+RPC(thread_activation_collect, 0, 0, 0
+ /* cap_t principal, cap_t thread */)
#undef RPC_STUB_PREFIX
#undef RPC_ID_PREFIX
-#undef RPC_TARGET
-#endif
+static inline vg_thread_id_t
+vg_myself (void)
+{
+ vg_thread_id_t tid;
+ error_t err = rm_thread_id (ADDR_VOID, ADDR_VOID, &tid);
+ if (err)
+ return vg_niltid;
+ return tid;
+}
+
+#endif /* _HURD_THREAD_H */
+#endif /* __need_vg_thread_id_t */