/* -*- mode: c++; c-basic-offset: 4; -*-
 *
 * MICO --- a CORBA implementation
 * Copyright (C) 1997-98 Kay Roemer & Arno Puder
 * 
 * message queue
 * Copyright (C) 1999 Andreas Schultz                                 
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Send comments and/or bug reports to:
 *                mico@informatik.uni-frankfurt.de
 * 
 * $Id: message.cc,v 1.21 2000/02/01 21:55:55 akerst Exp $
 *
 */

#define MICO_DEBUG_MODULE MICODebug::Thread

#define MICO_CONF_IMR
#include <CORBA-SMALL.h>
#include <mico/impl.h>

/****************************** MsgChannel ******************************/
MICO_Boolean
MICO::MsgChannel::check_msg( MICO::WorkerThread *kt ) { return FALSE; };

MICO::msg_type *
MICO::MsgChannel::get_msg( OP_id_type nextOP_id )
{
    assert( 0 );

    return 0;
};

/********************************* activeMsgQueue **************************************/

#ifdef DEBUG_NAMES
MICO::activeMsgQueue::activeMsgQueue() {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << "activeMsgQueue::activeMsgQueue(): (" << this << ")" << endl ));
    name ("UnNamed activeMsgQueue");
    Qaccess.name("Qaccess Mutex");
};

const char *
MICO::activeMsgQueue::name (const char *new_name) {
 
    if (new_name)
    {
        if (_name)
           delete [] _name;

        _name = new char [strlen (new_name) + strlen (".Qaccess Mutex") + 1];
        strcpy (_name, new_name);
        strcat (_name, ".Qaccess Mutex");
    }

    return _name;
}

#endif

MICO_Boolean
MICO::activeMsgQueue::check_msg( MICO::WorkerThread *kt )
{
    MICOMT::auto_Lock l(Qaccess);

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": activeMsgQueue::check_msg: (" << this << ") msg: " << endl ));

    if (Q.size() != 0) {
	if (!kt) {
	    kt = tp->get_idle_thread();
	    if (!kt)
		return FALSE;
	}
	msg_type *msg = Q.front();
	assert( msg );
#ifdef MTDEBUG
	msg->pop_time = OSMisc::timestamp();
	MT_PROFILE( { MICODebug::instance()->printer() 
	                  << "  time from create to pop:  " 
			  << msg->pop_time - msg->create_time << " ms" << endl;
	              MICODebug::instance()->printer() 
			  << "  time from push to pop:    " 
			  << msg->pop_time - msg->push_time << " ms" << endl;
	} );
#endif
	Q.pop();
	kt->put_msg(msg);
	kt->mark_busy();
	__MTOUT( MT_TRACE( MICODebug::instance()->printer() << msg << endl ));
	return TRUE;
    }
    return FALSE;
};

void
MICO::activeMsgQueue::put_msg( MICO::OP_id_type nextOP_id, MICO::msg_type *msg)
{
    MICO::WorkerThread *kt;

    assert( msg );
    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": activeMsgQueue::put_msg: (" << this << ") msg: " << msg << endl ));

    MICOMT::auto_Lock l(Qaccess);

    kt = tp->get_idle_thread();
#ifdef MTDEBUG
    msg->push_time = OSMisc::timestamp();
    __MTOUT( MT_PROFILE( MICODebug::instance()->printer() 
			 << "  time from create to MQ::put_msg: " 
			 << msg->push_time - msg->create_time << " ms" << endl ));
#endif
    if (kt) {
	kt->put_msg(msg);
	kt->mark_busy();
	kt->post_state_change();
    } else
	Q.push( msg );
};

MICO::activeMsgQueue::~activeMsgQueue() {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": activeMsgQueue::~activeMsgQueue(): (" << this << ")" << endl ));
};

/******************************** passiveMsgQueue *************************************/

#ifdef DEBUG_NAMES
MICO::passiveMsgQueue::passiveMsgQueue(): _namedObject () {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << "passiveMsgQueue::passiveMsgQueue(): (" << this << ")" << endl ));
    _namedObject::name ("UnNamed passiveMsgQueue");
    Qaccess.name("Qaccess Mutex");
    msg_cnt.name("msg_cnt Semaphore");
}

const char *
MICO::passiveMsgQueue::name (const char *new_name) {
 
    if (new_name) {

        char *tmp =
            new char [strlen (new_name) + strlen (".Qaccess Mutex") + 1];
        strcpy (tmp, new_name);
        strcat (tmp, ".Qaccess Mutex");

	Qaccess.name (tmp);
        delete [] tmp;

        tmp =
            new char [strlen (new_name) + strlen (".msg_cnt Semaphore") + 1];
        strcpy (tmp, new_name);
        strcat (tmp, ".msg_cnt Semaphore");

	msg_cnt.name (tmp);
        delete [] tmp;
    }

    return _namedObject::name (new_name);
}
#endif

MICO::passiveMsgQueue::~passiveMsgQueue() {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": passiveMsgQueue::~passiveMsgQueue(): (" << this << ")" << endl ));
};

MICO::msg_type *
MICO::passiveMsgQueue::get_msg( MICO::OP_id_type nextOP_id ) {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": passiveMsgQueue::get_msg: (" << this << ") msg: " << endl ));
    
    msg_cnt.wait();                     // wait for a message (block)
    Qaccess.lock();                     // make sure, we are the only ones
    msg_type *msg = Q.front();
    assert( msg );        

 #ifdef MTDEBUG
    msg->pop_time = OSMisc::timestamp();
    MT_PROFILE( {
		   MICODebug::instance()->printer() << "  time from create to pop:  "
						    << msg->pop_time - msg->create_time << " ms" << endl;
		   MICODebug::instance()->printer() << "  time from push to pop:    "
						    << msg->pop_time - msg->push_time << " ms" << endl;
    } );
#endif  
    Q.pop();
    Qaccess.unlock();
    __MTOUT( MT_TRACE( MICODebug::instance()->printer() << msg << endl ));
    return msg; 
}
    
void
MICO::passiveMsgQueue::put_msg( MICO::OP_id_type nextOP_id, MICO::msg_type *msg)
{
    assert( msg );
    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": passiveMsgQueue::put_msg: (" << this << ") msg: " << msg << endl ));

    Qaccess.lock();
    Q.push( msg );
#ifdef MTDEBUG
    msg->push_time = OSMisc::timestamp();
    __MTOUT( MT_PROFILE( MICODebug::instance()->printer() 
			 << "  time from create to MQ::put_msg: " 
			 << msg->push_time - msg->create_time << " ms" << endl ));
#endif
    Qaccess.unlock();
    msg_cnt.post();   
}


/******************************** directMsgConnector *************************************/

#ifdef DEBUG_NAMES
MICO::directMsgConnector::directMsgConnector(): _namedObject () {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << "directMsgConnector::directMsgConnector(): (" << this << ")" << endl ));
    name ("UnNamed directMsgConnector");
}

const char *
MICO::directMsgConnector::name (const char *new_name) {
 
    if (new_name) {

        if (_name)
            delete [] _name;

        _name = new char [strlen (new_name) + 1];
        strcpy (_name, new_name);
	
    }
    
    return _name;
}
#endif

MICO::directMsgConnector::~directMsgConnector() {

    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << _name << ": directMsgConnector::~directMsgConnector(): (" << this << ")" << endl ));
}

void
MICO::directMsgConnector::put_msg( MICO::OP_id_type nextOP_id, MICO::msg_type *msg)
{
    assert( msg );
    __MTOUT( MT_TRACE( MICODebug::instance()->printer() 
		       << name () << ": directMsgConnector::put_msg: (" << this << ") msg: " << msg << endl ));
    
    Operation* _myop = op->copy();
    
    _myop->put_msg( nextOP_id, msg);
    _myop->_run();
    
    delete _myop;
}
