bug-hurd
[Top][All Lists]
Advanced

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

Re: Some questions about libports and notification of ports


From: Da Zheng
Subject: Re: Some questions about libports and notification of ports
Date: Sat, 23 Aug 2008 13:25:46 +0200
User-agent: Thunderbird 2.0.0.16 (Macintosh/20080707)

Thomas Bushnell BSG wrote:
> struct port_info *foo;
> ports_create_port(portclass, bucket, sizeof(*foo), &foo);
> ....
> ports_port_deref(foo);      // ports_port_destroy(foo) doesn't work here.

It works just fine, *if your intention is to delete the receive right*--
a rare and unusual thing.
I have already done what your suggested, and when I look at my code again, I find it is unnecessary to do it.

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.

Yes, this is correct.

When the user program exits, the port for it can be destroyed by no-sender notification,

You are thinking "how can we destroy the port", which is the wrong
question.  But yes, when the user has had this event, the port can be
destroyed.
I have to make sure every ports has been destroyed so when the translator exits, it can check if there are still users.
and meanwhile, the other port should also be destroyed,

WHY?  What possible value is there in destroying the other port?

Notice, for example, the way pipes work.  Suppose the reader dies, and
there are no readers.  We do not destroy the writer's port.  Heaven's
no!  Instead, we accept requests on it, just as normal, *and we return
EPIPE*.

We don't need to destroy the port, nor should we.  It still has users.
Yes, their requests may fail, but that doesn't mean there aren't still
people holding send rights who are entitled to see the protocol
continue.
The reason is that one end is the user program, but the other is the device (that isn't the regular user).

OK, maybe I should make the things more clear.
I'm writing a filter translator called eth-filter whose function is to forward and filter the packet between the network device and the user program such as pfinet,
so eth-filter needs to build a "pipe" for them.
eth-filter needs two ports, so it can get the packet from the user program and the network device.

The user program can exit, it's quite normal, but the device cannot.
so the network device always holds the send right to the port of eth-filter. Let's see what the result will be. The device keeps sending the packet to the eth-filter and eth-filter should forward it to the user program.
But the user program doesn't exit any more.
In this case, eth-filter must tell the device: the user program doesn't exist, so please don't send me any packets that is to the user program. The only way I can find is to destroy the port for the device. I think it's the way of operating the network device. device_close() doesn't work. After the port is destroyed, the device will find the send right is a dead name and stop sending the packets (that should be to the user program) to eth-filter.
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.

I'm confused.  How does a device hold send rights to your port?  Mach devices don't work 
that way.  What is this "device" that is holding a send right?
Sorry, I forget to mention it's a network device.
When we set the filter with device_set_filter, we have to give the network device a send right, so when the network device gets a packet, it can deliver it with the send right.
Another thing surprises me is that in some code of hurd, ports_port_deref() is used with ports_get_right() together. For example,
error_t
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;
}

When we create the port_info, it has one reference, held by the variable
NEWUSER.  Then we call ports_get_right and create a send right.  Now
there are two references, one held by NEWUSER, and one held by the
outstanding send rights.  Then we release the references held by
NEWUSER, and return.

At the end of the function, the reference count is 1, and there is one
reference outstanding (the send rights).

You are busy thinking "how can we get things destroyed", in a way that
suggests you don't understand what reference counting is for.
Actually I'm thinking how I can manage the reference count correctly, so the port_info object can be destroyed at last when it's not needed.
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.

Huh? You may call ports_get_right on a port as many times as you can.
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()?

In the code above, we aren't dropping the reference from
ports_get_right, that would be crazy.  We are *creating* that reference.
We are dropping the reference that was created by make_sock_user.

All outstanding send rights on a port share a single reference.
It's exactly why I think it's difficult to operate.
ports_get_right() can be called several times. Let's think about the sequence as follow (it's not in the same function):
struct port_info *port;
ports_create_port(..., &port);
...
ports_get_right(port);
...
ports_get_right(port);
...
ports_get_right(port);
...
When should I call ports_port_deref()? after the first time of calling ports_get_right()? or after the last time? If it's the first time, then why ports_get_right() should increase the reference count?
If it's the last time, it's difficult to find out that it IS the last time.

Zheng Da




reply via email to

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