The following can be used as a template for a resource manager with multiple threads. (We've already seen a template that can be used for a single-threaded resource manager above in The resource manager library, when we discussed a /dev/null resource manager).
#include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <sys/iofunc.h> #include <sys/dispatch.h> #include <string.h> static resmgr_connect_funcs_t connect_func; static resmgr_io_funcs_t io_func; static iofunc_attr_t attr; int main (int argc, char **argv) { thread_pool_attr_t pool_attr; thread_pool_t *tpp; dispatch_t *dpp; resmgr_attr_t resmgr_attr; int id; if ((dpp = dispatch_create ()) == NULL) { fprintf (stderr, "%s: Unable to allocate dispatch context.\n", argv [0]); return (EXIT_FAILURE); } memset (&pool_attr, 0, sizeof (pool_attr)); pool_attr.handle = dpp; pool_attr.context_alloc = (void *) dispatch_context_alloc; pool_attr.block_func = (void *) dispatch_block; pool_attr.handler_func = (void *) dispatch_handler; pool_attr.context_free = (void *) dispatch_context_free; // 1) set up the number of threads that you want pool_attr.lo_water = 2; pool_attr.hi_water = 4; pool_attr.increment = 1; pool_attr.maximum = 50; if ((tpp = thread_pool_create (&pool_attr, POOL_FLAG_EXIT_SELF)) == NULL) { fprintf (stderr, "%s: Unable to initialize thread pool.\n", argv [0]); return (EXIT_FAILURE); } iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_func, _RESMGR_IO_NFUNCS, &io_func); iofunc_attr_init (&attr, S_IFNAM | 0777, 0, 0); // 2) override functions in "connect_func" and "io_func" as // required here memset (&resmgr_attr, 0, sizeof (resmgr_attr)); resmgr_attr.nparts_max = 1; resmgr_attr.msg_max_size = 2048; // 3) replace "/dev/whatever" with your device name if ((id = resmgr_attach (dpp, &resmgr_attr, "/dev/whatever", _FTYPE_ANY, 0, &connect_func, &io_func, &attr)) == -1) { fprintf (stderr, "%s: Unable to attach name.\n", argv [0]); return (EXIT_FAILURE); } // Never returns thread_pool_start (tpp); return (EXIT_SUCCESS); }
For more information about the dispatch interface (i.e., the dispatch_create() function), see the documentation in the QNX Neutrino C Library Reference.
io_func.io_read = my_io_read;
This overrides the POSIX-layer default function that got put into the table by iofunc_func_init() with a pointer to your function, my_io_read().