l4-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Viengoos IPC


From: Neal H. Walfield
Subject: Re: Viengoos IPC
Date: Mon, 13 Jul 2009 17:00:36 +0200
User-agent: Wanderlust/2.14.0 (Africa) SEMI/1.14.6 (Maruoka) FLIM/1.14.9 (Goj┼Ź) APEL/10.7 Emacs/22.3 (i486-pc-linux-gnu) MULE/5.0 (SAKAKI)

At Sun, 28 Jun 2009 00:11:40 +1000,
James Collier wrote:
> What I'm trying to accomplish in the following code is an ipc send
> operation from the main() thread and an ipc receive operation from the
> hello_server thread. i.e. enqueue a messenger on hello_servers
> messenger, then dequeue it from hello_server.

This sounds like a good start to learn about Viengoos.

> <code>
> /* struct messenger appears in the kernel headers, how is it
> initialised? */
> vg_messenger_t client_msnger;

You cannot directly inspect or manipulate a messenger using hardware
load and store operations.  This is the case for all kernel objects
except pages.  A kernel object is accessed by invoking the object with
the appropriate method (i.e., sending it an appropriate IPC).

When you allocate a messenger using folio_object_alloc, the kernel
initializes the specified storage and returns a reference (capability)
to the new object.

In user space, vg_messenger_t is really an alias for vg_addr_t, which
is the type of a local address.  (On Viengoos, local addresses are
64-bits wide.)  When you want to invoke an object, you call the IPC
system call and pass it the address of the object you want to invoke.
Viengoos looks up this address in the calling thread's name space.

> /* GLOBAL */ vg_messenger_t receive;
> /* used by the server thread. Global so that vg_ipc* in this thread can
> access it, does it need to? */
> 
> char* string = "hello";
> /* Create the server thread */
> pthread_t srvr;
> pthread_create(&srvr, NULL, (void*) &hello_server, &client_msnger);
> 
> /* Allocate a message buffer
> * -- Can hurd_message_buffer_alloc() help here?
> * Is the following the correct/expected method?
> */

hurd_message_buffer_alloc can definitely help here!  However,
allocating the messenger and initializing it properly on your own is
also a good exercise.

> struct vg_message *msg = malloc(PAGESIZE);

A message buffer is a page object.  Although you have allocated a page
worth of bytes using malloc, these bytes may straddle two pages:

         0              4096             8192
         |      |---------+--------|       |
                msg

There are a number of ways to allocate one page.  A low-level Hurd
function is hurd_storage_alloc.  mmap and posix_memalign will also
work and are a bit more convenient to use.

The reason that posix_memalign and mmap work is because Viengoos uses
a single address space for both data and capabilities.  This makes it
easy to determine the address of a page object given the address of a
byte in that page, cf. VG_ADDR_TO_PTR and VG_PTR_TO_ADDR.

> vg_message_clear(msg);
> /* I'm not really understanding capabilities here, from the reference
> * manual: "capability addresses are interpreted as the
> * lo-cation of the capabilities to send". Does this mean I need a
> * capability referencing the data I want to send (In this case
> * char* string)?
> * How do I get this capability?
> */

There is not necessarily a single capability associated with your
string (again, the string could be straddling multiple pages).  You
should first try to copy the string by value.  To do this, copy the
string into the message buffer as raw data.  After you get that
working, try allocating a page object, copying the data into that page
and then passing a reference to the page in the IPC.

> /* Now this message buffer needs to be associated with a messenger */
> 
> /* Send the message
> * VG_IPC_SEND: Do a send phase
> * VG_IPC_SEND_ACTIVATE: Keep giong once the message is transfered

To be clear: VG_IPC_SEND_ACTIVATE means that the kernel will activate
the thread once the message is sent.  When you expect a reply from the
server (which you don't), you would not generally include this but
wait until you get the reply to clean up the send buffers.

> * VG_IPC_SEND_SET_THREAD_TO_CALLER: Is this required? When should it be
> * used?

A messenger can reference a thread.  This determines which thread the
messenger activates.  This flag as well as the next one enables a
thread to initialize a messenger when it is starting up.  The issue is
that until a thread has initialized a messenger it can't really send
and receive messages.  (That is, this helps solve a bootstrap
problem.)

> * VG_IPC_SEND_SET_ASROOT_TO_CALLERS: Is this required? When should 
> * it be used?
> */

The message buffer address and any capability addresses in the message
must be resolved relative to some root.  This sets the root to be the
same as the caller's address space root.

> void
> hello_server()
> {
> struct vg_message *msg = malloc(PAGESIZE);
> vg_message_clear(msg);
> 
> /* Is __hurd_startup_data->activity valid for this thread? */

Yes, it should be.

> Apologies for the volume of the email and number of questions.

There is no need to apologize.

> The main
> ones that I'm interested in at this stage are capabilities and how they
> designate an object (e.g. a message buffer (struct vg_message)).

As I said above, there are kernel objects (e.g., messengers, pages).
These are designated using capabilities.  Capabilities, like kernel
objects, are also protected in the sense that a capability's bits are
not exposed.  To designate a capability, a capability address is used.
Capabilities addresses are local to an object.  Objects such as
threads and messengers have an address space root capability slot.
Capability addresses are usually resolved relative to this root.

Thus, an address space and an address together designate a capability.
A capability designates an object.

  (address space, cap addr) -> cap -> object

> Also
> how to properly enqueue and dequeue a message between threads.

To send a message, you allocate a messenger and have it deliver a
message (usually in the form of a message buffer) to another
messenger.

To receive a message, you allocate a messenger and a message buffer
and set the messenger up to wait for a message.  When another
messenger delivers a message, the receiver (optionally) activates a
thread.  The activation can include data that allows the receiver to
determine which messenger accepted a message.  Knowing this, it is
easy to determine where the message is stored.


Your questions are good ones.  Don't hesitate if you have more or need
more details.  I'll try to respond more promptly in the future.  In
this case, I got your mail when I was on vacation.

Thanks,

Neal




reply via email to

[Prev in Thread] Current Thread [Next in Thread]