From 54c739ba7d9c8dd3e990f73805b52214022465ef Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 14 Sep 2012 23:50:32 +0200 Subject: Give an example of RPC path in the Hurd. --- rpc.mdwn | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'rpc.mdwn') diff --git a/rpc.mdwn b/rpc.mdwn index 176197dd..550b6632 100644 --- a/rpc.mdwn +++ b/rpc.mdwn @@ -11,6 +11,92 @@ License|/fdl]]."]]"""]] RPC stands for remote procedure call. +This is the basis for about everything in the Hurd. It is based on the Mach +RPC mechanism (the mach_msg system call). An RPC is made against a Mach port, +which is the gateway to the translator which will serve the RPC. Let's take for +instance the case of opening a file, and advancing (lseek) 10 bytes into it. The +user program will be something like: + + #include + + int main(void) { + int fd = open("test.txt", O_RDONLY); + lseek(fd, 10, SEEK_CUR); + } + +Both open and lseek are functions provided the libc, which make RPC calls. + +Open is a bit complex because it finds its way to the eventual translator, but +for a mere file on the root filesystem, what happens boils down to calling +the dir_lookup function against the root filesystem. This is an RPC from the fs +interface (see fs.defs). The implementation of the function is thus actually +generated using mig during the glibc build in RPC_dir_lookup.c. This generated +function essentially encodes the parameters into a data buffer, and makes a +mach_msg system call to send the buffer to the root filesystem port, with the +dir_lookup RPC id. + +The root filesystem, for instance ext2fs, was sitting in its main +loop (libdiskfs/init-first.c, master_thread_function()), which calls +ports_manage_port_operations_multithread(), which essentially simply keeps +making a mach_msg system call to receive a message, and calls the demuxer +on it, here the demuxer parameter, diskfs_demuxer. This demuxer calls the +demuxers for the various interfaces supported by ext2fs. These demuxers are +generated using mig during the hurd build. For instance, the fs interface +demuxer for diskfs, diskfs_fs_server, is in libdiskfs/fsServer.c. It simply +checks whether the RPC id is an fs interface ID, and if so uses the +diskfs_fs_server_routines array to know which function should be +called according to the RPC id. Here it's _Xdir_lookup which thus gets +called. This decodes the parameters from the message data buffer, and calls +diskfs_S_dir_lookup. + +diskfs_S_dir_lookup() in the ext2fs translator does stuff to check that the file +exists, etc. and eventually creates a new port, which will symbolize the file +being opened, and a structure to store information about it. It returns the +port to its caller, _Xdir_lookup, which puts it into the reply message data +buffer and returns. ports_manage_port_operations_multithread() then calls +mach_msg to send that port to the user program. + +The mach_msg call in the user program thus returns, returning the port, decoded +by dir_lookup. glibc creates a new fd entry in its fd table, and records the +port into it. It returns 0 (success). + +Lseek is simpler. The glibc implementation simply calls the __io_seek function +against the port of the fd. This is an RPC from the io interface (see io.defs). +As explained above, the implementation is thus in RPC_io_seek.c, it encodes +parameters and makes a mach_msg system call to the port of the fd with the +io_seek RPC id. + +In the root filesystem, it's now the demuxer for the io interface, +diskfs_io_server, which will recognize the RPC id, and call _Xio_seek, which +finds the data structure for the port, and calls diskfs_S_io_seek. The latter +simply modifies the data structure to account for the file position change, and +returns the new position. _Xio_seek encodes the position into the reply message, +which is sent back by ports_manage_port_operations_multithread() +through mach_msg. + +The mach_msg call in the user program thus returns the new offset, decoded by +__io_seek. lseek can then return it to the user application. + + +When hacking, one does *not* need to keep all that in mind. All one needs +to remember is that when the application program calls open(), the glibc +implementation actually calls dir_lookup(), which triggers a call to +diskfs_S_dir_lookup in the ext2fs translator. When the application program calls +lseek(), the glibc implementation calls __io_seek(), which triggers a call to +diskfs_S_io_seek in the ext2fs translator. And so on... + +Q&A + +Q: How do I know whether a function is an RPC or not? + +A: Simply grep the function name (without leading underscores) in the +/usr/include/hurd/*.defs files. + +Q: Why is it libdiskfs functions which get called? + +A: Because ext2fs is libdiskfs-based (see HURDLIBS = diskfs in ext2fs/Makefile). +Other translators are libnetfs-based or libtrivfs-based. grep for RPC names into +those according to what your translator is based on. # See Also -- cgit v1.2.3 From bc59282d66189f60a1c6ee41e6243bd42eb51569 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 15 Sep 2012 00:06:19 +0200 Subject: mention special files served by special translators --- rpc.mdwn | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'rpc.mdwn') diff --git a/rpc.mdwn b/rpc.mdwn index 550b6632..5adae2d4 100644 --- a/rpc.mdwn +++ b/rpc.mdwn @@ -98,6 +98,16 @@ A: Because ext2fs is libdiskfs-based (see HURDLIBS = diskfs in ext2fs/Makefile). Other translators are libnetfs-based or libtrivfs-based. grep for RPC names into those according to what your translator is based on. +Q: How do I know which translator the RPC gets into? + +A: Check the type of file whose port the RPC was made on. Most files are handled +by the translator which is mounted where the files are opened. Some special +files are handled by particular translators: + +* PF_LOCAL/PF_UNIX sockets are served by /hurd/pflocal, see [[hurd/networking]] +* PF_INET sockets are served by /hurd/pfinet, see [[hurd/networking]] +* named sockets (aka fifo) are served by /hurd/fifo + # See Also * [[Mach RPC|microkernel/mach/rpc]]s -- cgit v1.2.3 From 6db3a4601533dcdc97a77bf2aaa3c964b026070c Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 16 Sep 2012 17:57:59 +0200 Subject: explain that mig uses .defs to generate stubs --- rpc.mdwn | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'rpc.mdwn') diff --git a/rpc.mdwn b/rpc.mdwn index 5adae2d4..87f22593 100644 --- a/rpc.mdwn +++ b/rpc.mdwn @@ -30,10 +30,10 @@ Open is a bit complex because it finds its way to the eventual translator, but for a mere file on the root filesystem, what happens boils down to calling the dir_lookup function against the root filesystem. This is an RPC from the fs interface (see fs.defs). The implementation of the function is thus actually -generated using mig during the glibc build in RPC_dir_lookup.c. This generated -function essentially encodes the parameters into a data buffer, and makes a -mach_msg system call to send the buffer to the root filesystem port, with the -dir_lookup RPC id. +generated from the fs.defs file using mig during the glibc build in RPC_dir_lookup.c. +This generated function essentially encodes the parameters into +a data buffer, and makes a mach_msg system call to send the buffer to the root +filesystem port, with the dir_lookup RPC id. The root filesystem, for instance ext2fs, was sitting in its main loop (libdiskfs/init-first.c, master_thread_function()), which calls -- cgit v1.2.3