<commit_before>/*****************************************************************************\
 *                        ANALYSIS PERFORMANCE TOOLS                         *
 *                               libparaver-api                              *
 *                       Paraver Main Computing Library                      *
 *****************************************************************************
 *     ___     This library is free software; you can redistribute it and/or *
 *    /  __         modify it under the terms of the GNU LGPL as published   *
 *   /  /  _____    by the Free Software Foundation; either version 2.1      *
 *  /  /  /     \   of the License, or (at your option) any later version.   *
 * (  (  ( B S C )                                                           *
 *  \  \  \_____/   This library is distributed in 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 LGPL for more details.   *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public License  *
 * along with this library; if not, write to the Free Software Foundation,   *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA          *
 * The GNU LEsser General Public License is contained in the file COPYING.   *
 *                                 ---------                                 *
 *   Barcelona Supercomputing Center - Centro Nacional de Supercomputacion   *
\*****************************************************************************/

#include <iostream>
#include <string>
#include <sstream>
#include <type_traits>

#include "tracebodyio_v1.h"

using namespace std;

string TraceBodyIO_v1::multiEventLine;
TraceBodyIO_v1::TMultiEventCommonInfo TraceBodyIO_v1::multiEventCommonInfo =
        { nullptr, (TThreadOrder)0, (TCPUOrder)0, (TRecordTime)0 };

string TraceBodyIO_v1::line;
ostringstream TraceBodyIO_v1::ostr;

// Optimization on conversion string to numbers, but with no error control
//#define USE_ATOLL
// Even more optimization using custom function instead of atoll with error checking
#define USE_PRV_ATOLL
constexpr bool prv_atoll_v( string::const_iterator& it, const string::const_iterator& end )
{
  return true;
}

template <typename T, typename... Targs>
bool prv_atoll_v( string::const_iterator& it, const string::const_iterator& end, T& result, Targs&... Fargs )
{
  T tmp = 0;
  bool neg = false;

  if( it == end )
    return false;

  if( *it == '-' )
  {
    neg = true;
    ++it;
  }

  if( neg && is_unsigned<T>::value )
    return false;

  while( *it >= '0' && *it <= '9' )
  {
    tmp = ( tmp * 10 ) + ( *it - '0' );
    ++it;
  }

  if( neg )
    result = -tmp;
  else
    result = tmp;

  if( it == end )
    return sizeof...( Targs ) == 0;

  return prv_atoll_v( ++it, end, Fargs... );
}

TraceBodyIO_v1::TraceBodyIO_v1( Trace* trace )
: whichTrace( trace )
{}

bool TraceBodyIO_v1::ordered() const
{
  return false;
}

void TraceBodyIO_v1::read( TraceStream *file, MemoryBlocks& records,
                           unordered_set<TState>& states, unordered_set<TEventType>& events,
                           MetadataManager& traceInfo ) const
{
  file->getline( line );

  if ( line.size() == 0 )
    return;

  switch ( line[0] )
  {
    case CommentRecord:
      readTraceInfo( line, traceInfo );
      break;

    case StateRecord:
      readState( line, records, states );
      break;

    case EventRecord:
      readEvent( line, records, events );
      break;

    case CommRecord:
      readComm( line, records );
      break;

    case GlobalCommRecord:
      //readGlobalComm( line, records );
      break;

    default:
      cerr << "TraceBodyIO_v1::read()" << endl;
      cerr << "Unkwnown record type." << endl;
      break;
  };
}

void TraceBodyIO_v1::bufferWrite( fstream& whichStream, bool writeReady, bool lineClear ) const
{
  if ( writeReady )
  {
    whichStream << line << '\n';
    if ( lineClear )
      line.clear();
  }
}

void TraceBodyIO_v1::write( fstream& whichStream,
                            const KTrace& whichTrace,
                            MemoryTrace::iterator *record,
                            PRV_INT32 numIter ) const
{
  bool writeReady = false;
  TRecordType type = record->getType();
  line.clear();

  if ( type == EMPTYREC )
  {
    writeReady = writePendingMultiEvent( whichTrace );
    bufferWrite( whichStream, writeReady );
  }
  else
  {
    if ( type & STATE )
    {
      writeReady = writePendingMultiEvent( whichTrace );
      bufferWrite( whichStream, writeReady );
      writeReady = writeState( whichTrace, record );
    }
    else if ( type & EVENT )
    {
      if ( !sameMultiEvent( record ) )
      {
        writeReady = writePendingMultiEvent( whichTrace );

        multiEventCommonInfo.myStream = &whichStream;
        multiEventCommonInfo.cpu = record->getCPU();
        multiEventCommonInfo.thread = record->getThread();
        multiEventCommonInfo.time = record->getTime();

        multiEventLine.clear();
      }

      appendEvent( record );
    }
    else if ( type & COMM )
    {
      writeReady = writePendingMultiEvent( whichTrace );
      bufferWrite( whichStream, writeReady );

      writeReady = writeComm( whichTrace, record );
    }
    else if ( type & GLOBCOMM )
    {
      writeReady = writePendingMultiEvent( whichTrace );
      bufferWrite( whichStream, writeReady );

      writeReady = writeGlobalComm( whichTrace, record );
    }
    else if ( type & RSEND || type & RRECV )
      writeReady = false;
    else
    {
      writeReady = false;
      cerr << "TraceBodyIO_v1::write()" << endl;
      cerr << "Unkwnown record type in memory." << endl;
    }

    bufferWrite( whichStream, writeReady, false );
  }
}

void TraceBodyIO_v1::writeCommInfo( fstream& whichStream,
                                    const KTrace& whichTrace,
                                    PRV_INT32 numIter ) const
{}

/**********************
  Read line functions
***********************/
inline void TraceBodyIO_v1::readTraceInfo(  const std::string& line, MetadataManager& traceInfo ) const
{
  traceInfo.NewMetadata( line );
  // dummy set also to false if it is a comment
}

inline void TraceBodyIO_v1::readState( const string& line, MemoryBlocks& records,
                                       unordered_set<TState>& states ) const
{
  TCPUOrder CPU;
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;
  TRecordTime time;
  TRecordTime endtime;
  TState state;

  auto it = line.begin() + 2;

  // Read the common info
  if ( !readCommon( it, line.cend(), CPU, appl, task, thread, time ) )
  {
    cerr << "Error reading state record." << endl;
    cerr << line << endl;
    return;
  }

  if( !prv_atoll_v( it, line.cend(), endtime, state ) )
  {
    cerr << "Error reading state record." << endl;
    cerr << line << endl;
    return;
  }

  records.newRecord();
  records.setType( STATE + BEGIN );
  records.setTime( time );
  records.setCPU( CPU );
  records.setThread( appl - 1, task - 1, thread - 1 );
  records.setState( state );
  records.setStateEndTime( endtime );

  if ( endtime != -1 )
  {
    records.newRecord();
    records.setType( STATE + END );
    records.setTime( endtime );
    records.setCPU( CPU );
    records.setThread( appl - 1, task - 1, thread - 1 );
    records.setState( state );
    records.setStateEndTime( time );
  }

  states.insert( state );
}

inline void TraceBodyIO_v1::readEvent( const string& line, MemoryBlocks& records,
                                       unordered_set<TEventType>& events ) const
{
  TCPUOrder CPU;
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;
  TRecordTime time;
  TEventType eventtype;
  TEventValue eventvalue;

  auto it = line.begin() + 2;

  // Read the common info
  if ( !readCommon( it, line.cend(), CPU, appl, task, thread, time ) )
  {
    cerr << "Error reading event record." << endl;
    cerr << line << endl;
    return;
  }

  while ( it != line.end() )
  {
    if( !prv_atoll_v( it, line.cend(), eventtype, eventvalue ) )
    {
      cerr << "Error reading event record." << endl;
      cerr << line << endl;
      return;
    }

    records.newRecord();
    records.setType( EVENT );
    records.setTime( time );
    records.setCPU( CPU );
    records.setThread( appl - 1, task - 1, thread - 1 );
    records.setEventType( eventtype );
    records.setEventValue( eventvalue );

    events.insert( eventtype );
  }
}

inline void TraceBodyIO_v1::readComm( const string& line, MemoryBlocks& records ) const
{
  TCPUOrder CPU;
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;
  TRecordTime logSend;
  TRecordTime phySend;
  TRecordTime logReceive;
  TRecordTime phyReceive;
  TCPUOrder remoteCPU;
  TApplOrder remoteAppl;
  TTaskOrder remoteTask;
  TThreadOrder remoteThread;
  TCommSize commSize;
  TCommTag commTag;

  auto it = line.begin() + 2;

  // Read the common info
  if ( !readCommon( it, line.cend(), CPU, appl, task, thread, logSend ) )
  {
    cerr << "Error reading communication record." << endl;
    cerr << line << endl;
    return;
  }

  if( !prv_atoll_v( it, line.cend(), phySend, remoteCPU, remoteAppl, remoteTask, remoteThread, logReceive, phyReceive, commSize, commTag ) )
  {
    cerr << "Error reading communication record." << endl;
    cerr << line << endl;
    return;
  }

  records.newComm();
  records.setSenderCPU( CPU );
  records.setSenderThread( appl - 1, task - 1, thread - 1 );
  records.setReceiverCPU( remoteCPU );
  records.setReceiverThread( remoteAppl - 1, remoteTask - 1, remoteThread - 1 );
  records.setLogicalSend( logSend );
  records.setPhysicalSend( phySend );
  records.setLogicalReceive( logReceive );
  records.setPhysicalReceive( phyReceive );
  records.setCommSize( commSize );
  records.setCommTag( commTag );
}

inline void TraceBodyIO_v1::readGlobalComm( const string& line, MemoryBlocks& records ) const
{}

inline bool TraceBodyIO_v1::readCommon( string::const_iterator& it,
                                        const string::const_iterator& end,
                                        TCPUOrder& CPU,
                                        TApplOrder& appl,
                                        TTaskOrder& task,
                                        TThreadOrder& thread,
                                        TRecordTime& time ) const
{
  bool result;

  result = prv_atoll_v( it, end, CPU, appl, task, thread, time );

  if ( !resourceModel->isValidGlobalCPU( CPU ) )
    return false;

  if ( !processModel->isValidThread( appl - 1, task - 1, thread - 1 ) )
    return false;

  return true;
}

/**************************
  Write records functions
***************************/
bool TraceBodyIO_v1::writeState( const KTrace& whichTrace,
                                 const MemoryTrace::iterator *record ) const
{
  if ( record->getType() & END )
    return false;

  ostr.clear();
  ostr.str( "" );
  ostr << fixed;
  ostr << dec;
  ostr.precision( 0 );

  ostr << StateRecord << ':';
  writeCommon( ostr, whichTrace, record );
  ostr << record->getStateEndTime() << ':' << record->getState();

  line += ostr.str();
  return true;
}

bool TraceBodyIO_v1::writePendingMultiEvent( const KTrace& whichTrace ) const
{
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;

  bool writeLine = !multiEventLine.empty();

  if ( writeLine )
  {
    ostr.clear();
    ostr.str( "" );
    ostr << fixed;
    ostr << dec;
    ostr.precision( 0 );

    ostr << EventRecord << ':';
    ostr << multiEventCommonInfo.cpu << ':';

    whichTrace.getThreadLocation( multiEventCommonInfo.thread, appl, task, thread );
    ostr << appl + 1 << ':' << task + 1 << ':' << thread + 1 << ':';

    ostr << multiEventCommonInfo.time << ':';
    ostr << multiEventLine;

    line += ostr.str();

    bufferWrite( *multiEventCommonInfo.myStream, true );

    multiEventCommonInfo.myStream = nullptr;
    multiEventCommonInfo.cpu = 0;
    multiEventCommonInfo.thread = 0;
    multiEventCommonInfo.time = 0;

    multiEventLine.clear();
  }

  return false;
}

void TraceBodyIO_v1::appendEvent( const MemoryTrace::iterator *record ) const
{
  ostr.clear();
  ostr.str( "" );
  ostr << fixed;
  ostr << dec;
  ostr.precision( 0 );

  if ( !multiEventLine.empty() )
    ostr << ':';

  ostr << record->getEventType() << ':' << record->getEventValueAsIs();

  multiEventLine += ostr.str();
}

bool TraceBodyIO_v1::writeComm( const KTrace& whichTrace,
                                const MemoryTrace::iterator *record ) const
{
  TCommID commID;
  TApplOrder recvAppl;
  TTaskOrder recvTask;
  TThreadOrder recvThread;

  ostr.clear();
  ostr.str( "" );
  ostr << fixed;
  ostr << dec;
  ostr.precision( 0 );

  if ( !( record->getType() == ( COMM + LOG + SEND ) ) )
    return false;

  commID = record->getCommIndex();

  ostr << CommRecord << ':';
  writeCommon( ostr, whichTrace, record );
  ostr << whichTrace.getPhysicalSend( commID ) << ':';
  if ( whichTrace.existResourceInfo() )
    ostr << whichTrace.getReceiverCPU( commID ) << ':';
  else
    ostr << '0' << ':';
  whichTrace.getThreadLocation( whichTrace.getReceiverThread( commID ),
                                recvAppl, recvTask, recvThread );
  ostr << recvAppl + 1 << ':' << recvTask + 1 << ':' << recvThread + 1 << ':';
  ostr << whichTrace.getLogicalReceive( commID ) << ':';
  ostr << whichTrace.getPhysicalReceive( commID ) << ':';

  ostr << whichTrace.getCommSize( commID ) << ':';
  ostr << whichTrace.getCommTag( commID );

  line += ostr.str();
  return true;
}

bool TraceBodyIO_v1::writeGlobalComm( const KTrace& whichTrace,
                                      const MemoryTrace::iterator *record ) const
{
  return true;
}

void TraceBodyIO_v1::writeCommon( ostringstream& line,
                                  const KTrace& whichTrace,
                                  const MemoryTrace::iterator *record ) const
{
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;

  if ( whichTrace.existResourceInfo() )
    line << record->getCPU() << ':';
  else
    line << '0' << ':';

  whichTrace.getThreadLocation( record->getThread(), appl, task, thread );
  line << appl + 1 << ':' << task + 1 << ':' << thread + 1 << ':';
  line << record->getTime() << ':';
}

bool TraceBodyIO_v1::sameMultiEvent( const MemoryTrace::iterator *record ) const
{
  return ( multiEventCommonInfo.cpu == record->getCPU() &&
           multiEventCommonInfo.thread == record->getThread() &&
           multiEventCommonInfo.time == record->getTime() );
}
<commit_msg>Small improvements to prv_atoll_v<commit_after>/*****************************************************************************\
 *                        ANALYSIS PERFORMANCE TOOLS                         *
 *                               libparaver-api                              *
 *                       Paraver Main Computing Library                      *
 *****************************************************************************
 *     ___     This library is free software; you can redistribute it and/or *
 *    /  __         modify it under the terms of the GNU LGPL as published   *
 *   /  /  _____    by the Free Software Foundation; either version 2.1      *
 *  /  /  /     \   of the License, or (at your option) any later version.   *
 * (  (  ( B S C )                                                           *
 *  \  \  \_____/   This library is distributed in 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 LGPL for more details.   *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public License  *
 * along with this library; if not, write to the Free Software Foundation,   *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA          *
 * The GNU LEsser General Public License is contained in the file COPYING.   *
 *                                 ---------                                 *
 *   Barcelona Supercomputing Center - Centro Nacional de Supercomputacion   *
\*****************************************************************************/

#include <iostream>
#include <string>
#include <sstream>
#include <type_traits>

#include "tracebodyio_v1.h"

using namespace std;

string TraceBodyIO_v1::multiEventLine;
TraceBodyIO_v1::TMultiEventCommonInfo TraceBodyIO_v1::multiEventCommonInfo =
        { nullptr, (TThreadOrder)0, (TCPUOrder)0, (TRecordTime)0 };

string TraceBodyIO_v1::line;
ostringstream TraceBodyIO_v1::ostr;

// Optimization on conversion string to numbers, but with no error control
//#define USE_ATOLL
// Even more optimization using custom function instead of atoll with error checking
#define USE_PRV_ATOLL
constexpr bool prv_atoll_v( string::const_iterator& it, const string::const_iterator& end )
{
  return true;
}

template <typename T, typename... Targs>
bool prv_atoll_v( string::const_iterator& it, const string::const_iterator& end, T& result, Targs&... Fargs )
{
  result = 0;
  bool negative = false;

  if( it == end )
    return false;

  if( *it == '-' )
  {
    if( is_unsigned<T>::value )
      return false;
    negative = true;
    ++it;
  }

  while( *it >= '0' && *it <= '9' )
  {
    result = ( result * 10 ) + ( *it - '0' );
    ++it;
  }

  result = negative ? -result : result;

  if( it == end )
    return sizeof...( Targs ) == 0;

  return prv_atoll_v( ++it, end, Fargs... );
}

TraceBodyIO_v1::TraceBodyIO_v1( Trace* trace )
: whichTrace( trace )
{}

bool TraceBodyIO_v1::ordered() const
{
  return false;
}

void TraceBodyIO_v1::read( TraceStream *file, MemoryBlocks& records,
                           unordered_set<TState>& states, unordered_set<TEventType>& events,
                           MetadataManager& traceInfo ) const
{
  file->getline( line );

  if ( line.size() == 0 )
    return;

  switch ( line[0] )
  {
    case CommentRecord:
      readTraceInfo( line, traceInfo );
      break;

    case StateRecord:
      readState( line, records, states );
      break;

    case EventRecord:
      readEvent( line, records, events );
      break;

    case CommRecord:
      readComm( line, records );
      break;

    case GlobalCommRecord:
      //readGlobalComm( line, records );
      break;

    default:
      cerr << "TraceBodyIO_v1::read()" << endl;
      cerr << "Unkwnown record type." << endl;
      break;
  };
}

void TraceBodyIO_v1::bufferWrite( fstream& whichStream, bool writeReady, bool lineClear ) const
{
  if ( writeReady )
  {
    whichStream << line << '\n';
    if ( lineClear )
      line.clear();
  }
}

void TraceBodyIO_v1::write( fstream& whichStream,
                            const KTrace& whichTrace,
                            MemoryTrace::iterator *record,
                            PRV_INT32 numIter ) const
{
  bool writeReady = false;
  TRecordType type = record->getType();
  line.clear();

  if ( type == EMPTYREC )
  {
    writeReady = writePendingMultiEvent( whichTrace );
    bufferWrite( whichStream, writeReady );
  }
  else
  {
    if ( type & STATE )
    {
      writeReady = writePendingMultiEvent( whichTrace );
      bufferWrite( whichStream, writeReady );
      writeReady = writeState( whichTrace, record );
    }
    else if ( type & EVENT )
    {
      if ( !sameMultiEvent( record ) )
      {
        writeReady = writePendingMultiEvent( whichTrace );

        multiEventCommonInfo.myStream = &whichStream;
        multiEventCommonInfo.cpu = record->getCPU();
        multiEventCommonInfo.thread = record->getThread();
        multiEventCommonInfo.time = record->getTime();

        multiEventLine.clear();
      }

      appendEvent( record );
    }
    else if ( type & COMM )
    {
      writeReady = writePendingMultiEvent( whichTrace );
      bufferWrite( whichStream, writeReady );

      writeReady = writeComm( whichTrace, record );
    }
    else if ( type & GLOBCOMM )
    {
      writeReady = writePendingMultiEvent( whichTrace );
      bufferWrite( whichStream, writeReady );

      writeReady = writeGlobalComm( whichTrace, record );
    }
    else if ( type & RSEND || type & RRECV )
      writeReady = false;
    else
    {
      writeReady = false;
      cerr << "TraceBodyIO_v1::write()" << endl;
      cerr << "Unkwnown record type in memory." << endl;
    }

    bufferWrite( whichStream, writeReady, false );
  }
}

void TraceBodyIO_v1::writeCommInfo( fstream& whichStream,
                                    const KTrace& whichTrace,
                                    PRV_INT32 numIter ) const
{}

/**********************
  Read line functions
***********************/
inline void TraceBodyIO_v1::readTraceInfo(  const std::string& line, MetadataManager& traceInfo ) const
{
  traceInfo.NewMetadata( line );
  // dummy set also to false if it is a comment
}

inline void TraceBodyIO_v1::readState( const string& line, MemoryBlocks& records,
                                       unordered_set<TState>& states ) const
{
  TCPUOrder CPU;
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;
  TRecordTime time;
  TRecordTime endtime;
  TState state;

  auto it = line.begin() + 2;

  // Read the common info
  if ( !readCommon( it, line.cend(), CPU, appl, task, thread, time ) )
  {
    cerr << "Error reading state record." << endl;
    cerr << line << endl;
    return;
  }

  if( !prv_atoll_v( it, line.cend(), endtime, state ) )
  {
    cerr << "Error reading state record." << endl;
    cerr << line << endl;
    return;
  }

  records.newRecord();
  records.setType( STATE + BEGIN );
  records.setTime( time );
  records.setCPU( CPU );
  records.setThread( appl - 1, task - 1, thread - 1 );
  records.setState( state );
  records.setStateEndTime( endtime );

  if ( endtime != -1 )
  {
    records.newRecord();
    records.setType( STATE + END );
    records.setTime( endtime );
    records.setCPU( CPU );
    records.setThread( appl - 1, task - 1, thread - 1 );
    records.setState( state );
    records.setStateEndTime( time );
  }

  states.insert( state );
}

inline void TraceBodyIO_v1::readEvent( const string& line, MemoryBlocks& records,
                                       unordered_set<TEventType>& events ) const
{
  TCPUOrder CPU;
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;
  TRecordTime time;
  TEventType eventtype;
  TEventValue eventvalue;

  auto it = line.begin() + 2;

  // Read the common info
  if ( !readCommon( it, line.cend(), CPU, appl, task, thread, time ) )
  {
    cerr << "Error reading event record." << endl;
    cerr << line << endl;
    return;
  }

  while ( it != line.end() )
  {
    if( !prv_atoll_v( it, line.cend(), eventtype, eventvalue ) )
    {
      cerr << "Error reading event record." << endl;
      cerr << line << endl;
      return;
    }

    records.newRecord();
    records.setType( EVENT );
    records.setTime( time );
    records.setCPU( CPU );
    records.setThread( appl - 1, task - 1, thread - 1 );
    records.setEventType( eventtype );
    records.setEventValue( eventvalue );

    events.insert( eventtype );
  }
}

inline void TraceBodyIO_v1::readComm( const string& line, MemoryBlocks& records ) const
{
  TCPUOrder CPU;
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;
  TRecordTime logSend;
  TRecordTime phySend;
  TRecordTime logReceive;
  TRecordTime phyReceive;
  TCPUOrder remoteCPU;
  TApplOrder remoteAppl;
  TTaskOrder remoteTask;
  TThreadOrder remoteThread;
  TCommSize commSize;
  TCommTag commTag;

  auto it = line.begin() + 2;

  // Read the common info
  if ( !readCommon( it, line.cend(), CPU, appl, task, thread, logSend ) )
  {
    cerr << "Error reading communication record." << endl;
    cerr << line << endl;
    return;
  }

  if( !prv_atoll_v( it, line.cend(), phySend, remoteCPU, remoteAppl, remoteTask, remoteThread, logReceive, phyReceive, commSize, commTag ) )
  {
    cerr << "Error reading communication record." << endl;
    cerr << line << endl;
    return;
  }

  records.newComm();
  records.setSenderCPU( CPU );
  records.setSenderThread( appl - 1, task - 1, thread - 1 );
  records.setReceiverCPU( remoteCPU );
  records.setReceiverThread( remoteAppl - 1, remoteTask - 1, remoteThread - 1 );
  records.setLogicalSend( logSend );
  records.setPhysicalSend( phySend );
  records.setLogicalReceive( logReceive );
  records.setPhysicalReceive( phyReceive );
  records.setCommSize( commSize );
  records.setCommTag( commTag );
}

inline void TraceBodyIO_v1::readGlobalComm( const string& line, MemoryBlocks& records ) const
{}

inline bool TraceBodyIO_v1::readCommon( string::const_iterator& it,
                                        const string::const_iterator& end,
                                        TCPUOrder& CPU,
                                        TApplOrder& appl,
                                        TTaskOrder& task,
                                        TThreadOrder& thread,
                                        TRecordTime& time ) const
{
  bool result;

  result = prv_atoll_v( it, end, CPU, appl, task, thread, time );

  if ( !resourceModel->isValidGlobalCPU( CPU ) )
    return false;

  if ( !processModel->isValidThread( appl - 1, task - 1, thread - 1 ) )
    return false;

  return true;
}

/**************************
  Write records functions
***************************/
bool TraceBodyIO_v1::writeState( const KTrace& whichTrace,
                                 const MemoryTrace::iterator *record ) const
{
  if ( record->getType() & END )
    return false;

  ostr.clear();
  ostr.str( "" );
  ostr << fixed;
  ostr << dec;
  ostr.precision( 0 );

  ostr << StateRecord << ':';
  writeCommon( ostr, whichTrace, record );
  ostr << record->getStateEndTime() << ':' << record->getState();

  line += ostr.str();
  return true;
}

bool TraceBodyIO_v1::writePendingMultiEvent( const KTrace& whichTrace ) const
{
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;

  bool writeLine = !multiEventLine.empty();

  if ( writeLine )
  {
    ostr.clear();
    ostr.str( "" );
    ostr << fixed;
    ostr << dec;
    ostr.precision( 0 );

    ostr << EventRecord << ':';
    ostr << multiEventCommonInfo.cpu << ':';

    whichTrace.getThreadLocation( multiEventCommonInfo.thread, appl, task, thread );
    ostr << appl + 1 << ':' << task + 1 << ':' << thread + 1 << ':';

    ostr << multiEventCommonInfo.time << ':';
    ostr << multiEventLine;

    line += ostr.str();

    bufferWrite( *multiEventCommonInfo.myStream, true );

    multiEventCommonInfo.myStream = nullptr;
    multiEventCommonInfo.cpu = 0;
    multiEventCommonInfo.thread = 0;
    multiEventCommonInfo.time = 0;

    multiEventLine.clear();
  }

  return false;
}

void TraceBodyIO_v1::appendEvent( const MemoryTrace::iterator *record ) const
{
  ostr.clear();
  ostr.str( "" );
  ostr << fixed;
  ostr << dec;
  ostr.precision( 0 );

  if ( !multiEventLine.empty() )
    ostr << ':';

  ostr << record->getEventType() << ':' << record->getEventValueAsIs();

  multiEventLine += ostr.str();
}

bool TraceBodyIO_v1::writeComm( const KTrace& whichTrace,
                                const MemoryTrace::iterator *record ) const
{
  TCommID commID;
  TApplOrder recvAppl;
  TTaskOrder recvTask;
  TThreadOrder recvThread;

  ostr.clear();
  ostr.str( "" );
  ostr << fixed;
  ostr << dec;
  ostr.precision( 0 );

  if ( !( record->getType() == ( COMM + LOG + SEND ) ) )
    return false;

  commID = record->getCommIndex();

  ostr << CommRecord << ':';
  writeCommon( ostr, whichTrace, record );
  ostr << whichTrace.getPhysicalSend( commID ) << ':';
  if ( whichTrace.existResourceInfo() )
    ostr << whichTrace.getReceiverCPU( commID ) << ':';
  else
    ostr << '0' << ':';
  whichTrace.getThreadLocation( whichTrace.getReceiverThread( commID ),
                                recvAppl, recvTask, recvThread );
  ostr << recvAppl + 1 << ':' << recvTask + 1 << ':' << recvThread + 1 << ':';
  ostr << whichTrace.getLogicalReceive( commID ) << ':';
  ostr << whichTrace.getPhysicalReceive( commID ) << ':';

  ostr << whichTrace.getCommSize( commID ) << ':';
  ostr << whichTrace.getCommTag( commID );

  line += ostr.str();
  return true;
}

bool TraceBodyIO_v1::writeGlobalComm( const KTrace& whichTrace,
                                      const MemoryTrace::iterator *record ) const
{
  return true;
}

void TraceBodyIO_v1::writeCommon( ostringstream& line,
                                  const KTrace& whichTrace,
                                  const MemoryTrace::iterator *record ) const
{
  TApplOrder appl;
  TTaskOrder task;
  TThreadOrder thread;

  if ( whichTrace.existResourceInfo() )
    line << record->getCPU() << ':';
  else
    line << '0' << ':';

  whichTrace.getThreadLocation( record->getThread(), appl, task, thread );
  line << appl + 1 << ':' << task + 1 << ':' << thread + 1 << ':';
  line << record->getTime() << ':';
}

bool TraceBodyIO_v1::sameMultiEvent( const MemoryTrace::iterator *record ) const
{
  return ( multiEventCommonInfo.cpu == record->getCPU() &&
           multiEventCommonInfo.thread == record->getThread() &&
           multiEventCommonInfo.time == record->getTime() );
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <almath/types/alpose2d.h>
#include <cmath>
#include <stdexcept>
#include <iostream>

namespace AL {
  namespace Math {

    Pose2D::Pose2D():x(0.0f), y(0.0f), theta(0.0f) {}

    Pose2D::Pose2D(float pInit):x(pInit), y(pInit), theta(pInit) {}

    Pose2D::Pose2D(
      float pX,
      float pY,
      float pTheta):
      x(pX),
      y(pY),
      theta(pTheta) {}

    Pose2D::Pose2D (const std::vector<float>& pFloats)
    {
      if (pFloats.size() == 3)
      {
        x = pFloats[0];
        y = pFloats[1];
        theta = pFloats[2];
      }
      else
      {
        std::cerr << "ALMath: WARNING: "
                  << "Pose2D constructor call with a wrong size of vector. "
                  << "Size expected: 3. Size given: " << pFloats.size() << ". "
                  << "Pose2D is set to default value." << std::endl;

        x = 0.0f;
        y = 0.0f;
        theta = 0.0f;
      }
    }

    Pose2D Pose2D::operator+ (const Pose2D& pPos2) const
    {
      Pose2D res;
      res.x = x + pPos2.x;
      res.y = y + pPos2.y;
      res.theta = theta + pPos2.theta;
      return res;
    }

    Pose2D Pose2D::operator- (const Pose2D& pPos2) const
    {
      Pose2D res;
      res.x = x - pPos2.x;
      res.y = y - pPos2.y;
      res.theta = theta - pPos2.theta;
      return res;
    }

    Pose2D Pose2D::operator+ () const
    {
      Pose2D res;
      res.x = x;
      res.y = y;
      res.theta = theta;
      return res;
    }

    Pose2D Pose2D::operator- () const
    {
      Pose2D res;
      res.x = -x;
      res.y = -y;
      res.theta = -theta;
      return res;
    }

    Pose2D Pose2D::operator* (const Pose2D& pPos2) const
    {
      Pose2D pOut;
      pOut.x = x + cosf(theta) * pPos2.x - sinf(theta) * pPos2.y;
      pOut.y = y + sinf(theta) * pPos2.x + cosf(theta) * pPos2.y;
      pOut.theta = theta + pPos2.theta;

      return pOut;
    }

    Pose2D& Pose2D::operator*= (const Pose2D& pPos2)
    {
      if (this == &pPos2)
      {
        return *this *= Pose2D(pPos2);
      }

      x += cosf(theta) * pPos2.x - sinf(theta) * pPos2.y;
      y += sinf(theta) * pPos2.x + cosf(theta) * pPos2.y;
      theta += pPos2.theta;

      return *this;
    }

    Pose2D& Pose2D::operator+= (const Pose2D& pPos2)
    {
      x     += pPos2.x;
      y     += pPos2.y;
      theta += pPos2.theta;
      return *this;
    }

    Pose2D& Pose2D::operator-= (const Pose2D& pPos2)
    {
      x     -= pPos2.x;
      y     -= pPos2.y;
      theta -= pPos2.theta;
      return *this;
    }

    bool Pose2D::operator==(const Pose2D& pPos2) const
    {
      return (x == pPos2.x &&
              y == pPos2.y &&
              theta == pPos2.theta);
    }

    bool Pose2D::operator!=(const Pose2D& pPos2) const
    {
      return ! (*this==pPos2);
    }

    float Pose2D::distanceSquared(const Pose2D& pPos) const
    {
      return Math::distanceSquared(*this, pPos);
    }

    float Pose2D::distance(const Pose2D& pPos2) const
    {
      return Math::distance(*this, pPos2);
    }

    Pose2D Pose2D::operator* (float pVal) const
    {
      Pose2D res;
      res.x     = x * pVal;
      res.y     = y * pVal;
      res.theta = theta * pVal;
      return res;
    }

    Pose2D Pose2D::operator/ (float pVal) const
    {
      if (pVal == 0.0f)
      {
        throw std::runtime_error(
          "ALPose2D: operator/ Division by zeros.");
      }
      return *this * (1.0f/pVal);
    }

    Pose2D& Pose2D::operator*= (const float pVal)
    {
      x     *= pVal;
      y     *= pVal;
      theta *= pVal;
      return *this;
    }

    Pose2D& Pose2D::operator/= (float pVal)
    {
      if (pVal == 0.0f)
      {
        throw std::runtime_error(
          "ALPose2D: operator/= Division by zeros.");
      }
      *this *= (1.0f/pVal);
      return *this;
    }

    Pose2D Pose2D::diff(const Pose2D& pPos2) const
    {
      return Math::pose2dDiff(*this, pPos2);
    }

    std::vector<float> Pose2D::toVector() const
    {
      std::vector<float> returnVector(3, 0.0f);

      returnVector[0] = x;
      returnVector[1] = y;
      returnVector[2] = theta;

      return returnVector;
    }

    float distanceSquared(
      const Pose2D& pPos1,
      const Pose2D& pPos2)
    {
      return (pPos1.x-pPos2.x)*(pPos1.x-pPos2.x)+(pPos1.y-pPos2.y)*(pPos1.y-pPos2.y);
    }

    float distance(
      const Pose2D& pPos1,
      const Pose2D& pPos2)
    {
      return sqrtf(distanceSquared(pPos1, pPos2));
    }

    bool Pose2D::isNear(
        const Pose2D& pPos2,
        const float&  pEpsilon) const
    {
      return (fabsf(x - pPos2.x) <= pEpsilon &&
              fabsf(y - pPos2.y) <= pEpsilon &&
              fabsf(theta - pPos2.theta) <= pEpsilon);
    }

    Pose2D Pose2D::inverse() const
    {
      return Math::pose2DInverse(*this);
    }

    void pose2DInverse(
      const Pose2D& pIn,
      Pose2D&       pOut)
    {
      pOut.theta = -pIn.theta;

      float cos = cosf(pOut.theta);
      float sin = sinf(pOut.theta);

      pOut.x = -( pIn.x*cos - pIn.y*sin);
      pOut.y = -( pIn.y*cos + pIn.x*sin);
    }

    void pose2dInvertInPlace(Pose2D& pPos)
    {
      pPos.theta = -pPos.theta;

      float cos = cosf(pPos.theta);
      float sin = sinf(pPos.theta);
      float x   = pPos.x;

      pPos.x = -(x*cos - pPos.y*sin);
      pPos.y = -(pPos.y*cos + x*sin);
    }

    Pose2D pose2dDiff(
      const Pose2D& pPos1,
      const Pose2D& pPos2)
    {
      Pose2D result = pPos1;

      pose2dInvertInPlace(result);
      result *= pPos2;
      return result;
    }

    Pose2D pose2DInverse(const Pose2D& pIn)
    {
      Pose2D pOut;
      pose2DInverse(pIn, pOut);
      return pOut;
    }

    Pose2D pinv(const Pose2D& pPos)
    {
      Pose2D result = pPos;
      pose2dInvertInPlace(result);
      return result;
    }

  } // end namespace math
} // end namespace AL
<commit_msg>POSE2D: Factoring pose2DInverse function.<commit_after>/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <almath/types/alpose2d.h>
#include <cmath>
#include <stdexcept>
#include <iostream>

namespace AL {
  namespace Math {

    Pose2D::Pose2D():x(0.0f), y(0.0f), theta(0.0f) {}

    Pose2D::Pose2D(float pInit):x(pInit), y(pInit), theta(pInit) {}

    Pose2D::Pose2D(
      float pX,
      float pY,
      float pTheta):
      x(pX),
      y(pY),
      theta(pTheta) {}

    Pose2D::Pose2D (const std::vector<float>& pFloats)
    {
      if (pFloats.size() == 3)
      {
        x = pFloats[0];
        y = pFloats[1];
        theta = pFloats[2];
      }
      else
      {
        std::cerr << "ALMath: WARNING: "
                  << "Pose2D constructor call with a wrong size of vector. "
                  << "Size expected: 3. Size given: " << pFloats.size() << ". "
                  << "Pose2D is set to default value." << std::endl;

        x = 0.0f;
        y = 0.0f;
        theta = 0.0f;
      }
    }

    Pose2D Pose2D::operator+ (const Pose2D& pPos2) const
    {
      Pose2D res;
      res.x = x + pPos2.x;
      res.y = y + pPos2.y;
      res.theta = theta + pPos2.theta;
      return res;
    }

    Pose2D Pose2D::operator- (const Pose2D& pPos2) const
    {
      Pose2D res;
      res.x = x - pPos2.x;
      res.y = y - pPos2.y;
      res.theta = theta - pPos2.theta;
      return res;
    }

    Pose2D Pose2D::operator+ () const
    {
      Pose2D res;
      res.x = x;
      res.y = y;
      res.theta = theta;
      return res;
    }

    Pose2D Pose2D::operator- () const
    {
      Pose2D res;
      res.x = -x;
      res.y = -y;
      res.theta = -theta;
      return res;
    }

    Pose2D Pose2D::operator* (const Pose2D& pPos2) const
    {
      Pose2D pOut;
      pOut.x = x + cosf(theta) * pPos2.x - sinf(theta) * pPos2.y;
      pOut.y = y + sinf(theta) * pPos2.x + cosf(theta) * pPos2.y;
      pOut.theta = theta + pPos2.theta;

      return pOut;
    }

    Pose2D& Pose2D::operator*= (const Pose2D& pPos2)
    {
      if (this == &pPos2)
      {
        return *this *= Pose2D(pPos2);
      }

      x += cosf(theta) * pPos2.x - sinf(theta) * pPos2.y;
      y += sinf(theta) * pPos2.x + cosf(theta) * pPos2.y;
      theta += pPos2.theta;

      return *this;
    }

    Pose2D& Pose2D::operator+= (const Pose2D& pPos2)
    {
      x     += pPos2.x;
      y     += pPos2.y;
      theta += pPos2.theta;
      return *this;
    }

    Pose2D& Pose2D::operator-= (const Pose2D& pPos2)
    {
      x     -= pPos2.x;
      y     -= pPos2.y;
      theta -= pPos2.theta;
      return *this;
    }

    bool Pose2D::operator==(const Pose2D& pPos2) const
    {
      return (x == pPos2.x &&
              y == pPos2.y &&
              theta == pPos2.theta);
    }

    bool Pose2D::operator!=(const Pose2D& pPos2) const
    {
      return ! (*this==pPos2);
    }

    float Pose2D::distanceSquared(const Pose2D& pPos) const
    {
      return Math::distanceSquared(*this, pPos);
    }

    float Pose2D::distance(const Pose2D& pPos2) const
    {
      return Math::distance(*this, pPos2);
    }

    Pose2D Pose2D::operator* (float pVal) const
    {
      Pose2D res;
      res.x     = x * pVal;
      res.y     = y * pVal;
      res.theta = theta * pVal;
      return res;
    }

    Pose2D Pose2D::operator/ (float pVal) const
    {
      if (pVal == 0.0f)
      {
        throw std::runtime_error(
          "ALPose2D: operator/ Division by zeros.");
      }
      return *this * (1.0f/pVal);
    }

    Pose2D& Pose2D::operator*= (const float pVal)
    {
      x     *= pVal;
      y     *= pVal;
      theta *= pVal;
      return *this;
    }

    Pose2D& Pose2D::operator/= (float pVal)
    {
      if (pVal == 0.0f)
      {
        throw std::runtime_error(
          "ALPose2D: operator/= Division by zeros.");
      }
      *this *= (1.0f/pVal);
      return *this;
    }

    Pose2D Pose2D::diff(const Pose2D& pPos2) const
    {
      return Math::pose2dDiff(*this, pPos2);
    }

    std::vector<float> Pose2D::toVector() const
    {
      std::vector<float> returnVector(3, 0.0f);

      returnVector[0] = x;
      returnVector[1] = y;
      returnVector[2] = theta;

      return returnVector;
    }

    float distanceSquared(
      const Pose2D& pPos1,
      const Pose2D& pPos2)
    {
      return (pPos1.x-pPos2.x)*(pPos1.x-pPos2.x)+(pPos1.y-pPos2.y)*(pPos1.y-pPos2.y);
    }

    float distance(
      const Pose2D& pPos1,
      const Pose2D& pPos2)
    {
      return sqrtf(distanceSquared(pPos1, pPos2));
    }

    bool Pose2D::isNear(
        const Pose2D& pPos2,
        const float&  pEpsilon) const
    {
      return (fabsf(x - pPos2.x) <= pEpsilon &&
              fabsf(y - pPos2.y) <= pEpsilon &&
              fabsf(theta - pPos2.theta) <= pEpsilon);
    }

    Pose2D Pose2D::inverse() const
    {
      return Math::pose2DInverse(*this);
    }

    void pose2DInverse(
      const Pose2D& pIn,
      Pose2D&       pOut)
    {
      pOut = pIn;
      pose2dInvertInPlace(pOut);
    }

    void pose2dInvertInPlace(Pose2D& pPos)
    {
      pPos.theta = -pPos.theta;

      float cos = cosf(pPos.theta);
      float sin = sinf(pPos.theta);
      float x   = pPos.x;

      pPos.x = -(x*cos - pPos.y*sin);
      pPos.y = -(pPos.y*cos + x*sin);
    }

    Pose2D pose2dDiff(
      const Pose2D& pPos1,
      const Pose2D& pPos2)
    {
      Pose2D result = pPos1;

      pose2dInvertInPlace(result);
      result *= pPos2;
      return result;
    }

    Pose2D pose2DInverse(const Pose2D& pIn)
    {
      Pose2D pOut;
      pose2DInverse(pIn, pOut);
      return pOut;
    }

    Pose2D pinv(const Pose2D& pPos)
    {
      Pose2D result = pPos;
      pose2dInvertInPlace(result);
      return result;
    }

  } // end namespace math
} // end namespace AL
<|endoftext|>


<commit_before>/*
 * Copyright (C) 1998-2001, The University of Queensland
 * Copyright (C) 2001, Sun Microsystems, Inc
 * Copyright (C) 2002, Trent Waddington
 *
 * See the file "LICENSE.TERMS" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL
 * WARRANTIES.
 *
 */

/*==============================================================================
 * FILE:       njmcDecoder.cc
 * OVERVIEW:   This file contains the machine independent
 *             decoding functionality.
 *
 * $Revision$
 *============================================================================*/
/*
 * 27 Apr 02 - Mike: Mods for boomerang
 */

#include <assert.h>
#if defined(_MSC_VER) && _MSC_VER <= 1200
#pragma warning(disable:4786)
#endif

#include <stdarg.h>         // For varargs
#include "rtl.h"
#include "decoder.h"
#include "exp.h"
#include "register.h"
#include "cfg.h"
#include "proc.h"
#include "prog.h"
#include "BinaryFile.h"
#include "boomerang.h"
// For some reason, MSVC 5.00 complains about use of undefined types a lot
#if defined(_MSC_VER) && _MSC_VER <= 1100
#include "signature.h"		// For MSVC 5.00
#endif

/**********************************
 * NJMCDecoder methods.
 **********************************/

/*==============================================================================
 * FUNCTION:       NJMCDecoder::NJMCDecoder
 * OVERVIEW:
 * PARAMETERS:     None
 * RETURNS:        N/A
 *============================================================================*/
NJMCDecoder::NJMCDecoder()
{}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::instantiate
 * OVERVIEW:       Given an instruction name and a variable list of SemStr's
 *                 representing the actual operands of the instruction, use the
 *                 RTL template dictionary to return the instantiated RTL
 *                 representing the semantics of the instruction.
 * PARAMETERS:     name - instruction name
 *                 ... - Semantic String ptrs representing actual operands
 * RETURNS:        an instantiated list of Exps
 *============================================================================*/
std::list<Statement*>* NJMCDecoder::instantiate(ADDRESS pc, const char* name,
  ...) {
    // Get the signature of the instruction and extract its parts
    std::pair<std::string,unsigned> sig = RTLDict.getSignature(name);
    std::string opcode = sig.first;
    unsigned numOperands = sig.second;

    // Put the operands into an vector
    std::vector<Exp*> actuals(numOperands);
    va_list args;
    va_start(args,name);
    for (unsigned i = 0; i < numOperands; i++)
        actuals[i] = va_arg(args,Exp*);
    va_end(args);

    if (Boomerang::get()->debugDecoder) {
        // Display a disassembly of this instruction if requested
        std::cout << std::hex << pc << std::dec << ": " << name << " ";
        for (std::vector<Exp*>::iterator itd = actuals.begin();
          itd != actuals.end(); itd++) {
            (*itd)->print(std::cout);
            if (itd != actuals.end()-1)
                std::cout << ", ";
        }
        std::cout << std::endl;
    }

    std::list<Statement*>* instance = RTLDict.instantiateRTL(opcode,actuals);

    // Delete the memory used for the actuals
    for (std::vector<Exp*>::iterator it = actuals.begin();
        it != actuals.end(); it++)
        delete *it;

    return instance;
}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::instantiateNamedParam
 * OVERVIEW:       Similarly to the above, given a parameter name
 *                  and a list of Exp*'s representing sub-parameters,
 *                  return a fully substituted Exp for the whole expression
 * NOTE:           Caller must delete result
 * PARAMETERS:     name - parameter name
 *                 ... - Exp* representing actual operands
 * RETURNS:        an instantiated list of Exps
 *============================================================================*/
Exp* NJMCDecoder::instantiateNamedParam(char* name, ...) {
    if (RTLDict.ParamSet.find(name) == RTLDict.ParamSet.end()) {
        std::cerr << "No entry for named parameter '" << name << "'\n";
        return 0;
    }
    assert(RTLDict.DetParamMap.find(name) != RTLDict.DetParamMap.end());
    ParamEntry &ent = RTLDict.DetParamMap[name];
    if (ent.kind != PARAM_ASGN && ent.kind != PARAM_LAMBDA ) {
        std::cerr << "Attempt to instantiate expressionless parameter '" << name
          << "'\n";
        return 0;
    }
    // Start with the RHS
    assert(ent.asgn->getKind() == STMT_ASSIGN);
    Exp* result = ent.asgn->getRight()->clone();

    va_list args;
    va_start(args,name);
    for( std::list<std::string>::iterator it = ent.params.begin();
      it != ent.params.end(); it++ ) {
        Exp* formal = new Unary(opParam, new Const((char*)it->c_str()));
        Exp* actual = va_arg(args, Exp*);
        bool change;
        result = result->searchReplaceAll(formal, actual, change);
        delete formal;
    }
    return result;
}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::substituteCallArgs
 * OVERVIEW:       In the event that it's necessary to synthesize the call of
 *                 a named parameter generated with instantiateNamedParam(),
 *                 this substituteCallArgs() will substitute the arguments that
 *                 follow into the expression.
 * NOTE:           Should only be used after instantiateNamedParam(name, ..);
 * NOTE:           exp (the pointer) could be changed
 * PARAMETERS:     name - parameter name
 *                 exp - expression to instantiate into
 *                 ... - Exp* representing actual operands
 * RETURNS:        an instantiated list of Exps
 *============================================================================*/
void NJMCDecoder::substituteCallArgs(char *name, Exp*& exp, ...)
{
    if (RTLDict.ParamSet.find(name) == RTLDict.ParamSet.end()) {
        std::cerr << "No entry for named parameter '" << name << "'\n";
        return;
    }
    ParamEntry &ent = RTLDict.DetParamMap[name];
    /*if (ent.kind != PARAM_ASGN && ent.kind != PARAM_LAMBDA) {
        std::cerr << "Attempt to instantiate expressionless parameter '" << name << "'\n";
        return;
    }*/

    va_list args;
    va_start(args, exp);
    for (std::list<std::string>::iterator it = ent.funcParams.begin();
         it != ent.funcParams.end(); it++) {
        Exp* formal = new Unary(opParam, new Const((char*)it->c_str()));
        Exp* actual = va_arg(args, Exp*);
        bool change;
        exp = exp->searchReplaceAll(formal, actual, change);
        delete formal;
    }
}

/*==============================================================================
 * FUNCTION:       DecodeResult::reset
 * OVERVIEW:       Resets the fields of a DecodeResult to their default values.
 * PARAMETERS:     <none>
 * RETURNS:        <nothing>
 *============================================================================*/
void DecodeResult::reset()
{
    numBytes = 0;
    type = NCT;
    valid = true;
    rtl = NULL;
    forceOutEdge = 0;
}

/*==============================================================================
 * These are functions used to decode instruction operands into
 * Exp*s.
 *============================================================================*/

/*==============================================================================
 * FUNCTION:        NJMCDecoder::dis_Reg
 * OVERVIEW:        Converts a numbered register to a suitable expression.
 * PARAMETERS:      reg - the register number, e.g. 0 for eax
 * RETURNS:         the Exp* for the register NUMBER (e.g. "int 36" for %f4)
 *============================================================================*/
Exp* NJMCDecoder::dis_Reg(int regNum)
{
      Exp* expr = Location::regOf(regNum);
      return expr;
}

/*==============================================================================
 * FUNCTION:        NJMCDecoder::dis_Num
 * OVERVIEW:        Converts a number to a Exp* expression.
 * PARAMETERS:      num - a number
 * RETURNS:         the Exp* representation of the given number
 *============================================================================*/
Exp* NJMCDecoder::dis_Num(unsigned num)
{
    Exp* expr = new Const((int)num);
    return expr;
}

/*==============================================================================
 * FUNCTION:        NJMCDecoder::unconditionalJump
 * OVERVIEW:        Process an unconditional jump instruction
 *                  Also check if the destination is a label
 * PARAMETERS:      <none>
 * RETURNS:         the reference to the RTLInstDict object
 *============================================================================*/
void NJMCDecoder::unconditionalJump(const char* name, int size,
  ADDRESS relocd, /*UserProc* proc,*/ int delta, ADDRESS pc, std::list<Statement*>* stmts,
  DecodeResult& result) {
    result.rtl = new RTL(pc, stmts);
    result.numBytes = size;
    GotoStatement* jump = new GotoStatement();
    jump->setDest(relocd-delta);
    result.rtl->appendStmt(jump);
    SHOW_ASM(name<<" "<<relocd)
}

<commit_msg>A few improvements to debugging (-dd)<commit_after>/*
 * Copyright (C) 1998-2001, The University of Queensland
 * Copyright (C) 2001, Sun Microsystems, Inc
 * Copyright (C) 2002, Trent Waddington
 *
 * See the file "LICENSE.TERMS" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL
 * WARRANTIES.
 *
 */

/*==============================================================================
 * FILE:       njmcDecoder.cc
 * OVERVIEW:   This file contains the machine independent
 *             decoding functionality.
 *
 * $Revision$
 *============================================================================*/
/*
 * 27 Apr 02 - Mike: Mods for boomerang
 */

#include <assert.h>
#if defined(_MSC_VER) && _MSC_VER <= 1200
#pragma warning(disable:4786)
#endif

#include <stdarg.h>         // For varargs
#include "rtl.h"
#include "decoder.h"
#include "exp.h"
#include "register.h"
#include "cfg.h"
#include "proc.h"
#include "prog.h"
#include "BinaryFile.h"
#include "boomerang.h"
// For some reason, MSVC 5.00 complains about use of undefined types a lot
#if defined(_MSC_VER) && _MSC_VER <= 1100
#include "signature.h"		// For MSVC 5.00
#endif

/**********************************
 * NJMCDecoder methods.
 **********************************/

/*==============================================================================
 * FUNCTION:       NJMCDecoder::NJMCDecoder
 * OVERVIEW:
 * PARAMETERS:     None
 * RETURNS:        N/A
 *============================================================================*/
NJMCDecoder::NJMCDecoder()
{}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::instantiate
 * OVERVIEW:       Given an instruction name and a variable list of SemStr's
 *                 representing the actual operands of the instruction, use the
 *                 RTL template dictionary to return the instantiated RTL
 *                 representing the semantics of the instruction.
 * PARAMETERS:     name - instruction name
 *                 ... - Semantic String ptrs representing actual operands
 * RETURNS:        an instantiated list of Exps
 *============================================================================*/
std::list<Statement*>* NJMCDecoder::instantiate(ADDRESS pc, const char* name,
  ...) {
    // Get the signature of the instruction and extract its parts
    std::pair<std::string,unsigned> sig = RTLDict.getSignature(name);
    std::string opcode = sig.first;
    unsigned numOperands = sig.second;

    // Put the operands into a vector
    std::vector<Exp*> actuals(numOperands);
    va_list args;
    va_start(args,name);
    for (unsigned i = 0; i < numOperands; i++)
        actuals[i] = va_arg(args,Exp*);
    va_end(args);

    if (DEBUG_DECODER) {
        // Display a disassembly of this instruction if requested
        std::cout << std::hex << pc << std::dec << ": " << name << " ";
        for (std::vector<Exp*>::iterator itd = actuals.begin();
          itd != actuals.end(); itd++) {
            (*itd)->print(std::cout);
            if (itd != actuals.end()-1)
                std::cout << ", ";
        }
        std::cout << std::endl;
    }

    std::list<Statement*>* instance = RTLDict.instantiateRTL(opcode, actuals);

    return instance;
}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::instantiateNamedParam
 * OVERVIEW:       Similarly to the above, given a parameter name
 *                  and a list of Exp*'s representing sub-parameters,
 *                  return a fully substituted Exp for the whole expression
 * NOTE:           Caller must delete result
 * PARAMETERS:     name - parameter name
 *                 ... - Exp* representing actual operands
 * RETURNS:        an instantiated list of Exps
 *============================================================================*/
Exp* NJMCDecoder::instantiateNamedParam(char* name, ...) {
    if (RTLDict.ParamSet.find(name) == RTLDict.ParamSet.end()) {
        std::cerr << "No entry for named parameter '" << name << "'\n";
        return 0;
    }
    assert(RTLDict.DetParamMap.find(name) != RTLDict.DetParamMap.end());
    ParamEntry &ent = RTLDict.DetParamMap[name];
    if (ent.kind != PARAM_ASGN && ent.kind != PARAM_LAMBDA ) {
        std::cerr << "Attempt to instantiate expressionless parameter '" << name
          << "'\n";
        return 0;
    }
    // Start with the RHS
    assert(ent.asgn->getKind() == STMT_ASSIGN);
    Exp* result = ent.asgn->getRight()->clone();

    va_list args;
    va_start(args,name);
    for( std::list<std::string>::iterator it = ent.params.begin();
      it != ent.params.end(); it++ ) {
        Exp* formal = new Unary(opParam, new Const((char*)it->c_str()));
        Exp* actual = va_arg(args, Exp*);
        bool change;
        result = result->searchReplaceAll(formal, actual, change);
        delete formal;
    }
    return result;
}

/*==============================================================================
 * FUNCTION:       NJMCDecoder::substituteCallArgs
 * OVERVIEW:       In the event that it's necessary to synthesize the call of
 *                 a named parameter generated with instantiateNamedParam(),
 *                 this substituteCallArgs() will substitute the arguments that
 *                 follow into the expression.
 * NOTE:           Should only be used after instantiateNamedParam(name, ..);
 * NOTE:           exp (the pointer) could be changed
 * PARAMETERS:     name - parameter name
 *                 exp - expression to instantiate into
 *                 ... - Exp* representing actual operands
 * RETURNS:        an instantiated list of Exps
 *============================================================================*/
void NJMCDecoder::substituteCallArgs(char *name, Exp*& exp, ...)
{
    if (RTLDict.ParamSet.find(name) == RTLDict.ParamSet.end()) {
        std::cerr << "No entry for named parameter '" << name << "'\n";
        return;
    }
    ParamEntry &ent = RTLDict.DetParamMap[name];
    /*if (ent.kind != PARAM_ASGN && ent.kind != PARAM_LAMBDA) {
        std::cerr << "Attempt to instantiate expressionless parameter '" << name << "'\n";
        return;
    }*/

    va_list args;
    va_start(args, exp);
    for (std::list<std::string>::iterator it = ent.funcParams.begin();
         it != ent.funcParams.end(); it++) {
        Exp* formal = new Unary(opParam, new Const((char*)it->c_str()));
        Exp* actual = va_arg(args, Exp*);
        bool change;
        exp = exp->searchReplaceAll(formal, actual, change);
        delete formal;
    }
}

/*==============================================================================
 * FUNCTION:       DecodeResult::reset
 * OVERVIEW:       Resets the fields of a DecodeResult to their default values.
 * PARAMETERS:     <none>
 * RETURNS:        <nothing>
 *============================================================================*/
void DecodeResult::reset()
{
    numBytes = 0;
    type = NCT;
    valid = true;
    rtl = NULL;
    forceOutEdge = 0;
}

/*==============================================================================
 * These are functions used to decode instruction operands into
 * Exp*s.
 *============================================================================*/

/*==============================================================================
 * FUNCTION:        NJMCDecoder::dis_Reg
 * OVERVIEW:        Converts a numbered register to a suitable expression.
 * PARAMETERS:      reg - the register number, e.g. 0 for eax
 * RETURNS:         the Exp* for the register NUMBER (e.g. "int 36" for %f4)
 *============================================================================*/
Exp* NJMCDecoder::dis_Reg(int regNum)
{
      Exp* expr = Location::regOf(regNum);
      return expr;
}

/*==============================================================================
 * FUNCTION:        NJMCDecoder::dis_Num
 * OVERVIEW:        Converts a number to a Exp* expression.
 * PARAMETERS:      num - a number
 * RETURNS:         the Exp* representation of the given number
 *============================================================================*/
Exp* NJMCDecoder::dis_Num(unsigned num)
{
    Exp* expr = new Const((int)num);
    return expr;
}

/*==============================================================================
 * FUNCTION:        NJMCDecoder::unconditionalJump
 * OVERVIEW:        Process an unconditional jump instruction
 *                  Also check if the destination is a label
 * PARAMETERS:      <none>
 * RETURNS:         the reference to the RTLInstDict object
 *============================================================================*/
void NJMCDecoder::unconditionalJump(const char* name, int size,
  ADDRESS relocd, /*UserProc* proc,*/ int delta, ADDRESS pc, std::list<Statement*>* stmts,
  DecodeResult& result) {
    result.rtl = new RTL(pc, stmts);
    result.numBytes = size;
    GotoStatement* jump = new GotoStatement();
    jump->setDest(relocd-delta);
    result.rtl->appendStmt(jump);
    SHOW_ASM(name<<" "<<relocd)
}

<|endoftext|>


<commit_before>#include "net.hpp"
#include <gio/gio.h>
#include <iostream>

struct network_provider_backend
{
    /* setup backend AND initially populate the connection info, then set updated = true */
    virtual bool create(connection_info *store) = 0;
    /* called by the thread starter, see network_widget source code */
    virtual void thread_loop() = 0;

    virtual ~network_provider_backend() = 0;
};

network_provider_backend::~network_provider_backend()
{
}

static void
on_wifi_properties_changed (GDBusProxy          *proxy,
                            GVariant            *changed_properties,
                            const gchar* const  *invalidated_properties,
                            gpointer             user_data)
{
    connection_info *info = (connection_info*) user_data;
    if (g_variant_n_children(changed_properties) > 0)
    {
        GVariantIter *iter;
        g_variant_get(changed_properties, "a{sv}", &iter);

        const gchar *key;
        GVariant *value;
        while (g_variant_iter_loop(iter, "{&sv}", &key, &value))
        {
            if (std::string(key) == "Strength")
            {
                info->mutex.lock();
                info->strength = g_variant_get_byte(value);
                info->updated = true;
                info->mutex.unlock();
            }
        }

        g_variant_iter_free(iter);
    }
}

using updater_callback = std::function<void()>;

static void
on_nm_properties_changed (GDBusProxy          *proxy,
                            GVariant            *changed_properties,
                            const gchar* const  *invalidated_properties,
                            gpointer             user_data)
{
    updater_callback *callback = (updater_callback*) user_data;
    if (g_variant_n_children(changed_properties) > 0)
    {
        GVariantIter *iter;
        g_variant_get(changed_properties, "a{sv}", &iter);

        const gchar *key;
        GVariant *value;
        while (g_variant_iter_loop(iter, "{&sv}", &key, &value))
        {
            if (std::string(key) == "PrimaryConnection")
                (*callback)();
        }

        g_variant_iter_free(iter);
    }
}

struct network_manager_provider : public network_provider_backend
{
    connection_info *info;
    GDBusConnection *dbus_connection;
    GDBusProxy *nm_proxy;

#define NM_DBUS_NAME "org.freedesktop.NetworkManager"

    bool setup_dbus_connection()
    {
        GError *error = NULL;
        dbus_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);

        if (!dbus_connection)
        {
            std::cerr << "Failed to connect to system bus: "
                      << error->message << std::endl;
            return false;
        }

        nm_proxy = g_dbus_proxy_new_sync(dbus_connection,
                                         G_DBUS_PROXY_FLAGS_NONE, NULL,
                                         NM_DBUS_NAME,
                                         "/org/freedesktop/NetworkManager",
                                         "org.freedesktop.NetworkManager",
                                         NULL, &error);

        return true;
    }

    GDBusProxy* current_specific_proxy = NULL;

    void load_wifi_data(const gchar *ap)
    {
        GError *error = NULL;
        current_specific_proxy =
            g_dbus_proxy_new_sync(dbus_connection, G_DBUS_PROXY_FLAGS_NONE, NULL,
                                  NM_DBUS_NAME,
                                  ap,
                                  "org.freedesktop.NetworkManager.AccessPoint",
                                  NULL, &error);

        if (!current_specific_proxy)
        {
            std::cerr << "Failed to obtain AP info: " << error->message << std::endl;
            return;
        }

        GVariant *gv = g_dbus_proxy_get_cached_property(current_specific_proxy, "Strength");

        info->mutex.lock();
        info->strength = g_variant_get_byte(gv);
        info->updated = true;
        info->mutex.unlock();

        g_variant_unref(gv);

        g_signal_connect(current_specific_proxy, "g-properties-changed",
                         G_CALLBACK(on_wifi_properties_changed), info);
    }

    void load_bluetooth_data(const gchar *dev)
    {
        info->mutex.lock();
        /* TODO: implement */
    }

    void load_ethernet_data(const gchar *dev)
    {
        info->mutex.lock();

        info->icon = "none";
        info->strength = 100;
        info->name = "Ethernet";

        info->updated = true;
        info->mutex.unlock();
    }

    void active_connection_updated()
    {
        GVariant *gv = g_dbus_proxy_get_cached_property(
                nm_proxy, "PrimaryConnection");

        gsize n;
        const gchar *active_connection = g_variant_get_string(gv, &n);

        /* no active connection */
        if (std::string(active_connection) == "/")
        {
            info->mutex.lock();
            info->name = "No network";
            info->updated = true;
            info->strength = 0;
            info->mutex.unlock();

            return;
        }

        GError *error = NULL;
        GDBusProxy *aconn_proxy =
            g_dbus_proxy_new_sync(dbus_connection,
                                  G_DBUS_PROXY_FLAGS_NONE, NULL,
                                  NM_DBUS_NAME,
                                  active_connection,
                                  "org.freedesktop.NetworkManager.Connection.Active",
                                  NULL, &error);

        if (!aconn_proxy)
        {
            std::cerr << "Failed to get active connection: " << error->message << std::endl;
            return;
        }

        gv = g_dbus_proxy_get_cached_property(aconn_proxy, "Type");
        std::string type = g_variant_get_string(gv, &n);

        g_variant_unref(gv);
        gv = g_dbus_proxy_get_cached_property(aconn_proxy, "Id");

        info->mutex.lock();
        info->name = g_variant_get_string(gv, &n);
        info->mutex.unlock();

        g_variant_unref(gv);
        gv = g_dbus_proxy_get_cached_property(aconn_proxy, "SpecificObject");
        const gchar *object = g_variant_get_string(gv, &n);

        if (current_specific_proxy)
            g_object_unref(current_specific_proxy);

        if (type == "bluetooth")
        {
            load_bluetooth_data(object);
        } else if (type.find("ethernet") != std::string::npos)
        {
            load_ethernet_data(object);
        } else if (type.find("wireless") != std::string::npos)
        {
            load_wifi_data(object);
        }

        g_variant_unref(gv);
        g_object_unref(aconn_proxy);
    }

    void load_initial_connection_info()
    {
        /* don't have to lock mutex, as we are still in the main thread */
        info->updated = true;
        info->icon = info->name = "none";
        info->strength = 0;

        active_connection_updated();
    }

    bool create(connection_info *info)
    {
        this->info = info;

        if (!setup_dbus_connection())
            return false;

        load_initial_connection_info();
        return true;
    }

    void thread_loop()
    {
        updater_callback callback =
            std::bind(std::mem_fn(&network_manager_provider::active_connection_updated), this);

        g_signal_connect(nm_proxy, "g-properties-changed",
                         G_CALLBACK(on_nm_properties_changed), &callback);

        GMainLoop *loop = g_main_loop_new(NULL, false);
        g_main_loop_run(loop);

        g_main_loop_unref(loop);
        g_object_unref(nm_proxy);
    }

    ~network_manager_provider()
    {
    }
};

void network_widget::create()
{
    backend = new network_manager_provider();
    if (!backend->create(&connection))
    {
        delete backend;
        backend = nullptr;
        return;
    }

    updater_thread = std::thread([=] () { backend->thread_loop(); });

    cairo_set_font_size(cr, font_size);
    cairo_set_font_face(cr, cairo_font_face);
}

bool network_widget::update()
{
    bool result;
    connection.mutex.lock();
    result = connection.updated;
    connection.mutex.unlock();
    return result;
}

void network_widget::repaint()
{
    constexpr wayfire_color color_good = {0, 1, 0, 1},
                            color_avg  = {1, 1, 0.3, 1},
                            color_bad  = {1, 0, 0, 1};

    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    render_rounded_rectangle(cr, center_x - max_w / 2, 0, max_w, panel_h, 7,
            widget::background_color.r, widget::background_color.g,
            widget::background_color.b, widget::background_color.a);

    cairo_set_operator(cr, CAIRO_OPERATOR_ATOP);

    std::string text;
    wayfire_color color;

    connection.mutex.lock();

    text = connection.name;
    if (connection.strength >= 50)
        color = color_good;
    else if (connection.strength > 30)
        color = color_avg;
    else
        color = color_bad;
    connection.updated = false;

    connection.mutex.unlock();

    cairo_text_extents_t te;
    cairo_text_extents(cr, text.c_str(), &te);

    double x = 0, y = font_size;
    cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);

    x = center_x + max_w / 2 - te.width;

    cairo_move_to(cr, x, y);
    cairo_show_text(cr, text.c_str());
}
<commit_msg>shell: interpolate network color according to signal strength<commit_after>#include "net.hpp"
#include <gio/gio.h>
#include <iostream>

struct network_provider_backend
{
    /* setup backend AND initially populate the connection info, then set updated = true */
    virtual bool create(connection_info *store) = 0;
    /* called by the thread starter, see network_widget source code */
    virtual void thread_loop() = 0;

    virtual ~network_provider_backend() = 0;
};

network_provider_backend::~network_provider_backend()
{
}

static void
on_wifi_properties_changed (GDBusProxy          *proxy,
                            GVariant            *changed_properties,
                            const gchar* const  *invalidated_properties,
                            gpointer             user_data)
{
    connection_info *info = (connection_info*) user_data;
    if (g_variant_n_children(changed_properties) > 0)
    {
        GVariantIter *iter;
        g_variant_get(changed_properties, "a{sv}", &iter);

        const gchar *key;
        GVariant *value;
        while (g_variant_iter_loop(iter, "{&sv}", &key, &value))
        {
            if (std::string(key) == "Strength")
            {
                info->mutex.lock();
                info->strength = g_variant_get_byte(value);
                info->updated = true;
                info->mutex.unlock();
            }
        }

        g_variant_iter_free(iter);
    }
}

using updater_callback = std::function<void()>;

static void
on_nm_properties_changed (GDBusProxy          *proxy,
                            GVariant            *changed_properties,
                            const gchar* const  *invalidated_properties,
                            gpointer             user_data)
{
    updater_callback *callback = (updater_callback*) user_data;
    if (g_variant_n_children(changed_properties) > 0)
    {
        GVariantIter *iter;
        g_variant_get(changed_properties, "a{sv}", &iter);

        const gchar *key;
        GVariant *value;
        while (g_variant_iter_loop(iter, "{&sv}", &key, &value))
        {
            if (std::string(key) == "PrimaryConnection")
                (*callback)();
        }

        g_variant_iter_free(iter);
    }
}

struct network_manager_provider : public network_provider_backend
{
    connection_info *info;
    GDBusConnection *dbus_connection;
    GDBusProxy *nm_proxy;

#define NM_DBUS_NAME "org.freedesktop.NetworkManager"

    bool setup_dbus_connection()
    {
        GError *error = NULL;
        dbus_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);

        if (!dbus_connection)
        {
            std::cerr << "Failed to connect to system bus: "
                      << error->message << std::endl;
            return false;
        }

        nm_proxy = g_dbus_proxy_new_sync(dbus_connection,
                                         G_DBUS_PROXY_FLAGS_NONE, NULL,
                                         NM_DBUS_NAME,
                                         "/org/freedesktop/NetworkManager",
                                         "org.freedesktop.NetworkManager",
                                         NULL, &error);

        return true;
    }

    GDBusProxy* current_specific_proxy = NULL;

    void load_wifi_data(const gchar *ap)
    {
        GError *error = NULL;
        current_specific_proxy =
            g_dbus_proxy_new_sync(dbus_connection, G_DBUS_PROXY_FLAGS_NONE, NULL,
                                  NM_DBUS_NAME,
                                  ap,
                                  "org.freedesktop.NetworkManager.AccessPoint",
                                  NULL, &error);

        if (!current_specific_proxy)
        {
            std::cerr << "Failed to obtain AP info: " << error->message << std::endl;
            return;
        }

        GVariant *gv = g_dbus_proxy_get_cached_property(current_specific_proxy, "Strength");

        info->mutex.lock();
        info->strength = g_variant_get_byte(gv);
        info->updated = true;
        info->mutex.unlock();

        g_variant_unref(gv);

        g_signal_connect(current_specific_proxy, "g-properties-changed",
                         G_CALLBACK(on_wifi_properties_changed), info);
    }

    void load_bluetooth_data(const gchar *dev)
    {
        info->mutex.lock();
        /* TODO: implement */
    }

    void load_ethernet_data(const gchar *dev)
    {
        info->mutex.lock();

        info->icon = "none";
        info->strength = 100;
        info->name = "Ethernet";

        info->updated = true;
        info->mutex.unlock();
    }

    void active_connection_updated()
    {
        GVariant *gv = g_dbus_proxy_get_cached_property(
                nm_proxy, "PrimaryConnection");

        gsize n;
        const gchar *active_connection = g_variant_get_string(gv, &n);

        /* no active connection */
        if (std::string(active_connection) == "/")
        {
            info->mutex.lock();
            info->name = "No network";
            info->updated = true;
            info->strength = 0;
            info->mutex.unlock();

            return;
        }

        GError *error = NULL;
        GDBusProxy *aconn_proxy =
            g_dbus_proxy_new_sync(dbus_connection,
                                  G_DBUS_PROXY_FLAGS_NONE, NULL,
                                  NM_DBUS_NAME,
                                  active_connection,
                                  "org.freedesktop.NetworkManager.Connection.Active",
                                  NULL, &error);

        if (!aconn_proxy)
        {
            std::cerr << "Failed to get active connection: " << error->message << std::endl;
            return;
        }

        gv = g_dbus_proxy_get_cached_property(aconn_proxy, "Type");
        std::string type = g_variant_get_string(gv, &n);

        g_variant_unref(gv);
        gv = g_dbus_proxy_get_cached_property(aconn_proxy, "Id");

        info->mutex.lock();
        info->name = g_variant_get_string(gv, &n);
        info->mutex.unlock();

        g_variant_unref(gv);
        gv = g_dbus_proxy_get_cached_property(aconn_proxy, "SpecificObject");
        const gchar *object = g_variant_get_string(gv, &n);

        if (current_specific_proxy)
            g_object_unref(current_specific_proxy);

        if (type == "bluetooth")
        {
            load_bluetooth_data(object);
        } else if (type.find("ethernet") != std::string::npos)
        {
            load_ethernet_data(object);
        } else if (type.find("wireless") != std::string::npos)
        {
            load_wifi_data(object);
        }

        g_variant_unref(gv);
        g_object_unref(aconn_proxy);
    }

    void load_initial_connection_info()
    {
        /* don't have to lock mutex, as we are still in the main thread */
        info->updated = true;
        info->icon = info->name = "none";
        info->strength = 0;

        active_connection_updated();
    }

    bool create(connection_info *info)
    {
        this->info = info;

        if (!setup_dbus_connection())
            return false;

        load_initial_connection_info();
        return true;
    }

    void thread_loop()
    {
        updater_callback callback =
            std::bind(std::mem_fn(&network_manager_provider::active_connection_updated), this);

        g_signal_connect(nm_proxy, "g-properties-changed",
                         G_CALLBACK(on_nm_properties_changed), &callback);

        GMainLoop *loop = g_main_loop_new(NULL, false);
        g_main_loop_run(loop);

        g_main_loop_unref(loop);
        g_object_unref(nm_proxy);
    }

    ~network_manager_provider()
    {
    }
};

void network_widget::create()
{
    backend = new network_manager_provider();
    if (!backend->create(&connection))
    {
        delete backend;
        backend = nullptr;
        return;
    }

    updater_thread = std::thread([=] () { backend->thread_loop(); });

    cairo_set_font_size(cr, font_size);
    cairo_set_font_face(cr, cairo_font_face);
}

bool network_widget::update()
{
    bool result;
    connection.mutex.lock();
    result = connection.updated;
    connection.mutex.unlock();
    return result;
}

inline wayfire_color interpolate_color(wayfire_color start, wayfire_color end, float a)
{
    wayfire_color r;
    r.r = start.r * a + end.r * (1. - a);
    r.g = start.g * a + end.g * (1. - a);
    r.b = start.b * a + end.b * (1. - a);
    r.a = start.a * a + end.a * (1. - a);

    return r;
}

void network_widget::repaint()
{
    constexpr wayfire_color color_good = {0, 1, 0, 1},
                            color_avg  = {1, 1, 0.3, 1},
                            color_bad  = {1, 0, 0, 1};

    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    render_rounded_rectangle(cr, center_x - max_w / 2, 0, max_w, panel_h, 7,
            widget::background_color.r, widget::background_color.g,
            widget::background_color.b, widget::background_color.a);

    cairo_set_operator(cr, CAIRO_OPERATOR_ATOP);

    std::string text;
    wayfire_color color;

    connection.mutex.lock();

#define STRENGTH_GOOD 40
#define STRENGTH_AVG 25

    text = connection.name;
    if (connection.strength >= STRENGTH_GOOD)
        color = interpolate_color(color_good, color_avg,
                (connection.strength - STRENGTH_GOOD) * 1.0 / (100 - STRENGTH_GOOD));
    else if (connection.strength >= STRENGTH_AVG)
        color = interpolate_color(color_avg, color_bad,
                (connection.strength - STRENGTH_AVG) * 1.0 / (STRENGTH_GOOD - STRENGTH_AVG));
    else
        color = color_bad;

    connection.updated = false;
    connection.mutex.unlock();

    cairo_text_extents_t te;
    cairo_text_extents(cr, text.c_str(), &te);

    double x = 0, y = font_size;
    cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);

    x = center_x + max_w / 2 - te.width;

    cairo_move_to(cr, x, y);
    cairo_show_text(cr, text.c_str());
}
<|endoftext|>


<commit_before>#include "udp_connection.h"
#include "global_include.h"
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <cassert>

namespace dronelink {

UdpConnection::UdpConnection(DroneLinkImpl *parent,
                             int local_port_number) :
    Connection(parent),
    _local_port_number(local_port_number),
    _should_exit(false)
{
    if (_local_port_number == 0) {
        _local_port_number = DEFAULT_UDP_LOCAL_PORT;
    }
}

UdpConnection::~UdpConnection()
{
    // If no one explicitly called stop before, we should at least do it.
    stop();
}

bool UdpConnection::is_ok() const
{
    return true;
}

DroneLink::ConnectionResult UdpConnection::start()
{
    if (!start_mavlink_receiver()) {
        return DroneLink::ConnectionResult::CONNECTIONS_EXHAUSTED;
    }

    DroneLink::ConnectionResult ret = setup_port();
    if (ret != DroneLink::ConnectionResult::SUCCESS) {
        return ret;
    }

    start_recv_thread();

    return DroneLink::ConnectionResult::SUCCESS;
}

DroneLink::ConnectionResult UdpConnection::setup_port()
{
    _socket_fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (_socket_fd < 0) {
        Debug() << "socket error" << strerror(errno);
        return DroneLink::ConnectionResult::SOCKET_ERROR;
    }

    struct sockaddr_in addr;
    memset((char *)&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(_local_port_number);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(_socket_fd, (sockaddr *)&addr, sizeof(addr)) != 0) {
        Debug() << "bind error: " << strerror(errno);
        return DroneLink::ConnectionResult::BIND_ERROR;
    }

    return DroneLink::ConnectionResult::SUCCESS;
}

void UdpConnection::start_recv_thread()
{
    _recv_thread = new std::thread(receive, this);
}

DroneLink::ConnectionResult UdpConnection::stop()
{
    _should_exit = true;

    // This interrupts a recv/recvfrom call.
    shutdown(_socket_fd, SHUT_RDWR);

    if (_recv_thread) {
        _recv_thread->join();
        delete _recv_thread;
        _recv_thread = nullptr;
    }

    close(_socket_fd);

    // We need to stop this after stopping the receive thread, otherwise
    // it can happen that we interfere with the parsing of a message.
    stop_mavlink_receiver();

    return DroneLink::ConnectionResult::SUCCESS;
}

bool UdpConnection::send_message(const mavlink_message_t &message)
{
    if (_remote_ip.empty()) {
        Debug() << "Remote IP unknown";
        return false;
    }

    if (_remote_port_number == 0) {
        Debug() << "Remote port unknown";
        return false;
    }

    struct sockaddr_in dest_addr;
    memset((char *)&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    inet_pton(AF_INET, _remote_ip.c_str(), &dest_addr.sin_addr.s_addr);

    dest_addr.sin_port = htons(_remote_port_number);

    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
    uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);

    // TODO: remove this assert again
    assert(buffer_len <= MAVLINK_MAX_PACKET_LEN);

    int send_len = sendto(_socket_fd, buffer, buffer_len, 0,
                          (const sockaddr *)&dest_addr, sizeof(dest_addr));

    if (send_len != buffer_len) {
        Debug() << "sendto failure: " << strerror(errno);
        return false;
    }

    return true;
}

void UdpConnection::receive(UdpConnection *parent)
{
    // Enough for MTU 1500 bytes.
    char buffer[2048];

    while (!parent->_should_exit) {

        struct sockaddr_in src_addr = {};
        socklen_t src_addr_len = sizeof(src_addr);
        int recv_len = recvfrom(parent->_socket_fd, buffer, sizeof(buffer), 0,
                                (struct sockaddr *)&src_addr, &src_addr_len);

        if (recv_len == 0) {
            // This can happen when shutdown is called on the socket,
            // therefore we check _should_exit again.
            continue;
        }

        if (recv_len < 0) {
            Debug() << "recvfrom error: " << strerror(errno);
            continue;
        }

        int new_remote_port_number = ntohs(src_addr.sin_port);
        std::string new_remote_ip(inet_ntoa(src_addr.sin_addr));

        // TODO make calls to remote threadsafe.

        if (parent->_remote_ip.empty()) {

            if (parent->_remote_port_number == 0 ||
                parent->_remote_port_number == new_remote_port_number) {
                // Set IP if we don't know it yet.
                parent->_remote_ip = new_remote_ip;
                parent->_remote_port_number = new_remote_port_number;

                Debug() << "Partner IP: " << parent->_remote_ip
                        << ":" << parent->_remote_port_number;

            } else {

                Debug() << "Ignoring message from remote port " << new_remote_port_number
                        << " instead of " << parent->_remote_port_number;
                continue;
            }

        } else if (parent->_remote_ip.compare(new_remote_ip) != 0) {
            Debug() << "Ignoring message from IP: " << new_remote_ip;
            continue;

        } else {
            if (parent->_remote_port_number != new_remote_port_number) {
                Debug() << "Ignoring message from remote port " << new_remote_port_number
                        << " instead of " << parent->_remote_port_number;
                continue;
            }
        }

        parent->_mavlink_receiver->set_new_datagram(buffer, recv_len);

        // Parse all mavlink messages in one datagram. Once exhausted, we'll exit while.
        while (parent->_mavlink_receiver->parse_message()) {
            parent->receive_message(parent->_mavlink_receiver->get_last_message());
        }
    }
}

} // namespace dronelink
<commit_msg>udp_connection: another cleanup fix<commit_after>#include "udp_connection.h"
#include "global_include.h"
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <cassert>

namespace dronelink {

UdpConnection::UdpConnection(DroneLinkImpl *parent,
                             int local_port_number) :
    Connection(parent),
    _local_port_number(local_port_number),
    _should_exit(false)
{
    if (_local_port_number == 0) {
        _local_port_number = DEFAULT_UDP_LOCAL_PORT;
    }
}

UdpConnection::~UdpConnection()
{
    // If no one explicitly called stop before, we should at least do it.
    stop();
}

bool UdpConnection::is_ok() const
{
    return true;
}

DroneLink::ConnectionResult UdpConnection::start()
{
    if (!start_mavlink_receiver()) {
        return DroneLink::ConnectionResult::CONNECTIONS_EXHAUSTED;
    }

    DroneLink::ConnectionResult ret = setup_port();
    if (ret != DroneLink::ConnectionResult::SUCCESS) {
        return ret;
    }

    start_recv_thread();

    return DroneLink::ConnectionResult::SUCCESS;
}

DroneLink::ConnectionResult UdpConnection::setup_port()
{
    _socket_fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (_socket_fd < 0) {
        Debug() << "socket error" << strerror(errno);
        return DroneLink::ConnectionResult::SOCKET_ERROR;
    }

    struct sockaddr_in addr;
    memset((char *)&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(_local_port_number);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(_socket_fd, (sockaddr *)&addr, sizeof(addr)) != 0) {
        Debug() << "bind error: " << strerror(errno);
        return DroneLink::ConnectionResult::BIND_ERROR;
    }

    return DroneLink::ConnectionResult::SUCCESS;
}

void UdpConnection::start_recv_thread()
{
    _recv_thread = new std::thread(receive, this);
}

DroneLink::ConnectionResult UdpConnection::stop()
{
    _should_exit = true;

    // This should interrupt a recv/recvfrom call.
    shutdown(_socket_fd, SHUT_RDWR);

    // But on Mac, closing is also needed to stop blocking recv/recvfrom.
    close(_socket_fd);

    if (_recv_thread) {
        _recv_thread->join();
        delete _recv_thread;
        _recv_thread = nullptr;
    }

    // We need to stop this after stopping the receive thread, otherwise
    // it can happen that we interfere with the parsing of a message.
    stop_mavlink_receiver();

    return DroneLink::ConnectionResult::SUCCESS;
}

bool UdpConnection::send_message(const mavlink_message_t &message)
{
    if (_remote_ip.empty()) {
        Debug() << "Remote IP unknown";
        return false;
    }

    if (_remote_port_number == 0) {
        Debug() << "Remote port unknown";
        return false;
    }

    struct sockaddr_in dest_addr;
    memset((char *)&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    inet_pton(AF_INET, _remote_ip.c_str(), &dest_addr.sin_addr.s_addr);

    dest_addr.sin_port = htons(_remote_port_number);

    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
    uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);

    // TODO: remove this assert again
    assert(buffer_len <= MAVLINK_MAX_PACKET_LEN);

    int send_len = sendto(_socket_fd, buffer, buffer_len, 0,
                          (const sockaddr *)&dest_addr, sizeof(dest_addr));

    if (send_len != buffer_len) {
        Debug() << "sendto failure: " << strerror(errno);
        return false;
    }

    return true;
}

void UdpConnection::receive(UdpConnection *parent)
{
    // Enough for MTU 1500 bytes.
    char buffer[2048];

    while (!parent->_should_exit) {

        struct sockaddr_in src_addr = {};
        socklen_t src_addr_len = sizeof(src_addr);
        int recv_len = recvfrom(parent->_socket_fd, buffer, sizeof(buffer), 0,
                                (struct sockaddr *)&src_addr, &src_addr_len);

        if (recv_len == 0) {
            // This can happen when shutdown is called on the socket,
            // therefore we check _should_exit again.
            continue;
        }

        if (recv_len < 0) {
            // This happens on desctruction when close(_socket_fd) is called,
            // therefore be quiet.
            //Debug() << "recvfrom error: " << strerror(errno);
            continue;
        }

        int new_remote_port_number = ntohs(src_addr.sin_port);
        std::string new_remote_ip(inet_ntoa(src_addr.sin_addr));

        // TODO make calls to remote threadsafe.

        if (parent->_remote_ip.empty()) {

            if (parent->_remote_port_number == 0 ||
                parent->_remote_port_number == new_remote_port_number) {
                // Set IP if we don't know it yet.
                parent->_remote_ip = new_remote_ip;
                parent->_remote_port_number = new_remote_port_number;

                Debug() << "Partner IP: " << parent->_remote_ip
                        << ":" << parent->_remote_port_number;

            } else {

                Debug() << "Ignoring message from remote port " << new_remote_port_number
                        << " instead of " << parent->_remote_port_number;
                continue;
            }

        } else if (parent->_remote_ip.compare(new_remote_ip) != 0) {
            Debug() << "Ignoring message from IP: " << new_remote_ip;
            continue;

        } else {
            if (parent->_remote_port_number != new_remote_port_number) {
                Debug() << "Ignoring message from remote port " << new_remote_port_number
                        << " instead of " << parent->_remote_port_number;
                continue;
            }
        }

        parent->_mavlink_receiver->set_new_datagram(buffer, recv_len);

        // Parse all mavlink messages in one datagram. Once exhausted, we'll exit while.
        while (parent->_mavlink_receiver->parse_message()) {
            parent->receive_message(parent->_mavlink_receiver->get_last_message());
        }
    }
}

} // namespace dronelink
<|endoftext|>