performance/message.c
///////////////////////////////////////////////////////////////////////////////
// Filename: message.c
///////////////////////////////////////////////////////////////////////////////
// Purpose: measure how long it takes to send/receive SYSV IPC messages
///////////////////////////////////////////////////////////////////////////////
// History:
// ========
//
// Date     Time     Name      Description   
// -------- -------- --------  ------------------------------------------------
// 96/03/02 02:30:17 muellerg: created
//
///////////////////////////////////////////////////////////////////////////////
// Feature test switches ///////////////////////////// Feature test switches //
    /* NONE */
// System headers /////////////////////////////////////////// System headers //
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
// Local headers ///////////////////////////////////////////// Local headers //
#include "../common.h"
// Macros /////////////////////////////////////////////////////////// Macros //
    /* NONE */
// File scope objects /////////////////////////////////// File scope objects //
const int NUMBER_REPEAT = 10000;        // how often for measurements
#ifndef MSGMAX
#define MSGMAX 2048
#endif
const int size_max = MSGMAX;            // maximum size of messages
const int MSG_MODE = 0666; // MSG_R | MSG_W;        // read and write
const int measure_max = 32;             // maximum number of measurements
// External variables, functions, and classes ///////////// External objects //
    /* NONE */
// Signal catching functions ///////////////////// Signal catching functions //
    /* NONE */
// Structures, unions, and class definitions /////////////////// Definitions //
    /* NONE */
// Functions and class implementation /// Functions and class implementation //
    /* NONE */
// Main /////////////////////////////////////////////////////////////// Main //
int
main(int argc, char *argv[])
{
    error.set_program_name(argv[0]);    
    int i;
    // do some performance measurements
    // check size
#ifdef linux
    if( size_max > MSGMAX)
        error.panic("MSGMAX too small, reduce size_max!");
#endif
    // create message queue
    int msgid = msgget(IPC_PRIVATE, MSG_MODE);
    if(msgid == -1)
        error.system("msgget error");
    synchronization_init();
    // get buffer which we can work
    struct msgbuf *buffer = (struct msgbuf *)malloc(size_max+4);
                             // +4 for long at beginning of buffer
    if(!buffer)
        error.panic("out of memory");
    // set type (priority)
    buffer->mtype = 1;      // has to be positive
    
    pid_t childpid;
    int size;
    childpid = fork();
    if(childpid == -1)
        error.system("fork error");
    if(childpid == 0)
    {
        // child, will receive data from parent
        for(size = 1; size <= size_max; size*=2)
        {
            for(i = 0; i < NUMBER_REPEAT; i++)
            {
                if( msgrcv(msgid, buffer, size_max+4, 0, 0) == -1)
                    error.system("msgrcv error");
            }
        }
        synchronization_signal_parent(getppid());
    }
    else
    {
        // parent, will send data to child
        measurement mes(argv[0], "write", measure_max);
        for(size = 1; size <= size_max; size*=2)
        {
            // start timer
            mes.start(size, NUMBER_REPEAT);
            for(i = 0; i < NUMBER_REPEAT; i++)
            {
                if( msgsnd(msgid, buffer, size, 0) == -1)
                    error.system("msgsnd error");
            }
            // end timer
            mes.end();
        }
        // wait till child has read all data
        synchronization_wait();
        mes.writeout_logfile(true, true, true);     // use cout as output file
        mes.writeout_plain_logfile(true, false);    // and write gnuplot data file
        // destroy message queue    
        if(msgctl(msgid, IPC_RMID, NULL) == -1)
            error.system("msgctl error");
    }
    if(buffer)
        free(buffer);
    return(EXIT_SUCCESS);
}