Putting in your own functions
When designing your very first resource manager, you'll most likely want to
take an incremental design approach.
It can be very frustrating to write thousands of lines of code only to
run into a fundamental misunderstanding and then having to
make the ugly decision of whether to try to kludge (er, I mean fix
)
all that code, or scrap it and start from scratch.
The recommended approach for getting things running is to use the iofunc_func_init() POSIX-layer default initializer function to fill the connect and I/O tables with the POSIX-layer default functions. This means that you can literally write your initial cut of your resource manager as we did above, in a few function calls.
Which function you'll want to implement first really depends on what kind of resource manager
you're writing. If it's a filesystem resource manager where you're taking over a mountpoint
and everything below it, you'll most likely be best off starting with the open connect function handler. (The
_RESMGR_FLAG_DIR flag indicates that the pathname should be treated as a directory.)
On the other hand, if it's a discretely manifested (device) resource manager that does
traditional
I/O operations (i.e., you primarily access it with client calls like
read() and write()), then the best place to start would be the
read I/O function handler and/or
write I/O function handler.
The third possibility is that it's a discretely manifested resource manager that doesn't do traditional I/O operations, but instead relies on devctl() or ioctl() client calls to perform the majority of its functionality. In that case, you'd start at the device control I/O function handler.
I'm here in the io_open!, and then
do whatever should be done,you're going to have an easy time of it. Here's a portion of a resource manager that takes over the open connect function handler:
// forward reference
int io_open (resmgr_context_t *, io_open_t *,
RESMGR_HANDLE_T *, void *);
int main ()
{
// everything as before, in the /dev/null example
// except after this line:
iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &cfuncs,
_RESMGR_IO_NFUNCS, &ifuncs);
// add the following to gain control:
cfuncs.open = io_open;
int io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void *extra)
{
printf ("I'm here in the io_open!\n");
return (iofunc_open_default (ctp, msg, handle, extra));
}
In this manner, you're still using the default POSIX-layer iofunc_open_default() handler, but you've also gained control to do a printf().
Obviously, you could do this for the read I/O function handler, write I/O function handler, and device control I/O function handler as well as any others that have POSIX-layer default functions. In fact, this is a really good idea, because it shows you that the client really is calling your resource manager as expected.