#include <iostream>
#include <vector>
#include <set>
#include <ace/OS.h>
#include <ace/OS_main.h>
#include <ace/Time_Value.h>
#include <ace/Thread_Manager.h>
#include <cpp_util_2/h/lexcast.hpp>
#include <so_4/api/h/api.hpp>
#include <so_4/rt/h/rt.hpp>
#include <so_4/timer_thread/simple/h/pub.hpp>
#include <so_4/disp/active_obj/h/pub.hpp>
#include <so_4/disp/qt_ui/h/pub.hpp>
#include <qapplication.h>
#include <qwidget.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qspinbox.h>
#include <qtextedit.h>
std::string
show_time_and_price(
const std::string & what,
int item_count,
const ACE_Time_Value start,
const ACE_Time_Value finish )
{
std::string result;
unsigned long diff = finish.msec() - start.msec();
if( diff )
{
double total = diff / 1000.0;
double price = total / item_count;
double throughput = 1.0 / price;
char msg[ 128 ];
ACE_OS::snprintf( msg, sizeof msg,
"total: %f sec, price: %f sec; troughput: %f",
total, price, throughput );
result = what + "=> " + msg + "\n";
}
else
result = what + ": too small time\n";
return result;
}
class a_starter_shutdowner_t;
class main_widget_t
: public QWidget
{
Q_OBJECT
public:
main_widget_t( QWidget * parent = 0 );
virtual ~main_widget_t();
void init( a_starter_shutdowner_t * starter );
void test_finished( const std::string & msg );
void enable_start();
private slots:
void slot_start();
protected:
void closeEvent( QCloseEvent * e );
private:
QPushButton * m_ok;
QSpinBox * m_width;
QSpinBox * m_height;
QSpinBox * m_rings;
QTextEdit * m_text;
a_starter_shutdowner_t * m_starter;
};
#include "moc/main.moc"
class a_starter_shutdowner_t
: public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
public :
a_starter_shutdowner_t( main_widget_t * widget );
~a_starter_shutdowner_t();
void
start_test(
std::auto_ptr< so_4::rt::dyn_agent_coop_t > customer_ring,
int size,
int tokens );
static const std::string
agent_name();
struct msg_ring_complete {};
virtual const char *
so_query_type() const;
virtual void
so_on_subscription();
void
evt_ring_complete();
void
evt_deregistered( const so_4::rt::msg_coop_deregistered & msg );
private :
int m_rings_completed;
ACE_Time_Value m_start_time;
main_widget_t * m_widget;
int m_size;
int m_tokens;
std::string m_result;
};
SOL4_CLASS_START( a_starter_shutdowner_t )
SOL4_MSG_START(
msg_ring_complete,
a_starter_shutdowner_t::msg_ring_complete )
SOL4_MSG_FINISH()
SOL4_EVENT( evt_ring_complete )
SOL4_EVENT_STC( evt_deregistered,
so_4::rt::msg_coop_deregistered )
SOL4_STATE_START( st_normal )
SOL4_STATE_EVENT( evt_ring_complete )
SOL4_STATE_FINISH()
SOL4_STATE_START( st_finish )
SOL4_STATE_EVENT( evt_deregistered )
SOL4_STATE_FINISH()
SOL4_CLASS_FINISH( )
a_starter_shutdowner_t::a_starter_shutdowner_t( main_widget_t * widget )
: base_type_t( agent_name() )
, m_rings_completed( 0 )
, m_widget( widget )
{
so_add_traits( so_4::disp::qt_ui::query_gui_thread_traits() );
if( m_widget )
m_widget->init( this );
}
a_starter_shutdowner_t::~a_starter_shutdowner_t()
{
}
const std::string
a_starter_shutdowner_t::agent_name()
{
return "a_starter_shutdowner";
}
void
a_starter_shutdowner_t::so_on_subscription()
{
so_subscribe( "evt_ring_complete", "msg_ring_complete" );
so_subscribe( "evt_deregistered",
so_4::rt::sobjectizer_agent_name(),
"msg_coop_deregistered" );
}
void
a_starter_shutdowner_t::start_test(
std::auto_ptr< so_4::rt::dyn_agent_coop_t > customer_ring,
int size, int tokens )
{
m_size = size;
m_tokens = tokens;
m_rings_completed = 0;
m_result.clear();
so_change_state( "st_normal" );
ACE_Time_Value reg_start = ACE_OS::gettimeofday();
so_4::rt::dyn_agent_coop_helper_t helper(
customer_ring.release() );
if( helper.result() )
{
if( m_widget )
m_widget->close();
std::cerr << "Unable to register customer_ring coop: "
<< helper.result() << std::endl;
so_4::api::send_msg(
so_4::rt::sobjectizer_agent_name(),
"msg_alarm_shutdown" );
}
else
{
m_start_time = ACE_OS::gettimeofday();
m_result += show_time_and_price(
"registration",
m_size,
reg_start,
m_start_time );
}
}
void
a_starter_shutdowner_t::evt_deregistered(
const so_4::rt::msg_coop_deregistered & msg )
{
if( "customer_ring" == msg.m_coop_name )
if( m_widget )
m_widget->enable_start();
}
void
a_starter_shutdowner_t::evt_ring_complete()
{
if( ++m_rings_completed == m_tokens )
{
so_change_state( "st_finish" );
ACE_Time_Value finish_time = ACE_OS::gettimeofday();
m_result += show_time_and_price(
"ringing",
m_size * m_tokens,
m_start_time,
finish_time );
if( m_widget )
m_widget->test_finished( m_result );
}
}
class a_customer_t
: public QWidget
, public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
public :
a_customer_t(
const std::string & self_name,
const std::string & next_name,
int tokens );
~a_customer_t();
struct msg_take_token {};
struct msg_shutdown {};
virtual const char *
so_query_type() const;
virtual void
so_on_subscription();
void
evt_start();
void
evt_take_token();
void
evt_shutdown();
private :
const std::string m_next_name;
void send_token_to_next();
int m_rings_completed;
int m_tokens;
QLabel * m_label;
};
SOL4_CLASS_START( a_customer_t )
SOL4_MSG_START( msg_take_token, a_customer_t::msg_take_token )
SOL4_MSG_FINISH()
SOL4_MSG_START( msg_shutdown, a_customer_t::msg_shutdown )
SOL4_MSG_FINISH()
SOL4_EVENT( evt_start )
SOL4_EVENT( evt_take_token )
SOL4_EVENT( evt_shutdown )
SOL4_STATE_START( st_normal )
SOL4_STATE_EVENT( evt_start )
SOL4_STATE_EVENT( evt_take_token )
SOL4_STATE_EVENT( evt_shutdown )
SOL4_STATE_FINISH()
SOL4_CLASS_FINISH( )
a_customer_t::a_customer_t(
const std::string & self_name,
const std::string & next_name,
int tokens )
: base_type_t( self_name )
, QWidget()
, m_next_name( next_name )
, m_label( 0 )
, m_rings_completed( 0 )
, m_tokens( tokens )
{
so_add_traits( so_4::disp::qt_ui::query_gui_thread_traits() );
QVBoxLayout * layout = new QVBoxLayout( this );
m_label = new QLabel( this );
m_label->setText( "Start" );
layout->addWidget( m_label );
}
a_customer_t::~a_customer_t()
{}
void
a_customer_t::so_on_subscription()
{
if( "a_customer_0" == so_query_name() )
so_subscribe(
"evt_start",
so_4::rt::sobjectizer_agent_name(),
"msg_start" );
so_subscribe( "evt_take_token", "msg_take_token" );
so_subscribe( "evt_shutdown", "msg_shutdown" );
}
void
a_customer_t::evt_start()
{
send_token_to_next();
}
void
a_customer_t::evt_shutdown()
{
if( "a_customer_0" != so_query_name() )
so_4::api::send_msg_safely(
m_next_name,
"msg_shutdown",
new msg_shutdown() );
else
so_4::api::deregister_coop( "customer_ring" );
close();
}
void
a_customer_t::evt_take_token()
{
static int num = 0;
m_label->setNum( ++num );
if( "a_customer_0" == so_query_name() )
{
so_4::api::send_msg(
a_starter_shutdowner_t::agent_name(),
"msg_ring_complete" );
if( ++m_rings_completed != m_tokens )
send_token_to_next();
else
so_4::api::send_msg_safely(
m_next_name,
"msg_shutdown",
new msg_shutdown() );
}
else
send_token_to_next();
}
void
a_customer_t::send_token_to_next()
{
so_4::api::send_msg_safely(
m_next_name,
"msg_take_token",
new msg_take_token() );
}
typedef std::vector< a_customer_t * > agents_ptr_storage_t;
std::auto_ptr< so_4::disp::qt_ui::dyn_coop_t >
create_customer_ring( QApplication * app, int width, int height, int rings )
{
std::vector< so_4::rt::agent_t* > customers;
customers.reserve( width * height );
QDesktopWidget * d = QApplication::desktop();
int w = double( d->width() ) / double( width );
int h = double( d->height() ) / double( height );
for( int i = 0; i != height; ++i )
for( int j = 0; j != width; ++j )
{
const std::string self_name = "a_customer_" +
cpp_util_2::slexcast( i * width + j );
const std::string next_name = "a_customer_" +
cpp_util_2::slexcast(
i * width + j + 1 == ( width * height ) ? 0 : i * width + j + 1 );
a_customer_t * customer =
new a_customer_t( self_name, next_name, rings );
customer->setGeometry( j * w, i * h, w, h );
customer->show();
customers.push_back( customer );
}
return std::auto_ptr< so_4::disp::qt_ui::dyn_coop_t >(
new so_4::disp::qt_ui::dyn_coop_t(
"customer_ring",
&customers[ 0 ],
customers.size() ) );
}
class sobj_thread_t
{
private :
so_4::rt::agent_coop_t * m_start_coop;
public :
sobj_thread_t( so_4::rt::agent_coop_t * start_coop = 0 )
: m_start_coop( start_coop )
{}
virtual ~sobj_thread_t()
{}
virtual void
start()
{
if( -1 == ACE_Thread_Manager::instance()->spawn(
entry_point,
this ) )
{
ACE_ERROR(( LM_ERROR, "unable to spawn work thread\n" ));
}
}
virtual void
wait()
{
ACE_Thread_Manager::instance()->wait();
}
protected :
virtual void
body()
{
so_4::ret_code_t rc = so_4::api::start(
so_4::disp::qt_ui::create_disp(
so_4::disp::active_obj::create_disp(
so_4::timer_thread::simple::create_timer_thread(),
so_4::auto_destroy_timer ) ),
so_4::auto_destroy_disp,
m_start_coop
);
if( rc )
{
std::cerr << "start: " << rc << std::endl;
}
}
static ACE_THR_FUNC_RETURN
entry_point( void * self_object )
{
sobj_thread_t * sobj_thread = ACE_reinterpret_cast(
sobj_thread_t *,
self_object );
sobj_thread->body();
return 0;
}
};
main_widget_t::main_widget_t( QWidget * parent )
: QWidget( parent )
, m_ok( 0 )
, m_width( 0 )
, m_height( 0 )
, m_rings( 0 )
, m_starter( 0 )
, m_text( 0 )
{
QVBoxLayout * frame = new QVBoxLayout( this );
QHBoxLayout * hframe = new QHBoxLayout( frame );
QVBoxLayout * vframe_1 = new QVBoxLayout( hframe );
QVBoxLayout * vframe_2 = new QVBoxLayout( hframe );
QVBoxLayout * vframe_3 = new QVBoxLayout( hframe );
QLabel * width_label = new QLabel( "Width", this );
width_label->setAlignment( Qt::AlignCenter );
vframe_1->addWidget( width_label );
QLabel * height_label = new QLabel( "Height", this );
height_label->setAlignment( Qt::AlignCenter );
vframe_2->addWidget( height_label );
QLabel * rings_label = new QLabel( "Rings", this );
rings_label->setAlignment( Qt::AlignCenter );
vframe_3->addWidget( rings_label );
m_width = new QSpinBox( 2, 150, 1, this );
vframe_1->addWidget( m_width );
m_height = new QSpinBox( 1, 150, 1, this );
vframe_2->addWidget( m_height );
m_rings = new QSpinBox( 1, 30000, 1, this );
vframe_3->addWidget( m_rings );
m_width->setValue( 10 );
m_height->setValue( 10 );
m_rings->setValue( 100 );
m_ok = new QPushButton( "Start Test", this );
frame->addWidget( m_ok );
m_text = new QTextEdit( this );
frame->addWidget( m_text );
connect( m_ok, SIGNAL( clicked() ), this, SLOT( slot_start() ) );
};
main_widget_t::~main_widget_t()
{
}
void
main_widget_t::enable_start()
{
m_ok->setEnabled( TRUE );
}
void
main_widget_t::init( a_starter_shutdowner_t * starter )
{
m_starter = starter;
}
void
main_widget_t::test_finished( const std::string & msg )
{
show();
m_text->setText( msg.c_str() );
}
void
main_widget_t::slot_start()
{
m_ok->setEnabled( FALSE );
hide();
m_starter->start_test(
create_customer_ring(
qApp,
m_width->value(),
m_height->value(),
m_rings->value() ),
m_width->value() * m_height->value(),
m_rings->value() );
}
void
main_widget_t::closeEvent( QCloseEvent * e )
{
so_4::api::send_msg(
so_4::rt::sobjectizer_agent_name(),
"msg_normal_shutdown" );
e->accept();
}
int
main( int argc, char ** argv )
{
QApplication app( argc, argv );
app.connect( &app, SIGNAL( lastWindowClosed() ),
&app, SLOT( quit() ) );
main_widget_t * main_widget = new main_widget_t();
app.setMainWidget( main_widget );
main_widget->show();
a_starter_shutdowner_t a_starter_shutdowner( main_widget );
so_4::rt::agent_coop_t starter_coop( a_starter_shutdowner );
sobj_thread_t sobj_thread( &starter_coop );
sobj_thread.start();
int q_result = app.exec();
so_4::api::shutdown();
sobj_thread.wait();
return q_result;
}