<commit_before>/**
 * @file Cosa/EEPROM.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_EEPROM_HH
#define COSA_EEPROM_HH

#include "Cosa/Types.h"
#include "Cosa/Power.hh"

/**
 * Driver for the ATmega/ATtiny internal EEPROM and abstraction of
 * EEPROM devices. See AT24CXX for an example of driver for external
 * EEPROM memory. The default device is the internal EEPROM. The class
 * EEPROM delegates to the EEPROM:Device class instance.
 */
class EEPROM {
public:
  /**
   * EEPROM Device abstraction; default device is the processors
   * internal EEPROM data memory. New devices should sub-class and
   * implement virtual methods.
   */
  class Device {
  public:
    /**
     * @override EEPROM::Device
     * Return true(1) if the device is ready, write cycle is completed,
     * otherwise false(0).
     * @return bool.
     */
    virtual bool is_ready();

    /**
     * @override EEPROM::Device
     * Read rom block with the given size into the buffer from the address.
     * Return number of bytes read or negative error code.
     * @param[in] dest buffer to read from rom into.
     * @param[in] src address in rom to read from.
     * @param[in] size number of bytes to read.
     * @return number of bytes or negative error code.
     */
    virtual int read(void* dest, const void* src, size_t size);

    /**
     * @override EEPROM::Device
     * Write rom block at given address with the contents from the buffer.
     * Return number of bytes written or negative error code.
     * @param[in] dest address in rom to write to.
     * @param[in] src buffer to write to rom.
     * @param[in] size number of bytes to write.
     * @return number of bytes or negative error code.
     */
    virtual int write(void* dest, const void* src, size_t size);

    /**
     * Default EEPROM device; handling of internal EEPROM Data Memory.
     */
    static Device eeprom;
  };

public:
  /**
   * Construct access object for EEPROM given device. Default device
   * is the internal EEPROM memory.
   * @param[in] dev device.
   */
  EEPROM(Device* dev = &Device::eeprom) : m_dev(dev) {}

  /**
   * Return true(1) if the device is ready, write cycle is completed,
   * otherwise false(0).
   * @return bool.
   */
  bool is_ready()
    __attribute__((always_inline))
  {
    return (m_dev->is_ready());
  }

  /**
   * Wait for write to complete.
   * @param[in] mode of sleep.
   */
  void write_await()
    __attribute__((always_inline))
  {
    while (!is_ready()) yield();
  }

  /**
   * Read rom block with the given size into the buffer from the address.
   * Return number of bytes read or negative error code.
   * @param[out] dest buffer to write to.
   * @param[in] src address in rom to read from.
   * @param[in] size number of bytes to read.
   * @return number of bytes or negative error code.
   */
  int read(void* dest, const void* src, size_t size)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, size));
  }

  /**
   * Template function to read a rom block with the given type to
   * given value reference. Returns true(1) if successful otherwise
   * false(0).
   * @param[out] dest address variable.
   * @param[in] src address in rom to read from.
   * @return bool.
   */
  template<class T> bool read(T* dest, const T* src)
  {
    return (m_dev->read(dest, src, sizeof(T)) == sizeof(T));
  }

  int read(unsigned char* dest, const unsigned char* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned char)));
  }

  int read(unsigned short* dest, const unsigned short* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned short)));
  }

  int read(unsigned int* dest, const unsigned int* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned int)));
  }

  int read(unsigned long* dest, const unsigned long* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned long)));
  }

  int read(char* dest, const char* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(char)));
  }

  int read(short* dest, const short* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(short)));
  }

  int read(int* dest, const int* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(int)));
  }

  int read(long* dest, const long* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(long)));
  }

  int read(float* dest, const float* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(float)));
  }

  /**
   * Write rom block at given address with the contents from the buffer.
   * Return number of bytes written or negative error code.
   * @param[out] dest address in rom to read write to.
   * @param[in] src buffer to write to rom.
   * @param[in] size number of bytes to write.
   * @return number of bytes or negative error code.
   */
  int write(void* dest, const void* src, size_t size)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, src, size));
  }

  /**
   * Write rom block at given address with the given value of given
   * data type. Returns true(1) if successful otherwise false(0).
   * @param[in] dest address in rom to read write to.
   * @param[in] src buffer to write to rom.
   * @param[in] size number of bytes to write.
   * @return boolean.
   */
  template<class T> int write(T* dest, const T* src)
  {
    return (m_dev->write(dest, src, sizeof(T)) == sizeof(T));
  }

  int write(unsigned char* dest, unsigned char src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned char)));
  }

  int write(unsigned short* dest, unsigned short src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned short)));
  }

  int write(unsigned int* dest, unsigned int src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned int)));
  }

  int write(unsigned long* dest, unsigned long src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned long)));
  }

  int write(char* dest, char src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(char)));
  }

  int write(short* dest, short src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(short)));
  }

  int write(int* dest, int src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(int)));
  }

  int write(long* dest, long src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(long)));
  }

  int write(float* dest, float src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(float)));
  }

private:
  Device* m_dev;		//!< Delegated device.
};

#endif
<commit_msg>Improve EEPROM interface.<commit_after>/**
 * @file Cosa/EEPROM.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_EEPROM_HH
#define COSA_EEPROM_HH

#include "Cosa/Types.h"
#include "Cosa/Power.hh"

/**
 * Driver for the ATmega/ATtiny internal EEPROM and abstraction of
 * EEPROM devices. See AT24CXX for an example of driver for external
 * EEPROM memory. The default device is the internal EEPROM. The class
 * EEPROM delegates to the EEPROM:Device class instance.
 */
class EEPROM {
public:
  /**
   * EEPROM Device abstraction; default device is the processors
   * internal EEPROM data memory. New devices should sub-class and
   * implement virtual methods.
   */
  class Device {
  public:
    /**
     * @override EEPROM::Device
     * Return true(1) if the device is ready, write cycle is completed,
     * otherwise false(0).
     * @return bool.
     */
    virtual bool is_ready();

    /**
     * @override EEPROM::Device
     * Read rom block with the given size into the buffer from the address.
     * Return number of bytes read or negative error code.
     * @param[in] dest buffer to read from rom into.
     * @param[in] src address in rom to read from.
     * @param[in] size number of bytes to read.
     * @return number of bytes or negative error code.
     */
    virtual int read(void* dest, const void* src, size_t size);

    /**
     * @override EEPROM::Device
     * Write rom block at given address with the contents from the buffer.
     * Return number of bytes written or negative error code.
     * @param[in] dest address in rom to write to.
     * @param[in] src buffer to write to rom.
     * @param[in] size number of bytes to write.
     * @return number of bytes or negative error code.
     */
    virtual int write(void* dest, const void* src, size_t size);

    /**
     * Default EEPROM device; handling of internal EEPROM Data Memory.
     */
    static Device eeprom;
  };

public:
  /**
   * Construct access object for EEPROM given device. Default device
   * is the internal EEPROM memory.
   * @param[in] dev device.
   */
  EEPROM(Device* dev = &Device::eeprom) : m_dev(dev) {}

  /**
   * Return true(1) if the device is ready, write cycle is completed,
   * otherwise false(0).
   * @return bool.
   */
  bool is_ready()
    __attribute__((always_inline))
  {
    return (m_dev->is_ready());
  }

  /**
   * Wait for write to complete.
   * @param[in] mode of sleep.
   */
  void write_await()
    __attribute__((always_inline))
  {
    while (!is_ready()) yield();
  }

  /**
   * Read rom block with the given size into the buffer from the address.
   * Return number of bytes read or negative error code.
   * @param[out] dest buffer to write to.
   * @param[in] src address in rom to read from.
   * @param[in] size number of bytes to read.
   * @return number of bytes or negative error code.
   */
  int read(void* dest, const void* src, size_t size)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, size));
  }

  /**
   * Template function to read a rom block with the given type to
   * given value reference. Returns number of bytes read or negative error code.
   * @param[out] dest address variable.
   * @param[in] src address in rom to read from.
   * @return number of bytes or negative error code.
   */
  template<class T> int read(T* dest, const T* src)
  {
    return (m_dev->read(dest, src, sizeof(T)));
  }

  int read(unsigned char* dest, const unsigned char* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned char)));
  }

  int read(unsigned short* dest, const unsigned short* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned short)));
  }

  int read(unsigned int* dest, const unsigned int* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned int)));
  }

  int read(unsigned long* dest, const unsigned long* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(unsigned long)));
  }

  int read(char* dest, const char* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(char)));
  }

  int read(short* dest, const short* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(short)));
  }

  int read(int* dest, const int* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(int)));
  }

  int read(long* dest, const long* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(long)));
  }

  int read(float* dest, const float* src)
    __attribute__((always_inline))
  {
    return (m_dev->read(dest, src, sizeof(float)));
  }

  /**
   * Write rom block at given address with the contents from the buffer.
   * Return number of bytes written or negative error code.
   * @param[out] dest address in rom to read write to.
   * @param[in] src buffer to write to rom.
   * @param[in] size number of bytes to write.
   * @return number of bytes or negative error code.
   */
  int write(void* dest, const void* src, size_t size)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, src, size));
  }

  /**
   * Write rom block at given address with the given value of given
   * data type. Returns number of bytes written or negative error code.
   * @param[in] dest address in rom to read write to.
   * @param[in] src buffer to write to rom.
   * @param[in] size number of bytes to write.
   * @return number of bytes or negative error code.
   */
  template<class T> int write(T* dest, const T* src)
  {
    return (m_dev->write(dest, src, sizeof(T)));
  }

  int write(unsigned char* dest, unsigned char src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned char)));
  }

  int write(unsigned short* dest, unsigned short src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned short)));
  }

  int write(unsigned int* dest, unsigned int src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned int)));
  }

  int write(unsigned long* dest, unsigned long src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(unsigned long)));
  }

  int write(char* dest, char src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(char)));
  }

  int write(short* dest, short src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(short)));
  }

  int write(int* dest, int src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(int)));
  }

  int write(long* dest, long src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(long)));
  }

  int write(float* dest, float src)
    __attribute__((always_inline))
  {
    return (m_dev->write(dest, &src, sizeof(float)));
  }

private:
  Device* m_dev;		//!< Delegated device.
};

#endif
<|endoftext|>


<commit_before>// $Id$

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * 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.                  *
 **************************************************************************/

/** @file   AliHLTAltroChannelSelectorComponent.cxx
    @author Matthias Richter
    @date
    @brief  A filter/selective readout component for TPC Altro data. */

// see header file for class documentation
// or
// refer to README to build package
// or
// visit http://web.ift.uib.no/~kjeks/doc/alice-hlt

#include <cassert>
#include "AliHLTAltroChannelSelectorComponent.h"
#include "AliHLTTPCTransform.h"
#include "AliHLTTPCDigitReaderRaw.h"
#include "AliHLTTPCDefinitions.h"
#include "AliHLTTPCPadArray.h"

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTAltroChannelSelectorComponent)

AliHLTAltroChannelSelectorComponent::AliHLTAltroChannelSelectorComponent()
  :
  AliHLTProcessor(),
  fRawreaderMode(0)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTAltroChannelSelectorComponent::~AliHLTAltroChannelSelectorComponent()
{
  // see header file for class documentation
}

const char* AliHLTAltroChannelSelectorComponent::GetComponentID()
{
  // see header file for class documentation
  return "AltroChannelSelector";
}

void AliHLTAltroChannelSelectorComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
{
  // see header file for class documentation
  list.clear();
  list.push_back(kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC);
  list.push_back(AliHLTTPCDefinitions::fgkActivePadsDataType);
}

AliHLTComponentDataType AliHLTAltroChannelSelectorComponent::GetOutputDataType()
{
  // see header file for class documentation
  return kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC;
}

void AliHLTAltroChannelSelectorComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
{
  // see header file for class documentation
  constBase=0;
  inputMultiplier=1.0;
}

AliHLTComponent* AliHLTAltroChannelSelectorComponent::Spawn()
{
  // see header file for class documentation
  return new AliHLTAltroChannelSelectorComponent;
}

int AliHLTAltroChannelSelectorComponent::DoInit(int argc, const char** argv)
{
  // see header file for class documentation
  int iResult=0;
  TString argument="";
  bool bMissingParam=0;
  for (int i=0; i<argc && iResult>=0; i++) {
    argument=argv[i];
    if (argument.IsNull()) continue;

    // -rawreadermode
    if (argument.CompareTo("-rawreadermode")==0) {
      if ((bMissingParam=(++i>=argc))) break;
      int mode=AliHLTTPCDigitReaderRaw::DecodeMode(argv[i]);
      if (mode<0) {
	HLTError("invalid rawreadermode specifier '%s'", argv[i]);
	iResult=-EINVAL;
      } else {
	fRawreaderMode=static_cast<unsigned>(mode);
      }
    } else {
      iResult=-EINVAL;
    }
  }

  if (bMissingParam) {
    HLTError("missing parameter for argument %s", argument.Data());
    iResult=-EINVAL;
  }

  return iResult;
}

int AliHLTAltroChannelSelectorComponent::DoDeinit()
{
  // see header file for class documentation
  return 0;
}

int AliHLTAltroChannelSelectorComponent::DoEvent(const AliHLTComponentEventData& evtData,
						 const AliHLTComponentBlockData* blocks,
						 AliHLTComponentTriggerData& /*trigData*/,
						 AliHLTUInt8_t* outputPtr,
						 AliHLTUInt32_t& size,
						 AliHLTComponentBlockDataList& outputBlocks )
{
  // see header file for class documentation
  int iResult=0;

  // process the DLL input
  int blockno=0;
  const AliHLTComponentBlockData* pDesc=NULL;

  for (pDesc=GetFirstInputBlock(kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC); pDesc!=NULL; pDesc=GetNextInputBlock(), blockno++) {

    // search for the active pad information
    AliHLTTPCPadArray::AliHLTTPCActivePads* pActivePadsArray=NULL;
    int iNofActivePads=0;
    for (int i=0; i<(int)evtData.fBlockCnt; i++ ) {
      if (blocks[i].fDataType == AliHLTTPCDefinitions::fgkActivePadsDataType &&
	  blocks[i].fSpecification==pDesc->fSpecification) {
	pActivePadsArray=reinterpret_cast<AliHLTTPCPadArray::AliHLTTPCActivePads*>(blocks[i].fPtr);
	iNofActivePads=blocks[i].fSize/sizeof(AliHLTTPCPadArray::AliHLTTPCActivePads);
      }
    }
    if (pActivePadsArray==NULL) {
      HLTWarning("no block of type %s for specification 0x%08x available, data block unchanged",
		 DataType2Text(AliHLTTPCDefinitions::fgkActivePadsDataType).c_str(),
		 pDesc->fSpecification);
      // forward the whole block
      outputBlocks.push_back(*pDesc);
      continue;
    }

    int part=AliHLTTPCDefinitions::GetMinPatchNr(*pDesc);
    assert(part==AliHLTTPCDefinitions::GetMaxPatchNr(*pDesc));
    int slice=AliHLTTPCDefinitions::GetMinSliceNr(*pDesc);
    assert(slice==AliHLTTPCDefinitions::GetMaxSliceNr(*pDesc));
    int firstRow=AliHLTTPCTransform::GetFirstRow(part);
    int lastRow=AliHLTTPCTransform::GetLastRow(part);
    AliHLTTPCDigitReaderRaw reader(fRawreaderMode);
    HLTDebug("init reader %p size %d", pDesc->fPtr,pDesc->fSize);
    reader.InitBlock(pDesc->fPtr,pDesc->fSize,firstRow,lastRow,part,slice);
    int iSelected=0;
    int iTotal=0;
    AliHLTUInt32_t iOutputSize=0;
    AliHLTUInt32_t iCapacity=size;
    while (reader.NextAltroBlock()) {
      iTotal++;
      int active=0;
      for (; active<iNofActivePads; active++) {
	if ((int)pActivePadsArray[active].fRow==reader.GetRow() &&
	    (int)pActivePadsArray[active].fPad==reader.GetPad()) {
	  break;
	}
      }
      if (active>=iNofActivePads) {
	HLTDebug("ALTRO block Row %d, Pad %d discarded (inactive)", reader.GetRow(), reader.GetPad());
	continue;
      }

      iSelected++;
      void* pChannel=NULL;
      AliHLTUInt16_t hwAddress=~(AliHLTUInt16_t)0;
      int channelSize=reader.GetAltroChannelRawData(pChannel, hwAddress);
      HLTDebug("ALTRO block hwAddress 0x%08x Row/Pad %d/%d selected (active), size %d", hwAddress, reader.GetRow(), reader.GetPad(), channelSize);
      if (channelSize>0 && pChannel!=NULL) {
	if (iOutputSize==0) {
	  // first add the RCU trailer
	  unsigned rcuTrailerLength=reader.GetRCUDataBlockLength();
	  AliHLTUInt8_t* pSrc=reinterpret_cast<AliHLTUInt8_t*>(pDesc->fPtr);
	  pSrc+=pDesc->fSize-rcuTrailerLength;
	  if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pSrc, rcuTrailerLength))>=0) {
	    assert(iResult==rcuTrailerLength);
	    iOutputSize+=rcuTrailerLength;
	  } else {
	    HLTError("failed to write RCU trailer of length %d for block %d", rcuTrailerLength, blockno);
	    break;
	  }
	}
      }
      if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pChannel, channelSize))>=0) {
	assert(iResult==channelSize);
	iOutputSize+=channelSize;
      } else {
	HLTError("failed to write ALTRO channel of length %d for block %d", channelSize, blockno);
	break;
      }
    }
    if (iResult>=0) {
      // write the common data header
      int cdhSize=reader.GetCommonDataHeaderSize();
      if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pDesc->fPtr, cdhSize))>=0) {
	assert(iResult==cdhSize);
	iOutputSize+=cdhSize;

	// set new length of the data block
	AliHLTUInt32_t* pCdhSize=reinterpret_cast<AliHLTUInt32_t*>(outputPtr+iCapacity-iOutputSize+1);
	*pCdhSize=iOutputSize;

	// insert block descriptor
	AliHLTComponentBlockData bd;
	FillBlockData(bd);
	bd.fOffset=iCapacity-iOutputSize;
	bd.fSize=iOutputSize;
	bd.fDataType=pDesc->fDataType;
	bd.fSpecification=pDesc->fSpecification;
	outputBlocks.push_back(bd);
	iCapacity-=iOutputSize;
      } else {
	HLTError("failed to write CDH of length %d for block %d", cdhSize, blockno);
	break;
      }
    }
    HLTInfo("data block %d (0x%08x): selected %d out of %d ALTRO channels", blockno, pDesc->fSpecification, iSelected, iTotal);
  }

  if (iResult<0) {
    outputBlocks.clear();
  }

  // !!! do not change the size since the output buffer is filled from the end !!!

  return iResult;
}

int AliHLTAltroChannelSelectorComponent::CopyBlockToEnd(AliHLTUInt8_t* pTgt, unsigned capacity, unsigned position, void* pSrc, unsigned size)
{
  int iResult=0;
  if (pTgt==NULL || pSrc==NULL) return -EINVAL;
  if (capacity-position<size) return -ENOSPC;

  memcpy(pTgt+(capacity-position-size), pSrc, size);
  iResult=size;

  return iResult;
}
<commit_msg>always use the digit reader in unsorted mode regardless of the argument<commit_after>// $Id$

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * 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.                  *
 **************************************************************************/

/** @file   AliHLTAltroChannelSelectorComponent.cxx
    @author Matthias Richter
    @date
    @brief  A filter/selective readout component for TPC Altro data. */

// see header file for class documentation
// or
// refer to README to build package
// or
// visit http://web.ift.uib.no/~kjeks/doc/alice-hlt

#include <cassert>
#include "AliHLTAltroChannelSelectorComponent.h"
#include "AliHLTTPCTransform.h"
#include "AliHLTTPCDigitReaderRaw.h"
#include "AliHLTTPCDefinitions.h"
#include "AliHLTTPCPadArray.h"

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTAltroChannelSelectorComponent)

AliHLTAltroChannelSelectorComponent::AliHLTAltroChannelSelectorComponent()
  :
  AliHLTProcessor(),
  fRawreaderMode(0)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTAltroChannelSelectorComponent::~AliHLTAltroChannelSelectorComponent()
{
  // see header file for class documentation
}

const char* AliHLTAltroChannelSelectorComponent::GetComponentID()
{
  // see header file for class documentation
  return "AltroChannelSelector";
}

void AliHLTAltroChannelSelectorComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
{
  // see header file for class documentation
  list.clear();
  list.push_back(kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC);
  list.push_back(AliHLTTPCDefinitions::fgkActivePadsDataType);
}

AliHLTComponentDataType AliHLTAltroChannelSelectorComponent::GetOutputDataType()
{
  // see header file for class documentation
  return kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC;
}

void AliHLTAltroChannelSelectorComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
{
  // see header file for class documentation
  constBase=0;
  inputMultiplier=1.0;
}

AliHLTComponent* AliHLTAltroChannelSelectorComponent::Spawn()
{
  // see header file for class documentation
  return new AliHLTAltroChannelSelectorComponent;
}

int AliHLTAltroChannelSelectorComponent::DoInit(int argc, const char** argv)
{
  // see header file for class documentation
  int iResult=0;
  TString argument="";
  bool bMissingParam=0;
  for (int i=0; i<argc && iResult>=0; i++) {
    argument=argv[i];
    if (argument.IsNull()) continue;

    // -rawreadermode
    if (argument.CompareTo("-rawreadermode")==0) {
      if ((bMissingParam=(++i>=argc))) break;
      int mode=AliHLTTPCDigitReaderRaw::DecodeMode(argv[i]);
      if (mode<0) {
	HLTError("invalid rawreadermode specifier '%s'", argv[i]);
	iResult=-EINVAL;
      } else {
	fRawreaderMode=static_cast<unsigned>(mode);
	// always use the reader in unsorted mode regardless of the
	// argument
	if (fRawreaderMode%2==0) fRawreaderMode++;
      }
    } else {
      iResult=-EINVAL;
    }
  }

  if (bMissingParam) {
    HLTError("missing parameter for argument %s", argument.Data());
    iResult=-EINVAL;
  }

  return iResult;
}

int AliHLTAltroChannelSelectorComponent::DoDeinit()
{
  // see header file for class documentation
  return 0;
}

int AliHLTAltroChannelSelectorComponent::DoEvent(const AliHLTComponentEventData& evtData,
						 const AliHLTComponentBlockData* blocks,
						 AliHLTComponentTriggerData& /*trigData*/,
						 AliHLTUInt8_t* outputPtr,
						 AliHLTUInt32_t& size,
						 AliHLTComponentBlockDataList& outputBlocks )
{
  // see header file for class documentation
  int iResult=0;

  // process the DLL input
  int blockno=0;
  const AliHLTComponentBlockData* pDesc=NULL;

  for (pDesc=GetFirstInputBlock(kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC); pDesc!=NULL; pDesc=GetNextInputBlock(), blockno++) {

    // search for the active pad information
    AliHLTTPCPadArray::AliHLTTPCActivePads* pActivePadsArray=NULL;
    int iNofActivePads=0;
    for (int i=0; i<(int)evtData.fBlockCnt; i++ ) {
      if (blocks[i].fDataType == AliHLTTPCDefinitions::fgkActivePadsDataType &&
	  blocks[i].fSpecification==pDesc->fSpecification) {
	pActivePadsArray=reinterpret_cast<AliHLTTPCPadArray::AliHLTTPCActivePads*>(blocks[i].fPtr);
	iNofActivePads=blocks[i].fSize/sizeof(AliHLTTPCPadArray::AliHLTTPCActivePads);
      }
    }
    if (pActivePadsArray==NULL) {
      HLTWarning("no block of type %s for specification 0x%08x available, data block unchanged",
		 DataType2Text(AliHLTTPCDefinitions::fgkActivePadsDataType).c_str(),
		 pDesc->fSpecification);
      // forward the whole block
      outputBlocks.push_back(*pDesc);
      continue;
    }

    int part=AliHLTTPCDefinitions::GetMinPatchNr(*pDesc);
    assert(part==AliHLTTPCDefinitions::GetMaxPatchNr(*pDesc));
    int slice=AliHLTTPCDefinitions::GetMinSliceNr(*pDesc);
    assert(slice==AliHLTTPCDefinitions::GetMaxSliceNr(*pDesc));
    int firstRow=AliHLTTPCTransform::GetFirstRow(part);
    int lastRow=AliHLTTPCTransform::GetLastRow(part);
    AliHLTTPCDigitReaderRaw reader(fRawreaderMode);
    HLTDebug("init reader %p size %d", pDesc->fPtr,pDesc->fSize);
    reader.InitBlock(pDesc->fPtr,pDesc->fSize,firstRow,lastRow,part,slice);
    int iSelected=0;
    int iTotal=0;
    AliHLTUInt32_t iOutputSize=0;
    AliHLTUInt32_t iCapacity=size;
    while (reader.NextAltroBlock()) {
      iTotal++;
      int active=0;
      for (; active<iNofActivePads; active++) {
	if ((int)pActivePadsArray[active].fRow==reader.GetRow() &&
	    (int)pActivePadsArray[active].fPad==reader.GetPad()) {
	  break;
	}
      }
      if (active>=iNofActivePads) {
	HLTDebug("ALTRO block Row %d, Pad %d discarded (inactive)", reader.GetRow(), reader.GetPad());
	continue;
      }

      iSelected++;
      void* pChannel=NULL;
      AliHLTUInt16_t hwAddress=~(AliHLTUInt16_t)0;
      int channelSize=reader.GetAltroChannelRawData(pChannel, hwAddress);
      HLTDebug("ALTRO block hwAddress 0x%08x Row/Pad %d/%d selected (active), size %d", hwAddress, reader.GetRow(), reader.GetPad(), channelSize);
      if (channelSize>0 && pChannel!=NULL) {
	if (iOutputSize==0) {
	  // first add the RCU trailer
	  unsigned rcuTrailerLength=reader.GetRCUDataBlockLength();
	  AliHLTUInt8_t* pSrc=reinterpret_cast<AliHLTUInt8_t*>(pDesc->fPtr);
	  pSrc+=pDesc->fSize-rcuTrailerLength;
	  if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pSrc, rcuTrailerLength))>=0) {
	    assert(iResult==rcuTrailerLength);
	    iOutputSize+=rcuTrailerLength;
	  } else {
	    HLTError("failed to write RCU trailer of length %d for block %d", rcuTrailerLength, blockno);
	    break;
	  }
	}
      }
      if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pChannel, channelSize))>=0) {
	assert(iResult==channelSize);
	iOutputSize+=channelSize;
      } else {
	HLTError("failed to write ALTRO channel of length %d for block %d", channelSize, blockno);
	break;
      }
    }
    if (iResult>=0) {
      // write the common data header
      int cdhSize=reader.GetCommonDataHeaderSize();
      if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pDesc->fPtr, cdhSize))>=0) {
	assert(iResult==cdhSize);
	iOutputSize+=cdhSize;

	// set new length of the data block
	AliHLTUInt32_t* pCdhSize=reinterpret_cast<AliHLTUInt32_t*>(outputPtr+iCapacity-iOutputSize+1);
	*pCdhSize=iOutputSize;

	// insert block descriptor
	AliHLTComponentBlockData bd;
	FillBlockData(bd);
	bd.fOffset=iCapacity-iOutputSize;
	bd.fSize=iOutputSize;
	bd.fDataType=pDesc->fDataType;
	bd.fSpecification=pDesc->fSpecification;
	outputBlocks.push_back(bd);
	iCapacity-=iOutputSize;
      } else {
	HLTError("failed to write CDH of length %d for block %d", cdhSize, blockno);
	break;
      }
    }
    HLTInfo("data block %d (0x%08x): selected %d out of %d ALTRO channels", blockno, pDesc->fSpecification, iSelected, iTotal);
  }

  if (iResult<0) {
    outputBlocks.clear();
  }

  // !!! do not change the size since the output buffer is filled from the end !!!

  return iResult;
}

int AliHLTAltroChannelSelectorComponent::CopyBlockToEnd(AliHLTUInt8_t* pTgt, unsigned capacity, unsigned position, void* pSrc, unsigned size)
{
  int iResult=0;
  if (pTgt==NULL || pSrc==NULL) return -EINVAL;
  if (capacity-position<size) return -ENOSPC;

  memcpy(pTgt+(capacity-position-size), pSrc, size);
  iResult=size;

  return iResult;
}
<|endoftext|>


<commit_before>/**
 * Everything related to the world, as an interface.
 *
 * License: Mozilla Public License Version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/ OR See accompanying file LICENSE)
 * Authors:
 *  - Dan Printzell
 */
#pragma once
#include <hydra/ext/api.hpp>

#include <string>
#include <memory>
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#undef min
#undef max
#include <json.hpp>

namespace Hydra::Renderer { struct HYDRA_API DrawObject; }

namespace Hydra::World {
	class HYDRA_API IEntity;
	class HYDRA_API IComponent;
	struct HYDRA_API Blueprint;

	// The tick function only accepts one value, but the wantTick is a bitfield
	enum class HYDRA_API TickAction {
		checkDead = 1 << 0,
		physics = 1 << 1,
		render = 1 << 2,
		renderTransparent = 1 << 3,
		network = 1 << 4
	};
	inline TickAction operator| (TickAction a, TickAction b) { return static_cast<TickAction>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b)); }
	inline TickAction operator& (TickAction a, TickAction b) { return static_cast<TickAction>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b)); }

	class HYDRA_API IWorld {
	public:
		virtual ~IWorld() = 0;

		virtual size_t getFreeID() = 0;

		// To emulate a IEntity, kinda
		virtual std::shared_ptr<IEntity> createEntity(const std::string& name) = 0;
		virtual void tick(TickAction action) = 0;

		virtual void setWorldRoot(std::shared_ptr<IEntity> root) = 0;
		virtual std::shared_ptr<IEntity> getWorldRoot() = 0;
	};
	inline IWorld::~IWorld() {}

	class HYDRA_API IEntity {
	public:
		inline IEntity(IWorld* world) : world(world), id(world->getFreeID()) {}
		virtual ~IEntity() = 0;

		virtual void tick(TickAction action) = 0;
		virtual TickAction wantTick() = 0;

		virtual void markDead() = 0;

		virtual IComponent* addComponent_(const std::type_index& id, std::unique_ptr<IComponent> component) = 0;
		virtual void removeComponent_(const std::type_index& id) = 0;
		virtual std::map<std::type_index, std::unique_ptr<IComponent>>& getComponents() = 0;

		template <typename T, typename... Args, typename std::enable_if<std::is_base_of<IComponent, T>::value>::type* = nullptr>
		T* addComponent(Args... args) {
			T* ptr = new T(this, args...);
			addComponent_(std::type_index(typeid(T)), std::unique_ptr<IComponent>(ptr));
			return ptr;
		}
		template <typename T, typename std::enable_if<std::is_base_of<IComponent, T>::value>::type* = nullptr>
		void removeComponent() { removeComponent_(std::type_index(typeid(T))); }
		template <typename T, typename std::enable_if<std::is_base_of<IComponent, T>::value>::type* = nullptr>
		T* getComponent() {
			try {
				return static_cast<T*>(getComponents().at(std::type_index(typeid(T))).get());
			} catch (std::out_of_range) {
				return nullptr;
			}
		}

		virtual std::shared_ptr<IEntity> spawn(std::shared_ptr<IEntity> entity) = 0;
		virtual std::shared_ptr<IEntity> createEntity(const std::string& name) = 0;
		virtual std::shared_ptr<IEntity> createEntity(nlohmann::json& json) = 0;

		inline size_t getID() { return id; }

		virtual void setParent(IEntity* parent) = 0;
		virtual IEntity* getParent() = 0;
		virtual const std::vector<std::shared_ptr<IEntity>>& getChildren() = 0;

		virtual void serialize(nlohmann::json& json, bool serializeChildren = true) const = 0;
		virtual void deserialize(nlohmann::json& json) = 0;

		virtual const std::string& getName() const = 0;
		virtual Hydra::Renderer::DrawObject* getDrawObject() = 0;
		virtual bool isDead() const = 0;
	protected:
		IWorld* world;
		size_t id;
	};
	inline IEntity::~IEntity() {}

	class HYDRA_API IComponent {
	public:
		inline IComponent(IEntity* entity) : entity(entity) {}
		virtual ~IComponent() = 0;

		virtual void tick(TickAction action) = 0;
		virtual TickAction wantTick() const = 0;

		virtual const std::string type() const = 0;

		virtual void serialize(nlohmann::json& json) const = 0;
		virtual void deserialize(nlohmann::json& json) = 0;
		virtual void registerUI() = 0;

		// TODO?: IComponent* getParent();
		// TODO?: std::vector<IComponent*> getChildren();
	protected:
		IEntity* entity;
	};
	inline IComponent::~IComponent() {}

	struct HYDRA_API Blueprint final {
		std::string name; // Blueprint Name

		inline nlohmann::json& getData() { return _root["data"]; }

		std::shared_ptr<IEntity> spawn(IWorld* world);

		nlohmann::json _root;
	};

	namespace World {
		HYDRA_API std::unique_ptr<IWorld> create();
	};

	namespace Entity {
		HYDRA_API std::shared_ptr<IEntity> createEmpty(IWorld* world, const std::string& name);
		HYDRA_API std::shared_ptr<IEntity> createFromBlueprint(IWorld* world, nlohmann::json& json);
	};
};
<commit_msg>Fixed some stupid code<commit_after>/**
 * Everything related to the world, as an interface.
 *
 * License: Mozilla Public License Version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/ OR See accompanying file LICENSE)
 * Authors:
 *  - Dan Printzell
 */
#pragma once
#include <hydra/ext/api.hpp>

#include <string>
#include <memory>
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#undef min
#undef max
#include <json.hpp>

namespace Hydra::Renderer { struct HYDRA_API DrawObject; }

namespace Hydra::World {
	class HYDRA_API IEntity;
	class HYDRA_API IComponent;
	struct HYDRA_API Blueprint;

	// The tick function only accepts one value, but the wantTick is a bitfield
	enum class HYDRA_API TickAction {
		checkDead = 1 << 0,
		physics = 1 << 1,
		render = 1 << 2,
		renderTransparent = 1 << 3,
		network = 1 << 4
	};
	inline TickAction operator| (TickAction a, TickAction b) { return static_cast<TickAction>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b)); }
	inline TickAction operator& (TickAction a, TickAction b) { return static_cast<TickAction>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b)); }

	class HYDRA_API IWorld {
	public:
		virtual ~IWorld() = 0;

		virtual size_t getFreeID() = 0;

		// To emulate a IEntity, kinda
		virtual std::shared_ptr<IEntity> createEntity(const std::string& name) = 0;
		virtual void tick(TickAction action) = 0;

		virtual void setWorldRoot(std::shared_ptr<IEntity> root) = 0;
		virtual std::shared_ptr<IEntity> getWorldRoot() = 0;
	};
	inline IWorld::~IWorld() {}

	class HYDRA_API IEntity {
	public:
		inline IEntity(IWorld* world) : world(world), id(world->getFreeID()) {}
		virtual ~IEntity() = 0;

		virtual void tick(TickAction action) = 0;
		virtual TickAction wantTick() = 0;

		virtual void markDead() = 0;

		virtual IComponent* addComponent_(const std::type_index& id, std::unique_ptr<IComponent> component) = 0;
		virtual void removeComponent_(const std::type_index& id) = 0;
		virtual std::map<std::type_index, std::unique_ptr<IComponent>>& getComponents() = 0;

		template <typename T, typename... Args, typename std::enable_if<std::is_base_of<IComponent, T>::value>::type* = nullptr>
		T* addComponent(Args... args) {
			T* ptr = new T(this, args...);
			addComponent_(std::type_index(typeid(T)), std::unique_ptr<IComponent>(ptr));
			return ptr;
		}
		template <typename T, typename std::enable_if<std::is_base_of<IComponent, T>::value>::type* = nullptr>
		void removeComponent() { removeComponent_(std::type_index(typeid(T))); }
		template <typename T, typename std::enable_if<std::is_base_of<IComponent, T>::value>::type* = nullptr>
		T* getComponent() {
			auto& components = getComponents();
			auto it = components.find(typeid(T));
			if (it != components.end())
				return (T*)it->second.get();
			return nullptr;
		}

		virtual std::shared_ptr<IEntity> spawn(std::shared_ptr<IEntity> entity) = 0;
		virtual std::shared_ptr<IEntity> createEntity(const std::string& name) = 0;
		virtual std::shared_ptr<IEntity> createEntity(nlohmann::json& json) = 0;

		inline size_t getID() { return id; }

		virtual void setParent(IEntity* parent) = 0;
		virtual IEntity* getParent() = 0;
		virtual const std::vector<std::shared_ptr<IEntity>>& getChildren() = 0;

		virtual void serialize(nlohmann::json& json, bool serializeChildren = true) const = 0;
		virtual void deserialize(nlohmann::json& json) = 0;

		virtual const std::string& getName() const = 0;
		virtual Hydra::Renderer::DrawObject* getDrawObject() = 0;
		virtual bool isDead() const = 0;
	protected:
		IWorld* world;
		size_t id;
	};
	inline IEntity::~IEntity() {}

	class HYDRA_API IComponent {
	public:
		inline IComponent(IEntity* entity) : entity(entity) {}
		virtual ~IComponent() = 0;

		virtual void tick(TickAction action) = 0;
		virtual TickAction wantTick() const = 0;

		virtual const std::string type() const = 0;

		virtual void serialize(nlohmann::json& json) const = 0;
		virtual void deserialize(nlohmann::json& json) = 0;
		virtual void registerUI() = 0;

		// TODO?: IComponent* getParent();
		// TODO?: std::vector<IComponent*> getChildren();
	protected:
		IEntity* entity;
	};
	inline IComponent::~IComponent() {}

	struct HYDRA_API Blueprint final {
		std::string name; // Blueprint Name

		inline nlohmann::json& getData() { return _root["data"]; }

		std::shared_ptr<IEntity> spawn(IWorld* world);

		nlohmann::json _root;
	};

	namespace World {
		HYDRA_API std::unique_ptr<IWorld> create();
	};

	namespace Entity {
		HYDRA_API std::shared_ptr<IEntity> createEmpty(IWorld* world, const std::string& name);
		HYDRA_API std::shared_ptr<IEntity> createFromBlueprint(IWorld* world, nlohmann::json& json);
	};
};
<|endoftext|>


<commit_before>//===-- cc1as_main.cpp - Clang Assembler  ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the clang -cc1as functionality, which implements
// the direct interface to the LLVM MC based assembler.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/Diagnostic.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/CC1AsOptions.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
#include "llvm/Target/TargetAsmBackend.h"
#include "llvm/Target/TargetAsmParser.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Target/TargetSelect.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;

namespace {

/// \brief Helper class for representing a single invocation of the assembler.
struct AssemblerInvocation {
  /// @name Target Options
  /// @{

  std::string Triple;

  /// @}
  /// @name Language Options
  /// @{

  std::vector<std::string> IncludePaths;
  unsigned NoInitialTextSection : 1;

  /// @}
  /// @name Frontend Options
  /// @{

  std::string InputFile;
  std::vector<std::string> LLVMArgs;
  std::string OutputPath;
  enum FileType {
    FT_Asm,  ///< Assembly (.s) output, transliterate mode.
    FT_Null, ///< No output, for timing purposes.
    FT_Obj   ///< Object file output.
  };
  FileType OutputType;
  unsigned ShowHelp : 1;
  unsigned ShowVersion : 1;

  /// @}
  /// @name Transliterate Options
  /// @{

  unsigned OutputAsmVariant;
  unsigned ShowEncoding : 1;
  unsigned ShowInst : 1;

  /// @}
  /// @name Assembler Options
  /// @{

  unsigned RelaxAll : 1;

  /// @}

public:
  AssemblerInvocation() {
    Triple = "";
    NoInitialTextSection = 0;
    InputFile = "-";
    OutputPath = "-";
    OutputType = FT_Asm;
    OutputAsmVariant = 0;
    ShowInst = 0;
    ShowEncoding = 0;
    RelaxAll = 0;
  }

  static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
                             const char **ArgEnd, Diagnostic &Diags);
};

}

void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
                                         const char **ArgBegin,
                                         const char **ArgEnd,
                                         Diagnostic &Diags) {
  using namespace clang::driver::cc1asoptions;
  // Parse the arguments.
  OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
  unsigned MissingArgIndex, MissingArgCount;
  OwningPtr<InputArgList> Args(
    OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));

  // Check for missing argument error.
  if (MissingArgCount)
    Diags.Report(diag::err_drv_missing_argument)
      << Args->getArgString(MissingArgIndex) << MissingArgCount;

  // Issue errors on unknown arguments.
  for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN),
         ie = Args->filtered_end(); it != ie; ++it)
    Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args);

  // Construct the invocation.

  // Target Options
  Opts.Triple = Triple::normalize(Args->getLastArgValue(OPT_triple));
  if (Opts.Triple.empty()) // Use the host triple if unspecified.
    Opts.Triple = sys::getHostTriple();

  // Language Options
  Opts.IncludePaths = Args->getAllArgValues(OPT_I);
  Opts.NoInitialTextSection = Args->hasArg(OPT_n);

  // Frontend Options
  if (Args->hasArg(OPT_INPUT)) {
    bool First = true;
    for (arg_iterator it = Args->filtered_begin(OPT_INPUT),
           ie = Args->filtered_end(); it != ie; ++it, First=false) {
      const Arg *A = it;
      if (First)
        Opts.InputFile = A->getValue(*Args);
      else
        Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
    }
  }
  Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
  Opts.OutputPath = Args->getLastArgValue(OPT_o);
  if (Arg *A = Args->getLastArg(OPT_filetype)) {
    StringRef Name = A->getValue(*Args);
    unsigned OutputType = StringSwitch<unsigned>(Name)
      .Case("asm", FT_Asm)
      .Case("null", FT_Null)
      .Case("obj", FT_Obj)
      .Default(~0U);
    if (OutputType == ~0U)
      Diags.Report(diag::err_drv_invalid_value)
        << A->getAsString(*Args) << Name;
    else
      Opts.OutputType = FileType(OutputType);
  }
  Opts.ShowHelp = Args->hasArg(OPT_help);
  Opts.ShowVersion = Args->hasArg(OPT_version);

  // Transliterate Options
  Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant,
                                                   0, Diags);
  Opts.ShowEncoding = Args->hasArg(OPT_show_encoding);
  Opts.ShowInst = Args->hasArg(OPT_show_inst);

  // Assemble Options
  Opts.RelaxAll = Args->hasArg(OPT_relax_all);
}

static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
                                              Diagnostic &Diags,
                                              bool Binary) {
  if (Opts.OutputPath.empty())
    Opts.OutputPath = "-";

  // Make sure that the Out file gets unlinked from the disk if we get a
  // SIGINT.
  if (Opts.OutputPath != "-")
    sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath));

  std::string Error;
  raw_fd_ostream *Out =
    new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
                       (Binary ? raw_fd_ostream::F_Binary : 0));
  if (!Error.empty()) {
    Diags.Report(diag::err_fe_unable_to_open_output)
      << Opts.OutputPath << Error;
    return 0;
  }

  return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM);
}

static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
  // Get the target specific parser.
  std::string Error;
  const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error));
  if (!TheTarget) {
    Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
    return false;
  }

  error_code ec;
  MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, ec);
  if (Buffer == 0) {
    Error = ec.message();
    Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
    return false;
  }

  SourceMgr SrcMgr;

  // Tell SrcMgr about this buffer, which is what the parser will pick up.
  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());

  // Record the location of the include directories so that the lexer can find
  // it later.
  SrcMgr.setIncludeDirs(Opts.IncludePaths);

  OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple));
  assert(MAI && "Unable to create target asm info!");

  MCContext Ctx(*MAI);
  bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
  formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
  if (!Out)
    return false;

  // FIXME: We shouldn't need to do this (and link in codegen).
  OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, ""));
  if (!TM) {
    Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
    return false;
  }

  OwningPtr<MCStreamer> Str;

  if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
    MCInstPrinter *IP =
      TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI);
    MCCodeEmitter *CE = 0;
    if (Opts.ShowEncoding)
      CE = TheTarget->createCodeEmitter(*TM, Ctx);
    Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(),
                                /*asmverbose*/true, IP, CE, Opts.ShowInst));
  } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
    Str.reset(createNullStreamer(Ctx));
  } else {
    assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
           "Invalid file type!");
    MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx);
    TargetAsmBackend *TAB = TheTarget->createAsmBackend(Opts.Triple);
    Str.reset(TheTarget->createObjectStreamer(Opts.Triple, Ctx, *TAB, *Out,
                                              CE, Opts.RelaxAll));
    Str.get()->InitSections();
  }

  OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx,
                                                  *Str.get(), *MAI));
  OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM));
  if (!TAP) {
    Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
    return false;
  }

  Parser->setTargetParser(*TAP.get());

  bool Success = !Parser->Run(Opts.NoInitialTextSection);

  // Close the output.
  delete Out;

  // Delete output on errors.
  if (!Success && Opts.OutputPath != "-")
    sys::Path(Opts.OutputPath).eraseFromDisk();

  return Success;
}

static void LLVMErrorHandler(void *UserData, const std::string &Message) {
  Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);

  Diags.Report(diag::err_fe_error_backend) << Message;

  // We cannot recover from llvm errors.
  exit(1);
}

int cc1as_main(const char **ArgBegin, const char **ArgEnd,
               const char *Argv0, void *MainAddr) {
  // Print a stack trace if we signal out.
  sys::PrintStackTraceOnErrorSignal();
  PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin);
  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.

  // Initialize targets and assembly printers/parsers.
  InitializeAllTargetInfos();
  // FIXME: We shouldn't need to initialize the Target(Machine)s.
  InitializeAllTargets();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();

  // Construct our diagnostic client.
  TextDiagnosticPrinter *DiagClient
    = new TextDiagnosticPrinter(errs(), DiagnosticOptions());
  DiagClient->setPrefix("clang -cc1as");
  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  Diagnostic Diags(DiagID, DiagClient);

  // Set an error handler, so that any LLVM backend diagnostics go through our
  // error handler.
  ScopedFatalErrorHandler FatalErrorHandler
    (LLVMErrorHandler, static_cast<void*>(&Diags));

  // Parse the arguments.
  AssemblerInvocation Asm;
  AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags);

  // Honor -help.
  if (Asm.ShowHelp) {
    llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
    Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
    return 0;
  }

  // Honor -version.
  //
  // FIXME: Use a better -version message?
  if (Asm.ShowVersion) {
    llvm::cl::PrintVersionMessage();
    return 0;
  }

  // Honor -mllvm.
  //
  // FIXME: Remove this, one day.
  if (!Asm.LLVMArgs.empty()) {
    unsigned NumArgs = Asm.LLVMArgs.size();
    const char **Args = new const char*[NumArgs + 2];
    Args[0] = "clang (LLVM option parsing)";
    for (unsigned i = 0; i != NumArgs; ++i)
      Args[i + 1] = Asm.LLVMArgs[i].c_str();
    Args[NumArgs + 1] = 0;
    llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
  }

  // Execute the invocation, unless there were parsing errors.
  bool Success = false;
  if (!Diags.hasErrorOccurred())
    Success = ExecuteAssembler(Asm, Diags);

  // If any timers were active but haven't been destroyed yet, print their
  // results now.
  TimerGroup::printAll(errs());

  return !Success;
}
<commit_msg>Update clang for the API changes in the cfi patch.<commit_after>//===-- cc1as_main.cpp - Clang Assembler  ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the clang -cc1as functionality, which implements
// the direct interface to the LLVM MC based assembler.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/Diagnostic.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/CC1AsOptions.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
#include "llvm/Target/TargetAsmBackend.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetAsmParser.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Target/TargetSelect.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;

namespace {

/// \brief Helper class for representing a single invocation of the assembler.
struct AssemblerInvocation {
  /// @name Target Options
  /// @{

  std::string Triple;

  /// @}
  /// @name Language Options
  /// @{

  std::vector<std::string> IncludePaths;
  unsigned NoInitialTextSection : 1;

  /// @}
  /// @name Frontend Options
  /// @{

  std::string InputFile;
  std::vector<std::string> LLVMArgs;
  std::string OutputPath;
  enum FileType {
    FT_Asm,  ///< Assembly (.s) output, transliterate mode.
    FT_Null, ///< No output, for timing purposes.
    FT_Obj   ///< Object file output.
  };
  FileType OutputType;
  unsigned ShowHelp : 1;
  unsigned ShowVersion : 1;

  /// @}
  /// @name Transliterate Options
  /// @{

  unsigned OutputAsmVariant;
  unsigned ShowEncoding : 1;
  unsigned ShowInst : 1;

  /// @}
  /// @name Assembler Options
  /// @{

  unsigned RelaxAll : 1;

  /// @}

public:
  AssemblerInvocation() {
    Triple = "";
    NoInitialTextSection = 0;
    InputFile = "-";
    OutputPath = "-";
    OutputType = FT_Asm;
    OutputAsmVariant = 0;
    ShowInst = 0;
    ShowEncoding = 0;
    RelaxAll = 0;
  }

  static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
                             const char **ArgEnd, Diagnostic &Diags);
};

}

void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
                                         const char **ArgBegin,
                                         const char **ArgEnd,
                                         Diagnostic &Diags) {
  using namespace clang::driver::cc1asoptions;
  // Parse the arguments.
  OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
  unsigned MissingArgIndex, MissingArgCount;
  OwningPtr<InputArgList> Args(
    OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));

  // Check for missing argument error.
  if (MissingArgCount)
    Diags.Report(diag::err_drv_missing_argument)
      << Args->getArgString(MissingArgIndex) << MissingArgCount;

  // Issue errors on unknown arguments.
  for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN),
         ie = Args->filtered_end(); it != ie; ++it)
    Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args);

  // Construct the invocation.

  // Target Options
  Opts.Triple = Triple::normalize(Args->getLastArgValue(OPT_triple));
  if (Opts.Triple.empty()) // Use the host triple if unspecified.
    Opts.Triple = sys::getHostTriple();

  // Language Options
  Opts.IncludePaths = Args->getAllArgValues(OPT_I);
  Opts.NoInitialTextSection = Args->hasArg(OPT_n);

  // Frontend Options
  if (Args->hasArg(OPT_INPUT)) {
    bool First = true;
    for (arg_iterator it = Args->filtered_begin(OPT_INPUT),
           ie = Args->filtered_end(); it != ie; ++it, First=false) {
      const Arg *A = it;
      if (First)
        Opts.InputFile = A->getValue(*Args);
      else
        Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
    }
  }
  Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
  Opts.OutputPath = Args->getLastArgValue(OPT_o);
  if (Arg *A = Args->getLastArg(OPT_filetype)) {
    StringRef Name = A->getValue(*Args);
    unsigned OutputType = StringSwitch<unsigned>(Name)
      .Case("asm", FT_Asm)
      .Case("null", FT_Null)
      .Case("obj", FT_Obj)
      .Default(~0U);
    if (OutputType == ~0U)
      Diags.Report(diag::err_drv_invalid_value)
        << A->getAsString(*Args) << Name;
    else
      Opts.OutputType = FileType(OutputType);
  }
  Opts.ShowHelp = Args->hasArg(OPT_help);
  Opts.ShowVersion = Args->hasArg(OPT_version);

  // Transliterate Options
  Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant,
                                                   0, Diags);
  Opts.ShowEncoding = Args->hasArg(OPT_show_encoding);
  Opts.ShowInst = Args->hasArg(OPT_show_inst);

  // Assemble Options
  Opts.RelaxAll = Args->hasArg(OPT_relax_all);
}

static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
                                              Diagnostic &Diags,
                                              bool Binary) {
  if (Opts.OutputPath.empty())
    Opts.OutputPath = "-";

  // Make sure that the Out file gets unlinked from the disk if we get a
  // SIGINT.
  if (Opts.OutputPath != "-")
    sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath));

  std::string Error;
  raw_fd_ostream *Out =
    new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
                       (Binary ? raw_fd_ostream::F_Binary : 0));
  if (!Error.empty()) {
    Diags.Report(diag::err_fe_unable_to_open_output)
      << Opts.OutputPath << Error;
    return 0;
  }

  return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM);
}

static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
  // Get the target specific parser.
  std::string Error;
  const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error));
  if (!TheTarget) {
    Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
    return false;
  }

  error_code ec;
  MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, ec);
  if (Buffer == 0) {
    Error = ec.message();
    Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
    return false;
  }

  SourceMgr SrcMgr;

  // Tell SrcMgr about this buffer, which is what the parser will pick up.
  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());

  // Record the location of the include directories so that the lexer can find
  // it later.
  SrcMgr.setIncludeDirs(Opts.IncludePaths);

  OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple));
  assert(MAI && "Unable to create target asm info!");

  bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
  formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
  if (!Out)
    return false;

  // FIXME: We shouldn't need to do this (and link in codegen).
  OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, ""));
  if (!TM) {
    Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
    return false;
  }

  const TargetAsmInfo tai(*TM);
  MCContext Ctx(*MAI, &tai);

  OwningPtr<MCStreamer> Str;

  const TargetLoweringObjectFile &TLOF =
    TM->getTargetLowering()->getObjFileLowering();
  const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(Ctx, *TM);

  if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
    MCInstPrinter *IP =
      TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI);
    MCCodeEmitter *CE = 0;
    if (Opts.ShowEncoding)
      CE = TheTarget->createCodeEmitter(*TM, Ctx);
    Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
                                           /*useLoc*/ true, IP, CE,
                                           Opts.ShowInst));
  } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
    Str.reset(createNullStreamer(Ctx));
  } else {
    assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
           "Invalid file type!");
    MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx);
    TargetAsmBackend *TAB = TheTarget->createAsmBackend(Opts.Triple);
    Str.reset(TheTarget->createObjectStreamer(Opts.Triple, Ctx, *TAB, *Out,
                                              CE, Opts.RelaxAll));
    Str.get()->InitSections();
  }

  OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx,
                                                  *Str.get(), *MAI));
  OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM));
  if (!TAP) {
    Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
    return false;
  }

  Parser->setTargetParser(*TAP.get());

  bool Success = !Parser->Run(Opts.NoInitialTextSection);

  // Close the output.
  delete Out;

  // Delete output on errors.
  if (!Success && Opts.OutputPath != "-")
    sys::Path(Opts.OutputPath).eraseFromDisk();

  return Success;
}

static void LLVMErrorHandler(void *UserData, const std::string &Message) {
  Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);

  Diags.Report(diag::err_fe_error_backend) << Message;

  // We cannot recover from llvm errors.
  exit(1);
}

int cc1as_main(const char **ArgBegin, const char **ArgEnd,
               const char *Argv0, void *MainAddr) {
  // Print a stack trace if we signal out.
  sys::PrintStackTraceOnErrorSignal();
  PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin);
  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.

  // Initialize targets and assembly printers/parsers.
  InitializeAllTargetInfos();
  // FIXME: We shouldn't need to initialize the Target(Machine)s.
  InitializeAllTargets();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();

  // Construct our diagnostic client.
  TextDiagnosticPrinter *DiagClient
    = new TextDiagnosticPrinter(errs(), DiagnosticOptions());
  DiagClient->setPrefix("clang -cc1as");
  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  Diagnostic Diags(DiagID, DiagClient);

  // Set an error handler, so that any LLVM backend diagnostics go through our
  // error handler.
  ScopedFatalErrorHandler FatalErrorHandler
    (LLVMErrorHandler, static_cast<void*>(&Diags));

  // Parse the arguments.
  AssemblerInvocation Asm;
  AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags);

  // Honor -help.
  if (Asm.ShowHelp) {
    llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
    Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
    return 0;
  }

  // Honor -version.
  //
  // FIXME: Use a better -version message?
  if (Asm.ShowVersion) {
    llvm::cl::PrintVersionMessage();
    return 0;
  }

  // Honor -mllvm.
  //
  // FIXME: Remove this, one day.
  if (!Asm.LLVMArgs.empty()) {
    unsigned NumArgs = Asm.LLVMArgs.size();
    const char **Args = new const char*[NumArgs + 2];
    Args[0] = "clang (LLVM option parsing)";
    for (unsigned i = 0; i != NumArgs; ++i)
      Args[i + 1] = Asm.LLVMArgs[i].c_str();
    Args[NumArgs + 1] = 0;
    llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
  }

  // Execute the invocation, unless there were parsing errors.
  bool Success = false;
  if (!Diags.hasErrorOccurred())
    Success = ExecuteAssembler(Asm, Diags);

  // If any timers were active but haven't been destroyed yet, print their
  // results now.
  TimerGroup::printAll(errs());

  return !Success;
}
<|endoftext|>


<commit_before>//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that aims to be a dropin replacement for
// Darwin's dsymutil.
//
//===----------------------------------------------------------------------===//

#include "DebugMap.h"
#include "dsymutil.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h"
#include <string>

using namespace llvm::dsymutil;

namespace {
using namespace llvm::cl;

OptionCategory DsymCategory("Specific Options");
static opt<bool> Help("h", desc("Alias for -help"), Hidden);
static opt<bool> Version("v", desc("Alias for -version"), Hidden);

static list<std::string> InputFiles(Positional, OneOrMore,
                                    desc("<input files>"), cat(DsymCategory));

static opt<std::string>
    OutputFileOpt("o",
                  desc("Specify the output file. default: <input file>.dwarf"),
                  value_desc("filename"), cat(DsymCategory));

static opt<std::string> OsoPrependPath(
    "oso-prepend-path",
    desc("Specify a directory to prepend to the paths of object files."),
    value_desc("path"), cat(DsymCategory));

static opt<bool> Verbose("verbose", desc("Verbosity level"), init(false),
                         cat(DsymCategory));

static opt<bool>
    NoOutput("no-output",
             desc("Do the link in memory, but do not emit the result file."),
             init(false), cat(DsymCategory));

static opt<bool>
    NoODR("no-odr",
          desc("Do not use ODR (One Definition Rule) for type uniquing."),
          init(false), cat(DsymCategory));

static opt<bool> DumpDebugMap(
    "dump-debug-map",
    desc("Parse and dump the debug map to standard output. Not DWARF link "
         "will take place."),
    init(false), cat(DsymCategory));

static opt<bool> InputIsYAMLDebugMap(
    "y", desc("Treat the input file is a YAML debug map rather than a binary."),
    init(false), cat(DsymCategory));
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
  llvm::llvm_shutdown_obj Shutdown;
  LinkOptions Options;

  HideUnrelatedOptions(DsymCategory);
  llvm::cl::ParseCommandLineOptions(
      argc, argv,
      "manipulate archived DWARF debug symbol files.\n\n"
      "dsymutil links the DWARF debug information found in the object files\n"
      "for the executable <input file> by using debug symbols information\n"
      "contained in its symbol table.\n");

  if (Help)
    PrintHelpMessage();

  if (Version) {
    llvm::cl::PrintVersionMessage();
    return 0;
  }

  Options.Verbose = Verbose;
  Options.NoOutput = NoOutput;
  Options.NoODR = NoODR;

  llvm::InitializeAllTargetInfos();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllTargets();
  llvm::InitializeAllAsmPrinters();

  if (InputFiles.size() > 1 && !OutputFileOpt.empty()) {
    llvm::errs() << "error: cannot use -o with multiple inputs\n";
    return 1;
  }

  for (auto &InputFile : InputFiles) {
    auto DebugMapPtrOrErr =
        parseDebugMap(InputFile, OsoPrependPath, Verbose, InputIsYAMLDebugMap);

    if (auto EC = DebugMapPtrOrErr.getError()) {
      llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
                   << "\": " << EC.message() << '\n';
      return 1;
    }

    if (Verbose || DumpDebugMap)
      (*DebugMapPtrOrErr)->print(llvm::outs());

    if (DumpDebugMap)
      continue;

    std::string OutputFile;
    if (OutputFileOpt.empty()) {
      if (InputFile == "-")
        OutputFile = "a.out.dwarf";
      else
        OutputFile = InputFile + ".dwarf";
    } else {
      OutputFile = OutputFileOpt;
    }

    if (!linkDwarf(OutputFile, **DebugMapPtrOrErr, Options))
      return 1;
  }

  return 0;
}
<commit_msg>[dsymutil] Split some logic into a helper function. NFC<commit_after>//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that aims to be a dropin replacement for
// Darwin's dsymutil.
//
//===----------------------------------------------------------------------===//

#include "DebugMap.h"
#include "dsymutil.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h"
#include <string>

using namespace llvm::dsymutil;

namespace {
using namespace llvm::cl;

OptionCategory DsymCategory("Specific Options");
static opt<bool> Help("h", desc("Alias for -help"), Hidden);
static opt<bool> Version("v", desc("Alias for -version"), Hidden);

static list<std::string> InputFiles(Positional, OneOrMore,
                                    desc("<input files>"), cat(DsymCategory));

static opt<std::string>
    OutputFileOpt("o",
                  desc("Specify the output file. default: <input file>.dwarf"),
                  value_desc("filename"), cat(DsymCategory));

static opt<std::string> OsoPrependPath(
    "oso-prepend-path",
    desc("Specify a directory to prepend to the paths of object files."),
    value_desc("path"), cat(DsymCategory));

static opt<bool> Verbose("verbose", desc("Verbosity level"), init(false),
                         cat(DsymCategory));

static opt<bool>
    NoOutput("no-output",
             desc("Do the link in memory, but do not emit the result file."),
             init(false), cat(DsymCategory));

static opt<bool>
    NoODR("no-odr",
          desc("Do not use ODR (One Definition Rule) for type uniquing."),
          init(false), cat(DsymCategory));

static opt<bool> DumpDebugMap(
    "dump-debug-map",
    desc("Parse and dump the debug map to standard output. Not DWARF link "
         "will take place."),
    init(false), cat(DsymCategory));

static opt<bool> InputIsYAMLDebugMap(
    "y", desc("Treat the input file is a YAML debug map rather than a binary."),
    init(false), cat(DsymCategory));
}

static std::string getOutputFileName(llvm::StringRef InputFile) {
  if (OutputFileOpt.empty()) {
    if (InputFile == "-")
      return "a.out.dwarf";
    return (InputFile + ".dwarf").str();
  }
  return OutputFileOpt;
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
  llvm::llvm_shutdown_obj Shutdown;
  LinkOptions Options;

  HideUnrelatedOptions(DsymCategory);
  llvm::cl::ParseCommandLineOptions(
      argc, argv,
      "manipulate archived DWARF debug symbol files.\n\n"
      "dsymutil links the DWARF debug information found in the object files\n"
      "for the executable <input file> by using debug symbols information\n"
      "contained in its symbol table.\n");

  if (Help)
    PrintHelpMessage();

  if (Version) {
    llvm::cl::PrintVersionMessage();
    return 0;
  }

  Options.Verbose = Verbose;
  Options.NoOutput = NoOutput;
  Options.NoODR = NoODR;

  llvm::InitializeAllTargetInfos();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllTargets();
  llvm::InitializeAllAsmPrinters();

  if (InputFiles.size() > 1 && !OutputFileOpt.empty()) {
    llvm::errs() << "error: cannot use -o with multiple inputs\n";
    return 1;
  }

  for (auto &InputFile : InputFiles) {
    auto DebugMapPtrOrErr =
        parseDebugMap(InputFile, OsoPrependPath, Verbose, InputIsYAMLDebugMap);

    if (auto EC = DebugMapPtrOrErr.getError()) {
      llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
                   << "\": " << EC.message() << '\n';
      return 1;
    }

    if (Verbose || DumpDebugMap)
      (*DebugMapPtrOrErr)->print(llvm::outs());

    if (DumpDebugMap)
      continue;

    std::string OutputFile = getOutputFileName(InputFile);
    if (!linkDwarf(OutputFile, **DebugMapPtrOrErr, Options))
      return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>#include <pthread.h>
#include <arpa/inet.h>

#include <cstdio>
#include <sstream>
#include <vector>

#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "loom/config.h"
#include "loom/Utils.h"

using namespace std;
using namespace llvm;

// TODO: find a way to display more description on action
static cl::opt<string> ControllerAction(cl::Positional,
                                        cl::desc("<action>"),
                                        cl::Required);
static cl::list<string> Args(cl::ConsumeAfter, cl::desc("<arguments>..."));

// protect <CtrlClientSock> and <DaemonSocks>
static pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
static int CtrlClientSock = -1;
static vector<int> DaemonSocks;
// needn't be protected, because it is only used by HandleControllerClient.
static vector<string> FilterFileNames(MaxNumFilters);

int HandleDaemon(int ClientSock) {
  pthread_mutex_lock(&Mutex);
  assert(find(DaemonSocks.begin(), DaemonSocks.end(), ClientSock) ==
         DaemonSocks.end());
  DaemonSocks.push_back(ClientSock);
  pthread_mutex_unlock(&Mutex);

  char Response[MaxBufferSize];
  while (ReceiveMessage(ClientSock, Response) == 0) {
    pthread_mutex_lock(&Mutex);
    if (CtrlClientSock == -1) {
      errs() << "Loom controller client is not started yet\n";
    } else {
      // Forward the response to the controller client. The controller client
      // may receive multiple responses from a multiprocess program. We could
      // have better handle this situation by sending OK only when all processes
      // have successfully installed the filter, and deleting the filter if any
      // process fails.
      SendMessage(CtrlClientSock, Response);
    }
    pthread_mutex_unlock(&Mutex);
  }

  // Remove <ClientSock> from <DaemonSocks>.
  pthread_mutex_lock(&Mutex);
  remove(DaemonSocks.begin(), DaemonSocks.end(), ClientSock);
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void HandleAddFilter(const string &FilterFileName) {
  if (find(FilterFileNames.begin(), FilterFileNames.end(), FilterFileName) !=
      FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "this filter is already installed");
    return;
  }

  // find the first unused ID
  vector<string>::iterator Pos = find(FilterFileNames.begin(),
                                      FilterFileNames.end(),
                                      "");
  if (Pos == FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "too many filters");
    return;
  }
  *Pos = FilterFileName;

  ostringstream OS;
  OS << "add " << (Pos - FilterFileNames.begin()) << " " << FilterFileName;
  pthread_mutex_lock(&Mutex);
  for (size_t i = 0; i < DaemonSocks.size(); ++i) {
    SendMessage(DaemonSocks[i], OS.str().c_str());
  }
  pthread_mutex_unlock(&Mutex);
}

void HandleDeleteFilter(unsigned FilterID) {
  if (FilterID >= MaxNumFilters) {
    SendMessage(CtrlClientSock, "invalid ID");
    return;
  }
  if (FilterFileNames[FilterID] == "") {
    SendMessage(CtrlClientSock, "this ID does not exist");
    return;
  }
  FilterFileNames[FilterID] = "";

  ostringstream OS;
  OS << "del " << FilterID;
  pthread_mutex_lock(&Mutex);
  for (size_t i = 0; i < DaemonSocks.size(); ++i) {
    SendMessage(DaemonSocks[i], OS.str().c_str());
  }
  pthread_mutex_unlock(&Mutex);
}

void HandleListFilters() {
  ostringstream OS;
  bool First = true;
  for (size_t i = 0; i < FilterFileNames.size(); ++i) {
    if (FilterFileNames[i] != "") {
      if (First)
        First = false;
      else
        OS << "\n";
      OS << i << "\t" << FilterFileNames[i];
    }
  }
  SendMessage(CtrlClientSock, OS.str().c_str());
}

int HandleControllerClient(int ClientSock) {
  pthread_mutex_lock(&Mutex);
  if (CtrlClientSock != -1) {
    errs() << "another Loom controller client is running\n";
    pthread_mutex_unlock(&Mutex);
    return -1;
  }
  CtrlClientSock = ClientSock;
  pthread_mutex_unlock(&Mutex);

  char Cmd[MaxBufferSize];
  // benign race when reading <CtrlClientSock>
  while (ReceiveMessage(CtrlClientSock, Cmd) == 0) {
    istringstream IS(Cmd);
    string Op;
    if (!(IS >> Op)) {
      SendMessage(CtrlClientSock, "wrong format");
      continue;
    }
    if (Op == "add") {
      string FilterFileName;
      if (!(IS >> FilterFileName)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleAddFilter(FilterFileName);
    } else if (Op == "del") {
      unsigned FilterID;
      if (!(IS >> FilterID)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleDeleteFilter(FilterID);
    } else if (Op == "ls") {
      HandleListFilters();
    } else {
      SendMessage(CtrlClientSock, "unknown command");
    }
  }

  // Reset <CtrlClientSock> to allow another controller.
  pthread_mutex_lock(&Mutex);
  CtrlClientSock = -1;
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void *HandleClient(void *Arg) {
  int ClientSock = (intptr_t)Arg;

  // Identify the client.
  char Buffer[MaxBufferSize];
  if (ReceiveMessage(ClientSock, Buffer) == -1) {
    close(ClientSock);
    return (void *)-1;
  }

  int Ret = 0;
  if (strcmp(Buffer, "iam loom_daemon") == 0) {
    outs() << "which is a Loom daemon\n";
    Ret = HandleDaemon(ClientSock);
  } else if (strcmp(Buffer, "iam loom_ctl") == 0) {
    outs() << "which is a Loom controller client\n";
    Ret = HandleControllerClient(ClientSock);
  } else {
    outs() << "which is an unknown client. ";
    outs() << "close the connection immediately\n";
  }

  close(ClientSock);
  return (void *)Ret;
}

int RunControllerServer() {
  int AcceptSock = socket(AF_INET, SOCK_STREAM, 0);
  if (AcceptSock == -1) {
    perror("socket");
    return -1;
  }
  int OptionVal = 1;
  if (setsockopt(AcceptSock, SOL_SOCKET,
                 SO_REUSEADDR, &OptionVal, sizeof(int)) == -1) {
    perror("setsockopt");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof(ServerAddr));
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  ServerAddr.sin_addr.s_addr = INADDR_ANY;
  if (bind(AcceptSock,
           (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) == -1) {
    perror("bind");
    return -1;
  }

  if (listen(AcceptSock, 5) == -1) {
    perror("listen");
    return -1;
  }

  outs() << "Loom controller started. ";
  outs() << "Press Ctrl+C to exit...\n";
  struct sockaddr_in ClientAddr;
  socklen_t ClientAddrLen = sizeof(ClientAddr);
  while (true) {
    int ClientSock = accept(AcceptSock,
                            (struct sockaddr *)&ClientAddr, &ClientAddrLen);
    if (ClientSock == -1) {
      perror("accept");
      return -1;
    }

    outs() << "connected by " << inet_ntoa(ClientAddr.sin_addr) << ":" <<
        ntohs(ClientAddr.sin_port) << ", ";
    pthread_t child;
    if (pthread_create(&child, NULL, HandleClient, (void *)ClientSock) != 0) {
      perror("pthread_create");
      return -1;
    }
  }

  return 0;
}

int CommandAddFilter(int CtrlServerSock, const string &FilterFileName) {
  ostringstream OS;
  OS << "add ";
  // Convert to full path whenever possible, so that the user can use relative
  // path.
  if (char *FullPath = realpath(FilterFileName.c_str(), NULL)) {
    OS << FullPath;
    free(FullPath);
  } else {
    OS << FilterFileName;
  }
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandDeleteFilter(int CtrlServerSock, unsigned FilterID) {
  ostringstream OS;
  OS << "del " << FilterID;
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandListFilters(int CtrlServerSock) {
  return SendMessage(CtrlServerSock, "ls");
}

int RunControllerClient() {
  int CtrlServerSock = socket(AF_INET, SOCK_STREAM, 0);
  if (CtrlServerSock == -1) {
    perror("socket");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof ServerAddr);
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_addr.s_addr = inet_addr(CONTROLLER_IP);
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  if (connect(CtrlServerSock,
              (struct sockaddr *)&ServerAddr, sizeof ServerAddr) == -1) {
    perror("failed to connect to the controller server");
    return -1;
  }

  if (SendMessage(CtrlServerSock, "iam loom_ctl") == -1) {
    close(CtrlServerSock);
    return -1;
  }

  int Ret = 0;
  if (ControllerAction == "add") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandAddFilter(CtrlServerSock, Args[0]);
    }
  } else if (ControllerAction == "delete") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      // TODO: check Args[0] is a number
      Ret = CommandDeleteFilter(CtrlServerSock, atoi(Args[0].c_str()));
    }
  } else if (ControllerAction == "ls") {
    if (Args.size() != 0) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandListFilters(CtrlServerSock);
    }
  } else {
    assert(false);
  }

  // Don't bother receiving the response if sending already failed.
  if (Ret == 0) {
    char Response[MaxBufferSize] = {'\0'};
    Ret = ReceiveMessage(CtrlServerSock, Response);
    if (Ret == 0) {
      outs() << Response << "\n";
    }
  }

  close(CtrlServerSock);
  return Ret;
}

int main(int argc, char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, "Loom controller");
  if (ControllerAction == "server") {
    if (RunControllerServer() == -1)
      return 1;
  } else if (ControllerAction == "add" ||
             ControllerAction == "delete" ||
             ControllerAction == "ls") {
    if (RunControllerClient() == -1)
      return 1;
  } else {
    errs() << "Not implemented yet\n";
  }
  return 0;
}
<commit_msg>Do not call SendMessage in a critical region<commit_after>#include <pthread.h>
#include <arpa/inet.h>

#include <cstdio>
#include <sstream>
#include <vector>

#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "loom/config.h"
#include "loom/Utils.h"

using namespace std;
using namespace llvm;

// TODO: find a way to display more description on action
static cl::opt<string> ControllerAction(cl::Positional,
                                        cl::desc("<action>"),
                                        cl::Required);
static cl::list<string> Args(cl::ConsumeAfter, cl::desc("<arguments>..."));

// protect <CtrlClientSock> and <DaemonSocks>
static pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
static int CtrlClientSock = -1;
static vector<int> DaemonSocks;
// needn't be protected, because it is only used by HandleControllerClient.
static vector<string> FilterFileNames(MaxNumFilters);

int HandleDaemon(int ClientSock) {
  pthread_mutex_lock(&Mutex);
  assert(find(DaemonSocks.begin(), DaemonSocks.end(), ClientSock) ==
         DaemonSocks.end());
  DaemonSocks.push_back(ClientSock);
  pthread_mutex_unlock(&Mutex);

  char Response[MaxBufferSize];
  while (ReceiveMessage(ClientSock, Response) == 0) {
    pthread_mutex_lock(&Mutex);
    if (CtrlClientSock == -1) {
      errs() << "Loom controller client is not started yet\n";
      pthread_mutex_unlock(&Mutex);
      continue;
    }
    int Sock = CtrlClientSock;
    pthread_mutex_unlock(&Mutex);

    // Forward the response to the controller client.
    // TODO: The controller client may receive multiple responses from a
    // multiprocess program. We could have better handle this situation by
    // sending OK only when all processes have successfully installed the
    // filter, and deleting the filter if any process fails.
    SendMessage(Sock, Response);
  }

  // Remove <ClientSock> from <DaemonSocks>.
  pthread_mutex_lock(&Mutex);
  remove(DaemonSocks.begin(), DaemonSocks.end(), ClientSock);
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void HandleAddFilter(const string &FilterFileName) {
  if (find(FilterFileNames.begin(), FilterFileNames.end(), FilterFileName) !=
      FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "this filter is already installed");
    return;
  }

  // find the first unused ID
  vector<string>::iterator Pos = find(FilterFileNames.begin(),
                                      FilterFileNames.end(),
                                      "");
  if (Pos == FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "too many filters");
    return;
  }
  *Pos = FilterFileName;

  ostringstream OS;
  OS << "add " << (Pos - FilterFileNames.begin()) << " " << FilterFileName;
  pthread_mutex_lock(&Mutex);
  for (size_t i = 0; i < DaemonSocks.size(); ++i) {
    SendMessage(DaemonSocks[i], OS.str().c_str());
  }
  pthread_mutex_unlock(&Mutex);
}

void HandleDeleteFilter(unsigned FilterID) {
  if (FilterID >= MaxNumFilters) {
    SendMessage(CtrlClientSock, "invalid ID");
    return;
  }
  if (FilterFileNames[FilterID] == "") {
    SendMessage(CtrlClientSock, "this ID does not exist");
    return;
  }
  FilterFileNames[FilterID] = "";

  ostringstream OS;
  OS << "del " << FilterID;
  pthread_mutex_lock(&Mutex);
  for (size_t i = 0; i < DaemonSocks.size(); ++i) {
    SendMessage(DaemonSocks[i], OS.str().c_str());
  }
  pthread_mutex_unlock(&Mutex);
}

void HandleListFilters() {
  ostringstream OS;
  bool First = true;
  for (size_t i = 0; i < FilterFileNames.size(); ++i) {
    if (FilterFileNames[i] != "") {
      if (First)
        First = false;
      else
        OS << "\n";
      OS << i << "\t" << FilterFileNames[i];
    }
  }
  SendMessage(CtrlClientSock, OS.str().c_str());
}

int HandleControllerClient(int ClientSock) {
  pthread_mutex_lock(&Mutex);
  if (CtrlClientSock != -1) {
    errs() << "another Loom controller client is running\n";
    pthread_mutex_unlock(&Mutex);
    return -1;
  }
  CtrlClientSock = ClientSock;
  pthread_mutex_unlock(&Mutex);

  char Cmd[MaxBufferSize];
  // benign race when reading <CtrlClientSock>
  while (ReceiveMessage(CtrlClientSock, Cmd) == 0) {
    istringstream IS(Cmd);
    string Op;
    if (!(IS >> Op)) {
      SendMessage(CtrlClientSock, "wrong format");
      continue;
    }
    if (Op == "add") {
      string FilterFileName;
      if (!(IS >> FilterFileName)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleAddFilter(FilterFileName);
    } else if (Op == "del") {
      unsigned FilterID;
      if (!(IS >> FilterID)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleDeleteFilter(FilterID);
    } else if (Op == "ls") {
      HandleListFilters();
    } else {
      SendMessage(CtrlClientSock, "unknown command");
    }
  }

  // Reset <CtrlClientSock> to allow another controller.
  pthread_mutex_lock(&Mutex);
  CtrlClientSock = -1;
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void *HandleClient(void *Arg) {
  int ClientSock = (intptr_t)Arg;

  // Identify the client.
  char Buffer[MaxBufferSize];
  if (ReceiveMessage(ClientSock, Buffer) == -1) {
    close(ClientSock);
    return (void *)-1;
  }

  int Ret = 0;
  if (strcmp(Buffer, "iam loom_daemon") == 0) {
    outs() << "which is a Loom daemon\n";
    Ret = HandleDaemon(ClientSock);
  } else if (strcmp(Buffer, "iam loom_ctl") == 0) {
    outs() << "which is a Loom controller client\n";
    Ret = HandleControllerClient(ClientSock);
  } else {
    outs() << "which is an unknown client. ";
    outs() << "close the connection immediately\n";
  }

  close(ClientSock);
  return (void *)Ret;
}

int RunControllerServer() {
  int AcceptSock = socket(AF_INET, SOCK_STREAM, 0);
  if (AcceptSock == -1) {
    perror("socket");
    return -1;
  }
  int OptionVal = 1;
  if (setsockopt(AcceptSock, SOL_SOCKET,
                 SO_REUSEADDR, &OptionVal, sizeof(int)) == -1) {
    perror("setsockopt");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof(ServerAddr));
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  ServerAddr.sin_addr.s_addr = INADDR_ANY;
  if (bind(AcceptSock,
           (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) == -1) {
    perror("bind");
    return -1;
  }

  if (listen(AcceptSock, 5) == -1) {
    perror("listen");
    return -1;
  }

  outs() << "Loom controller started. ";
  outs() << "Press Ctrl+C to exit...\n";
  struct sockaddr_in ClientAddr;
  socklen_t ClientAddrLen = sizeof(ClientAddr);
  while (true) {
    int ClientSock = accept(AcceptSock,
                            (struct sockaddr *)&ClientAddr, &ClientAddrLen);
    if (ClientSock == -1) {
      perror("accept");
      return -1;
    }

    outs() << "connected by " << inet_ntoa(ClientAddr.sin_addr) << ":" <<
        ntohs(ClientAddr.sin_port) << ", ";
    pthread_t child;
    if (pthread_create(&child, NULL, HandleClient, (void *)ClientSock) != 0) {
      perror("pthread_create");
      return -1;
    }
  }

  return 0;
}

int CommandAddFilter(int CtrlServerSock, const string &FilterFileName) {
  ostringstream OS;
  OS << "add ";
  // Convert to full path whenever possible, so that the user can use relative
  // path.
  if (char *FullPath = realpath(FilterFileName.c_str(), NULL)) {
    OS << FullPath;
    free(FullPath);
  } else {
    OS << FilterFileName;
  }
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandDeleteFilter(int CtrlServerSock, unsigned FilterID) {
  ostringstream OS;
  OS << "del " << FilterID;
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandListFilters(int CtrlServerSock) {
  return SendMessage(CtrlServerSock, "ls");
}

int RunControllerClient() {
  int CtrlServerSock = socket(AF_INET, SOCK_STREAM, 0);
  if (CtrlServerSock == -1) {
    perror("socket");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof ServerAddr);
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_addr.s_addr = inet_addr(CONTROLLER_IP);
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  if (connect(CtrlServerSock,
              (struct sockaddr *)&ServerAddr, sizeof ServerAddr) == -1) {
    perror("failed to connect to the controller server");
    return -1;
  }

  if (SendMessage(CtrlServerSock, "iam loom_ctl") == -1) {
    close(CtrlServerSock);
    return -1;
  }

  int Ret = 0;
  if (ControllerAction == "add") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandAddFilter(CtrlServerSock, Args[0]);
    }
  } else if (ControllerAction == "delete") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      // TODO: check Args[0] is a number
      Ret = CommandDeleteFilter(CtrlServerSock, atoi(Args[0].c_str()));
    }
  } else if (ControllerAction == "ls") {
    if (Args.size() != 0) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandListFilters(CtrlServerSock);
    }
  } else {
    assert(false);
  }

  // Don't bother receiving the response if sending already failed.
  if (Ret == 0) {
    char Response[MaxBufferSize] = {'\0'};
    Ret = ReceiveMessage(CtrlServerSock, Response);
    if (Ret == 0) {
      outs() << Response << "\n";
    }
  }

  close(CtrlServerSock);
  return Ret;
}

int main(int argc, char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, "Loom controller");
  if (ControllerAction == "server") {
    if (RunControllerServer() == -1)
      return 1;
  } else if (ControllerAction == "add" ||
             ControllerAction == "delete" ||
             ControllerAction == "ls") {
    if (RunControllerClient() == -1)
      return 1;
  } else {
    errs() << "Not implemented yet\n";
  }
  return 0;
}
<|endoftext|>