Using the helper functions

Updated: April 19, 2023

The default functions make use of helper functions. These functions can't be placed directly into the connect or I/O jump tables, but they do perform the bulk of the work.

Here's the source for the iofunc_chmod_default() function:

int
iofunc_chmod_default (resmgr_context_t *ctp, io_chmod_t *msg,
                      iofunc_ocb_t *ocb)
{
    return (iofunc_chmod (ctp, msg, ocb, ocb -> attr));
}

Notice how the iofunc_chmod() helper function performs all the work for the iofunc_chmod_default() default handler. This is typical for the simple functions.

The iofunc_stat_default() default handler is a more interesting case:

int iofunc_stat_default(resmgr_context_t *ctp, io_stat_t *msg, iofunc_ocb_t *ocb) {
    unsigned        len;

    /*  Update stale time fields (ctime, mtime, atime) this OCB. */
    (void)iofunc_time_update(ocb->attr);

    unsigned format = msg->i.format;
    int const status = iofunc_stat_format(ctp, ocb->attr, &format, &msg->o, &len);
    if(status != EOK) {
        return(status);
    }
    _RESMGR_STATUS(ctp, (long)format);
    return _RESMGR_PTR(ctp, &msg->o, len);
}

This handler calls two helper routines. First it calls iofunc_time_update() to ensure that all of the time fields (atime, ctime and mtime) are up to date. Then it calls iofunc_stat_format(), which builds the reply. The default handler then sets the status (to be returned via MsgReply) to the form of the status information. Finally, the default function builds a pointer in the ctp structure and returns -1, to indicate to the resource manager library that it should return one part from the ctp->iov structure to the client.

The most complicated handling is done by the iofunc_open_default() handler:

int
iofunc_open_default (resmgr_context_t *ctp, io_open_t *msg,
                     iofunc_attr_t *attr, void *extra)
{
    int     status;

    iofunc_attr_lock (attr);

    if ((status = iofunc_open (ctp, msg, attr, 0, 0)) != EOK) {
        iofunc_attr_unlock (attr);
        return (status);
    }

    if ((status = iofunc_ocb_attach (ctp, msg, 0, attr, 0)) 
        != EOK) {
        iofunc_attr_unlock (attr);
        return (status);
    }

    iofunc_attr_unlock (attr);
    return (EOK);
}

This handler calls four helper functions:

  1. It calls iofunc_attr_lock() to lock the attribute structure so that it has exclusive access to it (it's going to be updating things like the counters, so we need to make sure no one else is doing that at the same time).
  2. It then calls the helper function iofunc_open(), which does the actual verification of the permissions.
  3. Next it calls iofunc_ocb_attach() to bind an OCB to this request, so that it will get automatically passed to all of the I/O functions later.
  4. Finally, it calls iofunc_attr_unlock() to release the lock on the attribute structure.