[Top][All Lists]

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

Re: Some questions about libports and notification of ports

From: zhengda
Subject: Re: Some questions about libports and notification of ports
Date: Fri, 22 Aug 2008 02:54:38 +0200
User-agent: Thunderbird (X11/20080707)

Thomas Bushnell BSG wrote:
On Thu, 2008-08-21 at 11:26 +0200, zhengda wrote:
In eth-filter, I define a structure
struct proxy_info
  /* For receiving packets from pfinet. */
  struct port_info *pfinet_pi;
  hurd_ihash_locp_t p_pfinetpi_hashloc;

  /* For receiving packets from the network interface. */
  struct port_info *device_pi;
  hurd_ihash_locp_t p_devicepi_hashloc;

  /* For delivering packet to pfinet. */
  mach_port_t deliver_port;
  hurd_ihash_locp_t p_deliverport_hashloc;

  /* The port to the network interface. */
  mach_port_t device_port;
Because I cannot put two port_info objects in one structure, I put their pointers in the structure.

Ah, there's the mistake.  First, "struct proxy" is fine; no need for
"info".  You have a situation very much like a pipe, except that you are
doing network packet stuff on each port instead of read/write on each

So take a look at what pflocal does for a hint.

You want something like

struct proxy_user
  struct port_info pi;
  struct proxy *px;

struct proxy
  int refs;
  struct mutex lock;

  a queue;
  other stuff maybe;
ports_destroy_right decrease the reference count for the port only when the port has the send right (PORT_HAS_SENDRIGHTS flag). When the port gets the send right, its reference count is always increased by 1. so as long as the functions in libports are used correctly, ports_destroy_right() cannot destroy the port_info structure. As I understand, in order to destroy a port created by ports_create_port(), we have to call ports_destroy_right() and ports_port_deref().

Notice that Hurd servers basically never think "oh, I want to destroy a
port."  That's a very unusual thing.  You don't keep track of that; this
is exactly what libports is for.

Your interpretation of ports_destroy_right is wrong.  It does always
destroy the port, completely.

The mach_port_mod_refs is what destroys the port.  Note that *all* the
outstanding send rights, however many there may be, occupy only *one*
reference in PI->refcnt.  So when we do a ports_destroy_right, first we
blow away the receive right, which causes the kernel to nuke all the
outstanding send rights and turn them into MACH_PORT_NULL.  Then we
account for their loss by doing a ports_port_deref, if there were any
send rights.  (Notice that the no-senders notification we have
outstanding is going to be cancelled when we nuke the receive right.)

The only reason that ports_port_deref might not immediately eliminate
the port is because there are likely *other* references to the port,
perhaps in some other thread.  We can't actually free the structure
until they are done with it.  But trule, ports_destroy_right does blow
the whole thing away.
When a port_info object is created by ports_create_port() and ports_get_right() hasn't been called,
we have to call ports_port_deref() to destroy the port_info object.
struct port_info *foo;
ports_create_port(portclass, bucket, sizeof(*foo), &foo);
ports_port_deref(foo);      // ports_port_destroy(foo) doesn't work here.

When a port_info object is created and ports_get_right() is called,
struct port_info *foo;
mach_port_t port;
ports_create_port(portclass, bucket, sizeof(*foo), &foo);
In this case, there are two ways to destroy the port_info object:
either to call ports_port_deref() and then ports_destroy_right() explicitly,
or to call ports_port_deref() and then wait until no_senders notification is generated. The second way is much more usual as you said, but there are still some cases that the first way is used. My eth-filter works as a proxy and it needs something like a pipe as you said. One end of the pipe is the user program and the other is the device, so I need to create two port_info objects for the pipe. When the user program exits, the port for it can be destroyed by no-sender notification, and meanwhile, the other port should also be destroyed, and I have to call ports_destroy_right() (ports_deref_port() cannot work in this case because the port_info object still has PORT_HAS_SENDRIGHTS flag and the reference count is 1). If the port for the device isn't destroy with ports_destroy_right(), it might never be destroyed because its send right might always be kept by the device, and no-senders notification will never be generated.

So sometimes I have to destroy a port_info object with ports_port_deref() and sometimes with ports_destroy_right(). I have to use them carefully.

Another thing surprises me is that in some code of hurd, ports_port_deref() is used with ports_get_right() together. For example,
S_io_duplicate (struct sock_user *user,
       mach_port_t *newobject,
       mach_msg_type_name_t *newobject_type)
 struct sock_user *newuser;
 if (!user)
   return EOPNOTSUPP;

 __mutex_lock (&global_lock);
 newuser = make_sock_user (user->sock, user->isroot, 0, 0);
 *newobject = ports_get_right (newuser);
 *newobject_type = MACH_MSG_TYPE_MAKE_SEND;
 ports_port_deref (newuser);
 __mutex_unlock (&global_lock);
 return 0;
ports_port_deref() is need to be called here, otherwise the port_info object cannot be destroyed by ports_port_destroy() or no-senders notification later. The code is right here because ports_get_right() may be called on the port only once.
But sometimes we do need to call ports_get_right() on a port several times.
When should we call ports_port_deref() to decrease the reference count that is created by the first ports_get_right()?

For the second case, if notify is null, how can we receive the notification? The same question for the dead-name notification (the argument notify is also allowed to be null).
You can't.  The result is that you are cancelling the notification if
one is outstanding.
The mach manual doesn't tell that:(, or I understand it in a wrong way.

What was your understanding of it?
I thought, if notify is null, the no-senders notification can be generated, and it can be receive by the process someway.

Zheng Da

reply via email to

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