| Thanks.
At 19:49 13/01/2006, you wrote:
>Hi all, this is the base class for my multi user client-server host thing.
>All modules in the app inherit from this class and live in their own
>pthreads, including gui window, controller, csound, and midi i/o. They
>communicate with each other using the queues in the base class and all
>communication uses the generic message type. I would appreciate comments
>from those more experienced than me if you have time. Thanks. Will post
>more as they get cleaned up and ready for others to look at.
>
>Iain
>
>
>// flow_module.h, Iain Duncan, 2006. iainduncan@telus.net
>// declarations of flow_module messages and base class
>// any suggestions, comments, and criticisms welcom, please email me
>
>// we define debug here because all .cpp files include this header
>// defining debug causes all the queue modules to print to console when
>they are dealing with messages
>//#define DEBUG
>
>#include "/csound5/H/csound.h"
>#include
>#include
>#include
>
>#ifndef FLOW_MODULE_H
>#define FLOW_MODULE_H
>
>using namespace std;
>
>// all possible message types go here, more may be added later
>// keep this order
>enum Message_Type { COMMAND, SETTING, BUTTON, KNOB, KEY, MIDI, OSC,
>SERIAL, CS_DATA, VIEW_REQ, DATA_REQ, DATA_RES, NONE };
>
>// the generic message structure, all modules communicate with this structure
>struct Flow_Message {
> void *orig; // void base pointer to the
> originating module object
> Message_Type type;
> int slot_1; // if midi: chan & source. if
> widget: row for this widget type
> int slot_2; // corresponds usually with cc
> num, note num, or paramater
> MYFLT slot_3; // actual value we are after for csound,
> uses csound MYFLT
>};
>
>// node for input queues in modules
>struct Flow_Message_Node {
> Flow_Message msg;
> Flow_Message_Node *next_node;
>};
>
>
>// declaration of the base class, Flow_Module
>// all Flow modules inherit from this class
>class Flow_Module
>{
> public:
> // a string to identify the module object to aid in message
> tracing for debugging
> string mod_id;
>
> Flow_Module();
> Flow_Module( string str_id );
> ~Flow_Module();
>
> // methods to push and pop messages off the queues
> // priority arg is there for low and high priority queues ( 0 =
> high, 1 = low, defaults to high )
> // these return the length of the queue after push or pop, -1 if
> was empty on pop
> int push_msg( Flow_Message push_msg, int queue=0 );
> int pop_msg( Flow_Message *pop_msg, int queue=0 );
> int pop_msg_sleep( Flow_Message *pop_msg, int queue=0 );
>
> private:
> // for now we are making all modules with 2 queues, this can
> easily be changes later
> static const int num_queues = 2;
>
> // data members for internal queue handling
> int q_length[ num_queues ];
> Flow_Message_Node *q_front_node[ num_queues ];
> Flow_Message_Node *q_end_node[ num_queues ];
> pthread_mutex_t q_mtx[ num_queues ];
> pthread_cond_t q_cond[ num_queues ];
>
>};
>
>#endif
>
>
>// flow_module.cpp, Iain Duncan, 2006. iainduncan@telus.net
>// definitions of flow_module base class
>// any suggestions, comments, and criticisms welcom, please email me
>
>#include "/csound5/H/csound.h"
>#include "flow_module.h"
>#include
>#include
>#include
>#include
>
>using namespace std;
>
>// constructor to initialize base settings and queues
>Flow_Module::Flow_Module()
>{
> // initialize all the queues for this object
> // num_queues is a constant declared and defined in flow_module.h
> for ( int i=0; i <= num_queues; i++ )
> {
> q_length[i] = 0;
> q_front_node[i] = NULL;
> q_end_node[i] = NULL;
>
> // initialize the queue mutex and condition var
> pthread_mutex_init( &q_mtx[i], NULL );
> //pthread_cond_init( &q_cond[i], NULL );
> }
>
> // i have NO freaking idea why the below won't work when in the
> loop!
> // if anyone knows, feel free to fill me in
> pthread_cond_init( &q_cond[0], NULL );
> pthread_cond_init( &q_cond[1], NULL );
>
>}
>
>
>// same constructor with module id string for debugging tracing
>Flow_Module::Flow_Module( string str_id )
>{
> // initialize all the queues for this object
> for ( int i=0; i <= num_queues; i++ )
> {
> q_length[i] = 0;
> q_front_node[i] = NULL;
> q_end_node[i] = NULL;
>
> // initialize the in queue mutex and condition var
> pthread_mutex_init( &q_mtx[i], NULL );
> //pthread_cond_init( &q_cond[i], NULL );
> }
>
> // NO freaking idea why the below won't work in the loop.
> pthread_cond_init( &q_cond[0], NULL );
> pthread_cond_init( &q_cond[1], NULL );
>
> // initialize the id
> mod_id = str_id;
>
>}
>
>// destructor, needs to kill of all the queue memory and kill the pthread
>stuff
>// If I have done this incorrectly, someone please let me know!
>Flow_Module::~Flow_Module()
>{
> // free all the queues for this object
> for ( int queue=0; queue <= num_queues; queue++ )
> {
> int q_len, msg_res;
> Flow_Message m_pop;
> // pop all the messages off the queue
> while( ( msg_res = this->pop_msg( &m_pop, queue ) ) != -1 );
>
> // destroy the queue mutex
> int rm = pthread_mutex_destroy( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_destroy");
> pthread_exit(NULL); }
>
> // destroy the condition variable
> pthread_cond_destroy( &q_cond[queue] );
> }
>
>}
>
>
>// method to push message on to this module's queue
>// returns length of queue after message pushed, -1 on failure
>// this also signals the modules condition variable ( which may be ignored
>however )
>//int Flow_Module::push_msg( Flow_Message push_msg, int queue=0 )
>int Flow_Module::push_msg( Flow_Message push_msg, int queue )
>{
> // some message tracing debug tools
> #ifdef DEBUG
> cout << "Debug: module " << mod_id;
> printf( " push message: %i %i %i %i %5.3f \n",
> push_msg.orig, push_msg.type,
> push_msg.slot_1, push_msg.slot_2, push_msg.slot_3 );
> #endif
>
> // lock the queue protecting mutex
> // for some wacked reason this is printing "pthread error: success",
> // when I try to call it from a pointer to the base class, I must
> be confused about something there
> int rm = pthread_mutex_lock( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_lock"); pthread_exit(NULL); }
>
> // allocate memory for the new node
> Flow_Message_Node *push_msg_node = new( Flow_Message_Node );
>
> // copy the data over
> push_msg_node->msg.orig = push_msg.orig;
> push_msg_node->msg.type = push_msg.type;
> push_msg_node->msg.slot_1 = push_msg.slot_1;
> push_msg_node->msg.slot_2 = push_msg.slot_2;
> push_msg_node->msg.slot_3 = push_msg.slot_3;
>
> // this will be the last message in its queue, so it's next_node
> should be NULL
> push_msg_node->next_node = NULL;
>
> // now we do the queue insertion
> if ( q_length[queue] == 0 )
> {
> // this is the only message in the queue
> q_front_node[queue] = push_msg_node;
> q_end_node[queue] = push_msg_node;
> q_length[queue] = 1;
> }
> else
> {
> // set current end_nodes next_node to this one
> q_end_node[queue]->next_node = push_msg_node;
> // reset end_node pointer to this node and incr queue length
> q_end_node[queue] = push_msg_node;
> q_length[queue]++;
> }
>
> // unlock the queue mutex
> rm = pthread_mutex_unlock( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_unlock"); pthread_exit(NULL); }
>
> // signal the condition variable that an item has been put on the
> queue
> // if the module is not asleep waiting on this, I believe it is
> safely ignored
> // someone please tell me if this is a bad idea
> int rc = pthread_cond_signal( &q_cond[queue] );
>
> // now return the queue length AFTER the push
> return( q_length[queue] );
>}
>
>// method to pop a msg off the queue and keep going even if queue was empty
>// returns length of queue AFTER pop, and message in *pop_msg.
>// this will return -1 if queue was empty, and message contents will be
>not meaningful!
>// if no arg is supplied for int queue, default is 0 ( the high priority
>queue )
>int Flow_Module::pop_msg( Flow_Message *pop_msg, int queue )
>{
> // lock the queue mutex
> int rm = pthread_mutex_lock( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_lock"); pthread_exit(NULL); }
>
> // we need a seperate result flag so we can return -1 without
> illogical queue length
> int msg_res;
>
> // if the q in question was empty, then msg_res will be -1 ( no
> message on queue )
> // the msg returned in the pointer will be the last message and
> MUST be ignored
> if ( q_length[queue] == 0 )
> msg_res = -1;
> else
> {
> // grab the front nodes' data
> pop_msg->orig = q_front_node[queue]->msg.orig;
> pop_msg->type = q_front_node[queue]->msg.type;
> pop_msg->slot_1 = q_front_node[queue]->msg.slot_1;
> pop_msg->slot_2 = q_front_node[queue]->msg.slot_2;
> pop_msg->slot_3 = q_front_node[queue]->msg.slot_3;
>
> // save the front node in a temp pointer so we can
> destroy it later
> Flow_Message_Node *old_front_node = q_front_node[queue];
> // set the new front and decrement length
> q_front_node[queue] = q_front_node[queue]->next_node;
> q_length[queue]--;
> // free the memory of the old node
> delete ( old_front_node );
>
> // set msg_res to queue length after message pop
> msg_res = q_length[queue];
>
> // some debugging print out
> #ifdef DEBUG
> cout << "Debug: module " << mod_id;
> printf( " popped message: %i %i %i %i %5.3f \n",
> pop_msg->orig, pop_msg->type,
> pop_msg->slot_1, pop_msg->slot_2, pop_msg->slot_3 );
> #endif
> }
>
> // unlock queue mutex
> rm = pthread_mutex_unlock( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_unlock"); pthread_exit(NULL); }
>
> // return length of the queue after pop ( will be 0 if queue had
> only one message )
> return ( msg_res );
>}
>
>// method to pop a msg and sleep on a condition variable if there was no
>msg waiting
>// this is used if the module is supposed to go to sleep and wait for a
>msg on the queue to wake it up
>// returns length of queue AFTER pop, and message in *pop_msg.
>// this does NOT return from an empty queue, so it will never return -1
>and a meaningless message
>// default queue num is 0 ( high priority queue )
>int Flow_Module::pop_msg_sleep( Flow_Message *pop_msg, int queue )
>{
> // lock queue mutex
> int rm = pthread_mutex_lock( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_lock"); pthread_exit(NULL); }
>
> // if the q in question was empty, go to sleep on it's condition
> variable
> if ( q_length[queue] == 0 )
> {
> #ifdef DEBUG
> cout << "Debug: Module " << mod_id << " executing
> pop_msg_sleep. Queue empty, going to sleep.\n\n";
> #endif
>
> // queue mutex will be unlocked by pthread_cond_wait, and
> locked again on wake up
> int rc = pthread_cond_wait( &q_cond[queue], &q_mtx[queue] );
> #ifdef DEBUG
> cout << "Debug: module " << mod_id << " awakened
> on condition variable.\n";
> #endif
> }
>
> // if there is a message on the queue and the mutex locked ok
> if ( q_length[queue] > 0 && rm == 0 )
> {
> // grab the front nodes' data
> pop_msg->orig = q_front_node[queue]->msg.orig;
> pop_msg->type = q_front_node[queue]->msg.type;
> pop_msg->slot_1 = q_front_node[queue]->msg.slot_1;
> pop_msg->slot_2 = q_front_node[queue]->msg.slot_2;
> pop_msg->slot_3 = q_front_node[queue]->msg.slot_3;
>
> // save the front node in a temp pointer
> Flow_Message_Node *old_front_node = q_front_node[queue];
> // set the new front and decrement length
> q_front_node[queue] = q_front_node[queue]->next_node;
> q_length[queue]--;
> // free the memory of the old node
> delete ( old_front_node );
> }
>
> #ifdef DEBUG
> cout << "Debug: module " << mod_id;
> printf( " pop_msg_sleep popped message:
> %i %i %i %i %5.3f \n",
> pop_msg->orig, pop_msg->type,
> pop_msg->slot_1, pop_msg->slot_2, pop_msg->slot_3 );
> #endif
>
> // unlock mutex
> rm = pthread_mutex_unlock( &q_mtx[queue] );
> if ( rm ){ perror("pthread_mutex_unlock"); pthread_exit(NULL); }
>
> // return length of the queue after pop ( will be 0 if had one
> message )
> // N.B: this function does NOT return if the queue was empty. It
> just sleeps.
> return ( q_length[queue] );
>}
>
>// End of flow_module base class methods
>
>// dummy main in order to test compilation of the base class
>// this can be used to check for errors in base class compilation
>/*
>int main()
>{
> Flow_Module *fm = new Flow_Module();
>
> printf("Success!\n");
> return 0;
>}
>*/
Victor Lazzarini
Music Technology Laboratory
Music Department
National University of Ireland, Maynooth
-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems? Stop! Download the new AJAX search engine that makes
searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
_______________________________________________
Csound-devel mailing list
Csound-devel@lists.sourceforge.net |