#include "msgqueue.h" #include #include // usleep #include // PRIO_PROCESS #undef DEBUG using namespace std; // -------------------------------------------------------------------------- // // This creates the Message queue thread, // MsgQueue::MsgQueue() : fBreak(0) { fMp = new unsigned char; pthread_create(&fThread, NULL, MapThread, this); } // -------------------------------------------------------------------------- // // The destructor terminates the thread. // MsgQueue::~MsgQueue() { #ifdef DEBUG cout << "~MsgQueue::MsgQueue" << endl; #endif pthread_cancel(fThread); delete (unsigned char*)fMp; } // -------------------------------------------------------------------------- // // This is the function which must be overloaded. // Here you process the messages. mp is a pointer which you can // specify when posting the message. // // If a new messages is posted while the old one is not yet // finished the fBreak flag is set. Please test this flag with // Break() and try to finish (or stop) the current action as soon // as possible. This makes sure, that before a new action is started // the old action can be finished correctly by the user. // void *MsgQueue::Proc(int msg, void *mp) { return NULL; } // -------------------------------------------------------------------------- // // This is the thread mapper. // void *MsgQueue::MapThread(void *arg) { pthread_detach(pthread_self()); setpriority(PRIO_PROCESS, 0, -5); ((MsgQueue*)arg)->Thread(); return NULL; } // -------------------------------------------------------------------------- // // This is the thread which handles the processing. // As soon as a message is posted the fBreak flag is set (see PostMsg) // And as soon as the current action is finished the new action is executed // in this thread. This makes sure, that the calling program is not stalled. // 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 // if (fMuxMsg.Lock()==13) cout << "MsgQueue::Thread - mutex is already locked by this thread." << endl; fBreak = 0; if (fMuxMsg.UnLock()==13) cout << "MsgQueue::Thread - tried to unlock mutex locked by other thread." << endl; #ifdef DEBUG cout << "MsgQueue::Thread: Processing Msg 0x" << hex << fMsg << endl; #endif // --- bool quit = fMsg==WM_QUIT; fRc=Proc(fMsg, fMp); #ifdef DEBUG cout << "MsgQueue::PostMsg: Msg 0x" << hex << fMsg << " processed (rc=" << fRc << ")" << endl; #endif // --- if (quit) // --- break; } // --- fStart = 0; // --- cout << "WM_QUIT posted... leaving msg queue." << endl; } // -------------------------------------------------------------------------- // // Use this function to post a message. // mp can be a pointer to a data structure. size should be the size of it. // size bytes of this structure are copied and a pointer to the copy // is forwarded to the Proc function. // 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 // #ifdef DEBUG cout << "MsgQueue::PostMsg: Locking MsgQueue mutex..." << flush; #endif if (fMuxMsg.Lock()==13) cout << "MsgQueue::PostMsg - mutex is already locked by this thread." << endl; #ifdef DEBUG cout << "done." << endl; #endif // // 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 // /**** NEW 20/01/2003 ****/ if (fBreak) { if (fMuxMsg.UnLock()==13) cout << "MsgQueue::PostMsg - tried to unlock mutex locked by other thread." << endl; #ifdef DEBUG cout << "------------> MsgQueue::PostMsg: Proc still pending... Message IGNORED." << endl; #endif return NULL; } /**** NEW 20/01/2003 ****/ #ifdef DEBUG cout << "MsgQueue::PostMsg: ---> Break <---" << endl; #endif fBreak = 1; // // copy return code from Proc() and set new message // void *rc = fRc; fMsg = msg; delete (unsigned char*)fMp; fMp = new unsigned char[size]; memcpy(fMp, mp, size); // // Start Proc() // #ifdef DEBUG cout << "MsgQueue::PostMsg: Releasing MsgQueue mutex..." << flush; #endif fStart = 1; if (fMuxMsg.UnLock()==13) cout << "MsgQueue::PostMsg - tried to unlock mutex locked by other thread." << endl; #ifdef DEBUG cout << "done." << endl; #endif /* * **** NEW 20/01/2003 *** * * This can halt the main thread, because it is waiting until * Proc has finished its execution which can take a while * * A side effect is, because you don't wait for the end of * the execution of Proc, if a new message is posted fBreak * and fStart is set again, new values are copied to fMsg and * fMp (FIXME? Harmefull?) and the message is not processed at all. */ //while (fStart) // usleep(1); #ifdef DEBUG cout << "MsgQueue::PostMsg: Returning rc = " << hex << rc << endl; #endif return rc; } /* Start positioning. MsgQueue::PostMsg: Locking MsgQueue mutex...done. MsgQueue::PostMsg: ---> Break <--- +++++ MsgQueue::PostMsg: Releasing MsgQueue mutex...done. ===== MsgQueue::PostMsg: Returning rc = (nil) PostMsg (WM_Position) returned. done. Stopping movement...Movement stopped. WM_Position: done. (return 0x7777) MsgQueue::PostMsg: Msg 0x1001 processed (rc=0x7777) MsgQueue::Thread: Processing Msg 0x1001 WM_Position: start. Positioning to Target... */ /* Start positioning. MsgQueue::PostMsg: Locking MsgQueue mutex...done. MsgQueue::PostMsg: ---> Break <--- +++++ MsgQueue::PostMsg: Releasing MsgQueue mutex...done. done. Stopping movement...Movement stopped. WM_Position: done. (return 0x7777) MsgQueue::PostMsg: Msg 0x1001 processed (rc=0x7777) MsgQueue::Thread: Processing Msg 0x1001 WM_Position: start. Positioning to Target... ===== MsgQueue::PostMsg: Returning rc = (nil) */