message_attach()

QNX SDP8.0C Library ReferenceAPIDeveloper

Attach a message range

Note:
You can use _IO_MSG instead of message_attach() to add security more easily. This is because the handler for an _IO_MSG is provided with an OCB, unlike a handler for message_attach(), allowing for permission checking.

Synopsis:

#include <sys/iofunc.h>
#include <sys/dispatch.h>

int message_attach( dispatch_t * dpp,
                    message_attr_t * attr,
                    int low,
                    int high,
                    int (* func) (
                           message_context_t * ctp,
                           int type,
                           unsigned flags,
                           void * handle ),
                    void * handle );

Arguments:

dpp
The dispatch handle, as returned by a successful call to dispatch_create().
attr
A pointer to a message_attr_t structure structure (see below) that lets you specify the attributes for the message, or NULL to use the default attributes.
low, high
The range of messages that you're interested in.
Note:
Although these arguments are of type int, message_attach() stores them as signed char for pulses and unsigned short for messages. Out-of-range values are rejected with EINVAL.
func
The function that you want to call when a message in the given range is received; see Handler function, below.
handle
An arbitrary handle that you want to associate with data for the defined message range. This handle is passed to func.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The message_attach() function attaches a handler to the message range defined by the message type [low, high] (i.e., an inclusive message range) for dispatch handle dpp.

Note:
  • The message_attach() will reject any attempt to register overlapping message or pulse ranges with EINVAL. Message types should be greater than _IO_MAX (defined in <sys/iomsg.h>).
  • Once you've called dispatch_context_alloc(), don't call message_attach() or resmgr_attach() specifying a larger maximum message size or a larger number of message parts for the same dispatch handle. These functions indicate an error of EINVAL if this happens.

When a message with a type in that range is received, dispatch_handler() calls the user-supplied function func. You can also use the same function with pulse_attach(). By examining ctp->rcvid, func can determine whether a pulse or message was received.

This function is responsible for doing any specific work needed to handle the message pointed to by ctp->msg. The handle passed to the function is the handle initially passed to message_attach().

message_attr_t structure

The attr argument is a pointer to a message_attr_t structure:

typedef struct _message_attr {
   unsigned                 flags;
   unsigned                 nparts_max;
   size_t                   msg_max_size;
   unsigned                 reserved[5];
} message_attr_t;

You can use this structure to specify:

  • the maximum message size to be received (the context allocated must be at least big enough to contain a message of that size)
  • the maximum number of iovs to reserve in the message_context_t structure (attr->nparts_max)
  • various flags:

    Currently, the following attr->flags are defined:

    MSG_FLAG_ALLOC_PULSE
    Request registration for a pulse that has not previously been registered for this dpp. Only valid if MSG_FLAG_TYPE_PULSE is also set. If you set MSG_FLAG_ALLOC_PULSE, the low and high parameters are ignored.
    MSG_FLAG_CROSS_ENDIAN
    Allow the server to receive messages from clients on machines with different native endian formats.
    MSG_FLAG_DEFAULT_FUNC
    Call this function if no other match is found, in this case, low and high are ignored. This overrides the default behavior of dispatch_handler() which is to return MsgError (ENOSYS) to the sender when an unknown message is received.
    MSG_FLAG_TIMEOUT_FUNC
    Call this function if a timeout has occured; in this case low and high are ignored. This overrides the default behaviour of dispatch_handler() which is to silently ignore timeouts.
    MSG_FLAG_TYPE_PULSE
    Register a range [low, high] of pulse codes rather than of message types.
Note:
You may not use more than one of MSG_FLAG_TIMEOUT_FUNC, MSG_FLAG_DEFAULT_FUNC, or MSG_FLAG_TYPE_PULSE in the same call to message_attach().

Handler function

The user-supplied function func is called when a message in the defined range is received. This function is passed the message context ctp, in which the message was received, the message type, and the handle (the one passed to message_attach()). Currently, the argument flags is reserved. Your function should return 0; other return values are reserved.

Note:
Unlike I/O function callouts in a resource manager, there is no automatic client handling based on return value. You must explicitly unblock your client with a call to MsgReply*() or MsgError().

Here's a brief description of the context pointer fields:

ctp->rcvid
The receive ID of the message.
ctp->msg
A pointer to the message.
ctp->info
Data from a _msg_info structure.

The message_context_t structure is identical to resmgr_context_t.

Returns:

Zero on success, or -1 on failure (errno is set).

Errors:

EINVAL
One of the following occurred:
  • A message or pulse type is out of range.
  • You've already called dispatch_context_alloc() for this dpp, and you've now tried to increase the maximum message size or the number of message parts.
  • You've already called dispatch_context_alloc() for a dpp with DISPATCH_FLAG_NOLOCK, and you've now tried to add more message handlers.
  • The parameter attr.nparts_max exceeded 524288.
  • MSG_FLAG_ALLOC_PULSE was set without setting MSG_FLAG_TYPE_PULSE.
  • More than one of the flags MSG_FLAG_TYPE_PULSE, MSG_FLAG_TIMEOUT_FUNC, and MSG_FLAG_DEFAULT_FUNC were set.
ENOMEM
Insufficient memory to attach message type.

Examples:

In this example, we create a resource manager where we attach to a private message range and attach a pulse, which is then used as a timer event:

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

#define THREAD_POOL_PARAM_T     dispatch_context_t
#include <sys/iofunc.h>
#include <sys/dispatch.h>

static resmgr_connect_funcs_t   connect_func;
static resmgr_io_funcs_t        io_func;
static iofunc_attr_t            attr;

int
timer_tick(message_context_t *ctp, int type, 
           unsigned flags, void *handle) {

    union sigval       value = ctp->msg->pulse.value;
    /* Do some useful work on every timer firing... */
    printf("received timer event, value %d\n", value.sival_int);
    return 0;
}

int
message_handler(message_context_t *ctp, int type,
                unsigned flags, void *handle ) {
    printf("received private message, type %d\n", type);
    return 0;
}

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;
    int                   timer_id;
    struct sigevent       event;
    struct _itimer        itime;


    if((dpp = dispatch_create()) == NULL) {
        fprintf(stderr, 
                "%s: Unable to allocate dispatch handle.\n",
                argv[0]);
        return EXIT_FAILURE;
    }

    memset(&pool_attr, 0, sizeof pool_attr);
    pool_attr.handle = dpp;
    /* We are doing resmgr and pulse-type attaches */
    pool_attr.context_alloc = dispatch_context_alloc;
    pool_attr.block_func = dispatch_block;
    pool_attr.unblock_func = dispatch_unblock;
    pool_attr.handler_func = dispatch_handler;
    pool_attr.context_free = dispatch_context_free;
    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);

    /* You should restrict the permissions according to what you want other
       processes and users to be able to do with your resource manager. */

    iofunc_attr_init(&attr, S_IFNAM | 0660, 0, 0);
        
    memset(&resmgr_attr, 0, sizeof resmgr_attr);
    resmgr_attr.nparts_max = 1;
    resmgr_attr.msg_max_size = 2048;

    if((id = resmgr_attach(dpp, &resmgr_attr, "/dev/mynull", 
                 _FTYPE_ANY, 0,
                 &connect_func, &io_func, &attr)) == -1) {
        fprintf(stderr, "%s: Unable to attach name.\n", argv[0]);
        return EXIT_FAILURE;
    }

    /*
     We want to handle our own private messages, of type 
     0x5000 to 0x5fff
    */
    if(message_attach(dpp, NULL, 0x5000, 0x5fff, 
                      &message_handler, NULL) == -1) {
        fprintf(stderr, 
           "Unable to attach to private message range.\n");
        return EXIT_FAILURE;
    }

    /* Initialize an event structure and attach a pulse to it */
    if((event.sigev_code = pulse_attach(dpp, 
                              MSG_FLAG_ALLOC_PULSE, 0,
                              &timer_tick, NULL)) == -1) {
        fprintf(stderr, "Unable to attach timer pulse.\n");
        return EXIT_FAILURE;
    }

    /* Connect to our channel */
    if((event.sigev_coid = message_connect(dpp, 
                              MSG_FLAG_SIDE_CHANNEL)) == -1) {
        fprintf(stderr, "Unable to attach to channel.\n");
        return EXIT_FAILURE;
    }

    event.sigev_notify = SIGEV_PULSE;
    event.sigev_priority = -1;
    /*
     We could create several timers and use different 
     sigev values for each
    */
    event.sigev_value.sival_int = 0;

    if((timer_id = TimerCreate(CLOCK_MONOTONIC, &event)) == -1) {;
        fprintf(stderr, 
                "Unable to attach channel and connection.\n");
        return EXIT_FAILURE;
    }

    /* And now set up our timer to fire every second */
    itime.nsec = 1000000000;
    itime.interval_nsec = 1000000000;
    TimerSettime(timer_id, 0, &itime, NULL);

    /* Never returns */
    thread_pool_start(tpp);
    return EXIT_SUCCESS;
}

For more examples using the dispatch interface, see dispatch_create(), resmgr_attach(), and thread_pool_create().

Classification:

QNX OS

Safety:
Cancellation pointNo
Signal handlerNo
ThreadYes
Page updated: