[Previous]
[Contents]
[Next]

Sendmx()

send a message to another process

Synopsis:

#include <sys/kernel.h>
#include <sys/sendmx.h>
int Sendmx( pid_t pid,
            unsigned sparts, unsigned rparts,
            struct _mxfer_entry *smsg,
            struct _mxfer_entry *rmsg );

Description:

The kernel function Sendmx() sends a message, taken from the array of buffers pointed to by smsg, to the process identified by pid. Any reply is placed in the array of buffers pointed to by rmsg. The number of elements in the send array is given by sparts while the number of elements in the receive array is given by rparts. The size of these arrays must not exceed _QNX_MXTAB_LEN (defined in <limits.h>).

The number of bytes transferred is the minimum of that specified by both the sender and the receiver. The send data isn't allowed to overflow the receive buffer area provided by the receiver, nor can the receiver read past the end of the sender's buffer.

After sending the message, your task becomes blocked, waiting for a reply. If the receiving process is receive-blocked and ready to receive the message, the transfer of data into its address space occurs immediately, the receiver is unblocked and made ready to run, and your process goes into the REPLY BLOCKED state. If the receiver isn't ready to receive your message, you become SEND BLOCKED, and are placed in a queue (perhaps with other processes), and the transfer doesn't occur until the receiving task does a receive that satisfies the send.

If you specify a process that doesn't exist or dies while you're BLOCKED on it, Sendmx() returns -1 and errno is set to ESRCH.

Sendmx() may be interrupted by a signal, in which case it returns -1 and errno is set to EINTR.

It's quite common to send two-part messages consisting of a fixed header and a buffer of data. The Sendmx() gathers the data from the send list into a logical contiguous message and transfers it to the receiver. The receiver need not specify the same number or size of buffers. The data is laid down, filling each entry as required. The reply list entries should be large enough to hold all the replied data.


Note: Avoid stuffing each _mxfer_entry directly. Instead use the _setmx() macro to stuff each entry. This will make your code portable across 16- and 32-bit platforms.

Returns:

0
Success.
-1
An error occurred. errno is set to indicate the error.

Errors:

EAGAIN
No more Process Manager to Network Manager queue packets available.
EDSTFAULT
Destination would fault on a message pass.
EFAULT
In order to complete the message exchange, the current process would have incurred a segment violation. Your buffer(s) may be invalid or too small.
EHOSTUNREACH
The destination node is not in the net mapping, or a physical I/O error occurred trying to communicate to the node.
EINTR
Call interrupted by a signal.
EINVAL
The virtual circuit buffer can't be grown due to an invalid message length.
ENOMEM
The virtual circuit buffer can't be grown because no memory is available.
ESRCH
The process pid doesn't exist.

Examples:

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/sendmx.h>

/* Define all messages that are sent and replied */

#define WRDATA   1
#define STOP     2

/* The sizeof(type) == sizeof(status) in all messages */
struct msg_wrdata {
  short unsigned type;
  short unsigned nbytes;
  } ;

struct msg_wrdata_reply {
  short unsigned status;
  } ;

struct msg_stop {
  short unsigned type;
  } ;

struct msg_stop_reply {
  short unsigned status;
  } ;

/* Define the union of all messages */
union {
  short unsigned           type;
  short unsigned           status;
  struct msg_wrdata        wrdata;
  struct msg_wrdata_reply  wrdata_reply;
  struct msg_stop          stop;
  struct msg_stop_reply    stop_reply;
  } msg;

char buffer[1000];

void main( void )
  {
    pid_t child;

    if( child = fork() )
      client( child );
    else
      server();

    exit( EXIT_SUCCESS );
  }

void server()
  {
    pid_t pid;
    unsigned nbytes;
    struct _mxfer_entry mx;

    for( ;; ) {
      _setmx( &mx, &msg, sizeof msg);
      pid = Receivemx( 0, 1, &mx );
      nbytes = sizeof( msg.status );

      switch( msg.type ) {
        case WRDATA: 
          printf( "Server WRDATA %d ", msg.wrdata.nbytes );
          /*
           * For speed you could have the receive read the
           * data in one gulp rather than invoke Readmsgmx.
           * You would need a different structure for the
           * server which included the max number of bytes
           * of data you wished to read.
           */
          _setmx( &mx, buffer, msg.wrdata.nbytes);
          Readmsgmx( pid,
            sizeof( msg.wrdata ), 
            1, &mx );
          fwrite( buffer, msg.wrdata.nbytes, 1, stdout );
          fflush( stdout );
          msg.wrdata_reply.status = EOK;
          break;

        case STOP: 
          /*
           * Note that for this example we terminate without
           * replying to show that the client Send unblocks.
           */
          printf( "Server STOP\n" );
          fflush( stdout );
          return;

        default: 
          printf( "Server unknown message %04X\n",
            msg.type );
          msg.status = ENOSYS;
          break;
      }

      _setmx( &mx, &msg, nbytes);
      Replymx( pid, 1, &mx );
    }
  }

void client( child )
pid_t child;
  {
    int r;

    printf( "Client WRDATA\n" );
    r = wrdata( child, "Hello world!\n", 13 );
    printf( "Client WRDATA %d %d\n", r, errno );

    printf( "Client STOP\n" );
    r = stop( child );
    printf( "Client STOP %d %d\n", r, errno );
  }

int wrdata( pid, buf, nbytes )
pid_t          pid;
char          *buf;
unsigned int   nbytes;
  {
    union
    {
      struct msg_wrdata        s;
      struct msg_wrdata_reply  r;
    }        wmsg;
    struct _mxfer_entry mx[2];

    /* Set up the message header. */
    wmsg.s.type    = WRDATA;
    wmsg.s.nbytes  = nbytes;
    _setmx( &mx[0], &wmsg, sizeof( wmsg.s ) );

    /* Setup the message data description. */
    _setmx( &mx[1], buf, nbytes );

    if( Sendmx( pid, 2, 1, &mx, &mx ) == -1 )
      return( -1 );

    if( wmsg.r.status != EOK ) {
      errno = wmsg.r.status;
      return( -1 );
    }
    return( nbytes );
  }

int stop( pid )
pid_t pid;
  {
    union {
      struct msg_stop        s;
      struct msg_stop_reply  r;
      } smsg;
    struct _mxfer_entry mx[2];

    smsg.s.type = STOP;
    _setmx( mx, &smsg.s, sizeof(smsg.s) );
    _setmx( mx + 1, &smsg.r, sizeof(smsg.r) );
    if( Sendmx( pid, 1, 1, mx, mx + 1) == -1 )
      return( -1 );

    if( smsg.r.status != EOK ) {
      errno = smsg.r.status;
      return( -1 );
    }

    return( 0 );
  }

Classification:

QNX

Safety:
Interrupt handler No
Signal handler Yes, but modifies errno
Thread Yes

Caveats:

Sendmx() is a macro.

See also:

Creceive(), Creceivemx(), errno, Receive(), Receivemx(), Reply(), Replymx(), Readmsg(), Readmsgmx(), Send(), Sendfd(), Sendfdmx(), Writemsg(), Writemsgmx(), Trigger()


[Previous]
[Contents]
[Next]