#include "msgqueue.h"

#include <iostream.h>

#include <sys/resource.h>  // PRIO_PROCESS

MsgQueue::MsgQueue() : fBreak(0)
{
    fMp = new unsigned char;
    pthread_create(&fThread, NULL, MapThread, this);
}

MsgQueue::~MsgQueue()
{
    pthread_cancel(fThread);
    delete fMp;
}

void *MsgQueue::Proc(int msg, void *mp)
{
    return NULL;
}

void *MsgQueue::MapThread(void *arg)
{
    pthread_detach(pthread_self());

    setpriority(PRIO_PROCESS, 0, -5);

    ((MsgQueue*)arg)->Thread();

    return NULL;
}

void MsgQueue::Thread()
{
    //
    // Tell the poster that processing is done
    //
    fStart = 0;
    while (!fBreak)
        usleep(1);

    while(1)
    {
        while (!fStart) usleep(1);
        fStart = 0;

        //
        // This makes sure that also a very fast Break() after
        // a PostMsg is processed correctly
        //
        pthread_mutex_lock(&fMuxMsg);
        fBreak = 0;
        pthread_mutex_unlock(&fMuxMsg);

        fRc=Proc(fMsg, fMp);
    }
}

void *MsgQueue::PostMsg(int msg, void *mp, int size)
{
    //
    // Lock Mutex, put msg on stack and tell thread to process message
    //

    //
    // Make sure that only one Proc() is running and can be stopped
    // stopped and the messages are processed serialized
    //
    pthread_mutex_lock(&fMuxMsg);

    //
    // Set break state and wait until Proc() returned (break state deleted)
    // This means, that a new command is invoked and (if forseen) the
    // running command should stop execution.
    //
    // This is some kind of controlled user break without using signals
    //
    fBreak = 1;

    //
    // copy return code from Proc() and set new message
    //
    void *rc = fRc;

    fMsg = msg;

    delete fMp;
    fMp = new unsigned char[size];

    memcpy(fMp, mp, size);

    //
    // Start Proc()
    //
    fStart = 1;
    pthread_mutex_unlock(&fMuxMsg);
    while (fStart) usleep(1);

    return rc;
}

