<commit_before>#include <assert.h>
#include <collection.h>
#include <ppltasks.h>
#include <sstream>
#include "Statement.h"
#include "Database.h"

namespace SQLite3 {
  StatementPtr Statement::Prepare(sqlite3* sqlite, Platform::String^ sql) {
    sqlite3_stmt* statement;
    int ret = sqlite3_prepare16(sqlite, sql->Data(), -1, &statement, 0);

    if (ret != SQLITE_OK) {
      sqlite3_finalize(statement);
      throwSQLiteError(ret);
    }

    return StatementPtr(new Statement(statement));
  }

  Statement::Statement(sqlite3_stmt* statement)
    : statement(statement) {
  }

  Statement::~Statement() {
    sqlite3_finalize(statement);
  }

  void Statement::Bind(const SafeParameterVector& params) {
    for (SafeParameterVector::size_type i = 0; i < params.size(); ++i) {
      BindParameter(i + 1, params[i]);
    }
  }

  void Statement::Bind(ParameterMap^ params) {
    for (int i = 0; i < BindParameterCount(); ++i) {
      int index = i + 1;
      auto nameWithoutPrefix = BindParameterName(index).substr(1);
      auto name = ref new Platform::String(nameWithoutPrefix.data());
      if (params->HasKey(name)) {
        BindParameter(index, params->Lookup(name));
      }
    }
  }

  static inline uint64 FoundationTimeToUnixCompatible(Windows::Foundation::DateTime foundationTime) {
    return (foundationTime.UniversalTime / 10000) - 11644473600000;
  }

  void Statement::BindParameter(int index, Platform::Object^ value) {
    if (value == nullptr) {
      sqlite3_bind_null(statement, index);
    } else {
      auto typeCode = Platform::Type::GetTypeCode(value->GetType());
      switch (typeCode) {
      case Platform::TypeCode::DateTime:
        sqlite3_bind_int64(statement, index, FoundationTimeToUnixCompatible(static_cast<Windows::Foundation::DateTime>(value)));
        break;
      case Platform::TypeCode::Double:
        sqlite3_bind_double(statement, index, static_cast<double>(value));
        break;
      case Platform::TypeCode::String:
        sqlite3_bind_text16(statement, index, static_cast<Platform::String^>(value)->Data(), -1, SQLITE_TRANSIENT);
        break;
      case Platform::TypeCode::Boolean:
        sqlite3_bind_int(statement, index, static_cast<Platform::Boolean>(value) ? 1 : 0);
        break;
      case Platform::TypeCode::Int8:
      case Platform::TypeCode::Int16:
      case Platform::TypeCode::Int32:
      case Platform::TypeCode::UInt8:
      case Platform::TypeCode::UInt16:
      case Platform::TypeCode::UInt32:
        sqlite3_bind_int(statement, index, static_cast<int>(value));
        break;
      case Platform::TypeCode::Int64:
      case Platform::TypeCode::UInt64:
        sqlite3_bind_int64(statement, index, static_cast<int64>(value));
        break;
      default:
        throw ref new Platform::InvalidArgumentException();
      }
    }
  }

  int Statement::BindParameterCount() {
    return sqlite3_bind_parameter_count(statement);
  }

  std::wstring Statement::BindParameterName(int index) {
    return ToWString(sqlite3_bind_parameter_name(statement, index));
  }

  int Statement::BindText(int index, Platform::String^ val) {
    return sqlite3_bind_text16(statement, index, val->Data(), -1, SQLITE_TRANSIENT);
  }

  int Statement::BindInt(int index, int64 val) {
    return sqlite3_bind_int64(statement, index, val);
  }

  int Statement::BindDouble(int index, double val) {
    return sqlite3_bind_double(statement, index, val);
  }

  int Statement::BindNull(int index) {
    return sqlite3_bind_null(statement, index);
  }

  void Statement::Run() {
    Step();
  }

  Platform::String^ Statement::One() {
    std::wostringstream result;
    if (Step() == SQLITE_ROW) {
      GetRow(result);
      return ref new Platform::String(result.str().c_str());
    } else {
      return nullptr;
    }
  }

  Platform::String^ Statement::All() {
    std::wostringstream result;
    result << L"[";
    auto stepResult = Step();
    bool hasData = (stepResult == SQLITE_ROW);
    while (stepResult == SQLITE_ROW) {
      GetRow(result);
      result << L",";
      stepResult = Step();
    }
    if (hasData) {
      std::streamoff pos = result.tellp();
      result.seekp(pos-1);
    }
    result << L"]";
    return ref new Platform::String(result.str().c_str());
  }

  void Statement::Each(EachCallback^ callback) {
    while (Step() == SQLITE_ROW) {
      std::wostringstream output;
      GetRow(output);
      callback(ref new Platform::String(output.str().c_str()));
    }
  }

  void notifyUnlock(void* args[], int nArgs) {
    assert(nArgs == 1);
    for (int i = 0; i < nArgs; i++) {
      ((Statement*)args[i])->NotifyUnlock();
    }
  }

  void Statement::NotifyUnlock() {
    ReleaseMutex(dbLockMutex);
  }

  int Statement::Step() {
    int ret = sqlite3_step(statement);
    if (ret == SQLITE_LOCKED) {
      // HACK, HACK, HACK! Extract the sqlite connection from the statement
      sqlite3* db = (sqlite3*)((void**)statement)[0];
      dbLockMutex = CreateMutexExW(NULL, NULL, CREATE_MUTEX_INITIAL_OWNER, NULL);
      ret = sqlite3_unlock_notify(db, &notifyUnlock, this);
      if (ret == SQLITE_LOCKED) {
        ReleaseMutex(dbLockMutex);
        return SQLITE_LOCKED;
      }
      WaitForSingleObjectEx(dbLockMutex, INFINITE, false);
      sqlite3_reset(statement);
      return Step();
    }
    if (ret != SQLITE_ROW && ret != SQLITE_DONE) {
      throwSQLiteError(ret);
    }

    return ret;
  }

  bool Statement::ReadOnly() const {
    return sqlite3_stmt_readonly(statement) != 0;
  }

  void writeEscaped(std::wstring const& s, std::wostringstream& out) {
    out << '"';
    for (std::wstring::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
      wchar_t c = *i;
      if (' ' <= c && c <= '~' && c != '\\' && c != '"') {
        out << *i;
      }
      else {
        out << '\\';
        switch(c) {
        case '"':  out << '"';  break;
        case '\\': out << '\\'; break;
        case '\t': out << 't';  break;
        case '\r': out << 'r';  break;
        case '\n': out << 'n';  break;
        default:
          char const* const hexdig = "0123456789ABCDEF";
          out << 'x';
          out << hexdig[c >> 4];
          out << hexdig[c & 0xF];
        }
      }
    }
    out << '"';
  }

  void Statement::GetRow(std::wostringstream& outstream) {
    outstream << L"{";
    int columnCount = ColumnCount();
    for (int i = 0; i < columnCount; ++i) {
      auto colName = static_cast<const wchar_t*>(sqlite3_column_name16(statement, i));
      auto colValue = static_cast<const wchar_t*>(sqlite3_column_text16(statement, i));
      auto colType = ColumnType(i);
      outstream << L"\"" << colName  << L"\":";
      switch (colType) {
      case SQLITE_TEXT:
        writeEscaped(colValue, outstream);
        break;
      case SQLITE_INTEGER:
      case SQLITE_FLOAT:
        outstream << colValue;
        break;
      case SQLITE_NULL:
        outstream << L"null";
        break;
      }
      outstream << L",";
    }
    std::streamoff pos = outstream.tellp();
    outstream.seekp(pos - 1l);
    outstream << L"}";
  }

  Platform::Object^ Statement::GetColumn(int index) {
    switch (ColumnType(index)) {
    case SQLITE_INTEGER:
      return ColumnInt(index);
    case SQLITE_FLOAT:
      return ColumnDouble(index);
    case SQLITE_TEXT:
      return ColumnText(index);
    case SQLITE_NULL:
      return nullptr;
    default:
      throw ref new Platform::FailureException();
    }
  }

  int Statement::ColumnCount() {
    return sqlite3_column_count(statement);
  }

  int Statement::ColumnType(int index) {
    return sqlite3_column_type(statement, index);
  }

  Platform::String^ Statement::ColumnName(int index) {
    return ref new Platform::String(static_cast<const wchar_t*>(sqlite3_column_name16(statement, index)));
  }

  Platform::String^ Statement::ColumnText(int index) {
    return ref new Platform::String(static_cast<const wchar_t*>(sqlite3_column_text16(statement, index)));
  }

  int64 Statement::ColumnInt(int index) {
    return sqlite3_column_int64(statement, index);
  }

  double Statement::ColumnDouble(int index) {
    return sqlite3_column_double(statement, index);
  }
}
<commit_msg>Fix JSON string escaping<commit_after>#include <assert.h>
#include <collection.h>
#include <ppltasks.h>
#include <sstream>
#include <iomanip>
#include "Statement.h"
#include "Database.h"

namespace SQLite3 {
  StatementPtr Statement::Prepare(sqlite3* sqlite, Platform::String^ sql) {
    sqlite3_stmt* statement;
    int ret = sqlite3_prepare16(sqlite, sql->Data(), -1, &statement, 0);

    if (ret != SQLITE_OK) {
      sqlite3_finalize(statement);
      throwSQLiteError(ret);
    }

    return StatementPtr(new Statement(statement));
  }

  Statement::Statement(sqlite3_stmt* statement)
    : statement(statement) {
  }

  Statement::~Statement() {
    sqlite3_finalize(statement);
  }

  void Statement::Bind(const SafeParameterVector& params) {
    for (SafeParameterVector::size_type i = 0; i < params.size(); ++i) {
      BindParameter(i + 1, params[i]);
    }
  }

  void Statement::Bind(ParameterMap^ params) {
    for (int i = 0; i < BindParameterCount(); ++i) {
      int index = i + 1;
      auto nameWithoutPrefix = BindParameterName(index).substr(1);
      auto name = ref new Platform::String(nameWithoutPrefix.data());
      if (params->HasKey(name)) {
        BindParameter(index, params->Lookup(name));
      }
    }
  }

  static inline uint64 FoundationTimeToUnixCompatible(Windows::Foundation::DateTime foundationTime) {
    return (foundationTime.UniversalTime / 10000) - 11644473600000;
  }

  void Statement::BindParameter(int index, Platform::Object^ value) {
    if (value == nullptr) {
      sqlite3_bind_null(statement, index);
    } else {
      auto typeCode = Platform::Type::GetTypeCode(value->GetType());
      switch (typeCode) {
      case Platform::TypeCode::DateTime:
        sqlite3_bind_int64(statement, index, FoundationTimeToUnixCompatible(static_cast<Windows::Foundation::DateTime>(value)));
        break;
      case Platform::TypeCode::Double:
        sqlite3_bind_double(statement, index, static_cast<double>(value));
        break;
      case Platform::TypeCode::String:
        sqlite3_bind_text16(statement, index, static_cast<Platform::String^>(value)->Data(), -1, SQLITE_TRANSIENT);
        break;
      case Platform::TypeCode::Boolean:
        sqlite3_bind_int(statement, index, static_cast<Platform::Boolean>(value) ? 1 : 0);
        break;
      case Platform::TypeCode::Int8:
      case Platform::TypeCode::Int16:
      case Platform::TypeCode::Int32:
      case Platform::TypeCode::UInt8:
      case Platform::TypeCode::UInt16:
      case Platform::TypeCode::UInt32:
        sqlite3_bind_int(statement, index, static_cast<int>(value));
        break;
      case Platform::TypeCode::Int64:
      case Platform::TypeCode::UInt64:
        sqlite3_bind_int64(statement, index, static_cast<int64>(value));
        break;
      default:
        throw ref new Platform::InvalidArgumentException();
      }
    }
  }

  int Statement::BindParameterCount() {
    return sqlite3_bind_parameter_count(statement);
  }

  std::wstring Statement::BindParameterName(int index) {
    return ToWString(sqlite3_bind_parameter_name(statement, index));
  }

  int Statement::BindText(int index, Platform::String^ val) {
    return sqlite3_bind_text16(statement, index, val->Data(), -1, SQLITE_TRANSIENT);
  }

  int Statement::BindInt(int index, int64 val) {
    return sqlite3_bind_int64(statement, index, val);
  }

  int Statement::BindDouble(int index, double val) {
    return sqlite3_bind_double(statement, index, val);
  }

  int Statement::BindNull(int index) {
    return sqlite3_bind_null(statement, index);
  }

  void Statement::Run() {
    Step();
  }

  Platform::String^ Statement::One() {
    std::wostringstream result;
    if (Step() == SQLITE_ROW) {
      GetRow(result);
      return ref new Platform::String(result.str().c_str());
    } else {
      return nullptr;
    }
  }

  Platform::String^ Statement::All() {
    std::wostringstream result;
    result << L"[";
    auto stepResult = Step();
    bool hasData = (stepResult == SQLITE_ROW);
    while (stepResult == SQLITE_ROW) {
      GetRow(result);
      result << L",";
      stepResult = Step();
    }
    if (hasData) {
      std::streamoff pos = result.tellp();
      result.seekp(pos-1);
    }
    result << L"]";
    return ref new Platform::String(result.str().c_str());
  }

  void Statement::Each(EachCallback^ callback) {
    while (Step() == SQLITE_ROW) {
      std::wostringstream output;
      GetRow(output);
      callback(ref new Platform::String(output.str().c_str()));
    }
  }

  void notifyUnlock(void* args[], int nArgs) {
    assert(nArgs == 1);
    for (int i = 0; i < nArgs; i++) {
      ((Statement*)args[i])->NotifyUnlock();
    }
  }

  void Statement::NotifyUnlock() {
    ReleaseMutex(dbLockMutex);
  }

  int Statement::Step() {
    int ret = sqlite3_step(statement);
    if (ret == SQLITE_LOCKED) {
      // HACK, HACK, HACK! Extract the sqlite connection from the statement
      sqlite3* db = (sqlite3*)((void**)statement)[0];
      dbLockMutex = CreateMutexExW(NULL, NULL, CREATE_MUTEX_INITIAL_OWNER, NULL);
      ret = sqlite3_unlock_notify(db, &notifyUnlock, this);
      if (ret == SQLITE_LOCKED) {
        ReleaseMutex(dbLockMutex);
        return SQLITE_LOCKED;
      }
      WaitForSingleObjectEx(dbLockMutex, INFINITE, false);
      sqlite3_reset(statement);
      return Step();
    }
    if (ret != SQLITE_ROW && ret != SQLITE_DONE) {
      throwSQLiteError(ret);
    }

    return ret;
  }

  bool Statement::ReadOnly() const {
    return sqlite3_stmt_readonly(statement) != 0;
  }

  void writeEscaped(const std::wstring& s, std::wostringstream& out) {
    out << L'"';
    for (std::wstring::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
      wchar_t c = *i;
      if (L' ' <= c && c <= L'~' && c != L'\\' && c != L'"') {
        out << *i;
      }
      else {
        out << L'\\';
        switch(c) {
        case L'"':  out << L'"';  break;
        case L'\\': out << L'\\'; break;
        case L'\t': out << L't';  break;
        case L'\r': out << L'r';  break;
        case L'\n': out << L'n';  break;
        default:
          out << L'u';
          out << std::setw(4) << std::setfill(L'0') << std::hex << (WORD)c;
        }
      }
    }
    out << L'"';
  }

  void Statement::GetRow(std::wostringstream& outstream) {
    outstream << L'{';
    int columnCount = ColumnCount();
    for (int i = 0; i < columnCount; ++i) {
      auto colName = static_cast<const wchar_t*>(sqlite3_column_name16(statement, i));
      auto colValue = static_cast<const wchar_t*>(sqlite3_column_text16(statement, i));
      auto colType = ColumnType(i);
      outstream << L'"' << colName  << L"\":";
      switch (colType) {
      case SQLITE_TEXT:
        writeEscaped(colValue, outstream);
        break;
      case SQLITE_INTEGER:
      case SQLITE_FLOAT:
        outstream << colValue;
        break;
      case SQLITE_NULL:
        outstream << L"null";
        break;
      }
      outstream << L',';
    }
    std::streamoff pos = outstream.tellp();
    outstream.seekp(pos - 1l);
    outstream << L'}';
  }

  Platform::Object^ Statement::GetColumn(int index) {
    switch (ColumnType(index)) {
    case SQLITE_INTEGER:
      return ColumnInt(index);
    case SQLITE_FLOAT:
      return ColumnDouble(index);
    case SQLITE_TEXT:
      return ColumnText(index);
    case SQLITE_NULL:
      return nullptr;
    default:
      throw ref new Platform::FailureException();
    }
  }

  int Statement::ColumnCount() {
    return sqlite3_column_count(statement);
  }

  int Statement::ColumnType(int index) {
    return sqlite3_column_type(statement, index);
  }

  Platform::String^ Statement::ColumnName(int index) {
    return ref new Platform::String(static_cast<const wchar_t*>(sqlite3_column_name16(statement, index)));
  }

  Platform::String^ Statement::ColumnText(int index) {
    return ref new Platform::String(static_cast<const wchar_t*>(sqlite3_column_text16(statement, index)));
  }

  int64 Statement::ColumnInt(int index) {
    return sqlite3_column_int64(statement, index);
  }

  double Statement::ColumnDouble(int index) {
    return sqlite3_column_double(statement, index);
  }
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

//-------------------------------------------------------------------------
//                        Implemenation Class AliESDTZERO
//   This is a class that summarizes the TZERO data for the ESD
//   Origin: Christian Klein-Boesing, CERN, Christian.Klein-Boesing@cern.ch
//-------------------------------------------------------------------------

#include "AliESDTZERO.h"
#include "AliLog.h"

ClassImp(AliESDTZERO)

//______________________________________________________________________________
AliESDTZERO::AliESDTZERO() :
  TObject(),
  fT0clock(0),
  fT0zVertex(0),
  fT0timeStart(0),
  fT0trig(0),
  fPileup(kFALSE),
  fSattelite(kFALSE),
  fMultC(0),
  fMultA(0)

{
  for(int i = 0;i<24;i++) {
    fT0time[i] = fT0amplitude[i] = 0;
    for(Int_t iHit=0; iHit<5; iHit++) {
      fTimeFull[i][iHit] = 0;
      fOrA[iHit] = 0;
      fOrC[iHit] = 0;
      fTVDC[iHit] = 0;
    }
  }
  for(int i = 0;i<3;i++) fT0TOF[i]=0;
}
//______________________________________________________________________________
AliESDTZERO::AliESDTZERO(const AliESDTZERO &tzero ) :
  TObject(tzero),
  fT0clock(tzero.fT0clock),
  fT0zVertex(tzero.fT0zVertex),
  fT0timeStart(tzero.fT0timeStart),
  fT0trig(tzero.fT0trig),
  fPileup(tzero.fPileup),
  fSattelite(tzero.fSattelite),
  fMultC(tzero.fMultC),
  fMultA(tzero.fMultA)
{
  // copy constuctor
  for(int i = 0;i<3;i++) fT0TOF[i] = tzero.fT0TOF[i];

  for(int i = 0;i<24;i++){
    fT0time[i] = tzero.fT0time[i];
    fT0amplitude[i] = tzero.fT0amplitude[i];
    for(Int_t iHit=0; iHit<5; iHit++) {
      fTimeFull[i][iHit] = tzero.fTimeFull[i][iHit];
      fOrA[iHit] = tzero.fOrA[iHit];
      fOrC[iHit] = tzero.fOrC[iHit];
      fTVDC[iHit] = tzero.fTVDC[iHit];
    }
  }
}
//______________________________________________________________________________
AliESDTZERO& AliESDTZERO::operator=(const AliESDTZERO& tzero){
  // assigmnent operator
  if(this!=&tzero) {
    TObject::operator=(tzero);
    fT0clock = tzero.fT0clock;
    fT0zVertex = tzero.fT0zVertex;
    fT0timeStart = tzero.fT0timeStart;
    fMultC = tzero.fMultC;
    fMultA = tzero.fMultA;
    fT0trig = tzero.fT0trig;
    for(int i = 0;i<3;i++) fT0TOF[i] = tzero.fT0TOF[i];
    for(int i = 0;i<24;i++){
      fT0time[i] = tzero.fT0time[i];
      fT0amplitude[i] = tzero.fT0amplitude[i];
      for(Int_t iHit=0; iHit<5; iHit++) {
	fTimeFull[i][iHit] = tzero.fTimeFull[i][iHit];
	fOrA[iHit] = tzero.fOrA[iHit];
	fOrC[iHit] = tzero.fOrC[iHit];
	fTVDC[iHit] = tzero.fTVDC[iHit];
      }
   }
  }
  return *this;
}
//______________________________________________________________________________
void AliESDTZERO::Copy(TObject &obj) const {

  // this overwrites the virtual TOBject::Copy()
  // to allow run time copying without casting
  // in AliESDEvent

  if(this==&obj)return;
  AliESDTZERO *robj = dynamic_cast<AliESDTZERO*>(&obj);
  if(!robj)return; // not an AliESDTZERO
  *robj = *this;

}

//______________________________________________________________________________
void AliESDTZERO::Reset()
{
  // reset contents
  fT0clock=0;
  fT0zVertex = 0;
  fT0timeStart = 0;
  for(int i = 0;i<24;i++) {
    fT0time[i] = fT0amplitude[i] =  0;
    for(Int_t iHit=0; iHit<5; iHit++)  fTimeFull[i][iHit] = -10000;
  }
  for(Int_t iHit=0; iHit<5; iHit++) fOrA[iHit] = fOrC[iHit] = fTVDC[iHit] = -10000;

  for(int i = 0;i<3;i++) fT0TOF[i] = 0;
}

//______________________________________________________________________________
void AliESDTZERO::Print(const Option_t *) const
{
  // does noting fornow
  AliInfo(Form(" Vertex %f (T0A+T0C)/2 %f #channels T0signal %f ns OrA %f ns OrC %f \n",fT0zVertex,  fT0timeStart, fT0TOF[0],fT0TOF[1],fT0TOF[2]));

  Bool_t tr[5];
  for (Int_t i=0; i<5; i++) tr[i] = fT0trig & (1<<i);
  AliInfo(Form("T0 triggers %d %d %d %d %d",tr[0],tr[1],tr[2],tr[3],tr[4]));

}
<commit_msg>Initialization of data members in the assignment operator<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

//-------------------------------------------------------------------------
//                        Implemenation Class AliESDTZERO
//   This is a class that summarizes the TZERO data for the ESD
//   Origin: Christian Klein-Boesing, CERN, Christian.Klein-Boesing@cern.ch
//-------------------------------------------------------------------------

#include "AliESDTZERO.h"
#include "AliLog.h"

ClassImp(AliESDTZERO)

//______________________________________________________________________________
AliESDTZERO::AliESDTZERO() :
  TObject(),
  fT0clock(0),
  fT0zVertex(0),
  fT0timeStart(0),
  fT0trig(0),
  fPileup(kFALSE),
  fSattelite(kFALSE),
  fMultC(0),
  fMultA(0)

{
  for(int i = 0;i<24;i++) {
    fT0time[i] = fT0amplitude[i] = 0;
    for(Int_t iHit=0; iHit<5; iHit++) {
      fTimeFull[i][iHit] = 0;
      fOrA[iHit] = 0;
      fOrC[iHit] = 0;
      fTVDC[iHit] = 0;
    }
  }
  for(int i = 0;i<3;i++) fT0TOF[i]=0;
}
//______________________________________________________________________________
AliESDTZERO::AliESDTZERO(const AliESDTZERO &tzero ) :
  TObject(tzero),
  fT0clock(tzero.fT0clock),
  fT0zVertex(tzero.fT0zVertex),
  fT0timeStart(tzero.fT0timeStart),
  fT0trig(tzero.fT0trig),
  fPileup(tzero.fPileup),
  fSattelite(tzero.fSattelite),
  fMultC(tzero.fMultC),
  fMultA(tzero.fMultA)
{
  // copy constuctor
  for(int i = 0;i<3;i++) fT0TOF[i] = tzero.fT0TOF[i];

  for(int i = 0;i<24;i++){
    fT0time[i] = tzero.fT0time[i];
    fT0amplitude[i] = tzero.fT0amplitude[i];
    for(Int_t iHit=0; iHit<5; iHit++) {
      fTimeFull[i][iHit] = tzero.fTimeFull[i][iHit];
      fOrA[iHit] = tzero.fOrA[iHit];
      fOrC[iHit] = tzero.fOrC[iHit];
      fTVDC[iHit] = tzero.fTVDC[iHit];
    }
  }
}
//______________________________________________________________________________
AliESDTZERO& AliESDTZERO::operator=(const AliESDTZERO& tzero){
  // assigmnent operator
  if(this!=&tzero) {
    TObject::operator=(tzero);
    fT0clock = tzero.fT0clock;
    fT0zVertex = tzero.fT0zVertex;
    fT0timeStart = tzero.fT0timeStart;
    fPileup = tzero.fPileup;
    fSattelite = tzero.fSattelite;
    fMultC = tzero.fMultC;
    fMultA = tzero.fMultA;
    fT0trig = tzero.fT0trig;
    for(int i = 0;i<3;i++) fT0TOF[i] = tzero.fT0TOF[i];
    for(int i = 0;i<24;i++){
      fT0time[i] = tzero.fT0time[i];
      fT0amplitude[i] = tzero.fT0amplitude[i];
      for(Int_t iHit=0; iHit<5; iHit++) {
	fTimeFull[i][iHit] = tzero.fTimeFull[i][iHit];
	fOrA[iHit] = tzero.fOrA[iHit];
	fOrC[iHit] = tzero.fOrC[iHit];
	fTVDC[iHit] = tzero.fTVDC[iHit];
      }
   }
  }
  return *this;
}
//______________________________________________________________________________
void AliESDTZERO::Copy(TObject &obj) const {

  // this overwrites the virtual TOBject::Copy()
  // to allow run time copying without casting
  // in AliESDEvent

  if(this==&obj)return;
  AliESDTZERO *robj = dynamic_cast<AliESDTZERO*>(&obj);
  if(!robj)return; // not an AliESDTZERO
  *robj = *this;

}

//______________________________________________________________________________
void AliESDTZERO::Reset()
{
  // reset contents
  fT0clock=0;
  fT0zVertex = 0;
  fT0timeStart = 0;
  for(int i = 0;i<24;i++) {
    fT0time[i] = fT0amplitude[i] =  0;
    for(Int_t iHit=0; iHit<5; iHit++)  fTimeFull[i][iHit] = -10000;
  }
  for(Int_t iHit=0; iHit<5; iHit++) fOrA[iHit] = fOrC[iHit] = fTVDC[iHit] = -10000;

  for(int i = 0;i<3;i++) fT0TOF[i] = 0;
}

//______________________________________________________________________________
void AliESDTZERO::Print(const Option_t *) const
{
  // does noting fornow
  AliInfo(Form(" Vertex %f (T0A+T0C)/2 %f #channels T0signal %f ns OrA %f ns OrC %f \n",fT0zVertex,  fT0timeStart, fT0TOF[0],fT0TOF[1],fT0TOF[2]));

  Bool_t tr[5];
  for (Int_t i=0; i<5; i++) tr[i] = fT0trig & (1<<i);
  AliInfo(Form("T0 triggers %d %d %d %d %d",tr[0],tr[1],tr[2],tr[3],tr[4]));

}
<|endoftext|>


<commit_before>/* Copyright (c) 2008-2019 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "command.h"
#include "datatype.h"
#include "header.h"
#include "image.h"
#include "mrtrix.h"
#include "stride.h"
#include "types.h"

#include "algo/loop.h"
#include "algo/min_max.h"
#include "gui/mrview/colourmap.h"

using namespace MR;
using namespace App;

vector<std::string> colourmap_choices_std;
vector<const char*> colourmap_choices_cstr;

void usage ()
{

  const GUI::MRView::ColourMap::Entry* entry = GUI::MRView::ColourMap::maps;
  do {
    if (strcmp(entry->name, "Complex"))
      colourmap_choices_std.push_back (lowercase (entry->name));
    ++entry;
  } while (entry->name);
  colourmap_choices_cstr.reserve (colourmap_choices_std.size() + 1);
  for (const auto& s : colourmap_choices_std)
    colourmap_choices_cstr.push_back (s.c_str());
  colourmap_choices_cstr.push_back (nullptr);

  AUTHOR = "Robert E. Smith (robert.smith@florey.edu.au)";

  SYNOPSIS = "Apply a colour map to an image";

  DESCRIPTION
  + "Under typical usage, this command will receive as input ad 3D greyscale image, and "
    "output a 4D image with 3 volumes corresponding to red-green-blue components; "
    "other use cases are possible, and are described in more detail below."

  + "By default, the command will automatically determine the maximum and minimum "
    "intensities of the input image, and use that information to set the upper and "
    "lower bounds of the applied colourmap. This behaviour can be overridden by manually "
    "specifying these bounds using the -upper and -lower options respectively.";

  ARGUMENTS
  + Argument ("input",  "the input image").type_image_in()
  + Argument ("map",    "the colourmap to apply; choices are: " + join(colourmap_choices_std, ",")).type_choice (colourmap_choices_cstr.data())
  + Argument ("output", "the output image").type_image_out();

  OPTIONS
  + Option ("upper", "manually set the upper intensity of the colour mapping")
    + Argument ("value").type_float()

  + Option ("lower", "manually set the lower intensity of the colour mapping")
    + Argument ("value").type_float()

  + Option ("colour", "set the target colour for use of the 'colour' map (three comma-separated floating-point values)")
    + Argument ("values").type_sequence_float();

}

void run ()
{
  Header H_in = Header::open (argument[0]);
  const GUI::MRView::ColourMap::Entry colourmap = GUI::MRView::ColourMap::maps[argument[1]];
  Eigen::Vector3 fixed_colour (NaN, NaN, NaN);
  if (colourmap.is_colour) {
    if (!(H_in.ndim() == 3 || (H_in.ndim() == 4 && H_in.size(3) == 1)))
      throw Exception ("For applying a fixed colour, command expects a 3D image as input");
    auto opt = get_options ("colour");
    if (!opt.size())
      throw Exception ("For \'colour\' colourmap, target colour must be specified using the -colour option");
    const auto values = parse_floats (opt[0][0]);
    if (values.size() != 3)
      throw Exception ("Target colour must be specified as a comma-separated list of three values");
    fixed_colour = Eigen::Vector3 (values.data());
    if (fixed_colour.minCoeff() < 0.0)
      throw Exception ("Values for fixed colour provided via -colour option cannot be negative");
  } else if (colourmap.is_rgb) {
    if (!(H_in.ndim() == 4 && H_in.size(3) == 3))
      throw Exception ("\'rgb\' colourmap only applies to 4D images with 3 volumes");
    if (get_options ("lower").size()) {
      WARN ("Option -lower ignored: not compatible with \'rgb\' colourmap (a minimum of 0.0 is assumed)");
    }
  } else {
    if (!(H_in.ndim() == 3 || (H_in.ndim() == 4 && H_in.size(3) == 1)))
      throw Exception ("For standard colour maps, command expects a 3D image as input");
    if (get_options ("colour").size()) {
      WARN ("Option -colour ignored: only applies if \'colour\' colourmap is used");
    }
  }

  auto in = H_in.get_image<float>();
  float lower = int(argument[1]) == 6 ? 0.0 : get_option_value ("lower", NaN);
  float upper = get_option_value ("upper", NaN);
  if (!std::isfinite (lower) || !std::isfinite (upper)) {
    float image_min = NaN, image_max = NaN;
    min_max (in, image_min, image_max);
    if (int(argument[1]) == 6) { // RGB
      image_max = std::max (MR::abs (image_min), MR::abs (image_max));
    } else {
      if (!std::isfinite (lower)) {
        if (!std::isfinite (image_min))
          throw Exception ("Unable to determine minimum value from image");
        lower = image_min;
      }
    }
    if (!std::isfinite (upper)) {
      if (!std::isfinite (image_max))
        throw Exception ("Unable to determine maximum value from image");
      upper = image_max;
    }
  }
  const float multiplier = 1.0 / (upper - lower);

  auto scale = [&] (const float value) { return (multiplier * (value - lower)); };

  Header H_out (H_in);
  H_out.ndim() = 4;
  H_out.size(3) = 3;
  Stride::set (H_out, Stride::contiguous_along_axis (3, H_out));
  H_out.datatype() = DataType::Float32;
  H_out.datatype().set_byte_order_native();
  auto out = Image<float>::create (argument[2], H_out);

  if (colourmap.is_colour) {
    assert (fixed_colour.allFinite());
    for (auto l_outer = Loop ("Applying fixed RGB colour to greyscale image", H_in) (in, out); l_outer; ++l_outer) {
      const float amplitude = std::max (0.0f, std::min (1.0f, scale (in.value())));
      for (auto l_inner = Loop(3) (out); l_inner; ++l_inner)
        out.value() = amplitude * fixed_colour[out.index(3)];
    }
  } else if (colourmap.is_rgb) {
    for (auto l_outer = Loop ("Scaling RGB colour image", H_in) (in, out); l_outer; ++l_outer)
      out.value() = scale (in.value());
  } else {
    const GUI::MRView::ColourMap::Entry::basic_map_fn& map_fn = colourmap.basic_mapping;
    for (auto l_outer = Loop ("Mapping intensities to RGB colours", H_in) (in, out); l_outer; ++l_outer) {
      const Eigen::Array3f colour = map_fn (scale (in.value()));
      for (auto l_inner = Loop(3) (out); l_inner; ++l_inner)
        out.value() = colour[out.index(3)];
    }
  }
}
<commit_msg>mrcolour: Clamp input values<commit_after>/* Copyright (c) 2008-2019 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "command.h"
#include "datatype.h"
#include "header.h"
#include "image.h"
#include "mrtrix.h"
#include "stride.h"
#include "types.h"

#include "algo/loop.h"
#include "algo/min_max.h"
#include "gui/mrview/colourmap.h"

using namespace MR;
using namespace App;

vector<std::string> colourmap_choices_std;
vector<const char*> colourmap_choices_cstr;

void usage ()
{

  const GUI::MRView::ColourMap::Entry* entry = GUI::MRView::ColourMap::maps;
  do {
    if (strcmp(entry->name, "Complex"))
      colourmap_choices_std.push_back (lowercase (entry->name));
    ++entry;
  } while (entry->name);
  colourmap_choices_cstr.reserve (colourmap_choices_std.size() + 1);
  for (const auto& s : colourmap_choices_std)
    colourmap_choices_cstr.push_back (s.c_str());
  colourmap_choices_cstr.push_back (nullptr);

  AUTHOR = "Robert E. Smith (robert.smith@florey.edu.au)";

  SYNOPSIS = "Apply a colour map to an image";

  DESCRIPTION
  + "Under typical usage, this command will receive as input ad 3D greyscale image, and "
    "output a 4D image with 3 volumes corresponding to red-green-blue components; "
    "other use cases are possible, and are described in more detail below."

  + "By default, the command will automatically determine the maximum and minimum "
    "intensities of the input image, and use that information to set the upper and "
    "lower bounds of the applied colourmap. This behaviour can be overridden by manually "
    "specifying these bounds using the -upper and -lower options respectively.";

  ARGUMENTS
  + Argument ("input",  "the input image").type_image_in()
  + Argument ("map",    "the colourmap to apply; choices are: " + join(colourmap_choices_std, ",")).type_choice (colourmap_choices_cstr.data())
  + Argument ("output", "the output image").type_image_out();

  OPTIONS
  + Option ("upper", "manually set the upper intensity of the colour mapping")
    + Argument ("value").type_float()

  + Option ("lower", "manually set the lower intensity of the colour mapping")
    + Argument ("value").type_float()

  + Option ("colour", "set the target colour for use of the 'colour' map (three comma-separated floating-point values)")
    + Argument ("values").type_sequence_float();

}

void run ()
{
  Header H_in = Header::open (argument[0]);
  const GUI::MRView::ColourMap::Entry colourmap = GUI::MRView::ColourMap::maps[argument[1]];
  Eigen::Vector3 fixed_colour (NaN, NaN, NaN);
  if (colourmap.is_colour) {
    if (!(H_in.ndim() == 3 || (H_in.ndim() == 4 && H_in.size(3) == 1)))
      throw Exception ("For applying a fixed colour, command expects a 3D image as input");
    auto opt = get_options ("colour");
    if (!opt.size())
      throw Exception ("For \'colour\' colourmap, target colour must be specified using the -colour option");
    const auto values = parse_floats (opt[0][0]);
    if (values.size() != 3)
      throw Exception ("Target colour must be specified as a comma-separated list of three values");
    fixed_colour = Eigen::Vector3 (values.data());
    if (fixed_colour.minCoeff() < 0.0)
      throw Exception ("Values for fixed colour provided via -colour option cannot be negative");
  } else if (colourmap.is_rgb) {
    if (!(H_in.ndim() == 4 && H_in.size(3) == 3))
      throw Exception ("\'rgb\' colourmap only applies to 4D images with 3 volumes");
    if (get_options ("lower").size()) {
      WARN ("Option -lower ignored: not compatible with \'rgb\' colourmap (a minimum of 0.0 is assumed)");
    }
  } else {
    if (!(H_in.ndim() == 3 || (H_in.ndim() == 4 && H_in.size(3) == 1)))
      throw Exception ("For standard colour maps, command expects a 3D image as input");
    if (get_options ("colour").size()) {
      WARN ("Option -colour ignored: only applies if \'colour\' colourmap is used");
    }
  }

  auto in = H_in.get_image<float>();
  float lower = int(argument[1]) == 6 ? 0.0 : get_option_value ("lower", NaN);
  float upper = get_option_value ("upper", NaN);
  if (!std::isfinite (lower) || !std::isfinite (upper)) {
    float image_min = NaN, image_max = NaN;
    min_max (in, image_min, image_max);
    if (int(argument[1]) == 6) { // RGB
      image_max = std::max (MR::abs (image_min), MR::abs (image_max));
    } else {
      if (!std::isfinite (lower)) {
        if (!std::isfinite (image_min))
          throw Exception ("Unable to determine minimum value from image");
        lower = image_min;
      }
    }
    if (!std::isfinite (upper)) {
      if (!std::isfinite (image_max))
        throw Exception ("Unable to determine maximum value from image");
      upper = image_max;
    }
  }
  const float multiplier = 1.0f / (upper - lower);

  auto scale = [&] (const float value) { return std::max (0.0f, std::min (1.0f, multiplier * (value - lower))); };

  Header H_out (H_in);
  H_out.ndim() = 4;
  H_out.size(3) = 3;
  Stride::set (H_out, Stride::contiguous_along_axis (3, H_out));
  H_out.datatype() = DataType::Float32;
  H_out.datatype().set_byte_order_native();
  auto out = Image<float>::create (argument[2], H_out);

  if (colourmap.is_colour) {
    assert (fixed_colour.allFinite());
    for (auto l_outer = Loop ("Applying fixed RGB colour to greyscale image", H_in) (in, out); l_outer; ++l_outer) {
      const float amplitude = std::max (0.0f, std::min (1.0f, scale (in.value())));
      for (auto l_inner = Loop(3) (out); l_inner; ++l_inner)
        out.value() = amplitude * fixed_colour[out.index(3)];
    }
  } else if (colourmap.is_rgb) {
    for (auto l_outer = Loop ("Scaling RGB colour image", H_in) (in, out); l_outer; ++l_outer)
      out.value() = scale (in.value());
  } else {
    const GUI::MRView::ColourMap::Entry::basic_map_fn& map_fn = colourmap.basic_mapping;
    for (auto l_outer = Loop ("Mapping intensities to RGB colours", H_in) (in, out); l_outer; ++l_outer) {
      const Eigen::Array3f colour = map_fn (scale (in.value()));
      for (auto l_inner = Loop(3) (out); l_inner; ++l_inner)
        out.value() = colour[out.index(3)];
    }
  }
}
<|endoftext|>


<commit_before>#include "posixShell.h"

#include <cerrno>
#include <cstring>
#include <glob.h>
#include <limits>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
#include <wordexp.h>

#include <boost/filesystem.hpp>
#include <gsl/span>
#include <gsl/string_span>

#include "config/argv.h"
#include "config/envp.h"
#include "log/assertions.h"

#include "logger.h"
#include "task.h"

using std::numeric_limits;
using std::string;

using boost::filesystem::current_path;
using boost::system::error_code;
using boost::system::errc::success;
using gsl::span;
using gsl::zstring;

using execHelper::config::Argv;
using execHelper::config::Envp;

namespace {
const execHelper::core::PosixShell::ShellReturnCode POSIX_SUCCESS = 0U;
} // namespace

namespace execHelper {
namespace core {
PosixShell::ShellReturnCode PosixShell::execute(const Task& task) noexcept {
    pid_t pid = fork();
    if(pid == -1) {
        return std::numeric_limits<PosixShell::ShellReturnCode>::max();
    }
    if(pid == 0) {
        childProcessExecute(task);
    }
    return waitForChild(pid);
}

bool PosixShell::isExecutedSuccessfully(ShellReturnCode returnCode) const
    noexcept {
    return returnCode == POSIX_SUCCESS;
}

void PosixShell::childProcessExecute(const Task& task) const noexcept {
    int returnCode;

    // Change to the correct working directory
    error_code error;
    LOG(trace) << "Changing to directory " << task.getWorkingDirectory()
               << "...";
    current_path(task.getWorkingDirectory(), error);
    if(error != success) {
        LOG(error) << "Could not change to directory "
                   << task.getWorkingDirectory() << " (" << error << ")";
        _exit(127);
    }

    TaskCollection taskCollection = shellExpand(task);
    Envp envp(task.getEnvironment());
    LOG(trace) << R"(Environment: ")" << envp << R"(")";

    Argv argv(taskCollection);
    LOG(trace) << R"(Executing ")" << argv << R"(")";

    // A full copy of m_env is not required, since it is used in a separate process
    if((returnCode = execvpe(argv[0], argv.getArgv(), envp.getEnvp())) == -1) {
        LOG(error) << "Could not execvpe command: " << strerror(errno) << " ("
                   << errno << ")";
    }

    // execvp only returns if something goes wrong
    _exit(127);
}

PosixShell::ShellReturnCode PosixShell::waitForChild(pid_t pid) const noexcept {
    pid_t ret;
    int status;
    while((ret = waitpid(pid, &status, 0)) == -1) {
        if(errno != EINTR) {
            LOG(error) << "Child exited with error state";
            break;
        }
    }
    if(ret == -1) {
        LOG(error) << "Error executing command";
        return std::numeric_limits<PosixShell::ShellReturnCode>::max();
    }
    if(WIFEXITED(status)) {        // NOLINT(hicpp-signed-bitwise)
        if(!WEXITSTATUS(status)) { // NOLINT(hicpp-signed-bitwise)
            return POSIX_SUCCESS;
        }
        LOG(debug) << "Process terminated with return code '"
                   << WEXITSTATUS(status)
                   << "'";          // NOLINT(hicpp-signed-bitwise)
        return WEXITSTATUS(status); // NOLINT(hicpp-signed-bitwise)
    }
    if(WIFSIGNALED(status)) { // NOLINT(hicpp-signed-bitwise)
        LOG(warning) << "Child terminated because of uncaught signal '"
                     << WTERMSIG(status) << "'"; // NOLINT(hicpp-signed-bitwise)
        return WTERMSIG(status);                 // NOLINT(hicpp-signed-bitwise)
    }
    LOG(error) << "Child exited with unexpected child status: " << status;
    return status;
}

inline TaskCollection PosixShell::shellExpand(const Task& task) noexcept {
    return wordExpand(task);
}

inline TaskCollection PosixShell::wordExpand(const Task& task) noexcept {
    // Cache envp pointer
    char** cached_environ = environ;

    // Set global environment, since this is where wordexp will look for substitutions
    Envp envp = Envp(task.getEnvironment());
    environ = envp.getEnvp();

    TaskCollection result;
    for(const auto& taskItem : task.getTask()) {
        wordexp_t p{};
        size_t returnCode =
            wordexp(taskItem.c_str(), &p, WRDE_SHOWERR | WRDE_UNDEF);
        if(returnCode == 0) {
            span<zstring<>> w(p.we_wordv, p.we_wordc);
            for(const auto& expandedWord : w) {
                result.emplace_back(expandedWord);
            }
        } else {
            switch(returnCode) {
            case WRDE_BADVAL:
                user_feedback_error("Command contains undefined variable");
                break;
            case WRDE_SYNTAX:
                user_feedback_error("Syntax error in shell argument");
                break;
            case WRDE_BADCHAR:
                user_feedback_error("Bad character: Illegal occurrence of "
                                    "newline or one of |, &, ;, <, >, (, ), {, "
                                    "}.");
                break;
            default:
                user_feedback_error(
                    "An error occured during executing: " << returnCode);
                break;
            }
            result.push_back(taskItem);
        }
        wordfree(&p);
    }
    environ = cached_environ;
    return result;
}
} // namespace core
} // namespace execHelper
<commit_msg>Fix: Dev: Fixed source code format. !minor<commit_after>#include "posixShell.h"

#include <cerrno>
#include <cstring>
#include <glob.h>
#include <limits>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
#include <wordexp.h>

#include <boost/filesystem.hpp>
#include <gsl/span>
#include <gsl/string_span>

#include "config/argv.h"
#include "config/envp.h"
#include "log/assertions.h"

#include "logger.h"
#include "task.h"

using std::numeric_limits;
using std::string;

using boost::filesystem::current_path;
using boost::system::error_code;
using boost::system::errc::success;
using gsl::span;
using gsl::zstring;

using execHelper::config::Argv;
using execHelper::config::Envp;

namespace {
const execHelper::core::PosixShell::ShellReturnCode POSIX_SUCCESS = 0U;
} // namespace

namespace execHelper {
namespace core {
PosixShell::ShellReturnCode PosixShell::execute(const Task& task) noexcept {
    pid_t pid = fork();
    if(pid == -1) {
        return std::numeric_limits<PosixShell::ShellReturnCode>::max();
    }
    if(pid == 0) {
        childProcessExecute(task);
    }
    return waitForChild(pid);
}

bool PosixShell::isExecutedSuccessfully(ShellReturnCode returnCode) const
    noexcept {
    return returnCode == POSIX_SUCCESS;
}

void PosixShell::childProcessExecute(const Task& task) const noexcept {
    int returnCode;

    // Change to the correct working directory
    error_code error;
    LOG(trace) << "Changing to directory " << task.getWorkingDirectory()
               << "...";
    current_path(task.getWorkingDirectory(), error);
    if(error != success) {
        LOG(error) << "Could not change to directory "
                   << task.getWorkingDirectory() << " (" << error << ")";
        _exit(127);
    }

    TaskCollection taskCollection = shellExpand(task);
    Envp envp(task.getEnvironment());
    LOG(trace) << R"(Environment: ")" << envp << R"(")";

    Argv argv(taskCollection);
    LOG(trace) << R"(Executing ")" << argv << R"(")";

    // A full copy of m_env is not required, since it is used in a separate process
    if((returnCode = execvpe(argv[0], argv.getArgv(), envp.getEnvp())) == -1) {
        LOG(error) << "Could not execvpe command: " << strerror(errno) << " ("
                   << errno << ")";
    }

    // execvp only returns if something goes wrong
    _exit(127);
}

PosixShell::ShellReturnCode PosixShell::waitForChild(pid_t pid) const noexcept {
    pid_t ret;
    int status;
    while((ret = waitpid(pid, &status, 0)) == -1) {
        if(errno != EINTR) {
            LOG(error) << "Child exited with error state";
            break;
        }
    }
    if(ret == -1) {
        LOG(error) << "Error executing command";
        return std::numeric_limits<PosixShell::ShellReturnCode>::max();
    }
    if(WIFEXITED(status)) {        // NOLINT(hicpp-signed-bitwise)
        if(!WEXITSTATUS(status)) { // NOLINT(hicpp-signed-bitwise)
            return POSIX_SUCCESS;
        }
        LOG(debug) << "Process terminated with return code '"
                   << WEXITSTATUS(status) // NOLINT(hicpp-signed-bitwise)
                   << "'";
        return WEXITSTATUS(status); // NOLINT(hicpp-signed-bitwise)
    }
    if(WIFSIGNALED(status)) { // NOLINT(hicpp-signed-bitwise)
        LOG(warning) << "Child terminated because of uncaught signal '"
                     << WTERMSIG(status) << "'"; // NOLINT(hicpp-signed-bitwise)
        return WTERMSIG(status);                 // NOLINT(hicpp-signed-bitwise)
    }
    LOG(error) << "Child exited with unexpected child status: " << status;
    return status;
}

inline TaskCollection PosixShell::shellExpand(const Task& task) noexcept {
    return wordExpand(task);
}

inline TaskCollection PosixShell::wordExpand(const Task& task) noexcept {
    // Cache envp pointer
    char** cached_environ = environ;

    // Set global environment, since this is where wordexp will look for substitutions
    Envp envp = Envp(task.getEnvironment());
    environ = envp.getEnvp();

    TaskCollection result;
    for(const auto& taskItem : task.getTask()) {
        wordexp_t p{};
        size_t returnCode =
            wordexp(taskItem.c_str(), &p, WRDE_SHOWERR | WRDE_UNDEF);
        if(returnCode == 0) {
            span<zstring<>> w(p.we_wordv, p.we_wordc);
            for(const auto& expandedWord : w) {
                result.emplace_back(expandedWord);
            }
        } else {
            switch(returnCode) {
            case WRDE_BADVAL:
                user_feedback_error("Command contains undefined variable");
                break;
            case WRDE_SYNTAX:
                user_feedback_error("Syntax error in shell argument");
                break;
            case WRDE_BADCHAR:
                user_feedback_error("Bad character: Illegal occurrence of "
                                    "newline or one of |, &, ;, <, >, (, ), {, "
                                    "}.");
                break;
            default:
                user_feedback_error(
                    "An error occured during executing: " << returnCode);
                break;
            }
            result.push_back(taskItem);
        }
        wordfree(&p);
    }
    environ = cached_environ;
    return result;
}
} // namespace core
} // namespace execHelper
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include <nanoCLR_Runtime.h>

////////////////////////////////////////////////////////////////////////////////////////////////////

__nfweak void CLR_DBG_Debugger::Debugger_WaitForCommands()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
}

__nfweak void CLR_DBG_Debugger::PurgeCache()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
}

__nfweak HRESULT CLR_DBG_Debugger::CreateInstance()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
    g_CLR_DBG_Debugger = (CLR_DBG_Debugger*)&g_scratchDebugger[0];
    NANOCLR_SYSTEM_STUB_RETURN();
}

//--//

__nfweak HRESULT CLR_DBG_Debugger::DeleteInstance()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
    NANOCLR_SYSTEM_STUB_RETURN();
}

__nfweak void CLR_DBG_Debugger::BroadcastEvent( unsigned int cmd, unsigned int payloadSize, unsigned char* payload, unsigned int flags )
{
    (void)cmd;
    (void)payloadSize;
    (void)payload;
    (void)flags;

    NATIVE_PROFILE_CLR_DEBUGGER();
}

__nfweak void NFReleaseInfo::Init(
    NFReleaseInfo& NFReleaseInfo,
    unsigned short int major,
    unsigned short int minor,
    unsigned short int build,
    unsigned short int revision,
    const char *info,
    size_t infoLen,
    const char *target,
    size_t targetLen,
    const char *platform,
    size_t platformLen)
{
    size_t len;

    NFVersion::Init( NFReleaseInfo.Version, major, minor, build, revision );

    // better set these to empty strings, in case there is nothing to fill in
    NFReleaseInfo.InfoString[ 0 ] = 0;
    NFReleaseInfo.TargetName[ 0 ] = 0;
    NFReleaseInfo.PlatformName[ 0 ] = 0;

    // fill each one, if it was provided
    if ( NULL != info )
    {
        len = MIN(infoLen, sizeof(NFReleaseInfo.InfoString));
        memcpy(NFReleaseInfo.InfoString, info, len);
    }

    if ( NULL != target )
    {
        len = MIN(targetLen, sizeof(NFReleaseInfo.TargetName));
        memcpy(NFReleaseInfo.TargetName, target, len);
    }

    if ( NULL != platform )
    {
        len = MIN(platformLen, sizeof(NFReleaseInfo.PlatformName));
        memcpy(NFReleaseInfo.PlatformName, platform, len);
    }
}

__nfweak bool SOCKETS_DbgInitialize( int ComPortNum )
{
    NATIVE_PROFILE_CLR_DEBUGGER();

    (void)ComPortNum;
    return true;
}

__nfweak bool SOCKETS_DbgUninitialize( int ComPortNum )
{
    NATIVE_PROFILE_CLR_DEBUGGER();

    (void)ComPortNum;
    return true;
}
<commit_msg>Fix terminators on NFReleaseInfo strings (#1464)<commit_after>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include <nanoCLR_Runtime.h>

////////////////////////////////////////////////////////////////////////////////////////////////////

__nfweak void CLR_DBG_Debugger::Debugger_WaitForCommands()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
}

__nfweak void CLR_DBG_Debugger::PurgeCache()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
}

__nfweak HRESULT CLR_DBG_Debugger::CreateInstance()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
    g_CLR_DBG_Debugger = (CLR_DBG_Debugger*)&g_scratchDebugger[0];
    NANOCLR_SYSTEM_STUB_RETURN();
}

//--//

__nfweak HRESULT CLR_DBG_Debugger::DeleteInstance()
{
    NATIVE_PROFILE_CLR_DEBUGGER();
    NANOCLR_SYSTEM_STUB_RETURN();
}

__nfweak void CLR_DBG_Debugger::BroadcastEvent( unsigned int cmd, unsigned int payloadSize, unsigned char* payload, unsigned int flags )
{
    (void)cmd;
    (void)payloadSize;
    (void)payload;
    (void)flags;

    NATIVE_PROFILE_CLR_DEBUGGER();
}

__nfweak void NFReleaseInfo::Init(
    NFReleaseInfo& NFReleaseInfo,
    unsigned short int major,
    unsigned short int minor,
    unsigned short int build,
    unsigned short int revision,
    const char *info,
    size_t infoLen,
    const char *target,
    size_t targetLen,
    const char *platform,
    size_t platformLen)
{
    size_t len;

    NFVersion::Init( NFReleaseInfo.Version, major, minor, build, revision );

    // better set these to empty strings, in case there is nothing to fill in
    NFReleaseInfo.InfoString[ 0 ] = 0;
    NFReleaseInfo.TargetName[ 0 ] = 0;
    NFReleaseInfo.PlatformName[ 0 ] = 0;

    // fill each one, if it was provided
    if (NULL != info)
    {
        len = MIN(infoLen, sizeof(NFReleaseInfo.InfoString) - 1);
        memcpy(NFReleaseInfo.InfoString, info, len);
        NFReleaseInfo.InfoString[len] = 0;
    }

    if (NULL != target)
    {
        len = MIN(targetLen, sizeof(NFReleaseInfo.TargetName) - 1);
        memcpy(NFReleaseInfo.TargetName, target, len);
        NFReleaseInfo.TargetName[len] = 0;
    }

    if (NULL != platform)
    {
        len = MIN(platformLen, sizeof(NFReleaseInfo.PlatformName) - 1);
        memcpy(NFReleaseInfo.PlatformName, platform, len);
        NFReleaseInfo.PlatformName[len] = 0;
    }
}

__nfweak bool SOCKETS_DbgInitialize( int ComPortNum )
{
    NATIVE_PROFILE_CLR_DEBUGGER();

    (void)ComPortNum;
    return true;
}

__nfweak bool SOCKETS_DbgUninitialize( int ComPortNum )
{
    NATIVE_PROFILE_CLR_DEBUGGER();

    (void)ComPortNum;
    return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 */

#include <list>
#include <string>

#include "base/refcnt.hh"
#include "cpu/base_dyn_inst.hh"
#include "cpu/checker/cpu.hh"
#include "cpu/simple_thread.hh"
#include "cpu/thread_context.hh"
#include "cpu/static_inst.hh"
#include "mem/packet_impl.hh"
#include "sim/byteswap.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"

#if FULL_SYSTEM
#include "arch/vtophys.hh"
#endif // FULL_SYSTEM

using namespace std;
//The CheckerCPU does alpha only
using namespace AlphaISA;

template <class DynInstPtr>
void
Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
{
    DynInstPtr inst;

    // Either check this instruction, or add it to a list of
    // instructions waiting to be checked.  Instructions must be
    // checked in program order, so if a store has committed yet not
    // completed, there may be some instructions that are waiting
    // behind it that have completed and must be checked.
    if (!instList.empty()) {
        if (youngestSN < completed_inst->seqNum) {
            DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
                    completed_inst->seqNum, completed_inst->readPC());
            instList.push_back(completed_inst);
            youngestSN = completed_inst->seqNum;
        }

        if (!instList.front()->isCompleted()) {
            return;
        } else {
            inst = instList.front();
            instList.pop_front();
        }
    } else {
        if (!completed_inst->isCompleted()) {
            if (youngestSN < completed_inst->seqNum) {
                DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
                        completed_inst->seqNum, completed_inst->readPC());
                instList.push_back(completed_inst);
                youngestSN = completed_inst->seqNum;
            }
            return;
        } else {
            if (youngestSN < completed_inst->seqNum) {
                inst = completed_inst;
                youngestSN = completed_inst->seqNum;
            } else {
                return;
            }
        }
    }

    // Try to check all instructions that are completed, ending if we
    // run out of instructions to check or if an instruction is not
    // yet completed.
    while (1) {
        DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
                inst->seqNum, inst->readPC());
        unverifiedResult.integer = inst->readIntResult();
        unverifiedReq = inst->req;
        unverifiedMemData = inst->memData;
        numCycles++;

        Fault fault = NoFault;

        // maintain $r0 semantics
        thread->setIntReg(ZeroReg, 0);
#ifdef TARGET_ALPHA
        thread->setFloatRegDouble(ZeroReg, 0.0);
#endif // TARGET_ALPHA

        // Check if any recent PC changes match up with anything we
        // expect to happen.  This is mostly to check if traps or
        // PC-based events have occurred in both the checker and CPU.
        if (changedPC) {
            DPRINTF(Checker, "Changed PC recently to %#x\n",
                    thread->readPC());
            if (willChangePC) {
                if (newPC == thread->readPC()) {
                    DPRINTF(Checker, "Changed PC matches expected PC\n");
                } else {
                    warn("%lli: Changed PC does not match expected PC, "
                         "changed: %#x, expected: %#x",
                         curTick, thread->readPC(), newPC);
                    CheckerCPU::handleError();
                }
                willChangePC = false;
            }
            changedPC = false;
        }
        if (changedNextPC) {
            DPRINTF(Checker, "Changed NextPC recently to %#x\n",
                    thread->readNextPC());
            changedNextPC = false;
        }

        // Try to fetch the instruction

#if FULL_SYSTEM
#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
#else
#define IFETCH_FLAGS(pc)	0
#endif

        uint64_t fetch_PC = thread->readPC() & ~3;

        // set up memory request for instruction fetch
        memReq = new Request(inst->threadNumber, fetch_PC,
                             sizeof(uint32_t),
                             IFETCH_FLAGS(thread->readPC()),
                             fetch_PC, thread->readCpuId(), inst->threadNumber);

        bool succeeded = translateInstReq(memReq);

        if (!succeeded) {
            if (inst->getFault() == NoFault) {
                // In this case the instruction was not a dummy
                // instruction carrying an ITB fault.  In the single
                // threaded case the ITB should still be able to
                // translate this instruction; in the SMT case it's
                // possible that its ITB entry was kicked out.
                warn("%lli: Instruction PC %#x was not found in the ITB!",
                     curTick, thread->readPC());
                handleError(inst);

                // go to the next instruction
                thread->setPC(thread->readNextPC());
                thread->setNextPC(thread->readNextPC() + sizeof(MachInst));

                return;
            } else {
                // The instruction is carrying an ITB fault.  Handle
                // the fault and see if our results match the CPU on
                // the next tick().
                fault = inst->getFault();
            }
        }

        if (fault == NoFault) {
            Packet *pkt = new Packet(memReq, Packet::ReadReq,
                                     Packet::Broadcast);

            pkt->dataStatic(&machInst);

            icachePort->sendFunctional(pkt);

            delete pkt;

            // keep an instruction count
            numInst++;

            // decode the instruction
            machInst = gtoh(machInst);
            // Checks that the instruction matches what we expected it to be.
            // Checks both the machine instruction and the PC.
            validateInst(inst);

            curStaticInst = StaticInst::decode(makeExtMI(machInst,
                                                         thread->readPC()));

#if FULL_SYSTEM
            thread->setInst(machInst);
#endif // FULL_SYSTEM

            fault = inst->getFault();
        }

        // Discard fetch's memReq.
        delete memReq;
        memReq = NULL;

        // Either the instruction was a fault and we should process the fault,
        // or we should just go ahead execute the instruction.  This assumes
        // that the instruction is properly marked as a fault.
        if (fault == NoFault) {

            thread->funcExeInst++;

            fault = curStaticInst->execute(this, NULL);

            // Checks to make sure instrution results are correct.
            validateExecution(inst);

            if (curStaticInst->isLoad()) {
                ++numLoad;
            }
        }

        if (fault != NoFault) {
#if FULL_SYSTEM
            fault->invoke(tc);
            willChangePC = true;
            newPC = thread->readPC();
            DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
#else // !FULL_SYSTEM
            fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC());
#endif // FULL_SYSTEM
        } else {
#if THE_ISA != MIPS_ISA
            // go to the next instruction
            thread->setPC(thread->readNextPC());
            thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
#else
            // go to the next instruction
            thread->setPC(thread->readNextPC());
            thread->setNextPC(thread->readNextNPC());
            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
#endif

        }

#if FULL_SYSTEM
        // @todo: Determine if these should happen only if the
        // instruction hasn't faulted.  In the SimpleCPU case this may
        // not be true, but in the O3 or Ozone case this may be true.
        Addr oldpc;
        int count = 0;
        do {
            oldpc = thread->readPC();
            system->pcEventQueue.service(tc);
            count++;
        } while (oldpc != thread->readPC());
        if (count > 1) {
            willChangePC = true;
            newPC = thread->readPC();
            DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
        }
#endif

        // @todo:  Optionally can check all registers. (Or just those
        // that have been modified).
        validateState();

        if (memReq) {
            delete memReq;
            memReq = NULL;
        }

        // Continue verifying instructions if there's another completed
        // instruction waiting to be verified.
        if (instList.empty()) {
            break;
        } else if (instList.front()->isCompleted()) {
            inst = instList.front();
            instList.pop_front();
        } else {
            break;
        }
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::switchOut(Sampler *s)
{
    instList.clear();
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
{
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
{
    if (inst->readPC() != thread->readPC()) {
        warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
             curTick, inst->readPC(), thread->readPC());
        if (changedPC) {
            warn("%lli: Changed PCs recently, may not be an error",
                 curTick);
        } else {
            handleError(inst);
        }
    }

    MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);

    if (mi != machInst) {
        warn("%lli: Binary instructions do not match! Inst: %#x, "
             "checker: %#x",
             curTick, mi, machInst);
        handleError(inst);
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
{
    bool result_mismatch = false;
    if (inst->numDestRegs()) {
        // @todo: Support more destination registers.
        if (inst->isUnverifiable()) {
            // Unverifiable instructions assume they were executed
            // properly by the CPU. Grab the result from the
            // instruction and write it to the register.
            copyResult(inst);
        } else if (result.integer != inst->readIntResult()) {
            result_mismatch = true;
        }
    }

    if (result_mismatch) {
        warn("%lli: Instruction results do not match! (Values may not "
             "actually be integers) Inst: %#x, checker: %#x",
             curTick, inst->readIntResult(), result.integer);

        // It's useful to verify load values from memory, but in MP
        // systems the value obtained at execute may be different than
        // the value obtained at completion.  Similarly DMA can
        // present the same problem on even UP systems.  Thus there is
        // the option to only warn on loads having a result error.
        if (inst->isLoad() && warnOnlyOnLoadError) {
            copyResult(inst);
        } else {
            handleError(inst);
        }
    }

    if (inst->readNextPC() != thread->readNextPC()) {
        warn("%lli: Instruction next PCs do not match! Inst: %#x, "
             "checker: %#x",
             curTick, inst->readNextPC(), thread->readNextPC());
        handleError(inst);
    }

    // Checking side effect registers can be difficult if they are not
    // checked simultaneously with the execution of the instruction.
    // This is because other valid instructions may have modified
    // these registers in the meantime, and their values are not
    // stored within the DynInst.
    while (!miscRegIdxs.empty()) {
        int misc_reg_idx = miscRegIdxs.front();
        miscRegIdxs.pop();

        if (inst->tcBase()->readMiscReg(misc_reg_idx) !=
            thread->readMiscReg(misc_reg_idx)) {
            warn("%lli: Misc reg idx %i (side effect) does not match! "
                 "Inst: %#x, checker: %#x",
                 curTick, misc_reg_idx,
                 inst->tcBase()->readMiscReg(misc_reg_idx),
                 thread->readMiscReg(misc_reg_idx));
            handleError(inst);
        }
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::validateState()
{
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
{
    RegIndex idx = inst->destRegIdx(0);
    if (idx < TheISA::FP_Base_DepTag) {
        thread->setIntReg(idx, inst->readIntResult());
    } else if (idx < TheISA::Fpcr_DepTag) {
        thread->setFloatRegBits(idx, inst->readIntResult());
    } else {
        thread->setMiscReg(idx, inst->readIntResult());
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
{
    cprintf("Error detected, instruction information:\n");
    cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
            "Completed:%i\n",
            inst->readPC(),
            inst->readNextPC(),
            inst->seqNum,
            inst->threadNumber,
            inst->isCompleted());
    inst->dump();
    CheckerCPU::dumpAndExit();
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::dumpInsts()
{
    int num = 0;

    InstListIt inst_list_it = --(instList.end());

    cprintf("Inst list size: %i\n", instList.size());

    while (inst_list_it != instList.end())
    {
        cprintf("Instruction:%i\n",
                num);

        cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
                "Completed:%i\n",
                (*inst_list_it)->readPC(),
                (*inst_list_it)->seqNum,
                (*inst_list_it)->threadNumber,
                (*inst_list_it)->isCompleted());

        cprintf("\n");

        inst_list_it--;
        ++num;
    }

}
<commit_msg>Checker ignores any faults that occur in syscall emulation mode for now.<commit_after>/*
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 */

#include <list>
#include <string>

#include "base/refcnt.hh"
#include "cpu/base_dyn_inst.hh"
#include "cpu/checker/cpu.hh"
#include "cpu/simple_thread.hh"
#include "cpu/thread_context.hh"
#include "cpu/static_inst.hh"
#include "mem/packet_impl.hh"
#include "sim/byteswap.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"

#if FULL_SYSTEM
#include "arch/vtophys.hh"
#endif // FULL_SYSTEM

using namespace std;
//The CheckerCPU does alpha only
using namespace AlphaISA;

template <class DynInstPtr>
void
Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
{
    DynInstPtr inst;

    // Either check this instruction, or add it to a list of
    // instructions waiting to be checked.  Instructions must be
    // checked in program order, so if a store has committed yet not
    // completed, there may be some instructions that are waiting
    // behind it that have completed and must be checked.
    if (!instList.empty()) {
        if (youngestSN < completed_inst->seqNum) {
            DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
                    completed_inst->seqNum, completed_inst->readPC());
            instList.push_back(completed_inst);
            youngestSN = completed_inst->seqNum;
        }

        if (!instList.front()->isCompleted()) {
            return;
        } else {
            inst = instList.front();
            instList.pop_front();
        }
    } else {
        if (!completed_inst->isCompleted()) {
            if (youngestSN < completed_inst->seqNum) {
                DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
                        completed_inst->seqNum, completed_inst->readPC());
                instList.push_back(completed_inst);
                youngestSN = completed_inst->seqNum;
            }
            return;
        } else {
            if (youngestSN < completed_inst->seqNum) {
                inst = completed_inst;
                youngestSN = completed_inst->seqNum;
            } else {
                return;
            }
        }
    }

    // Try to check all instructions that are completed, ending if we
    // run out of instructions to check or if an instruction is not
    // yet completed.
    while (1) {
        DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
                inst->seqNum, inst->readPC());
        unverifiedResult.integer = inst->readIntResult();
        unverifiedReq = inst->req;
        unverifiedMemData = inst->memData;
        numCycles++;

        Fault fault = NoFault;

        // maintain $r0 semantics
        thread->setIntReg(ZeroReg, 0);
#ifdef TARGET_ALPHA
        thread->setFloatRegDouble(ZeroReg, 0.0);
#endif // TARGET_ALPHA

        // Check if any recent PC changes match up with anything we
        // expect to happen.  This is mostly to check if traps or
        // PC-based events have occurred in both the checker and CPU.
        if (changedPC) {
            DPRINTF(Checker, "Changed PC recently to %#x\n",
                    thread->readPC());
            if (willChangePC) {
                if (newPC == thread->readPC()) {
                    DPRINTF(Checker, "Changed PC matches expected PC\n");
                } else {
                    warn("%lli: Changed PC does not match expected PC, "
                         "changed: %#x, expected: %#x",
                         curTick, thread->readPC(), newPC);
                    CheckerCPU::handleError();
                }
                willChangePC = false;
            }
            changedPC = false;
        }
        if (changedNextPC) {
            DPRINTF(Checker, "Changed NextPC recently to %#x\n",
                    thread->readNextPC());
            changedNextPC = false;
        }

        // Try to fetch the instruction

#if FULL_SYSTEM
#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
#else
#define IFETCH_FLAGS(pc)	0
#endif

        uint64_t fetch_PC = thread->readPC() & ~3;

        // set up memory request for instruction fetch
        memReq = new Request(inst->threadNumber, fetch_PC,
                             sizeof(uint32_t),
                             IFETCH_FLAGS(thread->readPC()),
                             fetch_PC, thread->readCpuId(), inst->threadNumber);

        bool succeeded = translateInstReq(memReq);

        if (!succeeded) {
            if (inst->getFault() == NoFault) {
                // In this case the instruction was not a dummy
                // instruction carrying an ITB fault.  In the single
                // threaded case the ITB should still be able to
                // translate this instruction; in the SMT case it's
                // possible that its ITB entry was kicked out.
                warn("%lli: Instruction PC %#x was not found in the ITB!",
                     curTick, thread->readPC());
                handleError(inst);

                // go to the next instruction
                thread->setPC(thread->readNextPC());
                thread->setNextPC(thread->readNextPC() + sizeof(MachInst));

                return;
            } else {
                // The instruction is carrying an ITB fault.  Handle
                // the fault and see if our results match the CPU on
                // the next tick().
                fault = inst->getFault();
            }
        }

        if (fault == NoFault) {
            Packet *pkt = new Packet(memReq, Packet::ReadReq,
                                     Packet::Broadcast);

            pkt->dataStatic(&machInst);

            icachePort->sendFunctional(pkt);

            delete pkt;

            // keep an instruction count
            numInst++;

            // decode the instruction
            machInst = gtoh(machInst);
            // Checks that the instruction matches what we expected it to be.
            // Checks both the machine instruction and the PC.
            validateInst(inst);

            curStaticInst = StaticInst::decode(makeExtMI(machInst,
                                                         thread->readPC()));

#if FULL_SYSTEM
            thread->setInst(machInst);
#endif // FULL_SYSTEM

            fault = inst->getFault();
        }

        // Discard fetch's memReq.
        delete memReq;
        memReq = NULL;

        // Either the instruction was a fault and we should process the fault,
        // or we should just go ahead execute the instruction.  This assumes
        // that the instruction is properly marked as a fault.
        if (fault == NoFault) {

            thread->funcExeInst++;

            fault = curStaticInst->execute(this, NULL);

            // Checks to make sure instrution results are correct.
            validateExecution(inst);

            if (curStaticInst->isLoad()) {
                ++numLoad;
            }
        }

        if (fault != NoFault) {
#if FULL_SYSTEM
            fault->invoke(tc);
            willChangePC = true;
            newPC = thread->readPC();
            DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
#endif
        } else {
#if THE_ISA != MIPS_ISA
            // go to the next instruction
            thread->setPC(thread->readNextPC());
            thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
#else
            // go to the next instruction
            thread->setPC(thread->readNextPC());
            thread->setNextPC(thread->readNextNPC());
            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
#endif

        }

#if FULL_SYSTEM
        // @todo: Determine if these should happen only if the
        // instruction hasn't faulted.  In the SimpleCPU case this may
        // not be true, but in the O3 or Ozone case this may be true.
        Addr oldpc;
        int count = 0;
        do {
            oldpc = thread->readPC();
            system->pcEventQueue.service(tc);
            count++;
        } while (oldpc != thread->readPC());
        if (count > 1) {
            willChangePC = true;
            newPC = thread->readPC();
            DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
        }
#endif

        // @todo:  Optionally can check all registers. (Or just those
        // that have been modified).
        validateState();

        if (memReq) {
            delete memReq;
            memReq = NULL;
        }

        // Continue verifying instructions if there's another completed
        // instruction waiting to be verified.
        if (instList.empty()) {
            break;
        } else if (instList.front()->isCompleted()) {
            inst = instList.front();
            instList.pop_front();
        } else {
            break;
        }
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::switchOut(Sampler *s)
{
    instList.clear();
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
{
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
{
    if (inst->readPC() != thread->readPC()) {
        warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
             curTick, inst->readPC(), thread->readPC());
        if (changedPC) {
            warn("%lli: Changed PCs recently, may not be an error",
                 curTick);
        } else {
            handleError(inst);
        }
    }

    MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);

    if (mi != machInst) {
        warn("%lli: Binary instructions do not match! Inst: %#x, "
             "checker: %#x",
             curTick, mi, machInst);
        handleError(inst);
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
{
    bool result_mismatch = false;
    if (inst->numDestRegs()) {
        // @todo: Support more destination registers.
        if (inst->isUnverifiable()) {
            // Unverifiable instructions assume they were executed
            // properly by the CPU. Grab the result from the
            // instruction and write it to the register.
            copyResult(inst);
        } else if (result.integer != inst->readIntResult()) {
            result_mismatch = true;
        }
    }

    if (result_mismatch) {
        warn("%lli: Instruction results do not match! (Values may not "
             "actually be integers) Inst: %#x, checker: %#x",
             curTick, inst->readIntResult(), result.integer);

        // It's useful to verify load values from memory, but in MP
        // systems the value obtained at execute may be different than
        // the value obtained at completion.  Similarly DMA can
        // present the same problem on even UP systems.  Thus there is
        // the option to only warn on loads having a result error.
        if (inst->isLoad() && warnOnlyOnLoadError) {
            copyResult(inst);
        } else {
            handleError(inst);
        }
    }

    if (inst->readNextPC() != thread->readNextPC()) {
        warn("%lli: Instruction next PCs do not match! Inst: %#x, "
             "checker: %#x",
             curTick, inst->readNextPC(), thread->readNextPC());
        handleError(inst);
    }

    // Checking side effect registers can be difficult if they are not
    // checked simultaneously with the execution of the instruction.
    // This is because other valid instructions may have modified
    // these registers in the meantime, and their values are not
    // stored within the DynInst.
    while (!miscRegIdxs.empty()) {
        int misc_reg_idx = miscRegIdxs.front();
        miscRegIdxs.pop();

        if (inst->tcBase()->readMiscReg(misc_reg_idx) !=
            thread->readMiscReg(misc_reg_idx)) {
            warn("%lli: Misc reg idx %i (side effect) does not match! "
                 "Inst: %#x, checker: %#x",
                 curTick, misc_reg_idx,
                 inst->tcBase()->readMiscReg(misc_reg_idx),
                 thread->readMiscReg(misc_reg_idx));
            handleError(inst);
        }
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::validateState()
{
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
{
    RegIndex idx = inst->destRegIdx(0);
    if (idx < TheISA::FP_Base_DepTag) {
        thread->setIntReg(idx, inst->readIntResult());
    } else if (idx < TheISA::Fpcr_DepTag) {
        thread->setFloatRegBits(idx, inst->readIntResult());
    } else {
        thread->setMiscReg(idx, inst->readIntResult());
    }
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
{
    cprintf("Error detected, instruction information:\n");
    cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
            "Completed:%i\n",
            inst->readPC(),
            inst->readNextPC(),
            inst->seqNum,
            inst->threadNumber,
            inst->isCompleted());
    inst->dump();
    CheckerCPU::dumpAndExit();
}

template <class DynInstPtr>
void
Checker<DynInstPtr>::dumpInsts()
{
    int num = 0;

    InstListIt inst_list_it = --(instList.end());

    cprintf("Inst list size: %i\n", instList.size());

    while (inst_list_it != instList.end())
    {
        cprintf("Instruction:%i\n",
                num);

        cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
                "Completed:%i\n",
                (*inst_list_it)->readPC(),
                (*inst_list_it)->seqNum,
                (*inst_list_it)->threadNumber,
                (*inst_list_it)->isCompleted());

        cprintf("\n");

        inst_list_it--;
        ++num;
    }

}
<|endoftext|>