An alternative to dumping code into the kernel, is
to leave the stub in the users piece itself.
But have a structured mechanism, for communication between the
client stub and the kernel. And that structured mechanism is
a shared descriptor. And the shared descriptor, is a
way by a which the sub can describe to the
kernel that here is some stuff sitting in the
user space. And I am going to tell you how exactly
you can extract this information, from the user space
and construct it into this buffer for transmission on
the wire. Recall what I told you earlier and
that is the kernel has no idea, of the semantics
of this call and therefore, it has no knowledge
of the actual arguments. The data structures that are
being used in the call. So what we're going to
do is use the shared descriptor as a vehicle for
the stub to communicate to the kernel the data structures
that need to be passed. So for instance, let's say
that the argument for the call has four parameters. Then
this descriptor has four entries, and each entry is saying,
this is a starting point of a particular Data item,
and this is the length of the data item. This
is the starting point of the second data item, and
this is the length of the data item. Third data
item, fourth data item. Kernel doesn't have to know the semantics
of these data items. All it needs to know is, what
is the starting address for a particular data item, and what
is the length of the data item. That's all it needs to
know. And this is the descriptor that. Allows the stub to
inform the kernel about the arguments, how many arguments there are
and what are the size of each argument. It doesn't have
to tell the kernel, oh, here is an integer, here's a floating
point, here's an array. No, none of that. All
that the stub is doing is, it's saying. Here is
the starting address for an argument, and here is the
length of that argument. Because usually data structures are organized
contiguously, so if you have a, an integer, it is
occupying full contiguous bytes and memory. If you have floating
point number, it is occupying some number of contiguous bytes
in memory, and therefore. What the stub is doing is,
is creating the shared descriptor that is providing the
information of the kernel in the layer of the
arguments on the stack, and once the layer of
the arguments and the stack are known to the kernel,
then the kernel can use these contiguous data items.
That are living on the stack, describe the shared
descriptor, and create a contiguous packet in its internal
buffer. That's a second way you can do, in order
to reduce the number of copies from two to
one. So in both cases, what we have done
is either the first approach of pushing the client
stub into the kernel or the second approach of having
a shared descriptor between the user stub, which is
living. In user space and the kernel in order to
describe the layout of the data structures, that need
to be assembled into a data packet by the kernel
using the shared descriptor. Both of these allow
us to reduce the number of copies from
three down to two. Either the one copy
that is happening Going from this stack into the
kernel buffer and this second copy, as I
said, is unavailable if the network controller is
requiring DMA to be done from the system
memory into its internal buffer before the bits can
be pushed out of the wire. So that's the
first source of overhead, these are techniques that we
have looked at. Two differnet techniquest for reducign the
copying overhead that is the dominate part of marshalling
the arguments. And this happens on both sides. It
happens when the client has to push the arguments
to the server side. And it happens again on
the server side when the server has to push
the results back to the client. So the marshalling is happening on both
ends, and for both ends we can Use this technique of using a
shared descriptor or pushing the clients dub or the service dub into the
kernel in order to reduce the number of copies from two down to one.