<commit_before>//===- MachineSSAUpdater.cpp - Unstructured SSA Update Tool ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the MachineSSAUpdater class. It's based on SSAUpdater
// class in lib/Transforms/Utils.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineSSAUpdater.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/SSAUpdaterImpl.h"
using namespace llvm;

typedef DenseMap<MachineBasicBlock*, unsigned> AvailableValsTy;
static AvailableValsTy &getAvailableVals(void *AV) {
  return *static_cast<AvailableValsTy*>(AV);
}

MachineSSAUpdater::MachineSSAUpdater(MachineFunction &MF,
                                     SmallVectorImpl<MachineInstr*> *NewPHI)
  : AV(0), InsertedPHIs(NewPHI) {
  TII = MF.getTarget().getInstrInfo();
  MRI = &MF.getRegInfo();
}

MachineSSAUpdater::~MachineSSAUpdater() {
  delete &getAvailableVals(AV);
}

/// Initialize - Reset this object to get ready for a new set of SSA
/// updates.  ProtoValue is the value used to name PHI nodes.
void MachineSSAUpdater::Initialize(unsigned V) {
  if (AV == 0)
    AV = new AvailableValsTy();
  else
    getAvailableVals(AV).clear();

  VR = V;
  VRC = MRI->getRegClass(VR);
}

/// HasValueForBlock - Return true if the MachineSSAUpdater already has a value for
/// the specified block.
bool MachineSSAUpdater::HasValueForBlock(MachineBasicBlock *BB) const {
  return getAvailableVals(AV).count(BB);
}

/// AddAvailableValue - Indicate that a rewritten value is available in the
/// specified block with the specified value.
void MachineSSAUpdater::AddAvailableValue(MachineBasicBlock *BB, unsigned V) {
  getAvailableVals(AV)[BB] = V;
}

/// GetValueAtEndOfBlock - Construct SSA form, materializing a value that is
/// live at the end of the specified block.
unsigned MachineSSAUpdater::GetValueAtEndOfBlock(MachineBasicBlock *BB) {
  return GetValueAtEndOfBlockInternal(BB);
}

static
unsigned LookForIdenticalPHI(MachineBasicBlock *BB,
          SmallVector<std::pair<MachineBasicBlock*, unsigned>, 8> &PredValues) {
  if (BB->empty())
    return 0;

  MachineBasicBlock::iterator I = BB->front();
  if (!I->isPHI())
    return 0;

  AvailableValsTy AVals;
  for (unsigned i = 0, e = PredValues.size(); i != e; ++i)
    AVals[PredValues[i].first] = PredValues[i].second;
  while (I != BB->end() && I->isPHI()) {
    bool Same = true;
    for (unsigned i = 1, e = I->getNumOperands(); i != e; i += 2) {
      unsigned SrcReg = I->getOperand(i).getReg();
      MachineBasicBlock *SrcBB = I->getOperand(i+1).getMBB();
      if (AVals[SrcBB] != SrcReg) {
        Same = false;
        break;
      }
    }
    if (Same)
      return I->getOperand(0).getReg();
    ++I;
  }
  return 0;
}

/// InsertNewDef - Insert an empty PHI or IMPLICIT_DEF instruction which define
/// a value of the given register class at the start of the specified basic
/// block. It returns the virtual register defined by the instruction.
static
MachineInstr *InsertNewDef(unsigned Opcode,
                           MachineBasicBlock *BB, MachineBasicBlock::iterator I,
                           const TargetRegisterClass *RC,
                           MachineRegisterInfo *MRI,
                           const TargetInstrInfo *TII) {
  unsigned NewVR = MRI->createVirtualRegister(RC);
  return BuildMI(*BB, I, DebugLoc(), TII->get(Opcode), NewVR);
}

/// GetValueInMiddleOfBlock - Construct SSA form, materializing a value that
/// is live in the middle of the specified block.
///
/// GetValueInMiddleOfBlock is the same as GetValueAtEndOfBlock except in one
/// important case: if there is a definition of the rewritten value after the
/// 'use' in BB.  Consider code like this:
///
///      X1 = ...
///   SomeBB:
///      use(X)
///      X2 = ...
///      br Cond, SomeBB, OutBB
///
/// In this case, there are two values (X1 and X2) added to the AvailableVals
/// set by the client of the rewriter, and those values are both live out of
/// their respective blocks.  However, the use of X happens in the *middle* of
/// a block.  Because of this, we need to insert a new PHI node in SomeBB to
/// merge the appropriate values, and this value isn't live out of the block.
///
unsigned MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB) {
  // If there is no definition of the renamed variable in this block, just use
  // GetValueAtEndOfBlock to do our work.
  if (!HasValueForBlock(BB))
    return GetValueAtEndOfBlockInternal(BB);

  // If there are no predecessors, just return undef.
  if (BB->pred_empty()) {
    // Insert an implicit_def to represent an undef value.
    MachineInstr *NewDef = InsertNewDef(TargetOpcode::IMPLICIT_DEF,
                                        BB, BB->getFirstTerminator(),
                                        VRC, MRI, TII);
    return NewDef->getOperand(0).getReg();
  }

  // Otherwise, we have the hard case.  Get the live-in values for each
  // predecessor.
  SmallVector<std::pair<MachineBasicBlock*, unsigned>, 8> PredValues;
  unsigned SingularValue = 0;

  bool isFirstPred = true;
  for (MachineBasicBlock::pred_iterator PI = BB->pred_begin(),
         E = BB->pred_end(); PI != E; ++PI) {
    MachineBasicBlock *PredBB = *PI;
    unsigned PredVal = GetValueAtEndOfBlockInternal(PredBB);
    PredValues.push_back(std::make_pair(PredBB, PredVal));

    // Compute SingularValue.
    if (isFirstPred) {
      SingularValue = PredVal;
      isFirstPred = false;
    } else if (PredVal != SingularValue)
      SingularValue = 0;
  }

  // Otherwise, if all the merged values are the same, just use it.
  if (SingularValue != 0)
    return SingularValue;

  // If an identical PHI is already in BB, just reuse it.
  unsigned DupPHI = LookForIdenticalPHI(BB, PredValues);
  if (DupPHI)
    return DupPHI;

  // Otherwise, we do need a PHI: insert one now.
  MachineBasicBlock::iterator Loc = BB->empty() ? BB->end() : BB->front();
  MachineInstr *InsertedPHI = InsertNewDef(TargetOpcode::PHI, BB,
                                           Loc, VRC, MRI, TII);

  // Fill in all the predecessors of the PHI.
  MachineInstrBuilder MIB(InsertedPHI);
  for (unsigned i = 0, e = PredValues.size(); i != e; ++i)
    MIB.addReg(PredValues[i].second).addMBB(PredValues[i].first);

  // See if the PHI node can be merged to a single value.  This can happen in
  // loop cases when we get a PHI of itself and one other value.
  if (unsigned ConstVal = InsertedPHI->isConstantValuePHI()) {
    InsertedPHI->eraseFromParent();
    return ConstVal;
  }

  // If the client wants to know about all new instructions, tell it.
  if (InsertedPHIs) InsertedPHIs->push_back(InsertedPHI);

  DEBUG(dbgs() << "  Inserted PHI: " << *InsertedPHI << "\n");
  return InsertedPHI->getOperand(0).getReg();
}

static
MachineBasicBlock *findCorrespondingPred(const MachineInstr *MI,
                                         MachineOperand *U) {
  for (unsigned i = 1, e = MI->getNumOperands(); i != e; i += 2) {
    if (&MI->getOperand(i) == U)
      return MI->getOperand(i+1).getMBB();
  }

  llvm_unreachable("MachineOperand::getParent() failure?");
  return 0;
}

/// RewriteUse - Rewrite a use of the symbolic value.  This handles PHI nodes,
/// which use their value in the corresponding predecessor.
void MachineSSAUpdater::RewriteUse(MachineOperand &U) {
  MachineInstr *UseMI = U.getParent();
  unsigned NewVR = 0;
  if (UseMI->isPHI()) {
    MachineBasicBlock *SourceBB = findCorrespondingPred(UseMI, &U);
    NewVR = GetValueAtEndOfBlockInternal(SourceBB);
  } else {
    NewVR = GetValueInMiddleOfBlock(UseMI->getParent());
  }

  U.setReg(NewVR);
}

void MachineSSAUpdater::ReplaceRegWith(unsigned OldReg, unsigned NewReg) {
  MRI->replaceRegWith(OldReg, NewReg);

  AvailableValsTy &AvailableVals = getAvailableVals(AV);
  for (DenseMap<MachineBasicBlock*, unsigned>::iterator
         I = AvailableVals.begin(), E = AvailableVals.end(); I != E; ++I)
    if (I->second == OldReg)
      I->second = NewReg;
}

/// MachinePHIiter - Iterator for PHI operands.  This is used for the
/// PHI_iterator in the SSAUpdaterImpl template.
namespace {
  class MachinePHIiter {
  private:
    MachineInstr *PHI;
    unsigned idx;

  public:
    explicit MachinePHIiter(MachineInstr *P) // begin iterator
      : PHI(P), idx(1) {}
    MachinePHIiter(MachineInstr *P, bool) // end iterator
      : PHI(P), idx(PHI->getNumOperands()) {}

    MachinePHIiter &operator++() { idx += 2; return *this; }
    bool operator==(const MachinePHIiter& x) const { return idx == x.idx; }
    bool operator!=(const MachinePHIiter& x) const { return !operator==(x); }
    unsigned getIncomingValue() { return PHI->getOperand(idx).getReg(); }
    MachineBasicBlock *getIncomingBlock() {
      return PHI->getOperand(idx+1).getMBB();
    }
  };
}

/// SSAUpdaterTraits<MachineSSAUpdater> - Traits for the SSAUpdaterImpl
/// template, specialized for MachineSSAUpdater.
namespace llvm {
template<>
class SSAUpdaterTraits<MachineSSAUpdater> {
public:
  typedef MachineBasicBlock BlkT;
  typedef unsigned ValT;
  typedef MachineInstr PhiT;

  typedef MachineBasicBlock::succ_iterator BlkSucc_iterator;
  static BlkSucc_iterator BlkSucc_begin(BlkT *BB) { return BB->succ_begin(); }
  static BlkSucc_iterator BlkSucc_end(BlkT *BB) { return BB->succ_end(); }

  typedef MachinePHIiter PHI_iterator;
  static inline PHI_iterator PHI_begin(PhiT *PHI) { return PHI_iterator(PHI); }
  static inline PHI_iterator PHI_end(PhiT *PHI) {
    return PHI_iterator(PHI, true);
  }

  /// FindPredecessorBlocks - Put the predecessors of BB into the Preds
  /// vector.
  static void FindPredecessorBlocks(MachineBasicBlock *BB,
                                    SmallVectorImpl<MachineBasicBlock*> *Preds){
    for (MachineBasicBlock::pred_iterator PI = BB->pred_begin(),
           E = BB->pred_end(); PI != E; ++PI)
      Preds->push_back(*PI);
  }

  /// GetUndefVal - Create an IMPLICIT_DEF instruction with a new register.
  /// Add it into the specified block and return the register.
  static unsigned GetUndefVal(MachineBasicBlock *BB,
                              MachineSSAUpdater *Updater) {
    // Insert an implicit_def to represent an undef value.
    MachineInstr *NewDef = InsertNewDef(TargetOpcode::IMPLICIT_DEF,
                                        BB, BB->getFirstTerminator(),
                                        Updater->VRC, Updater->MRI,
                                        Updater->TII);
    return NewDef->getOperand(0).getReg();
  }

  /// CreateEmptyPHI - Create a PHI instruction that defines a new register.
  /// Add it into the specified block and return the register.
  static unsigned CreateEmptyPHI(MachineBasicBlock *BB, unsigned NumPreds,
                                 MachineSSAUpdater *Updater) {
    MachineBasicBlock::iterator Loc = BB->empty() ? BB->end() : BB->front();
    MachineInstr *PHI = InsertNewDef(TargetOpcode::PHI, BB, Loc,
                                     Updater->VRC, Updater->MRI,
                                     Updater->TII);
    return PHI->getOperand(0).getReg();
  }

  /// AddPHIOperand - Add the specified value as an operand of the PHI for
  /// the specified predecessor block.
  static void AddPHIOperand(MachineInstr *PHI, unsigned Val,
                            MachineBasicBlock *Pred) {
    PHI->addOperand(MachineOperand::CreateReg(Val, false));
    PHI->addOperand(MachineOperand::CreateMBB(Pred));
  }

  /// InstrIsPHI - Check if an instruction is a PHI.
  ///
  static MachineInstr *InstrIsPHI(MachineInstr *I) {
    if (I && I->isPHI())
      return I;
    return 0;
  }

  /// ValueIsPHI - Check if the instruction that defines the specified register
  /// is a PHI instruction.
  static MachineInstr *ValueIsPHI(unsigned Val, MachineSSAUpdater *Updater) {
    return InstrIsPHI(Updater->MRI->getVRegDef(Val));
  }

  /// ValueIsNewPHI - Like ValueIsPHI but also check if the PHI has no source
  /// operands, i.e., it was just added.
  static MachineInstr *ValueIsNewPHI(unsigned Val, MachineSSAUpdater *Updater) {
    MachineInstr *PHI = ValueIsPHI(Val, Updater);
    if (PHI && PHI->getNumOperands() <= 1)
      return PHI;
    return 0;
  }

  /// GetPHIValue - For the specified PHI instruction, return the register
  /// that it defines.
  static unsigned GetPHIValue(MachineInstr *PHI) {
    return PHI->getOperand(0).getReg();
  }
};

} // End llvm namespace

/// GetValueAtEndOfBlockInternal - Check to see if AvailableVals has an entry
/// for the specified BB and if so, return it.  If not, construct SSA form by
/// first calculating the required placement of PHIs and then inserting new
/// PHIs where needed.
unsigned MachineSSAUpdater::GetValueAtEndOfBlockInternal(MachineBasicBlock *BB){
  AvailableValsTy &AvailableVals = getAvailableVals(AV);
  if (unsigned V = AvailableVals[BB])
    return V;

  SSAUpdaterImpl<MachineSSAUpdater> Impl(this, &AvailableVals, InsertedPHIs);
  return Impl.GetValue(BB);
}
<commit_msg>Mix some minor misuse of MachineBasicBlock iterator.<commit_after>//===- MachineSSAUpdater.cpp - Unstructured SSA Update Tool ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the MachineSSAUpdater class. It's based on SSAUpdater
// class in lib/Transforms/Utils.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineSSAUpdater.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/SSAUpdaterImpl.h"
using namespace llvm;

typedef DenseMap<MachineBasicBlock*, unsigned> AvailableValsTy;
static AvailableValsTy &getAvailableVals(void *AV) {
  return *static_cast<AvailableValsTy*>(AV);
}

MachineSSAUpdater::MachineSSAUpdater(MachineFunction &MF,
                                     SmallVectorImpl<MachineInstr*> *NewPHI)
  : AV(0), InsertedPHIs(NewPHI) {
  TII = MF.getTarget().getInstrInfo();
  MRI = &MF.getRegInfo();
}

MachineSSAUpdater::~MachineSSAUpdater() {
  delete &getAvailableVals(AV);
}

/// Initialize - Reset this object to get ready for a new set of SSA
/// updates.  ProtoValue is the value used to name PHI nodes.
void MachineSSAUpdater::Initialize(unsigned V) {
  if (AV == 0)
    AV = new AvailableValsTy();
  else
    getAvailableVals(AV).clear();

  VR = V;
  VRC = MRI->getRegClass(VR);
}

/// HasValueForBlock - Return true if the MachineSSAUpdater already has a value for
/// the specified block.
bool MachineSSAUpdater::HasValueForBlock(MachineBasicBlock *BB) const {
  return getAvailableVals(AV).count(BB);
}

/// AddAvailableValue - Indicate that a rewritten value is available in the
/// specified block with the specified value.
void MachineSSAUpdater::AddAvailableValue(MachineBasicBlock *BB, unsigned V) {
  getAvailableVals(AV)[BB] = V;
}

/// GetValueAtEndOfBlock - Construct SSA form, materializing a value that is
/// live at the end of the specified block.
unsigned MachineSSAUpdater::GetValueAtEndOfBlock(MachineBasicBlock *BB) {
  return GetValueAtEndOfBlockInternal(BB);
}

static
unsigned LookForIdenticalPHI(MachineBasicBlock *BB,
          SmallVector<std::pair<MachineBasicBlock*, unsigned>, 8> &PredValues) {
  if (BB->empty())
    return 0;

  MachineBasicBlock::iterator I = BB->begin();
  if (!I->isPHI())
    return 0;

  AvailableValsTy AVals;
  for (unsigned i = 0, e = PredValues.size(); i != e; ++i)
    AVals[PredValues[i].first] = PredValues[i].second;
  while (I != BB->end() && I->isPHI()) {
    bool Same = true;
    for (unsigned i = 1, e = I->getNumOperands(); i != e; i += 2) {
      unsigned SrcReg = I->getOperand(i).getReg();
      MachineBasicBlock *SrcBB = I->getOperand(i+1).getMBB();
      if (AVals[SrcBB] != SrcReg) {
        Same = false;
        break;
      }
    }
    if (Same)
      return I->getOperand(0).getReg();
    ++I;
  }
  return 0;
}

/// InsertNewDef - Insert an empty PHI or IMPLICIT_DEF instruction which define
/// a value of the given register class at the start of the specified basic
/// block. It returns the virtual register defined by the instruction.
static
MachineInstr *InsertNewDef(unsigned Opcode,
                           MachineBasicBlock *BB, MachineBasicBlock::iterator I,
                           const TargetRegisterClass *RC,
                           MachineRegisterInfo *MRI,
                           const TargetInstrInfo *TII) {
  unsigned NewVR = MRI->createVirtualRegister(RC);
  return BuildMI(*BB, I, DebugLoc(), TII->get(Opcode), NewVR);
}

/// GetValueInMiddleOfBlock - Construct SSA form, materializing a value that
/// is live in the middle of the specified block.
///
/// GetValueInMiddleOfBlock is the same as GetValueAtEndOfBlock except in one
/// important case: if there is a definition of the rewritten value after the
/// 'use' in BB.  Consider code like this:
///
///      X1 = ...
///   SomeBB:
///      use(X)
///      X2 = ...
///      br Cond, SomeBB, OutBB
///
/// In this case, there are two values (X1 and X2) added to the AvailableVals
/// set by the client of the rewriter, and those values are both live out of
/// their respective blocks.  However, the use of X happens in the *middle* of
/// a block.  Because of this, we need to insert a new PHI node in SomeBB to
/// merge the appropriate values, and this value isn't live out of the block.
///
unsigned MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB) {
  // If there is no definition of the renamed variable in this block, just use
  // GetValueAtEndOfBlock to do our work.
  if (!HasValueForBlock(BB))
    return GetValueAtEndOfBlockInternal(BB);

  // If there are no predecessors, just return undef.
  if (BB->pred_empty()) {
    // Insert an implicit_def to represent an undef value.
    MachineInstr *NewDef = InsertNewDef(TargetOpcode::IMPLICIT_DEF,
                                        BB, BB->getFirstTerminator(),
                                        VRC, MRI, TII);
    return NewDef->getOperand(0).getReg();
  }

  // Otherwise, we have the hard case.  Get the live-in values for each
  // predecessor.
  SmallVector<std::pair<MachineBasicBlock*, unsigned>, 8> PredValues;
  unsigned SingularValue = 0;

  bool isFirstPred = true;
  for (MachineBasicBlock::pred_iterator PI = BB->pred_begin(),
         E = BB->pred_end(); PI != E; ++PI) {
    MachineBasicBlock *PredBB = *PI;
    unsigned PredVal = GetValueAtEndOfBlockInternal(PredBB);
    PredValues.push_back(std::make_pair(PredBB, PredVal));

    // Compute SingularValue.
    if (isFirstPred) {
      SingularValue = PredVal;
      isFirstPred = false;
    } else if (PredVal != SingularValue)
      SingularValue = 0;
  }

  // Otherwise, if all the merged values are the same, just use it.
  if (SingularValue != 0)
    return SingularValue;

  // If an identical PHI is already in BB, just reuse it.
  unsigned DupPHI = LookForIdenticalPHI(BB, PredValues);
  if (DupPHI)
    return DupPHI;

  // Otherwise, we do need a PHI: insert one now.
  MachineBasicBlock::iterator Loc = BB->empty() ? BB->end() : BB->begin();
  MachineInstr *InsertedPHI = InsertNewDef(TargetOpcode::PHI, BB,
                                           Loc, VRC, MRI, TII);

  // Fill in all the predecessors of the PHI.
  MachineInstrBuilder MIB(InsertedPHI);
  for (unsigned i = 0, e = PredValues.size(); i != e; ++i)
    MIB.addReg(PredValues[i].second).addMBB(PredValues[i].first);

  // See if the PHI node can be merged to a single value.  This can happen in
  // loop cases when we get a PHI of itself and one other value.
  if (unsigned ConstVal = InsertedPHI->isConstantValuePHI()) {
    InsertedPHI->eraseFromParent();
    return ConstVal;
  }

  // If the client wants to know about all new instructions, tell it.
  if (InsertedPHIs) InsertedPHIs->push_back(InsertedPHI);

  DEBUG(dbgs() << "  Inserted PHI: " << *InsertedPHI << "\n");
  return InsertedPHI->getOperand(0).getReg();
}

static
MachineBasicBlock *findCorrespondingPred(const MachineInstr *MI,
                                         MachineOperand *U) {
  for (unsigned i = 1, e = MI->getNumOperands(); i != e; i += 2) {
    if (&MI->getOperand(i) == U)
      return MI->getOperand(i+1).getMBB();
  }

  llvm_unreachable("MachineOperand::getParent() failure?");
  return 0;
}

/// RewriteUse - Rewrite a use of the symbolic value.  This handles PHI nodes,
/// which use their value in the corresponding predecessor.
void MachineSSAUpdater::RewriteUse(MachineOperand &U) {
  MachineInstr *UseMI = U.getParent();
  unsigned NewVR = 0;
  if (UseMI->isPHI()) {
    MachineBasicBlock *SourceBB = findCorrespondingPred(UseMI, &U);
    NewVR = GetValueAtEndOfBlockInternal(SourceBB);
  } else {
    NewVR = GetValueInMiddleOfBlock(UseMI->getParent());
  }

  U.setReg(NewVR);
}

void MachineSSAUpdater::ReplaceRegWith(unsigned OldReg, unsigned NewReg) {
  MRI->replaceRegWith(OldReg, NewReg);

  AvailableValsTy &AvailableVals = getAvailableVals(AV);
  for (DenseMap<MachineBasicBlock*, unsigned>::iterator
         I = AvailableVals.begin(), E = AvailableVals.end(); I != E; ++I)
    if (I->second == OldReg)
      I->second = NewReg;
}

/// MachinePHIiter - Iterator for PHI operands.  This is used for the
/// PHI_iterator in the SSAUpdaterImpl template.
namespace {
  class MachinePHIiter {
  private:
    MachineInstr *PHI;
    unsigned idx;

  public:
    explicit MachinePHIiter(MachineInstr *P) // begin iterator
      : PHI(P), idx(1) {}
    MachinePHIiter(MachineInstr *P, bool) // end iterator
      : PHI(P), idx(PHI->getNumOperands()) {}

    MachinePHIiter &operator++() { idx += 2; return *this; }
    bool operator==(const MachinePHIiter& x) const { return idx == x.idx; }
    bool operator!=(const MachinePHIiter& x) const { return !operator==(x); }
    unsigned getIncomingValue() { return PHI->getOperand(idx).getReg(); }
    MachineBasicBlock *getIncomingBlock() {
      return PHI->getOperand(idx+1).getMBB();
    }
  };
}

/// SSAUpdaterTraits<MachineSSAUpdater> - Traits for the SSAUpdaterImpl
/// template, specialized for MachineSSAUpdater.
namespace llvm {
template<>
class SSAUpdaterTraits<MachineSSAUpdater> {
public:
  typedef MachineBasicBlock BlkT;
  typedef unsigned ValT;
  typedef MachineInstr PhiT;

  typedef MachineBasicBlock::succ_iterator BlkSucc_iterator;
  static BlkSucc_iterator BlkSucc_begin(BlkT *BB) { return BB->succ_begin(); }
  static BlkSucc_iterator BlkSucc_end(BlkT *BB) { return BB->succ_end(); }

  typedef MachinePHIiter PHI_iterator;
  static inline PHI_iterator PHI_begin(PhiT *PHI) { return PHI_iterator(PHI); }
  static inline PHI_iterator PHI_end(PhiT *PHI) {
    return PHI_iterator(PHI, true);
  }

  /// FindPredecessorBlocks - Put the predecessors of BB into the Preds
  /// vector.
  static void FindPredecessorBlocks(MachineBasicBlock *BB,
                                    SmallVectorImpl<MachineBasicBlock*> *Preds){
    for (MachineBasicBlock::pred_iterator PI = BB->pred_begin(),
           E = BB->pred_end(); PI != E; ++PI)
      Preds->push_back(*PI);
  }

  /// GetUndefVal - Create an IMPLICIT_DEF instruction with a new register.
  /// Add it into the specified block and return the register.
  static unsigned GetUndefVal(MachineBasicBlock *BB,
                              MachineSSAUpdater *Updater) {
    // Insert an implicit_def to represent an undef value.
    MachineInstr *NewDef = InsertNewDef(TargetOpcode::IMPLICIT_DEF,
                                        BB, BB->getFirstTerminator(),
                                        Updater->VRC, Updater->MRI,
                                        Updater->TII);
    return NewDef->getOperand(0).getReg();
  }

  /// CreateEmptyPHI - Create a PHI instruction that defines a new register.
  /// Add it into the specified block and return the register.
  static unsigned CreateEmptyPHI(MachineBasicBlock *BB, unsigned NumPreds,
                                 MachineSSAUpdater *Updater) {
    MachineBasicBlock::iterator Loc = BB->empty() ? BB->end() : BB->begin();
    MachineInstr *PHI = InsertNewDef(TargetOpcode::PHI, BB, Loc,
                                     Updater->VRC, Updater->MRI,
                                     Updater->TII);
    return PHI->getOperand(0).getReg();
  }

  /// AddPHIOperand - Add the specified value as an operand of the PHI for
  /// the specified predecessor block.
  static void AddPHIOperand(MachineInstr *PHI, unsigned Val,
                            MachineBasicBlock *Pred) {
    PHI->addOperand(MachineOperand::CreateReg(Val, false));
    PHI->addOperand(MachineOperand::CreateMBB(Pred));
  }

  /// InstrIsPHI - Check if an instruction is a PHI.
  ///
  static MachineInstr *InstrIsPHI(MachineInstr *I) {
    if (I && I->isPHI())
      return I;
    return 0;
  }

  /// ValueIsPHI - Check if the instruction that defines the specified register
  /// is a PHI instruction.
  static MachineInstr *ValueIsPHI(unsigned Val, MachineSSAUpdater *Updater) {
    return InstrIsPHI(Updater->MRI->getVRegDef(Val));
  }

  /// ValueIsNewPHI - Like ValueIsPHI but also check if the PHI has no source
  /// operands, i.e., it was just added.
  static MachineInstr *ValueIsNewPHI(unsigned Val, MachineSSAUpdater *Updater) {
    MachineInstr *PHI = ValueIsPHI(Val, Updater);
    if (PHI && PHI->getNumOperands() <= 1)
      return PHI;
    return 0;
  }

  /// GetPHIValue - For the specified PHI instruction, return the register
  /// that it defines.
  static unsigned GetPHIValue(MachineInstr *PHI) {
    return PHI->getOperand(0).getReg();
  }
};

} // End llvm namespace

/// GetValueAtEndOfBlockInternal - Check to see if AvailableVals has an entry
/// for the specified BB and if so, return it.  If not, construct SSA form by
/// first calculating the required placement of PHIs and then inserting new
/// PHIs where needed.
unsigned MachineSSAUpdater::GetValueAtEndOfBlockInternal(MachineBasicBlock *BB){
  AvailableValsTy &AvailableVals = getAvailableVals(AV);
  if (unsigned V = AvailableVals[BB])
    return V;

  SSAUpdaterImpl<MachineSSAUpdater> Impl(this, &AvailableVals, InsertedPHIs);
  return Impl.GetValue(BB);
}
<|endoftext|>


<commit_before>//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains code to lower ARM MachineInstrs to their corresponding
// MCInst records.
//
//===----------------------------------------------------------------------===//

#include "ARM.h"
#include "ARMMCInstLower.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/Constants.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/SmallString.h"
using namespace llvm;

MCSymbol *ARMMCInstLower::GetGlobalAddressSymbol(const GlobalValue *GV) const {
  return Printer.Mang->getSymbol(GV);
}

const MCSymbolRefExpr *ARMMCInstLower::
GetSymbolRef(const MachineOperand &MO) const {
  assert(MO.isGlobal() && "Isn't a global address reference?");
  // FIXME: HANDLE PLT references how??

  const MCSymbolRefExpr *SymRef;
  const MCSymbol *Symbol = GetGlobalAddressSymbol(MO.getGlobal());

  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on GV operand");
  case 0:
    SymRef = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_None, Ctx);
    break;
  case ARMII::MO_LO16:
    SymRef = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_ARM_LO16, Ctx);
    break;
  case ARMII::MO_HI16:
    SymRef = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_ARM_HI16, Ctx);
    break;
  }

  return SymRef;
}

MCSymbol *ARMMCInstLower::
GetExternalSymbolSymbol(const MachineOperand &MO) const {
  // FIXME: HANDLE PLT references how??
  // FIXME: This probably needs to be merged with the above SymbolRef stuff
  // to handle :lower16: and :upper16: (?)
  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on GV operand");
  case 0: break;
  }

  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
}

MCSymbol *ARMMCInstLower::
GetJumpTableSymbol(const MachineOperand &MO) const {
  SmallString<256> Name;
  raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI"
    << Printer.getFunctionNumber() << '_' << MO.getIndex();

#if 0
  switch (MO.getTargetFlags()) {
    default: llvm_unreachable("Unknown target flag on GV operand");
  }
#endif

  // Create a symbol for the name.
  return Ctx.GetOrCreateSymbol(Name.str());
}

MCSymbol *ARMMCInstLower::
GetConstantPoolIndexSymbol(const MachineOperand &MO) const {
  SmallString<256> Name;
  raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI"
    << Printer.getFunctionNumber() << '_' << MO.getIndex();

#if 0
  switch (MO.getTargetFlags()) {
  default: llvm_unreachable("Unknown target flag on GV operand");
  }
#endif

  // Create a symbol for the name.
  return Ctx.GetOrCreateSymbol(Name.str());
}

MCOperand ARMMCInstLower::
LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const {
  // FIXME: We would like an efficient form for this, so we don't have to do a
  // lot of extra uniquing.
  const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx);

#if 0
  switch (MO.getTargetFlags()) {
  default: llvm_unreachable("Unknown target flag on GV operand");
  }
#endif

  if (!MO.isJTI() && MO.getOffset())
    Expr = MCBinaryExpr::CreateAdd(Expr,
                                   MCConstantExpr::Create(MO.getOffset(), Ctx),
                                   Ctx);
  return MCOperand::CreateExpr(Expr);
}

MCOperand ARMMCInstLower::
LowerSymbolRefOperand(const MachineOperand &MO,
                      const MCSymbolRefExpr *Sym) const {
  const MCExpr *Expr = Sym;
  if (!MO.isJTI() && MO.getOffset())
    Expr = MCBinaryExpr::CreateAdd(Expr,
                                   MCConstantExpr::Create(MO.getOffset(), Ctx),
                                   Ctx);
  return MCOperand::CreateExpr(Expr);
}

void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
  OutMI.setOpcode(MI->getOpcode());

  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = MI->getOperand(i);

    MCOperand MCOp;
    switch (MO.getType()) {
    default:
      MI->dump();
      assert(0 && "unknown operand type");
    case MachineOperand::MO_Register:
      // Ignore all non-CPSR implicit register operands.
      if (MO.isImplicit() && MO.getReg() != ARM::CPSR) continue;
      assert(!MO.getSubReg() && "Subregs should be eliminated!");
      MCOp = MCOperand::CreateReg(MO.getReg());
      break;
    case MachineOperand::MO_Immediate:
      MCOp = MCOperand::CreateImm(MO.getImm());
      break;
    case MachineOperand::MO_MachineBasicBlock:
      MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create(
                       MO.getMBB()->getSymbol(), Ctx));
      break;
    case MachineOperand::MO_GlobalAddress:
      MCOp = LowerSymbolRefOperand(MO, GetSymbolRef(MO));
      break;
    case MachineOperand::MO_ExternalSymbol:
      MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
      break;
    case MachineOperand::MO_JumpTableIndex:
      MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO));
      break;
    case MachineOperand::MO_ConstantPoolIndex:
      MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO));
      break;
    case MachineOperand::MO_BlockAddress:
      MCOp = LowerSymbolOperand(MO, Printer.GetBlockAddressSymbol(
                                              MO.getBlockAddress()));
      break;
    case MachineOperand::MO_FPImmediate:
      APFloat Val = MO.getFPImm()->getValueAPF();
      bool ignored;
      Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored);
      MCOp = MCOperand::CreateFPImm(Val.convertToDouble());
      break;
    }

    OutMI.addOperand(MCOp);
  }

}
<commit_msg>Enable a few additional asserts in MC instruction lowering.<commit_after>//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains code to lower ARM MachineInstrs to their corresponding
// MCInst records.
//
//===----------------------------------------------------------------------===//

#include "ARM.h"
#include "ARMMCInstLower.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/Constants.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/SmallString.h"
using namespace llvm;

MCSymbol *ARMMCInstLower::GetGlobalAddressSymbol(const GlobalValue *GV) const {
  return Printer.Mang->getSymbol(GV);
}

const MCSymbolRefExpr *ARMMCInstLower::
GetSymbolRef(const MachineOperand &MO) const {
  assert(MO.isGlobal() && "Isn't a global address reference?");
  // FIXME: HANDLE PLT references how??

  const MCSymbolRefExpr *SymRef;
  const MCSymbol *Symbol = GetGlobalAddressSymbol(MO.getGlobal());

  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on GV operand");
  case 0:
    SymRef = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_None, Ctx);
    break;
  case ARMII::MO_LO16:
    SymRef = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_ARM_LO16, Ctx);
    break;
  case ARMII::MO_HI16:
    SymRef = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_ARM_HI16, Ctx);
    break;
  }

  return SymRef;
}

MCSymbol *ARMMCInstLower::
GetExternalSymbolSymbol(const MachineOperand &MO) const {
  // FIXME: HANDLE PLT references how??
  // FIXME: This probably needs to be merged with the above SymbolRef stuff
  // to handle :lower16: and :upper16: (?)
  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on GV operand");
  case 0: break;
  }

  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
}

MCSymbol *ARMMCInstLower::
GetJumpTableSymbol(const MachineOperand &MO) const {
  SmallString<256> Name;
  raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI"
    << Printer.getFunctionNumber() << '_' << MO.getIndex();

  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on jump table operand");
  case 0: break;
  }

  // Create a symbol for the name.
  return Ctx.GetOrCreateSymbol(Name.str());
}

MCSymbol *ARMMCInstLower::
GetConstantPoolIndexSymbol(const MachineOperand &MO) const {
  SmallString<256> Name;
  raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI"
    << Printer.getFunctionNumber() << '_' << MO.getIndex();

  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on CPI operand");
  case 0: break;
  }

  // Create a symbol for the name.
  return Ctx.GetOrCreateSymbol(Name.str());
}

MCOperand ARMMCInstLower::
LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const {
  // FIXME: We would like an efficient form for this, so we don't have to do a
  // lot of extra uniquing.
  const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx);

  switch (MO.getTargetFlags()) {
  default: assert(0 && "Unknown target flag on Symbol operand");
  case 0: break;
  }

  if (!MO.isJTI() && MO.getOffset())
    Expr = MCBinaryExpr::CreateAdd(Expr,
                                   MCConstantExpr::Create(MO.getOffset(), Ctx),
                                   Ctx);
  return MCOperand::CreateExpr(Expr);
}

MCOperand ARMMCInstLower::
LowerSymbolRefOperand(const MachineOperand &MO,
                      const MCSymbolRefExpr *Sym) const {
  const MCExpr *Expr = Sym;
  if (!MO.isJTI() && MO.getOffset())
    Expr = MCBinaryExpr::CreateAdd(Expr,
                                   MCConstantExpr::Create(MO.getOffset(), Ctx),
                                   Ctx);
  return MCOperand::CreateExpr(Expr);
}

void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
  OutMI.setOpcode(MI->getOpcode());

  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = MI->getOperand(i);

    MCOperand MCOp;
    switch (MO.getType()) {
    default:
      MI->dump();
      assert(0 && "unknown operand type");
    case MachineOperand::MO_Register:
      // Ignore all non-CPSR implicit register operands.
      if (MO.isImplicit() && MO.getReg() != ARM::CPSR) continue;
      assert(!MO.getSubReg() && "Subregs should be eliminated!");
      MCOp = MCOperand::CreateReg(MO.getReg());
      break;
    case MachineOperand::MO_Immediate:
      MCOp = MCOperand::CreateImm(MO.getImm());
      break;
    case MachineOperand::MO_MachineBasicBlock:
      MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create(
                       MO.getMBB()->getSymbol(), Ctx));
      break;
    case MachineOperand::MO_GlobalAddress:
      MCOp = LowerSymbolRefOperand(MO, GetSymbolRef(MO));
      break;
    case MachineOperand::MO_ExternalSymbol:
      MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
      break;
    case MachineOperand::MO_JumpTableIndex:
      MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO));
      break;
    case MachineOperand::MO_ConstantPoolIndex:
      MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO));
      break;
    case MachineOperand::MO_BlockAddress:
      MCOp = LowerSymbolOperand(MO, Printer.GetBlockAddressSymbol(
                                              MO.getBlockAddress()));
      break;
    case MachineOperand::MO_FPImmediate:
      APFloat Val = MO.getFPImm()->getValueAPF();
      bool ignored;
      Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored);
      MCOp = MCOperand::CreateFPImm(Val.convertToDouble());
      break;
    }

    OutMI.addOperand(MCOp);
  }

}
<|endoftext|>


<commit_before>#include <elevator/sessionmanager.h>
#include <elevator/serialization.h>
#include <elevator/restartwrapper.h>

namespace elevator {

using namespace serialization;

const udp::Address SessionManager::commSend{ udp::IPv4Address::any, udp::Port{ 64032 } };
const udp::Address SessionManager::commRcv{ udp::IPv4Address::any, udp::Port{ 64033 } };
const udp::Address SessionManager::commBroadcast{ udp::IPv4Address::broadcast, udp::Port{ 64033 } };

struct Initial {
    Initial() = default;
    Initial( std::tuple<> ) { };
    std::tuple<> tuple() const { return std::tuple<>(); }
    static TypeSignature type() {
        return TypeSignature::InitialPacket;
    }
};

struct Ready {
    Ready() = default;
    Ready( std::tuple<> ) { };
    std::tuple<> tuple() const { return std::tuple<>(); }
    static TypeSignature type() {
        return TypeSignature::ElevatorReady;
    }
};

struct RecoveryPeers {
    RecoveryPeers() = default;
    RecoveryPeers( std::set< udp::IPv4Address > peers ) : peers( peers ) { }
    RecoveryPeers( std::tuple< std::set< udp::IPv4Address > > t )
        : RecoveryPeers( std::get< 0 >( t ) )
    { }
    static TypeSignature type() { return TypeSignature::RecoveryPeers; }
    std::tuple< std::set< udp::IPv4Address > > tuple() const {
        return std::make_tuple( peers );
    }

    std::set< udp::IPv4Address > peers;
};

struct RecoveryState {
    RecoveryState() = default;
    RecoveryState( ElevatorState state, std::set< udp::IPv4Address > peers ) :
        state( state ), peers( peers )
    { }
    RecoveryState( std::tuple< ElevatorState, std::set< udp::IPv4Address > > t )
        : RecoveryState( std::get< 0 >( t ), std::get< 1 >( t ) )
    { }
    static TypeSignature type() { return TypeSignature::RecoveryState; }
    std::tuple< ElevatorState, std::set< udp::IPv4Address > > tuple() const {
        return std::make_tuple( state, peers );
    }

    ElevatorState state;
    std::set< udp::IPv4Address > peers;
};

SessionManager::SessionManager( GlobalState &glo ) : _state( glo ),
    _sendSock{ commSend, true }, _recvSock{ commRcv, true }
{ }

void SessionManager::_initSender( std::atomic< int > *initPhase ) {
    _sendSock.enableBroadcast();
    while( *initPhase < 2 ) {
          udp::Packet pack;
          switch ( *initPhase ) {
                case 0: {
                    pack = Serializer::toPacket( Initial() );
                    break; }
                case 1: {
                    pack = Serializer::toPacket( Ready() );
                    break; }
          }
          pack.address() = commBroadcast;
          bool sent = _sendSock.sendPacket( pack );
          assert( sent, "send failed" );
          std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
    }
}

void SessionManager::_initListener( std::atomic< int > *initPhase, int count ) {
    std::set< udp::IPv4Address > barrier;

    while ( *initPhase < 2 ) {
        udp::Packet pack = _recvSock.recvPacketWithTimeout( 300 );
        if ( pack.size() != 0 ) {
            switch ( Serializer::packetType( pack ) ) {
                case TypeSignature::InitialPacket: {
                    _peers.insert( pack.address().ip() );
                    break; }
                case TypeSignature::ElevatorReady: {
                    _peers.insert( pack.address().ip() ); // it might still be that we dont know
                    barrier.insert( pack.address().ip() );
                    break; }
                case TypeSignature::RecoveryPeers: {
                    auto maybePeers = Serializer::fromPacket< RecoveryPeers >( pack );
                    assert( !maybePeers.isNothing(), "error deserializing Peers" );
                    RecoveryPeers recovered = maybePeers.value();
                    _peers = recovered.peers;
                    *initPhase = 2;
                    break; }
                case TypeSignature::RecoveryState: {
                    _needRecovery = true;
                    auto maybeRecovered = Serializer::fromPacket< RecoveryState >( pack );
                    assert( !maybeRecovered.isNothing(), "error deserializing Recovery" );
                    RecoveryState recovered = maybeRecovered.value();
                    _state.update( recovered.state );
                    _peers = recovered.peers;
                    *initPhase = 2;
                    break; }
                default:
                    std::cerr << "Unknown packet received on service channel" << std::endl;
            }
            if ( int( barrier.size() ) == count )
                *initPhase = 2;
            else if ( int( _peers.size() ) == count )
                *initPhase = 1;
        }
    }
}

void SessionManager::connect( int count ) {
    // first continue sending Initial messages untill we have count peers

    std::atomic< int > initPhase{ 0 };
    std::thread findPeers( &SessionManager::_initSender, this, &initPhase );
    _initListener( &initPhase, count );
    findPeers.join();

    auto localAddrs = udp::IPv4Address::getMachineAddresses();
    int i = 0;

    // the set is sorted (guaranteed by C++) and therefore same on all elevators
    for ( auto addr : _peers ) {
        if ( localAddrs.find( addr ) != localAddrs.end() ) {
            _id = i;
            break;
        }
        ++i;
    }
    assert_leq( 0, _id, "Could not assing ID" );
    std::cout << "detected id " << _id << std::endl;

    // if RecoveryState is received use it for initialization, save it
    // and save recovery flag

    // when we have count peers start sending Ready message untill we have
    // count peers in ready set

    // if Ready is received add to ready set

    // now start monitoring thread
    _thr = std::thread( restartWrapper( &SessionManager::_loop ), this );
}

void SessionManager::_loop() {

    while ( true ) {
        udp::Packet pack = _recvSock.recvPacketWithTimeout( 300 );
        if ( pack.size() != 0
                && Serializer::packetType( pack ) == TypeSignature::InitialPacket )
        {
            int i = 0;
            bool found = false;
            for ( auto addr : _peers ) {
                if ( addr == pack.address().ip() ) {
                    found = true;
                    break;
                }
                ++i;
            }
            if ( !found ) {
                /* NOTE: we can't add unknown elevator, it would change IDs and make
                 * mess in recovery mechanisms */
                std::cerr << "WARNING: Attempt to socialization from unknown IP "
                          << pack.address().ip() << ". It will be ignored." << std::endl;
                continue;
            }

            // we cannot use broadcast here: it would cause infinite recovery loop
            udp::Address target{ pack.address().ip(), commBroadcast.port() };

            if ( _state.has( i ) ) {
                std::cerr << "NOTICE: Sending recovery to elevator " << i << ", ("
                          << pack.address().ip() << ")" << std::endl;
                udp::Packet recovery = Serializer::toPacket( RecoveryState( _state.get( i ), _peers ) );
                recovery.address() = target;
                _sendSock.sendPacket( recovery );
            } else {
                std::cerr << "NOTICE: Late initialization of elevator " << i << ", ("
                          << pack.address().ip() << ")" << std::endl;
                // this is rare case when elevator initializes and then fails before
                // sending state, it is so rare we will no wait for it to confirm
                // explicitly (if it resends initial or ready, then we would
                // resend ready anyway in this loop)
                udp::Packet ready = Serializer::toPacket( RecoveryPeers( _peers ) );
                ready.address() = target;
                _sendSock.sendPacket( ready );
            }
        }
    }
}

}
<commit_msg>sessionmanager: Make sure initialization exits after recovery.<commit_after>#include <elevator/sessionmanager.h>
#include <elevator/serialization.h>
#include <elevator/restartwrapper.h>

namespace elevator {

using namespace serialization;

const udp::Address SessionManager::commSend{ udp::IPv4Address::any, udp::Port{ 64032 } };
const udp::Address SessionManager::commRcv{ udp::IPv4Address::any, udp::Port{ 64033 } };
const udp::Address SessionManager::commBroadcast{ udp::IPv4Address::broadcast, udp::Port{ 64033 } };

struct Initial {
    Initial() = default;
    Initial( std::tuple<> ) { };
    std::tuple<> tuple() const { return std::tuple<>(); }
    static TypeSignature type() {
        return TypeSignature::InitialPacket;
    }
};

struct Ready {
    Ready() = default;
    Ready( std::tuple<> ) { };
    std::tuple<> tuple() const { return std::tuple<>(); }
    static TypeSignature type() {
        return TypeSignature::ElevatorReady;
    }
};

struct RecoveryPeers {
    RecoveryPeers() = default;
    RecoveryPeers( std::set< udp::IPv4Address > peers ) : peers( peers ) { }
    RecoveryPeers( std::tuple< std::set< udp::IPv4Address > > t )
        : RecoveryPeers( std::get< 0 >( t ) )
    { }
    static TypeSignature type() { return TypeSignature::RecoveryPeers; }
    std::tuple< std::set< udp::IPv4Address > > tuple() const {
        return std::make_tuple( peers );
    }

    std::set< udp::IPv4Address > peers;
};

struct RecoveryState {
    RecoveryState() = default;
    RecoveryState( ElevatorState state, std::set< udp::IPv4Address > peers ) :
        state( state ), peers( peers )
    { }
    RecoveryState( std::tuple< ElevatorState, std::set< udp::IPv4Address > > t )
        : RecoveryState( std::get< 0 >( t ), std::get< 1 >( t ) )
    { }
    static TypeSignature type() { return TypeSignature::RecoveryState; }
    std::tuple< ElevatorState, std::set< udp::IPv4Address > > tuple() const {
        return std::make_tuple( state, peers );
    }

    ElevatorState state;
    std::set< udp::IPv4Address > peers;
};

SessionManager::SessionManager( GlobalState &glo ) : _state( glo ),
    _sendSock{ commSend, true }, _recvSock{ commRcv, true }
{ }

void SessionManager::_initSender( std::atomic< int > *initPhase ) {
    _sendSock.enableBroadcast();
    while( *initPhase < 2 ) {
          udp::Packet pack;
          switch ( *initPhase ) {
                case 0: {
                    pack = Serializer::toPacket( Initial() );
                    break; }
                case 1: {
                    pack = Serializer::toPacket( Ready() );
                    break; }
          }
          pack.address() = commBroadcast;
          bool sent = _sendSock.sendPacket( pack );
          assert( sent, "send failed" );
          std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
    }
}

void SessionManager::_initListener( std::atomic< int > *initPhase, int count ) {
    std::set< udp::IPv4Address > barrier;

    while ( *initPhase < 2 ) {
        udp::Packet pack = _recvSock.recvPacketWithTimeout( 300 );
        if ( pack.size() != 0 ) {
            switch ( Serializer::packetType( pack ) ) {
                case TypeSignature::InitialPacket: {
                    _peers.insert( pack.address().ip() );
                    break; }
                case TypeSignature::ElevatorReady: {
                    _peers.insert( pack.address().ip() ); // it might still be that we dont know
                    barrier.insert( pack.address().ip() );
                    break; }
                case TypeSignature::RecoveryPeers: {
                    auto maybePeers = Serializer::fromPacket< RecoveryPeers >( pack );
                    assert( !maybePeers.isNothing(), "error deserializing Peers" );
                    RecoveryPeers recovered = maybePeers.value();
                    barrier = _peers = recovered.peers;
                    *initPhase = 2;
                    break; }
                case TypeSignature::RecoveryState: {
                    _needRecovery = true;
                    auto maybeRecovered = Serializer::fromPacket< RecoveryState >( pack );
                    assert( !maybeRecovered.isNothing(), "error deserializing Recovery" );
                    RecoveryState recovered = maybeRecovered.value();
                    _state.update( recovered.state );
                    _peers = recovered.peers;
                    *initPhase = 2;
                    break; }
                default:
                    std::cerr << "Unknown packet received on service channel" << std::endl;
            }
            if ( int( barrier.size() ) == count )
                *initPhase = 2;
            else if ( int( _peers.size() ) == count )
                *initPhase = 1;
        }
    }
}

void SessionManager::connect( int count ) {
    // first continue sending Initial messages untill we have count peers

    std::atomic< int > initPhase{ 0 };
    std::thread findPeers( &SessionManager::_initSender, this, &initPhase );
    _initListener( &initPhase, count );
    findPeers.join();

    auto localAddrs = udp::IPv4Address::getMachineAddresses();
    int i = 0;

    // the set is sorted (guaranteed by C++) and therefore same on all elevators
    for ( auto addr : _peers ) {
        if ( localAddrs.find( addr ) != localAddrs.end() ) {
            _id = i;
            break;
        }
        ++i;
    }
    assert_leq( 0, _id, "Could not assing ID" );
    std::cout << "detected id " << _id << std::endl;

    // if RecoveryState is received use it for initialization, save it
    // and save recovery flag

    // when we have count peers start sending Ready message untill we have
    // count peers in ready set

    // if Ready is received add to ready set

    // now start monitoring thread
    _thr = std::thread( restartWrapper( &SessionManager::_loop ), this );
}

void SessionManager::_loop() {

    while ( true ) {
        udp::Packet pack = _recvSock.recvPacketWithTimeout( 300 );
        if ( pack.size() != 0
                && Serializer::packetType( pack ) == TypeSignature::InitialPacket )
        {
            int i = 0;
            bool found = false;
            for ( auto addr : _peers ) {
                if ( addr == pack.address().ip() ) {
                    found = true;
                    break;
                }
                ++i;
            }
            if ( !found ) {
                /* NOTE: we can't add unknown elevator, it would change IDs and make
                 * mess in recovery mechanisms */
                std::cerr << "WARNING: Attempt to socialization from unknown IP "
                          << pack.address().ip() << ". It will be ignored." << std::endl;
                continue;
            }

            // we cannot use broadcast here: it would cause infinite recovery loop
            udp::Address target{ pack.address().ip(), commBroadcast.port() };

            if ( _state.has( i ) ) {
                std::cerr << "NOTICE: Sending recovery to elevator " << i << ", ("
                          << pack.address().ip() << ")" << std::endl;
                udp::Packet recovery = Serializer::toPacket( RecoveryState( _state.get( i ), _peers ) );
                recovery.address() = target;
                _sendSock.sendPacket( recovery );
            } else {
                std::cerr << "NOTICE: Late initialization of elevator " << i << ", ("
                          << pack.address().ip() << ")" << std::endl;
                // this is rare case when elevator initializes and then fails before
                // sending state, it is so rare we will no wait for it to confirm
                // explicitly (if it resends initial or ready, then we would
                // resend ready anyway in this loop)
                udp::Packet ready = Serializer::toPacket( RecoveryPeers( _peers ) );
                ready.address() = target;
                _sendSock.sendPacket( ready );
            }
        }
    }
}

}
<|endoftext|>


<commit_before>#ifndef NEK_TYPE_TRAITS_IS_CONSTRUCTIBLE_HPP
#define NEK_TYPE_TRAITS_IS_CONSTRUCTIBLE_HPP

#include <type_traits> // TODO : std::is_function, std::destructible

#include <nek/mpl/and.hpp>
#include <nek/mpl/if.hpp>
#include <nek/mpl/not.hpp>
#include <nek/mpl/or.hpp>
#include <nek/type_traits/is_base_of.hpp>
#include <nek/type_traits/is_lvalue_reference.hpp>
#include <nek/type_traits/is_reference.hpp>
#include <nek/type_traits/is_rvalue_reference.hpp>
#include <nek/type_traits/is_default_construdtible.hpp>
#include <nek/type_traits/is_same.hpp>
#include <nek/type_traits/is_static_castable.hpp>
#include <nek/type_traits/is_void.hpp>
#include <nek/type_traits/remove_cv.hpp>
#include <nek/type_traits/remove_reference.hpp>
#include <nek/utility/declval.hpp>

namespace nek
{
  namespace is_constructible_detail
  {
    template <class From, class To>
    struct is_l_ref_to_r_ref_impl
    {
    private:
      using from_type = nek::remove_cv_t<nek::remove_reference_t<From>>;
      using to_type = nek::remove_cv_t<nek::remove_reference_t<To>>;

    public:
      using type =
        mpl::and_<
          mpl::not_<std::is_function<From>>,
          mpl::or_<
            nek::is_same<from_type, to_type>,
            nek::is_base_of<from_type, to_type>
          >
        >;
    };

    template <class From, class To, bool = mpl::and_<nek::is_lvalue_reference<From>, nek::is_rvalue_reference<To>>::value>
    struct is_l_ref_to_r_ref;

    template <class From, class To>
    struct is_l_ref_to_r_ref<From, To, true>
      : public is_l_ref_to_r_ref_impl<From, To>::type
    {
    };

    template <class From, class To>
    struct is_l_ref_to_r_ref<From, To, false>
      : public nek::false_type
    {
    };

    template <class Base, class Derived>
    struct is_base_to_derived_ref_impl
    {
    private:
      using base_type = nek::remove_cv_t<nek::remove_reference_t<Base>>;
      using derived_type = nek::remove_cv_t<nek::remove_reference_t<Derived>>;

    public:
      using type =
        mpl::and_<
          mpl::not_<nek::is_same<base_type, derived_type>>,
          nek::is_base_of<base_type, derived_type>
        >;
    };

    template <class Base, class Derived, bool = mpl::not_<mpl::or_<nek::is_void<Base>, std::is_function<Base>>>::value>
    struct is_base_to_derived_ref;

    template <class Base, class Derived>
    struct is_base_to_derived_ref<Base, Derived, true>
      : public is_base_to_derived_ref_impl<Base, Derived>::type
    {
    };

    template <class T, class Arg>
    struct is_direct_constructible_ref
      : public mpl::and_<
          nek::is_static_castable<Arg, T>,
          mpl::not_<mpl::or_<
            is_base_to_derived_ref<Arg, T>,
            is_l_ref_to_r_ref<Arg, T>
          >>
        >
    {
    };

    template <class Base, class Derived>
    struct is_base_to_derived_ref<Base, Derived, false>
      : public nek::false_type
    {
    };

    template <class T, class Arg>
    struct is_able_to_placement_new_impl
    {
    private:
      template <class T2, class Arg2, class = decltype(::new T2(nek::declval<Arg>()))>
      static nek::true_type check(int);

      template <class, class>
      static nek::false_type check(long);

    public:
      using type = decltype(check<T, Arg>(0));
    };

    template <class From, class To>
    struct is_able_to_placement_new
      : public mpl::and_<std::is_destructible<From>, typename is_able_to_placement_new_impl<From, To>::type>::type
    {
    };

    template <class T, class Arg>
    struct is_direct_cosntructible
      : public mpl::if_t<nek::is_reference<T>, is_direct_constructible_ref<T, Arg>, is_able_to_placement_new<T, Arg>>
    {
    };

    template <class T, class... Args>
    struct is_constructible_impl
    {
    private:
      template <class T2, class... Args2, class = decltype(T2(nek::declval<Args2>()...))>
      static nek::true_type check(int);

      template <class, class...>
      static nek::false_type check(long);

    public:
      using type = decltype(check<T, Args...>(0));
    };

    template <class T, class... Args>
    struct is_constructible_
      : public is_constructible_impl<T, Args...>::type
    {
    };

    template <class T, class Arg>
    struct is_constructible_<T, Arg>
      : public is_direct_cosntructible<T, Arg>
    {
    };

    template <class T>
    struct is_constructible_<T>
      : nek::is_default_constructible<T>
    {
    };
  }

  template <class T, class... Args>
  struct is_constructible
    : public is_constructible_detail::is_constructible_<T, Args...>
  {
  };
}

#endif<commit_msg>fix is_constructible<commit_after>#ifndef NEK_TYPE_TRAITS_IS_CONSTRUCTIBLE_HPP
#define NEK_TYPE_TRAITS_IS_CONSTRUCTIBLE_HPP

#include <type_traits> // TODO : std::is_function, std::destructible

#include <nek/mpl/and.hpp>
#include <nek/mpl/if.hpp>
#include <nek/mpl/not.hpp>
#include <nek/mpl/or.hpp>
#include <nek/type_traits/is_base_of.hpp>
#include <nek/type_traits/is_lvalue_reference.hpp>
#include <nek/type_traits/is_reference.hpp>
#include <nek/type_traits/is_rvalue_reference.hpp>
#include <nek/type_traits/is_default_construdtible.hpp>
#include <nek/type_traits/is_same.hpp>
#include <nek/type_traits/is_static_castable.hpp>
#include <nek/type_traits/is_void.hpp>
#include <nek/type_traits/remove_cv.hpp>
#include <nek/type_traits/remove_reference.hpp>
#include <nek/utility/declval.hpp>

#include <boost/mpl/print.hpp>
#include <boost/mpl/vector.hpp>
namespace nek
{
  namespace is_constructible_detail
  {
    template <class From, class To>
    struct is_l_ref_to_r_ref_impl
    {
    private:
      using from_type = nek::remove_cv_t<nek::remove_reference_t<From>>;
      using to_type = nek::remove_cv_t<nek::remove_reference_t<To>>;

    public:
      using type =
        mpl::and_<
          mpl::not_<std::is_function<from_type>>,
          mpl::or_<
            nek::is_same<from_type, to_type>,
            nek::is_base_of<to_type, from_type>
          >
        >;
    };

    template <class From, class To, bool = mpl::and_<nek::is_lvalue_reference<From>, nek::is_rvalue_reference<To>>::value>
    struct is_l_ref_to_r_ref
      : public is_l_ref_to_r_ref_impl<From, To>::type
    {
    };

    template <class From, class To>
    struct is_l_ref_to_r_ref<From, To, false>
      : public nek::false_type
    {
    };

    template <class Base, class Derived>
    struct is_base_to_derived_ref_impl
    {
    private:
      using base_type = nek::remove_cv_t<nek::remove_reference_t<Base>>;
      using derived_type = nek::remove_cv_t<nek::remove_reference_t<Derived>>;

    public:
      using type =
        mpl::and_<
          mpl::not_<nek::is_same<base_type, derived_type>>,
          nek::is_base_of<base_type, derived_type>
        >;
    };

    template <class Base, class Derived, bool = mpl::not_<mpl::or_<nek::is_void<Base>, std::is_function<Base>>>::value>
    struct is_base_to_derived_ref
      : public is_base_to_derived_ref_impl<Base, Derived>::type
    {
    };

    template <class Base, class Derived>
    struct is_base_to_derived_ref<Base, Derived, false>
      : public nek::false_type
    {
    };

    template <class T, class Arg>
    struct is_direct_constructible_ref
      : public mpl::and_<
          nek::is_static_castable<T, Arg>,
          mpl::not_<mpl::or_<
            is_base_to_derived_ref<Arg, T>,
            is_l_ref_to_r_ref<Arg, T>
          >>
        >
    {
    };

    template <class T, class Arg>
    struct is_able_to_placement_new_impl
    {
    private:
      template <class T2, class Arg2, class = decltype(::new T2(nek::declval<Arg>()))>
      static nek::true_type check(int);

      template <class, class>
      static nek::false_type check(long);

    public:
      using type = decltype(check<T, Arg>(0));
    };

    template <class From, class To>
    struct is_able_to_placement_new
      : public mpl::and_<std::is_destructible<From>, typename is_able_to_placement_new_impl<From, To>::type>::type
    {
    };

    template <class T, class Arg>
    struct is_direct_cosntructible
      : public mpl::if_t<nek::is_reference<T>,
          is_direct_constructible_ref<T, Arg>,
          is_able_to_placement_new<T, Arg>>
    {
    };

    template <class T, class... Args>
    struct is_constructible_impl
    {
    private:
      template <class T2, class... Args2, class = decltype(T2(nek::declval<Args2>()...))>
      static nek::true_type check(int);

      template <class, class...>
      static nek::false_type check(long);

    public:
      using type = decltype(check<T, Args...>(0));
    };

    template <class T, class... Args>
    struct is_constructible_
      : public is_constructible_impl<T, Args...>::type
    {
    };

    template <class T, class Arg>
    struct is_constructible_<T, Arg>
      : public is_direct_cosntructible<T, Arg>
    {
    };

    template <class T>
    struct is_constructible_<T>
      : nek::is_default_constructible<T>
    {
    };
  }

  template <class T, class... Args>
  struct is_constructible
    : public is_constructible_detail::is_constructible_<T, Args...>
  {
  };
}

#endif<|endoftext|>


<commit_before>// $Id$
// Author: Sergey Linev   8/01/2018

/*************************************************************************
 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "THttpLongPollEngine.h"

#include "THttpCallArg.h"
#include "TSystem.h"
#include <ROOT/TLogger.hxx>

#include <cstring>
#include <cstdlib>

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THttpLongPollEngine                                                  //
//                                                                      //
// Emulation of websocket with long poll requests                       //
// Allows to send data from server to client without explicit request   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

const char *THttpLongPollEngine::gLongPollNope = "<<nope>>";

//////////////////////////////////////////////////////////////////////////
/// constructor

THttpLongPollEngine::THttpLongPollEngine(std::shared_ptr<THttpCallArg> arg, bool raw) : THttpWSEngine(arg), fRaw(raw)
{
   arg->SetWSId(GetId());
}

//////////////////////////////////////////////////////////////////////////
/// returns ID of the engine, created from this pointer

UInt_t THttpLongPollEngine::GetId() const
{
   const void *ptr = (const void *)this;
   return TString::Hash((void *)&ptr, sizeof(void *));
}

//////////////////////////////////////////////////////////////////////////
/// clear request, waiting for next portion of data

void THttpLongPollEngine::ClearHandle()
{
   if (fPoll) {
      fPoll->Set404();
      fPoll->NotifyCondition();
      fPoll.reset();
   }
}

//////////////////////////////////////////////////////////////////////////
/// Create raw buffer which should be send as reply
/// For the raw mode all information must be send via binary response

std::string THttpLongPollEngine::MakeBuffer(const void *buf, int len, const char *hdr)
{
   std::string res;

   if (!fRaw) {
      res.resize(len);
      memcpy((void *) res.data(), buf, len);
      return res;
   }

   int hdrlen = hdr ? strlen(hdr) : 0;
   std::string hdrstr = "bin:";
   hdrstr.append(std::to_string(hdrlen));

   while ((hdrstr.length() + 1 + hdrlen) % 8 != 0)
      hdrstr.append(" ");
   hdrstr.append(":");
   if (hdrlen > 0)
      hdrstr.append(hdr);

   res.resize(hdrstr.length() + len);

   memcpy((void *)res.data(), hdrstr.data(), hdrstr.length());
   memcpy((char *)res.data() + hdrstr.length(), buf, len);

   return res;
}

//////////////////////////////////////////////////////////////////////////
/// Send binary data via connection - not supported

void THttpLongPollEngine::Send(const void *buf, int len)
{
   std::string buf2 = MakeBuffer(buf, len);

   if (fPoll) {
      fPoll->SetBinaryContent(std::move(buf2));
      fPoll->NotifyCondition();
      fPoll.reset();
   } else {
      fQueue.emplace_back(true, std::move(buf2));
      if (fQueue.size() > 100)
         R__ERROR_HERE("http") << "Too many send operations " << fQueue.size() << " in the queue, check algorithms";
   }
}

//////////////////////////////////////////////////////////////////////////
/// Send binary data with text header via connection - not supported

void THttpLongPollEngine::SendHeader(const char *hdr, const void *buf, int len)
{
   std::string buf2 = MakeBuffer(buf, len, hdr);

   if (fPoll) {
      fPoll->SetBinaryContent(std::move(buf2));
      if (!fRaw)
         fPoll->SetExtraHeader("LongpollHeader", hdr);
      fPoll->NotifyCondition();
      fPoll.reset();
   } else {
      fQueue.emplace_back(true, std::move(buf2), hdr);
      if (fQueue.size() > 100)
         R__ERROR_HERE("http") << "Too many send operations " << fQueue.size() << " in the queue, check algorithms";
   }
}

//////////////////////////////////////////////////////////////////////////
/// Send const char data
/// Either do it immediately or keep in internal buffer

void THttpLongPollEngine::SendCharStar(const char *buf)
{
   std::string sendbuf(fRaw ? "txt:" : "");
   sendbuf.append(buf);

   if (fPoll) {
      fPoll->SetTextContent(std::move(sendbuf));
      fPoll->NotifyCondition();
      fPoll.reset();
   } else {
      fQueue.emplace_back(false, std::move(sendbuf));
      if (fQueue.size() > 100)
         R__ERROR_HERE("http") << "Too many send operations " << fQueue.size() << " in the queue, check algorithms";
   }
}

//////////////////////////////////////////////////////////////////////////////
/// Preview data for given socket
/// function called in the user code before processing correspondent websocket data
/// returns kTRUE when user should ignore such http request - it is for internal use

Bool_t THttpLongPollEngine::PreviewData(std::shared_ptr<THttpCallArg> &arg)
{
   if (!strstr(arg->GetQuery(), "&dummy")) {
      // this is normal request, deliver and process it as any other
      // put dummy content, it can be overwritten in the future
      arg->SetTextContent(std::string(gLongPollNope));
      return kFALSE;
   }

   if (arg == fPoll)
      R__FATAL_HERE("http") << "Same object once again";

   if (fPoll) {
      R__ERROR_HERE("http") << "Get next dummy request when previous not completed";
      // if there are pending request, reply it immediately
      fPoll->SetTextContent(std::string(gLongPollNope)); // normally should never happen
      fPoll->NotifyCondition();         // inform http server that request is processed
      fPoll.reset();
   }

   if (fQueue.size() > 0) {
      QueueItem &item = fQueue.front();
      if (item.fBinary) {
         arg->SetBinaryContent(std::move(item.fData));
         if (!fRaw && !item.fHdr.empty())
            arg->SetExtraHeader("LongpollHeader", item.fHdr.c_str());
      } else {
         arg->SetTextContent(std::move(item.fData));
      }
      fQueue.erase(fQueue.begin());
   } else {
      arg->SetPostponed(); // mark http request as pending, http server should wait for notification
      fPoll = arg;         // keep reference on polling request
   }

   // if arguments has "&dummy" string, user should not process it
   return kTRUE;
}

//////////////////////////////////////////////////////////////////////////////
/// Normally requests from client does not replied directly
/// Therefore one can use it to send data with it

void THttpLongPollEngine::PostProcess(std::shared_ptr<THttpCallArg> &arg)
{
   if ((fQueue.size() > 0) && arg->IsText() &&
       (arg->GetContentLength() == (Long_t)strlen(gLongPollNope)) &&
       (strcmp((const char *)arg->GetContent(), gLongPollNope) == 0)) {
      QueueItem &item = fQueue.front();
      if (item.fBinary) {
         arg->SetBinaryContent(std::move(item.fData));
         if (!fRaw && !item.fHdr.empty())
            arg->SetExtraHeader("LongpollHeader", item.fHdr.c_str());
      } else {
         arg->SetTextContent(std::move(item.fData));
      }
      fQueue.erase(fQueue.begin());
   }
}
<commit_msg>http: fix problem with longpoll engine<commit_after>// $Id$
// Author: Sergey Linev   8/01/2018

/*************************************************************************
 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "THttpLongPollEngine.h"

#include "THttpCallArg.h"
#include "TSystem.h"
#include <ROOT/TLogger.hxx>

#include <cstring>
#include <cstdlib>

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THttpLongPollEngine                                                  //
//                                                                      //
// Emulation of websocket with long poll requests                       //
// Allows to send data from server to client without explicit request   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

const char *THttpLongPollEngine::gLongPollNope = "<<nope>>";

//////////////////////////////////////////////////////////////////////////
/// constructor

THttpLongPollEngine::THttpLongPollEngine(std::shared_ptr<THttpCallArg> arg, bool raw) : THttpWSEngine(arg), fRaw(raw)
{
   arg->SetWSId(GetId());
}

//////////////////////////////////////////////////////////////////////////
/// returns ID of the engine, created from this pointer

UInt_t THttpLongPollEngine::GetId() const
{
   const void *ptr = (const void *)this;
   return TString::Hash((void *)&ptr, sizeof(void *));
}

//////////////////////////////////////////////////////////////////////////
/// clear request, waiting for next portion of data

void THttpLongPollEngine::ClearHandle()
{
   if (fPoll) {
      fPoll->Set404();
      fPoll->NotifyCondition();
      fPoll.reset();
   }
}

//////////////////////////////////////////////////////////////////////////
/// Create raw buffer which should be send as reply
/// For the raw mode all information must be send via binary response

std::string THttpLongPollEngine::MakeBuffer(const void *buf, int len, const char *hdr)
{
   std::string res;

   if (!fRaw) {
      res.resize(len);
      memcpy((void *) res.data(), buf, len);
      return res;
   }

   int hdrlen = hdr ? strlen(hdr) : 0;
   std::string hdrstr = "bin:";
   hdrstr.append(std::to_string(hdrlen));

   while ((hdrstr.length() + 1 + hdrlen) % 8 != 0)
      hdrstr.append(" ");
   hdrstr.append(":");
   if (hdrlen > 0)
      hdrstr.append(hdr);

   res.resize(hdrstr.length() + len);

   memcpy((void *)res.data(), hdrstr.data(), hdrstr.length());
   memcpy((char *)res.data() + hdrstr.length(), buf, len);

   return res;
}

//////////////////////////////////////////////////////////////////////////
/// Send binary data via connection - not supported

void THttpLongPollEngine::Send(const void *buf, int len)
{
   std::string buf2 = MakeBuffer(buf, len);

   if (fPoll) {
      fPoll->SetBinaryContent(std::move(buf2));
      fPoll->NotifyCondition();
      fPoll.reset();
   } else {
      fQueue.emplace_back(true, std::move(buf2));
      if (fQueue.size() > 100)
         R__ERROR_HERE("http") << "Too many send operations " << fQueue.size() << " in the queue, check algorithms";
   }
}

//////////////////////////////////////////////////////////////////////////
/// Send binary data with text header via connection - not supported

void THttpLongPollEngine::SendHeader(const char *hdr, const void *buf, int len)
{
   std::string buf2 = MakeBuffer(buf, len, hdr);

   if (fPoll) {
      fPoll->SetBinaryContent(std::move(buf2));
      if (!fRaw)
         fPoll->SetExtraHeader("LongpollHeader", hdr);
      fPoll->NotifyCondition();
      fPoll.reset();
   } else {
      fQueue.emplace_back(true, std::move(buf2), hdr);
      if (fQueue.size() > 100)
         R__ERROR_HERE("http") << "Too many send operations " << fQueue.size() << " in the queue, check algorithms";
   }
}

//////////////////////////////////////////////////////////////////////////
/// Send const char data
/// Either do it immediately or keep in internal buffer

void THttpLongPollEngine::SendCharStar(const char *buf)
{
   std::string sendbuf(fRaw ? "txt:" : "");
   sendbuf.append(buf);

   if (fPoll) {
      if (fRaw) fPoll->SetBinaryContent(std::move(sendbuf));
           else fPoll->SetTextContent(std::move(sendbuf));
      fPoll->NotifyCondition();
      fPoll.reset();
   } else {
      fQueue.emplace_back(false, std::move(sendbuf));
      if (fQueue.size() > 100)
         R__ERROR_HERE("http") << "Too many send operations " << fQueue.size() << " in the queue, check algorithms";
   }
}

//////////////////////////////////////////////////////////////////////////////
/// Preview data for given socket
/// function called in the user code before processing correspondent websocket data
/// returns kTRUE when user should ignore such http request - it is for internal use

Bool_t THttpLongPollEngine::PreviewData(std::shared_ptr<THttpCallArg> &arg)
{
   if (!strstr(arg->GetQuery(), "&dummy")) {
      // this is normal request, deliver and process it as any other
      // put dummy content, it can be overwritten in the future
      arg->SetTextContent(std::string(gLongPollNope));
      return kFALSE;
   }

   if (arg == fPoll)
      R__FATAL_HERE("http") << "Same object once again";

   if (fPoll) {
      R__ERROR_HERE("http") << "Get next dummy request when previous not completed";
      // if there are pending request, reply it immediately
      if (fRaw) fPoll->SetBinaryContent(std::string("txt:") + gLongPollNope);
           else fPoll->SetTextContent(std::string(gLongPollNope)); // normally should never happen
      fPoll->NotifyCondition();         // inform http server that request is processed
      fPoll.reset();
   }

   if (fQueue.size() > 0) {
      QueueItem &item = fQueue.front();
      if (item.fBinary) {
         arg->SetBinaryContent(std::move(item.fData));
         if (!fRaw && !item.fHdr.empty())
            arg->SetExtraHeader("LongpollHeader", item.fHdr.c_str());
      } else {
         arg->SetTextContent(std::move(item.fData));
      }
      fQueue.erase(fQueue.begin());
   } else {
      arg->SetPostponed(); // mark http request as pending, http server should wait for notification
      fPoll = arg;         // keep reference on polling request
   }

   // if arguments has "&dummy" string, user should not process it
   return kTRUE;
}

//////////////////////////////////////////////////////////////////////////////
/// Normally requests from client does not replied directly
/// Therefore one can use it to send data with it

void THttpLongPollEngine::PostProcess(std::shared_ptr<THttpCallArg> &arg)
{
   if (arg->IsText() && (arg->GetContentLength() == (Long_t)strlen(gLongPollNope)) &&
       (strcmp((const char *)arg->GetContent(), gLongPollNope) == 0)) {
      if (fQueue.size() > 0) {
         QueueItem &item = fQueue.front();
         if (item.fBinary) {
            arg->SetBinaryContent(std::move(item.fData));
            if (!fRaw && !item.fHdr.empty())
               arg->SetExtraHeader("LongpollHeader", item.fHdr.c_str());
         } else {
            arg->SetTextContent(std::move(item.fData));
         }
         fQueue.erase(fQueue.begin());
      } else if (fRaw) {
         arg->SetContent(std::string("txt:") + gLongPollNope);
      }
   }
}
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief stream and line stream class

	Copyright (C) Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <iosfwd>
#include <cybozu/exception.hpp>
#include <cybozu/stream_fwd.hpp>

namespace cybozu {

namespace stream_local {

template <typename From, typename To>
struct is_convertible {
	typedef char yes;
	typedef int no;

	static no test(...);
	static yes test(const To*);
	static const bool value = sizeof(test(static_cast<const From*>(0))) == sizeof(yes);
};

template <bool b, class T = void>
struct enable_if { typedef T type; };

template <class T>
struct enable_if<false, T> {};

/* specialization for istream */
template<class InputStream>
size_t readSome_inner(InputStream& is, void *buf, size_t size, typename enable_if<is_convertible<InputStream, std::istream>::value>::type* = 0)
{
	is.read(static_cast<char *>(buf), size);
	const std::streamsize readSize = is.gcount();
	if (readSize < 0) throw cybozu::Exception("stream:readSome_inner:bad readSize") << size << readSize;
	return readSize;
}

/* generic version for size_t readSome(void *, size_t) */
template<class InputStream>
size_t readSome_inner(InputStream& is, void *buf, size_t size, typename enable_if<!is_convertible<InputStream, std::istream>::value>::type* = 0)
{
	return is.readSome(buf, size);
}

/* specialization for ostream */
template<class OutputStream>
void writeSub(OutputStream& os, const void *buf, size_t size, typename enable_if<is_convertible<OutputStream, std::ostream>::value>::type* = 0)
{
	if (!os.write(static_cast<const char *>(buf), size)) throw cybozu::Exception("stream:writeSub") << size;
}

/* generic version for void write(const void*, size_t), which writes all data */
template<class OutputStream>
void writeSub(OutputStream& os, const void *buf, size_t size, typename enable_if<!is_convertible<OutputStream, std::ostream>::value>::type* = 0)
{
	os.write(buf, size);
}

} // stream_local

/*
	make a specializaiton of class to use new InputStream, OutputStream
*/
template<class InputStream>
struct InputStreamTag {
	static inline size_t readSome(InputStream& is, void *buf, size_t size)
	{
		return stream_local::readSome_inner<InputStream>(is, buf, size);
	}
};

template<class OutputStream>
struct OutputStreamTag {
	static inline void write(OutputStream& os, const void *buf, size_t size)
	{
		stream_local::writeSub<OutputStream>(os, buf, size);
	}
};

class MemoryInputStream {
	const char *p_;
	size_t size_;
public:
	size_t pos;
	MemoryInputStream(const void *p, size_t size) : p_(static_cast<const char *>(p)), size_(size), pos(0) {}
	size_t readSome(void *buf, size_t size)
	{
		if (size > size_  - pos) size = size_ - pos;
		memcpy(buf, p_ + pos, size);
		pos += size;
		return size;
	}
};

class MemoryOutputStream {
	char *p_;
	size_t size_;
public:
	size_t pos;
	MemoryOutputStream(void *p, size_t size) : p_(static_cast<char *>(p)), size_(size), pos(0) {}
	void write(const void *buf, size_t size)
	{
		if (size > size_ - pos) throw cybozu::Exception("MemoryOutputStream:write") << size << size_ << pos;
		memcpy(p_ + pos, buf, size);
		pos += size;
	}
};

class StringInputStream {
	const std::string& str_;
	StringInputStream(const StringInputStream&);
	void operator=(const StringInputStream&);
public:
	size_t pos;
	explicit StringInputStream(const std::string& str) : str_(str), pos(0) {}
	size_t readSome(void *buf, size_t size)
	{
		const size_t remainSize = str_.size() - pos;
		if (size > remainSize) size = remainSize;
		memcpy(buf, &str_[pos], size);
		pos += size;
		return size;
	}
};

class StringOutputStream {
	std::string& str_;
	StringOutputStream(const StringOutputStream&);
	void operator=(const StringOutputStream&);
public:
	explicit StringOutputStream(std::string& str) : str_(str) {}
	void write(const void *buf, size_t size)
	{
		str_.append(static_cast<const char *>(buf), size);
	}
};

} // cybozu
<commit_msg>remove warning for 32-bit vc<commit_after>#pragma once
/**
	@file
	@brief stream and line stream class

	Copyright (C) Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <iosfwd>
#include <cybozu/exception.hpp>
#include <cybozu/stream_fwd.hpp>

namespace cybozu {

namespace stream_local {

template <typename From, typename To>
struct is_convertible {
	typedef char yes;
	typedef int no;

	static no test(...);
	static yes test(const To*);
	static const bool value = sizeof(test(static_cast<const From*>(0))) == sizeof(yes);
};

template <bool b, class T = void>
struct enable_if { typedef T type; };

template <class T>
struct enable_if<false, T> {};

/* specialization for istream */
template<class InputStream>
size_t readSome_inner(InputStream& is, void *buf, size_t size, typename enable_if<is_convertible<InputStream, std::istream>::value>::type* = 0)
{
	is.read(static_cast<char *>(buf), size);
	const std::streamsize readSize = is.gcount();
	if (readSize < 0) throw cybozu::Exception("stream:readSome_inner:bad readSize") << size << readSize;
	if (readSize > size_t(-1)) throw cybozu::Exception("stream:readSome_inner:too large") << readSize;
	return static_cast<size_t>(readSize);
}

/* generic version for size_t readSome(void *, size_t) */
template<class InputStream>
size_t readSome_inner(InputStream& is, void *buf, size_t size, typename enable_if<!is_convertible<InputStream, std::istream>::value>::type* = 0)
{
	return is.readSome(buf, size);
}

/* specialization for ostream */
template<class OutputStream>
void writeSub(OutputStream& os, const void *buf, size_t size, typename enable_if<is_convertible<OutputStream, std::ostream>::value>::type* = 0)
{
	if (!os.write(static_cast<const char *>(buf), size)) throw cybozu::Exception("stream:writeSub") << size;
}

/* generic version for void write(const void*, size_t), which writes all data */
template<class OutputStream>
void writeSub(OutputStream& os, const void *buf, size_t size, typename enable_if<!is_convertible<OutputStream, std::ostream>::value>::type* = 0)
{
	os.write(buf, size);
}

} // stream_local

/*
	make a specializaiton of class to use new InputStream, OutputStream
*/
template<class InputStream>
struct InputStreamTag {
	static inline size_t readSome(InputStream& is, void *buf, size_t size)
	{
		return stream_local::readSome_inner<InputStream>(is, buf, size);
	}
};

template<class OutputStream>
struct OutputStreamTag {
	static inline void write(OutputStream& os, const void *buf, size_t size)
	{
		stream_local::writeSub<OutputStream>(os, buf, size);
	}
};

class MemoryInputStream {
	const char *p_;
	size_t size_;
public:
	size_t pos;
	MemoryInputStream(const void *p, size_t size) : p_(static_cast<const char *>(p)), size_(size), pos(0) {}
	size_t readSome(void *buf, size_t size)
	{
		if (size > size_  - pos) size = size_ - pos;
		memcpy(buf, p_ + pos, size);
		pos += size;
		return size;
	}
};

class MemoryOutputStream {
	char *p_;
	size_t size_;
public:
	size_t pos;
	MemoryOutputStream(void *p, size_t size) : p_(static_cast<char *>(p)), size_(size), pos(0) {}
	void write(const void *buf, size_t size)
	{
		if (size > size_ - pos) throw cybozu::Exception("MemoryOutputStream:write") << size << size_ << pos;
		memcpy(p_ + pos, buf, size);
		pos += size;
	}
};

class StringInputStream {
	const std::string& str_;
	StringInputStream(const StringInputStream&);
	void operator=(const StringInputStream&);
public:
	size_t pos;
	explicit StringInputStream(const std::string& str) : str_(str), pos(0) {}
	size_t readSome(void *buf, size_t size)
	{
		const size_t remainSize = str_.size() - pos;
		if (size > remainSize) size = remainSize;
		memcpy(buf, &str_[pos], size);
		pos += size;
		return size;
	}
};

class StringOutputStream {
	std::string& str_;
	StringOutputStream(const StringOutputStream&);
	void operator=(const StringOutputStream&);
public:
	explicit StringOutputStream(std::string& str) : str_(str) {}
	void write(const void *buf, size_t size)
	{
		str_.append(static_cast<const char *>(buf), size);
	}
};

} // cybozu
<|endoftext|>