<commit_before>#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Pass.h"
#include "llvm/DataLayout.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/GlobalVariable.h"
#include "accept.h"
#include <fstream>
#include <string>

using namespace llvm;

namespace {
  struct AcceptAA : public ImmutablePass, public AliasAnalysis {
    static char ID;
    ACCEPTPass *transformPass;
    ApproxInfo *AI;
    int relaxId;
    int relaxParam;

    AcceptAA() : ImmutablePass(ID) {
      initializeAcceptAAPass(*PassRegistry::getPassRegistry());
      if (!sharedAcceptTransformPass) {
        errs() << "Alias analysis loaded without transform pass!\n";
        return;
      }
      transformPass = (ACCEPTPass*)sharedAcceptTransformPass;
      AI = transformPass->AI;
    }

    virtual const char *getPassName() const {
      return "ACCEPT approximate alias analysis";
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      // dependencies?
    }

    virtual void initializePass() {
      InitializeAliasAnalysis(this);

      // One global optimization parameter controls whether we should enable
      // alias relaxation. (For now.)
      relaxId = transformPass->opportunityId;
      ++(transformPass->opportunityId);
      if (transformPass->relax) {
        relaxParam = transformPass->relaxConfig[relaxId];
      } else {
        relaxParam = 0;
        transformPass->relaxConfig[relaxId] = 0;
        transformPass->configDesc[relaxId] = "alias relaxation";
      }
    }

    virtual AliasResult alias(const Location &LocA, const Location &LocB) {
      if (!relaxParam)
        return MayAlias;

      // Mallocs, callocs...
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr)) {
        if (const CallInst *ci = dyn_cast<CallInst>(inst)) {
          std::string type_str;
          llvm::raw_string_ostream rso(type_str);
          rso << *inst;
          if (rso.str().find("alloc") != std::string::npos) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              if (const Instruction *user = dyn_cast<Instruction>(*ui)) {
                if (const StoreInst *si = dyn_cast<StoreInst>(user)) {
                  if (isApproxPtr(si) || isApprox(si)) return NoAlias;
                } else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(user)) {
                  if (isApproxPtr(user)) return NoAlias;
                } else if (const BitCastInst *bc = dyn_cast<BitCastInst>(user)) {
                  for (Value::const_use_iterator bc_ui = user->use_begin();
                        bc_ui != user->use_end();
                        ++bc_ui) {
                    if (const Instruction *bc_user = dyn_cast<Instruction>(*bc_ui))
                      if (const StoreInst *si_bc_user = dyn_cast<StoreInst>(bc_user))
                        if (isApproxPtr(si_bc_user) || isApprox(si_bc_user)) return NoAlias;
                  }
                }
              }
            }
          }
        }
      }
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr)) {
        if (const CallInst *ci = dyn_cast<CallInst>(inst)) {
          std::string type_str;
          llvm::raw_string_ostream rso(type_str);
          rso << *inst;
          if (rso.str().find("alloc") != std::string::npos) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              if (const Instruction *user = dyn_cast<Instruction>(*ui)) {
                if (const StoreInst *si = dyn_cast<StoreInst>(user)) {
                  if (isApproxPtr(si) || isApprox(si)) return NoAlias;
                } else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(user)) {
                  if (isApproxPtr(user)) return NoAlias;
                } else if (const BitCastInst *bc = dyn_cast<BitCastInst>(user)) {
                  for (Value::const_use_iterator bc_ui = user->use_begin();
                        bc_ui != user->use_end();
                        ++bc_ui) {
                    if (const Instruction *bc_user = dyn_cast<Instruction>(*bc_ui))
                      if (const StoreInst *si_bc_user = dyn_cast<StoreInst>(bc_user))
                        if (isApproxPtr(si_bc_user) || isApprox(si_bc_user)) return NoAlias;
                  }
                }
              }
            }
          }
        }
      }

      // Globals
      if (const GlobalValue *GV = dyn_cast<GlobalValue>(LocA.Ptr))
        if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV))
          if (isApproxPtr(V)) return NoAlias;
      if (const GlobalValue *GV = dyn_cast<GlobalValue>(LocB.Ptr))
        if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV))
          if (isApproxPtr(V)) return NoAlias;

      // Getelementptr
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr))
        if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(inst))
          if (isApproxPtr(GEP)) return NoAlias;
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr))
        if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(inst))
          if (isApproxPtr(GEP)) return NoAlias;

      // Bitcasts
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr))
        if (const BitCastInst *BC = dyn_cast<BitCastInst>(inst)) {
          std::string type_str;
          llvm::raw_string_ostream rso(type_str);
          rso << *(inst->getOperand(0));
          if (rso.str().find("alloc") != std::string::npos) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              const Instruction *user = dyn_cast<Instruction>(*ui);
              if (const StoreInst *st = dyn_cast<StoreInst>(user))
                if (isApprox(st) || isApproxPtr(st)) return NoAlias;
            }
          }
        }
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr))
        if (const BitCastInst *BC = dyn_cast<BitCastInst>(inst)) {
          std::string type_str;
          llvm::raw_string_ostream rso(type_str);
          rso << *(inst->getOperand(0));
          if (rso.str().find("alloc") != std::string::npos) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              const Instruction *user = dyn_cast<Instruction>(*ui);
              if (const StoreInst *st = dyn_cast<StoreInst>(user))
                if (isApprox(st) || isApproxPtr(st)) return NoAlias;
            }
          }
        }

      // Ordinary instructions
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr))
        if (isApprox(inst) || isApproxPtr(inst)) return NoAlias;
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr))
        if (isApprox(inst) || isApproxPtr(inst)) return NoAlias;

      /* DEBUG
      else if (instA && instB) {
        errs() << "instructions:\n";
        instA->dump();
        instB->dump();
      } else {
        const GlobalValue *gvA = dyn_cast<GlobalValue>(LocA.Ptr);
        const GlobalValue *gvB = dyn_cast<GlobalValue>(LocB.Ptr);
        if (gvA && gvB) {
          errs() << "global values:\n";
          gvA->dump();
          gvB->dump();
        }
      }
      */

      // Delegate to other alias analyses.
      return AliasAnalysis::alias(LocA, LocB);
    }

    // This required bit works around C++'s multiple inheritance weirdness.
    // Casting this to AliasAnalysis* gets the correct vtable for those calls.
    virtual void *getAdjustedAnalysisPointer(const void *ID) {
      if (ID == &AliasAnalysis::ID)
        return (AliasAnalysis*)this;
      return this;
    }
  };
}

char AcceptAA::ID = 0;
INITIALIZE_AG_PASS(AcceptAA, AliasAnalysis, "acceptaa",
                   "ACCEPT approximate alias analysis",
                   false, true, false)

ImmutablePass *llvm::createAcceptAAPass() { return new AcceptAA(); }
<commit_msg>aa: helper function to check for mallocs<commit_after>#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Pass.h"
#include "llvm/DataLayout.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/GlobalVariable.h"
#include "accept.h"
#include <fstream>
#include <string>
#include <ctime>

using namespace llvm;

namespace {
  bool isMalloc(const Value *val) {
      if (const CallInst *call = dyn_cast<CallInst>(val)) {
          if (Function *func = call->getCalledFunction()) {
              return func->getName().find("alloc") != StringRef::npos;
          }
      }
      return false;
  }

  struct AcceptAA : public ImmutablePass, public AliasAnalysis {
    static char ID;
    ACCEPTPass *transformPass;
    ApproxInfo *AI;
    int relaxId;
    int relaxParam;

    AcceptAA() : ImmutablePass(ID) {
      initializeAcceptAAPass(*PassRegistry::getPassRegistry());
      if (!sharedAcceptTransformPass) {
        errs() << "Alias analysis loaded without transform pass!\n";
        return;
      }
      transformPass = (ACCEPTPass*)sharedAcceptTransformPass;
      AI = transformPass->AI;
    }

    virtual const char *getPassName() const {
      return "ACCEPT approximate alias analysis";
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      // dependencies?
    }

    virtual void initializePass() {
      InitializeAliasAnalysis(this);

      // One global optimization parameter controls whether we should enable
      // alias relaxation. (For now.)
      relaxId = transformPass->opportunityId;
      ++(transformPass->opportunityId);
      if (transformPass->relax) {
        relaxParam = transformPass->relaxConfig[relaxId];
      } else {
        relaxParam = 0;
        transformPass->relaxConfig[relaxId] = 0;
        transformPass->configDesc[relaxId] = "alias relaxation";
      }
    }

    virtual AliasResult alias(const Location &LocA, const Location &LocB) {
      if (!relaxParam)
        return MayAlias;

      // Mallocs, callocs...
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr)) {
        if (isMalloc(inst)) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              if (const Instruction *user = dyn_cast<Instruction>(*ui)) {
                if (const StoreInst *si = dyn_cast<StoreInst>(user)) {
                  if (isApproxPtr(si) || isApprox(si)) {
                      return NoAlias;
                  }
                } else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(user)) {
                  if (isApproxPtr(user)) {
                      return NoAlias;
                  }
                } else if (const BitCastInst *bc = dyn_cast<BitCastInst>(user)) {
                  for (Value::const_use_iterator bc_ui = user->use_begin();
                        bc_ui != user->use_end();
                        ++bc_ui) {
                    if (const Instruction *bc_user = dyn_cast<Instruction>(*bc_ui))
                      if (const StoreInst *si_bc_user = dyn_cast<StoreInst>(bc_user))
                        if (isApproxPtr(si_bc_user) || isApprox(si_bc_user)) {
                            return NoAlias;
                        }
                  }
                }
              }
            }
        }
      }
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr)) {
        if (isMalloc(inst)) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              if (const Instruction *user = dyn_cast<Instruction>(*ui)) {
                if (const StoreInst *si = dyn_cast<StoreInst>(user)) {
                  if (isApproxPtr(si) || isApprox(si)) {
                      return NoAlias;
                  }
                } else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(user)) {
                  if (isApproxPtr(user)) {
                      return NoAlias;
                  }
                } else if (const BitCastInst *bc = dyn_cast<BitCastInst>(user)) {
                  for (Value::const_use_iterator bc_ui = user->use_begin();
                        bc_ui != user->use_end();
                        ++bc_ui) {
                    if (const Instruction *bc_user = dyn_cast<Instruction>(*bc_ui))
                      if (const StoreInst *si_bc_user = dyn_cast<StoreInst>(bc_user))
                        if (isApproxPtr(si_bc_user) || isApprox(si_bc_user)) {
                            return NoAlias;
                        }
                  }
                }
              }
            }
        }
      }

      // Globals
      if (const GlobalValue *GV = dyn_cast<GlobalValue>(LocA.Ptr))
        if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV))
          if (isApproxPtr(V)) {
              return NoAlias;
          }
      if (const GlobalValue *GV = dyn_cast<GlobalValue>(LocB.Ptr))
        if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV))
          if (isApproxPtr(V)) {
              return NoAlias;
          }

      // Getelementptr
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr))
        if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(inst))
          if (isApproxPtr(GEP)) {
              return NoAlias;
          }
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr))
        if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(inst))
          if (isApproxPtr(GEP)) {
              return NoAlias;
          }

      // Bitcasts
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr))
        if (const BitCastInst *BC = dyn_cast<BitCastInst>(inst)) {
          if (isMalloc(inst->getOperand(0))) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              const Instruction *user = dyn_cast<Instruction>(*ui);
              if (const StoreInst *st = dyn_cast<StoreInst>(user))
                if (isApprox(st) || isApproxPtr(st)) {
                    return NoAlias;
                }
            }
          }
        }
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr))
        if (const BitCastInst *BC = dyn_cast<BitCastInst>(inst)) {
          if (isMalloc(inst->getOperand(0))) {
            for (Value::const_use_iterator ui = inst->use_begin();
                  ui != inst->use_end();
                  ++ui) {
              const Instruction *user = dyn_cast<Instruction>(*ui);
              if (const StoreInst *st = dyn_cast<StoreInst>(user))
                if (isApprox(st) || isApproxPtr(st)) {
                    return NoAlias;
                }
            }
          }
        }

      // Ordinary instructions
      if (const Instruction *inst = dyn_cast<Instruction>(LocA.Ptr))
        if (isApprox(inst) || isApproxPtr(inst)) {
            return NoAlias;
        }
      if (const Instruction *inst = dyn_cast<Instruction>(LocB.Ptr))
        if (isApprox(inst) || isApproxPtr(inst)) {
            return NoAlias;
        }

      /* DEBUG
      else if (instA && instB) {
        errs() << "instructions:\n";
        instA->dump();
        instB->dump();
      } else {
        const GlobalValue *gvA = dyn_cast<GlobalValue>(LocA.Ptr);
        const GlobalValue *gvB = dyn_cast<GlobalValue>(LocB.Ptr);
        if (gvA && gvB) {
          errs() << "global values:\n";
          gvA->dump();
          gvB->dump();
        }
      }
      */

      // Delegate to other alias analyses.
      return AliasAnalysis::alias(LocA, LocB);
    }

    // This required bit works around C++'s multiple inheritance weirdness.
    // Casting this to AliasAnalysis* gets the correct vtable for those calls.
    virtual void *getAdjustedAnalysisPointer(const void *ID) {
      if (ID == &AliasAnalysis::ID)
        return (AliasAnalysis*)this;
      return this;
    }
  };
}

char AcceptAA::ID = 0;
INITIALIZE_AG_PASS(AcceptAA, AliasAnalysis, "acceptaa",
                   "ACCEPT approximate alias analysis",
                   false, true, false)

ImmutablePass *llvm::createAcceptAAPass() { return new AcceptAA(); }
<|endoftext|>


<commit_before>#include "accept.h"

#include "llvm/Analysis/LoopPass.h"
#include "llvm/IRBuilder.h"
#include "llvm/Module.h"

#include <sstream>

using namespace llvm;

namespace {
  struct LoopPerfPass : public LoopPass {
    static char ID;
    ACCEPTPass *transformPass;
    ApproxInfo *AI;
    Module *module;
    llvm::raw_fd_ostream *log;
    LoopInfo *LI;

    LoopPerfPass() : LoopPass(ID) {}

    virtual bool doInitialization(Loop *loop, LPPassManager &LPM) {
      transformPass = (ACCEPTPass*)sharedAcceptTransformPass;
      AI = transformPass->AI;
      log = AI->log;
      return false;
    }
    virtual bool runOnLoop(Loop *loop, LPPassManager &LPM) {
      module = loop->getHeader()->getParent()->getParent();
      LI = &getAnalysis<LoopInfo>();
      return tryToOptimizeLoop(loop);
    }
    virtual bool doFinalization() {
      return false;
    }
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      LoopPass::getAnalysisUsage(AU);
      AU.addRequired<LoopInfo>();
    }

    IntegerType *getNativeIntegerType() {
      DataLayout layout(module->getDataLayout());
      return Type::getIntNTy(module->getContext(),
                              layout.getPointerSizeInBits());
    }

    // Assess whether a loop can be optimized and, if so, log some messages and
    // update the configuration map. If optimization is turned on, the
    // configuration map will be used to actually transform the loop. Returns a
    // boolean indicating whether the code was changed (i.e., the loop
    // perforated).
    bool tryToOptimizeLoop(Loop *loop) {
      std::stringstream ss;
      ss << "loop at "
         << srcPosDesc(*module, loop->getHeader()->begin()->getDebugLoc());
      std::string loopName = ss.str();

      *log << "---\n" << loopName << "\n";

      // Look for ACCEPT_FORBID marker.
      if (AI->instMarker(loop->getHeader()->begin()) == markerForbid) {
        *log << "optimization forbidden\n";
        return false;
      }

      // We only consider loops for which there is a header (condition), a
      // latch (increment, in "for"), and a preheader (initialization).
      if (!loop->getHeader() || !loop->getLoopLatch()
          || !loop->getLoopPreheader()) {
        *log << "loop not in perforatable form\n";
        return false;
      }

      // Skip array constructor loops manufactured by Clang.
      if (loop->getHeader()->getName().startswith("arrayctor.loop")) {
        *log << "array constructor\n";
        return false;
      }

      // Skip empty-body loops (where perforation would do nothing anyway).
      if (loop->getNumBlocks() == 2
          && loop->getHeader() != loop->getLoopLatch()) {
        BasicBlock *latch = loop->getLoopLatch();
        if (&(latch->front()) == &(latch->back())) {
          *log << "empty body\n";
          return false;
        }
      }

      /*
      if (acceptUseProfile) {
        ProfileInfo &PI = getAnalysis<ProfileInfo>();
        double trips = PI.getExecutionCount(loop->getHeader());
        *log << "trips: " << trips << "\n";
      }
      */

      // Determine whether this is a for-like or while-like loop. This informs
      // the heuristic that determines which parts of the loop to perforate.
      bool isForLike = false;
      if (loop->getHeader()->getName().startswith("for.cond")) {
        *log << "for-like loop\n";
        isForLike = true;
      } else {
        *log << "while-like loop\n";
      }

      if (transformPass->relax) {
        int param = transformPass->relaxConfig[loopName];
        if (param) {
          *log << "perforating with factor 2^" << param << "\n";
          perforateLoop(loop, param, isForLike);
          return true;
        } else {
          *log << "not perforating\n";
          return false;
        }
      }

      // Get the body blocks of the loop: those that will not be executed during
      // some iterations of a perforated loop.
      std::set<BasicBlock*> bodyBlocks;
      for (Loop::block_iterator bi = loop->block_begin();
            bi != loop->block_end(); ++bi) {
        if (*bi == loop->getHeader()) {
          // Even in perforated loops, the header gets executed every time. So we
          // don't check it.
          continue;
        } else if (isForLike && *bi == loop->getLoopLatch()) {
          // When perforating for-like loops, we also execute the latch each
          // time.
          continue;
        }
        bodyBlocks.insert(*bi);
      }
      if (bodyBlocks.empty()) {
        *log << "empty body\n";
        return false;
      }

      // Check for control flow in the loop body. We don't perforate anything
      // with a break, continue, return, etc.
      for (std::set<BasicBlock*>::iterator i = bodyBlocks.begin();
            i != bodyBlocks.end(); ++i) {
        if (loop->isLoopExiting(*i)) {
          *log << "contains loop exit\n";
          return false;
        }
      }

      // Check whether the body of this loop is elidable (precise-pure).
      std::set<Instruction*> blockers = AI->preciseEscapeCheck(bodyBlocks);
      *log << "blockers: " << blockers.size() << "\n";
      for (std::set<Instruction*>::iterator i = blockers.begin();
            i != blockers.end(); ++i) {
        *log << " * " << instDesc(*module, *i) << "\n";
      }

      if (!blockers.size()) {
        *log << "can perforate loop\n";
        transformPass->relaxConfig[loopName] = 0;
      }

      return false;
    }

    // Transform a loop to skip iterations.
    // The loop should already be validated as perforatable, but checks will be
    // performed nonetheless to ensure safety.
    void perforateLoop(Loop *loop, int logfactor, bool isForLike) {
      // Check whether this loop is perforatable.
      // First, check for required blocks.
      if (!loop->getHeader() || !loop->getLoopLatch()
          || !loop->getLoopPreheader() || !loop->getExitBlock()) {
        errs() << "malformed loop\n";
        return;
      }
      // Next, make sure the header (condition block) ends with a body/exit
      // conditional branch.
      BranchInst *condBranch = dyn_cast<BranchInst>(
          loop->getHeader()->getTerminator()
      );
      if (!condBranch || condBranch->getNumSuccessors() != 2) {
        errs() << "malformed loop condition\n";
        return;
      }
      BasicBlock *bodyBlock;
      if (condBranch->getSuccessor(0) == loop->getExitBlock()) {
        bodyBlock = condBranch->getSuccessor(1);
      } else if (condBranch->getSuccessor(1) == loop->getExitBlock()) {
        bodyBlock = condBranch->getSuccessor(0);
      } else {
        errs() << "loop condition does not exit\n";
        return;
      }

      // Get the shortcut for the destination. In for-like loop perforation, we
      // shortcut to the latch (increment block). In while-like perforation, we
      // jump to the header (condition block).
      BasicBlock *shortcutDest;
      if (isForLike) {
        shortcutDest = loop->getLoopLatch();
      } else {
        shortcutDest = loop->getHeader();
      }

      IRBuilder<> builder(module->getContext());
      Value *result;

      // Allocate stack space for the counter.
      // LLVM "alloca" instructions go in the function's entry block. Otherwise,
      // they have to adjust the frame size dynamically (and, in my experience,
      // can actually segfault!). And we only want one of these per static loop
      // anyway.
      builder.SetInsertPoint(
          loop->getLoopPreheader()->getParent()->getEntryBlock().begin()
      );

      IntegerType *nativeInt = getNativeIntegerType();
      AllocaInst *counterAlloca = builder.CreateAlloca(
          nativeInt,
          0,
          "accept_counter"
      );

      // Initialize the counter in the preheader.
      builder.SetInsertPoint(loop->getLoopPreheader()->getTerminator());
      builder.CreateStore(
          ConstantInt::get(nativeInt, 0, false),
          counterAlloca
      );

      // Increment the counter in the latch.
      builder.SetInsertPoint(loop->getLoopLatch()->getTerminator());
      result = builder.CreateLoad(
          counterAlloca,
          "accept_tmp"
      );
      result = builder.CreateAdd(
          result,
          ConstantInt::get(nativeInt, 1, false),
          "accept_inc"
      );
      builder.CreateStore(
          result,
          counterAlloca
      );

      // Get the first body block.

      // Check the counter before the loop's body.
      BasicBlock *checkBlock = BasicBlock::Create(
          module->getContext(),
          "accept_cond",
          bodyBlock->getParent(),
          bodyBlock
      );
      builder.SetInsertPoint(checkBlock);
      result = builder.CreateLoad(
          counterAlloca,
          "accept_tmp"
      );
      // Check whether the low n bits of the counter are zero.
      result = builder.CreateTrunc(
          result,
          Type::getIntNTy(module->getContext(), logfactor),
          "accept_trunc"
      );
      result = builder.CreateIsNull(
          result,
          "accept_cmp"
      );
      result = builder.CreateCondBr(
          result,
          bodyBlock,
          loop->getLoopLatch()
      );

      // Change the condition block to point to our new condition
      // instead of the body.
      condBranch->setSuccessor(0, checkBlock);

      // Add block to the loop structure.
      loop->addBasicBlockToLoop(checkBlock, LI->getBase());
    }

  };
}

char LoopPerfPass::ID = 0;
LoopPass *llvm::createLoopPerfPass() { return new LoopPerfPass(); }

<commit_msg>skip forbidden functions in new loop perforator<commit_after>#include "accept.h"

#include "llvm/Analysis/LoopPass.h"
#include "llvm/IRBuilder.h"
#include "llvm/Module.h"

#include <sstream>

using namespace llvm;

namespace {
  struct LoopPerfPass : public LoopPass {
    static char ID;
    ACCEPTPass *transformPass;
    ApproxInfo *AI;
    Module *module;
    llvm::raw_fd_ostream *log;
    LoopInfo *LI;

    LoopPerfPass() : LoopPass(ID) {}

    virtual bool doInitialization(Loop *loop, LPPassManager &LPM) {
      transformPass = (ACCEPTPass*)sharedAcceptTransformPass;
      AI = transformPass->AI;
      log = AI->log;
      return false;
    }
    virtual bool runOnLoop(Loop *loop, LPPassManager &LPM) {
      if (transformPass->shouldSkipFunc(*(loop->getHeader()->getParent())))
          return false;
      module = loop->getHeader()->getParent()->getParent();
      LI = &getAnalysis<LoopInfo>();
      return tryToOptimizeLoop(loop);
    }
    virtual bool doFinalization() {
      return false;
    }
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      LoopPass::getAnalysisUsage(AU);
      AU.addRequired<LoopInfo>();
    }

    IntegerType *getNativeIntegerType() {
      DataLayout layout(module->getDataLayout());
      return Type::getIntNTy(module->getContext(),
                              layout.getPointerSizeInBits());
    }

    // Assess whether a loop can be optimized and, if so, log some messages and
    // update the configuration map. If optimization is turned on, the
    // configuration map will be used to actually transform the loop. Returns a
    // boolean indicating whether the code was changed (i.e., the loop
    // perforated).
    bool tryToOptimizeLoop(Loop *loop) {
      std::stringstream ss;
      ss << "loop at "
         << srcPosDesc(*module, loop->getHeader()->begin()->getDebugLoc());
      std::string loopName = ss.str();

      *log << "---\n" << loopName << "\n";

      // Look for ACCEPT_FORBID marker.
      if (AI->instMarker(loop->getHeader()->begin()) == markerForbid) {
        *log << "optimization forbidden\n";
        return false;
      }

      // We only consider loops for which there is a header (condition), a
      // latch (increment, in "for"), and a preheader (initialization).
      if (!loop->getHeader() || !loop->getLoopLatch()
          || !loop->getLoopPreheader()) {
        *log << "loop not in perforatable form\n";
        return false;
      }

      // Skip array constructor loops manufactured by Clang.
      if (loop->getHeader()->getName().startswith("arrayctor.loop")) {
        *log << "array constructor\n";
        return false;
      }

      // Skip empty-body loops (where perforation would do nothing anyway).
      if (loop->getNumBlocks() == 2
          && loop->getHeader() != loop->getLoopLatch()) {
        BasicBlock *latch = loop->getLoopLatch();
        if (&(latch->front()) == &(latch->back())) {
          *log << "empty body\n";
          return false;
        }
      }

      /*
      if (acceptUseProfile) {
        ProfileInfo &PI = getAnalysis<ProfileInfo>();
        double trips = PI.getExecutionCount(loop->getHeader());
        *log << "trips: " << trips << "\n";
      }
      */

      // Determine whether this is a for-like or while-like loop. This informs
      // the heuristic that determines which parts of the loop to perforate.
      bool isForLike = false;
      if (loop->getHeader()->getName().startswith("for.cond")) {
        *log << "for-like loop\n";
        isForLike = true;
      } else {
        *log << "while-like loop\n";
      }

      if (transformPass->relax) {
        int param = transformPass->relaxConfig[loopName];
        if (param) {
          *log << "perforating with factor 2^" << param << "\n";
          perforateLoop(loop, param, isForLike);
          return true;
        } else {
          *log << "not perforating\n";
          return false;
        }
      }

      // Get the body blocks of the loop: those that will not be executed during
      // some iterations of a perforated loop.
      std::set<BasicBlock*> bodyBlocks;
      for (Loop::block_iterator bi = loop->block_begin();
            bi != loop->block_end(); ++bi) {
        if (*bi == loop->getHeader()) {
          // Even in perforated loops, the header gets executed every time. So we
          // don't check it.
          continue;
        } else if (isForLike && *bi == loop->getLoopLatch()) {
          // When perforating for-like loops, we also execute the latch each
          // time.
          continue;
        }
        bodyBlocks.insert(*bi);
      }
      if (bodyBlocks.empty()) {
        *log << "empty body\n";
        return false;
      }

      // Check for control flow in the loop body. We don't perforate anything
      // with a break, continue, return, etc.
      for (std::set<BasicBlock*>::iterator i = bodyBlocks.begin();
            i != bodyBlocks.end(); ++i) {
        if (loop->isLoopExiting(*i)) {
          *log << "contains loop exit\n";
          return false;
        }
      }

      // Check whether the body of this loop is elidable (precise-pure).
      std::set<Instruction*> blockers = AI->preciseEscapeCheck(bodyBlocks);
      *log << "blockers: " << blockers.size() << "\n";
      for (std::set<Instruction*>::iterator i = blockers.begin();
            i != blockers.end(); ++i) {
        *log << " * " << instDesc(*module, *i) << "\n";
      }

      if (!blockers.size()) {
        *log << "can perforate loop\n";
        transformPass->relaxConfig[loopName] = 0;
      }

      return false;
    }

    // Transform a loop to skip iterations.
    // The loop should already be validated as perforatable, but checks will be
    // performed nonetheless to ensure safety.
    void perforateLoop(Loop *loop, int logfactor, bool isForLike) {
      // Check whether this loop is perforatable.
      // First, check for required blocks.
      if (!loop->getHeader() || !loop->getLoopLatch()
          || !loop->getLoopPreheader() || !loop->getExitBlock()) {
        errs() << "malformed loop\n";
        return;
      }
      // Next, make sure the header (condition block) ends with a body/exit
      // conditional branch.
      BranchInst *condBranch = dyn_cast<BranchInst>(
          loop->getHeader()->getTerminator()
      );
      if (!condBranch || condBranch->getNumSuccessors() != 2) {
        errs() << "malformed loop condition\n";
        return;
      }
      BasicBlock *bodyBlock;
      if (condBranch->getSuccessor(0) == loop->getExitBlock()) {
        bodyBlock = condBranch->getSuccessor(1);
      } else if (condBranch->getSuccessor(1) == loop->getExitBlock()) {
        bodyBlock = condBranch->getSuccessor(0);
      } else {
        errs() << "loop condition does not exit\n";
        return;
      }

      // Get the shortcut for the destination. In for-like loop perforation, we
      // shortcut to the latch (increment block). In while-like perforation, we
      // jump to the header (condition block).
      BasicBlock *shortcutDest;
      if (isForLike) {
        shortcutDest = loop->getLoopLatch();
      } else {
        shortcutDest = loop->getHeader();
      }

      IRBuilder<> builder(module->getContext());
      Value *result;

      // Allocate stack space for the counter.
      // LLVM "alloca" instructions go in the function's entry block. Otherwise,
      // they have to adjust the frame size dynamically (and, in my experience,
      // can actually segfault!). And we only want one of these per static loop
      // anyway.
      builder.SetInsertPoint(
          loop->getLoopPreheader()->getParent()->getEntryBlock().begin()
      );

      IntegerType *nativeInt = getNativeIntegerType();
      AllocaInst *counterAlloca = builder.CreateAlloca(
          nativeInt,
          0,
          "accept_counter"
      );

      // Initialize the counter in the preheader.
      builder.SetInsertPoint(loop->getLoopPreheader()->getTerminator());
      builder.CreateStore(
          ConstantInt::get(nativeInt, 0, false),
          counterAlloca
      );

      // Increment the counter in the latch.
      builder.SetInsertPoint(loop->getLoopLatch()->getTerminator());
      result = builder.CreateLoad(
          counterAlloca,
          "accept_tmp"
      );
      result = builder.CreateAdd(
          result,
          ConstantInt::get(nativeInt, 1, false),
          "accept_inc"
      );
      builder.CreateStore(
          result,
          counterAlloca
      );

      // Get the first body block.

      // Check the counter before the loop's body.
      BasicBlock *checkBlock = BasicBlock::Create(
          module->getContext(),
          "accept_cond",
          bodyBlock->getParent(),
          bodyBlock
      );
      builder.SetInsertPoint(checkBlock);
      result = builder.CreateLoad(
          counterAlloca,
          "accept_tmp"
      );
      // Check whether the low n bits of the counter are zero.
      result = builder.CreateTrunc(
          result,
          Type::getIntNTy(module->getContext(), logfactor),
          "accept_trunc"
      );
      result = builder.CreateIsNull(
          result,
          "accept_cmp"
      );
      result = builder.CreateCondBr(
          result,
          bodyBlock,
          loop->getLoopLatch()
      );

      // Change the condition block to point to our new condition
      // instead of the body.
      condBranch->setSuccessor(0, checkBlock);

      // Add block to the loop structure.
      loop->addBasicBlockToLoop(checkBlock, LI->getBase());
    }

  };
}

char LoopPerfPass::ID = 0;
LoopPass *llvm::createLoopPerfPass() { return new LoopPerfPass(); }

<|endoftext|>


<commit_before>#include <ros/ros.h>

#include <geometry_msgs/Twist.h>

#include <tf/transform_broadcaster.h>

#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>

#include <sys/time.h>

#include "imu/bool_msg.h"
#include "Comm.h"

#include <sensor_msgs/Imu.h>

inline float deg_to_rad(float deg) {
	// 180度リミッター（Z軸のみ）
	return deg/180.0f*M_PI;
}
// 角度ごとにURGのデータを送信するためのサービス
// 要求があったときに，URGのデータを別のトピックに送信するだけ
class IMU {
	private :
		ros::Publisher imu_pub_;
		ros::ServiceServer reset_service_;
		ros::ServiceServer carivrate_service_;
		float geta;
		CComm usb;
        double gyro_unit;
		double acc_unit;
		double init_angle;
		std::string port_name;
		int   baudrate;
		ros::Rate loop_rate;
		int  z_axis_dir_;

	public:
		bool resetCallback(imu::bool_msg::Request  &req,
				imu::bool_msg::Response &res)
		{
			char command[2] = {0};
			sprintf(command, "0");
			usb.Send(command, strlen(command));			//送信
			sleep(1);
			std::cout << "Gyro 0 Reset" << std::endl;
			return true;
		}
		bool caribrateCallback(imu::bool_msg::Request  &req,
				imu::bool_msg::Response &res)
		{
			char command[2] = {0};
			std::cout << "Calibration" << std::endl;
			sprintf(command, "a");
			usb.Send(command, strlen(command));
			std::cout << "Caribrate start ";
			for(int i=0; i<8; ++i) {
				std::cout << ". ";
				sleep(1);
			}
			std::cout << "finish." << std::endl;
			return true;
		}
		IMU(ros::NodeHandle node) :
			imu_pub_(node.advertise<sensor_msgs::Imu>("imu", 1000)),
			reset_service_(node.advertiseService("imu_reset", &IMU::resetCallback, this)),
			carivrate_service_(node.advertiseService("imu_caribrate", &IMU::caribrateCallback, this)),
			geta(0), gyro_unit(0.00836181640625), acc_unit(0.8), init_angle(0.0),
			port_name("/dev/ttyUSB0"), baudrate(115200), loop_rate(1000), z_axis_dir_(-1)
	{
        ros::NodeHandle private_nh("~");
        private_nh.getParam("port_name", port_name);
        private_nh.param<double>("gyro_unit", gyro_unit, gyro_unit);
        private_nh.param<double>("acc_unit", acc_unit, acc_unit);
        private_nh.param<int>("baud_rate", baudrate, baudrate);
        private_nh.param<double>("init_angle", init_angle, init_angle);
        private_nh.param<int>("z_axis_dir", z_axis_dir_, z_axis_dir_);
    }
		bool init() {
			char command[2] = {0};
			char command2[101] = {0};
			//シリアルポートオープン
			char* s = new char[port_name.length()+1];
			strcpy(s, port_name.c_str());
			if (!usb.Open((char*)s, baudrate)) {
				std::cerr << "open error" << std::endl;
				delete [] s;
				return false;
			}
			delete [] s;
			std::cout << "device open success" << std::endl;
			sleep(1);
			//コンフィギュレーション キャリブレーション
			// if(m_calibration == true){
			std::cout << "Calibration" << std::endl;
			sprintf(command, "a");
			usb.Send(command, strlen(command));
			std::cout << "send = " << command << std::endl;
			for(int i=0; i<8; ++i) {
				printf(". ");
				sleep(1);
			}
			// }
			//コンフィギュレーション リセット
			// if(m_reset == true){
			sprintf(command, "0");
			usb.Send(command, strlen(command));			//送信
			std::cout << "send = " << command << std::endl;
			sleep(1);
			std::cout << "Gyro 0 Reset" << std::endl;
			// }
			geta = 0;
			usb.Recv(command2, 100);	//空読み バッファクリアが効かない？
			usb.ClearRecvBuf();		//バッファクリア
			return true;
		}
		void run() {
			while (ros::ok()) {
				char command[2] = {0};
				char command2[50] = {0};
				char temp[6];
				const float temp_unit = 0.00565;
				float tempdata;
				//コマンド送信
				//oコマンドでジャイロ3軸、加速度3軸、温度が出力される
				sprintf(command, "o");
				usb.Send(command, strlen(command));			//送信
				usleep(30000);
				//結果受信
				usb.Recv(command2, 50);			//受信
				std::cout << "recv = " << command2 << std::endl;
				geometry_msgs::Twist output_data;
				//ジャイロ読み込み
				memmove(temp,command2,4);
				output_data.angular.x = ((short)strtol(temp, NULL, 16)) * gyro_unit;
				memmove(temp,command2+4,4);
				output_data.angular.y = ((short)strtol(temp, NULL, 16)) * gyro_unit;
				memmove(temp,command2+8,4);
				output_data.angular.z = ((short)strtol(temp, NULL, 16)) * gyro_unit * z_axis_dir_;
				//加速度読み込み
				memmove(temp,command2+12,4);
				output_data.linear.x = ((short)strtol(temp, NULL, 16)) * acc_unit;
				memmove(temp,command2+16,4);
				output_data.linear.y = ((short)strtol(temp, NULL, 16)) * acc_unit;
				memmove(temp,command2+20,4);
				output_data.linear.z = init_angle + ((short)strtol(temp, NULL, 16)) * acc_unit ;
				//while (output_data.angular.z < -180)
				//	output_data.angular.z += 180;
				//while (output_data.angular.z > 180)
				//	output_data.angular.z -= 180;
				//温度読み込み
				memmove(temp,command2+24,4);
				tempdata = ((short)strtol(temp, NULL, 16)) * temp_unit + 25.0;
				// 出力データの表示
				std::cout << "ang_x = " << output_data.angular.x
					<< "ang_y = " << output_data.angular.y
					<< "ang_z = " << output_data.angular.z
					<< "ang_z_orig = " << output_data.angular.z  << std::endl;
				std::cout << "acc_x = " << output_data.linear.x
					<< "acc_y = " << output_data.linear.y
					<< "acc_z = " << output_data.linear.z << std::endl;
				std::cout << "temp  = " << tempdata << std::endl;
				output_data.angular.x = deg_to_rad(output_data.angular.x);
				output_data.angular.y = deg_to_rad(output_data.angular.y);
				output_data.angular.z = deg_to_rad(output_data.angular.z);

                sensor_msgs::Imu output_data_imu;
                output_data_imu.header.stamp = ros::Time::now();
                output_data_imu.orientation = tf::createQuaternionMsgFromYaw(output_data.angular.z);
                /*
                tf::quaternionTFToMsg(tf::Quaternion(
                                        output_data.angular.x,
                                        output_data.angular.y,
                                        output_data.angular.z
                                     ),
                                     output_data_imu.orientation
                );
                */

                output_data_imu.angular_velocity.x = output_data.angular.x;
                output_data_imu.angular_velocity.y = output_data.angular.y;
                output_data_imu.angular_velocity.z = output_data.angular.z;

                output_data_imu.linear_acceleration.x = output_data.linear.x;
                output_data_imu.linear_acceleration.y = output_data.linear.y;
                output_data_imu.linear_acceleration.z = output_data.linear.z;

				imu_pub_.publish(output_data_imu);

                ros::spinOnce();
				loop_rate.sleep();
			}
		}
};

int main(int argc, char * argv[])
{
	ros::init(argc, argv, "imu");
	ros::NodeHandle node;
	IMU imu(node);
	if(!imu.init()) return 1;
	imu.run();
	return 0;
}
<commit_msg>Modified to use the ROS_INFO macro<commit_after>#include <ros/ros.h>

#include <geometry_msgs/Twist.h>

#include <tf/transform_broadcaster.h>

#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>

#include <sys/time.h>

#include "imu/bool_msg.h"
#include "Comm.h"

#include <sensor_msgs/Imu.h>

inline float deg_to_rad(float deg) {
	// 180度リミッター（Z軸のみ）
	return deg/180.0f*M_PI;
}
// 角度ごとにURGのデータを送信するためのサービス
// 要求があったときに，URGのデータを別のトピックに送信するだけ
class IMU {
	private :
		ros::Publisher imu_pub_;
		ros::ServiceServer reset_service_;
		ros::ServiceServer carivrate_service_;
		float geta;
		CComm usb;
        double gyro_unit;
		double acc_unit;
		double init_angle;
		std::string port_name;
		int   baudrate;
		ros::Rate loop_rate;
		int  z_axis_dir_;

	public:
		bool resetCallback(imu::bool_msg::Request  &req,
				imu::bool_msg::Response &res)
		{
			char command[2] = {0};
			sprintf(command, "0");
			usb.Send(command, strlen(command));			//送信
			sleep(1);
			std::cout << "Gyro 0 Reset" << std::endl;
			return true;
		}
		bool caribrateCallback(imu::bool_msg::Request  &req,
				imu::bool_msg::Response &res)
		{
			char command[2] = {0};
			std::cout << "Calibration" << std::endl;
			sprintf(command, "a");
			usb.Send(command, strlen(command));
			std::cout << "Caribrate start ";
			for(int i=0; i<8; ++i) {
				std::cout << ". ";
				sleep(1);
			}
			std::cout << "finish." << std::endl;
			return true;
		}
		IMU(ros::NodeHandle node) :
			imu_pub_(node.advertise<sensor_msgs::Imu>("imu", 1000)),
			reset_service_(node.advertiseService("imu_reset", &IMU::resetCallback, this)),
			carivrate_service_(node.advertiseService("imu_caribrate", &IMU::caribrateCallback, this)),
			geta(0), gyro_unit(0.00836181640625), acc_unit(0.8), init_angle(0.0),
			port_name("/dev/ttyUSB0"), baudrate(115200), loop_rate(1000), z_axis_dir_(-1)
	{
        ros::NodeHandle private_nh("~");
        private_nh.getParam("port_name", port_name);
        private_nh.param<double>("gyro_unit", gyro_unit, gyro_unit);
        private_nh.param<double>("acc_unit", acc_unit, acc_unit);
        private_nh.param<int>("baud_rate", baudrate, baudrate);
        private_nh.param<double>("init_angle", init_angle, init_angle);
        private_nh.param<int>("z_axis_dir", z_axis_dir_, z_axis_dir_);
    }
		bool init() {
			char command[2] = {0};
			char command2[101] = {0};
			//シリアルポートオープン
			char* s = new char[port_name.length()+1];
			strcpy(s, port_name.c_str());
			if (!usb.Open((char*)s, baudrate)) {
				std::cerr << "open error" << std::endl;
				delete [] s;
				return false;
			}
			delete [] s;
			std::cout << "device open success" << std::endl;
			sleep(1);
			//コンフィギュレーション キャリブレーション
			// if(m_calibration == true){
			std::cout << "Calibration" << std::endl;
			sprintf(command, "a");
			usb.Send(command, strlen(command));
			std::cout << "send = " << command << std::endl;
			for(int i=0; i<8; ++i) {
				printf(". ");
				sleep(1);
			}
			// }
			//コンフィギュレーション リセット
			// if(m_reset == true){
			sprintf(command, "0");
			usb.Send(command, strlen(command));			//送信
			std::cout << "send = " << command << std::endl;
			sleep(1);
			std::cout << "Gyro 0 Reset" << std::endl;
			// }
			geta = 0;
			usb.Recv(command2, 100);	//空読み バッファクリアが効かない？
			usb.ClearRecvBuf();		//バッファクリア
			return true;
		}
		void run() {
			while (ros::ok()) {
				char command[2] = {0};
				char command2[50] = {0};
				char temp[6];
				const float temp_unit = 0.00565;
				float tempdata;
				//コマンド送信
				//oコマンドでジャイロ3軸、加速度3軸、温度が出力される
				sprintf(command, "o");
				usb.Send(command, strlen(command));			//送信
				usleep(30000);
				//結果受信
				usb.Recv(command2, 50);			//受信
				ROS_INFO_STREAM("recv = " << command2);
				sensor_msgs::Imu output_data;
                output_data.header.stamp = ros::Time::now();

                memmove(temp,command2,4);
				double angular_x_deg = ((short)strtol(temp, NULL, 16)) * gyro_unit;
				memmove(temp,command2+4,4);
				double angular_y_deg = ((short)strtol(temp, NULL, 16)) * gyro_unit;
				memmove(temp,command2+8,4);
				double angular_z_deg = ((short)strtol(temp, NULL, 16)) * gyro_unit * z_axis_dir_;

                ROS_INFO_STREAM("x_deg = " << angular_x_deg);
                ROS_INFO_STREAM("y_deg = " << angular_y_deg);
                ROS_INFO_STREAM("z_deg = " << angular_z_deg);

                output_data.orientation = tf::createQuaternionMsgFromYaw(deg_to_rad(angular_z_deg));

                //加速度読み込み
				memmove(temp,command2+12,4);
				output_data.linear_acceleration.x = ((short)strtol(temp, NULL, 16)) * acc_unit;
				memmove(temp,command2+16,4);
				output_data.linear_acceleration.y = ((short)strtol(temp, NULL, 16)) * acc_unit;
				memmove(temp,command2+20,4);
				output_data.linear_acceleration.z = init_angle + ((short)strtol(temp, NULL, 16)) * acc_unit ;

				memmove(temp,command2+24,4);
				tempdata = ((short)strtol(temp, NULL, 16)) * temp_unit + 25.0;
				ROS_INFO_STREAM("temp = " << tempdata);

				imu_pub_.publish(output_data);

                ros::spinOnce();
				loop_rate.sleep();
			}
		}
};

int main(int argc, char * argv[])
{
	ros::init(argc, argv, "imu");
	ros::NodeHandle node;
	IMU imu(node);
	if(!imu.init()) return 1;
	imu.run();
	return 0;
}
<|endoftext|>


<commit_before>//----------------------------  distorted_cells_04.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2003, 2004, 2005, 2009, 2010 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  distorted_cells_04.cc  ---------------------------

// like _03, but catch the exception and pass it to GridTools::fix_up_distorted_child_cells

#include "../tests.h"
#include <base/logstream.h>
#include <base/quadrature_lib.h>
#include <grid/tria.h>
#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <grid/grid_reordering.h>
#include <grid/grid_tools.h>
#include <grid/grid_generator.h>
#include <grid/tria_boundary.h>
#include <grid/grid_out.h>
#include <dofs/dof_handler.h>
#include <fe/fe_q.h>
#include <fe/fe_values.h>

#include <fstream>

template <int dim>
class MyBoundary : public Boundary<dim>
{
    virtual Point<dim>
    get_new_point_on_line (const typename Triangulation<dim>::line_iterator &line) const
      {
	deallog << "Finding point between "
		<< line->vertex(0) << " and "
		<< line->vertex(1) << std::endl;

					 // in 2d, find a point that
					 // lies on the opposite side
					 // of the quad. in 3d, choose
					 // the midpoint of the edge
	if (dim == 2)
	  return Point<dim>(0,0.75);
	else
	  return (line->vertex(0) + line->vertex(1)) / 2;
      }

    virtual Point<dim>
    get_new_point_on_quad (const typename Triangulation<dim>::quad_iterator &quad) const
      {
	deallog << "Finding point between "
		<< quad->vertex(0) << " and "
		<< quad->vertex(1) << " and "
		<< quad->vertex(2) << " and "
		<< quad->vertex(3) << std::endl;

	return Point<dim>(0,0,.75);
      }

    Point<dim>
    project_to_surface (const typename Triangulation<dim>::line_iterator &line,
			const Point<dim> &p) const
      {
	deallog << "Projecting line point " << p << std::endl;

	if (dim == 2)
	  return Point<dim>(p[0], 0.75-1.75*std::fabs(p[0]));
	else
	  return p;
      }

    Point<dim>
    project_to_surface (const typename Triangulation<dim>::quad_iterator &line,
			const Point<dim> &p) const
      {
	deallog << "Projecting quad point " << p << std::endl;

	Assert (dim == 3, ExcInternalError());

	return Point<dim>(p[0], p[1],
			  0.75-1.75*std::max(std::fabs(p[0]),
					     std::fabs(p[1])));
      }
};

template <int dim>
void check ()
{
  MyBoundary<dim> my_boundary;

				   // create a single square/cube
  Triangulation<dim> coarse_grid (Triangulation<dim>::none, true);
  GridGenerator::hyper_cube (coarse_grid, -1, 1);

				   // set bottom face to use MyBoundary
  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
    if (coarse_grid.begin_active()->face(f)->center()[dim-1] == -1)
      coarse_grid.begin_active()->face(f)->set_boundary_indicator (1);
  coarse_grid.set_boundary (1, my_boundary);

				   // now try to refine this one
				   // cell. we should get an exception
  try
    {
      coarse_grid.begin_active()->set_refine_flag ();
      coarse_grid.execute_coarsening_and_refinement ();
    }
  catch (typename Triangulation<dim>::DistortedCellList &dcv)
    {
      typename Triangulation<dim>::DistortedCellList
	subset = GridTools::fix_up_distorted_child_cells (dcv,
							  coarse_grid);
      Assert (subset.distorted_cells.size() == 0,
	      ExcInternalError());
    }

  Assert (coarse_grid.n_levels() == 2, ExcInternalError());
  Assert (coarse_grid.n_active_cells() == 1<<dim, ExcInternalError());

				   // output the coordinates of the
				   // child cells
  GridOut().write_gnuplot (coarse_grid, deallog.get_file_stream());
}

int main ()
{
  std::ofstream logfile("distorted_cells_04/output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-8);

  check<2> ();
  check<3> ();
}

<commit_msg>Avoid warning message about hidden virtual function. Remove name of unused argument.<commit_after>//----------------------------  distorted_cells_04.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2003, 2004, 2005, 2009, 2010 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  distorted_cells_04.cc  ---------------------------

// like _03, but catch the exception and pass it to GridTools::fix_up_distorted_child_cells

#include "../tests.h"
#include <base/logstream.h>
#include <base/quadrature_lib.h>
#include <grid/tria.h>
#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <grid/grid_reordering.h>
#include <grid/grid_tools.h>
#include <grid/grid_generator.h>
#include <grid/tria_boundary.h>
#include <grid/grid_out.h>
#include <dofs/dof_handler.h>
#include <fe/fe_q.h>
#include <fe/fe_values.h>

#include <fstream>

template <int dim>
class MyBoundary : public Boundary<dim>
{
    virtual Point<dim>
    get_new_point_on_line (const typename Triangulation<dim>::line_iterator &line) const
      {
	deallog << "Finding point between "
		<< line->vertex(0) << " and "
		<< line->vertex(1) << std::endl;

					 // in 2d, find a point that
					 // lies on the opposite side
					 // of the quad. in 3d, choose
					 // the midpoint of the edge
	if (dim == 2)
	  return Point<dim>(0,0.75);
	else
	  return (line->vertex(0) + line->vertex(1)) / 2;
      }

    virtual Point<dim>
    get_new_point_on_quad (const typename Triangulation<dim>::quad_iterator &quad) const
      {
	deallog << "Finding point between "
		<< quad->vertex(0) << " and "
		<< quad->vertex(1) << " and "
		<< quad->vertex(2) << " and "
		<< quad->vertex(3) << std::endl;

	return Point<dim>(0,0,.75);
      }

    virtual
    Point<dim>
    project_to_surface (const typename Triangulation<dim>::line_iterator &,
			const Point<dim> &p) const
      {
	deallog << "Projecting line point " << p << std::endl;

	if (dim == 2)
	  return Point<dim>(p[0], 0.75-1.75*std::fabs(p[0]));
	else
	  return p;
      }

    virtual
    Point<dim>
    project_to_surface (const typename Triangulation<dim>::quad_iterator &,
			const Point<dim> &p) const
      {
	deallog << "Projecting quad point " << p << std::endl;

	Assert (dim == 3, ExcInternalError());

	return Point<dim>(p[0], p[1],
			  0.75-1.75*std::max(std::fabs(p[0]),
					     std::fabs(p[1])));
      }

    virtual
    Point<dim>
    project_to_surface (const typename Triangulation<dim>::hex_iterator &,
			const Point<dim> &) const
      {
	Assert (false, ExcInternalError());
	return Point<dim>();
      }
};

template <int dim>
void check ()
{
  MyBoundary<dim> my_boundary;

				   // create a single square/cube
  Triangulation<dim> coarse_grid (Triangulation<dim>::none, true);
  GridGenerator::hyper_cube (coarse_grid, -1, 1);

				   // set bottom face to use MyBoundary
  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
    if (coarse_grid.begin_active()->face(f)->center()[dim-1] == -1)
      coarse_grid.begin_active()->face(f)->set_boundary_indicator (1);
  coarse_grid.set_boundary (1, my_boundary);

				   // now try to refine this one
				   // cell. we should get an exception
  try
    {
      coarse_grid.begin_active()->set_refine_flag ();
      coarse_grid.execute_coarsening_and_refinement ();
    }
  catch (typename Triangulation<dim>::DistortedCellList &dcv)
    {
      typename Triangulation<dim>::DistortedCellList
	subset = GridTools::fix_up_distorted_child_cells (dcv,
							  coarse_grid);
      Assert (subset.distorted_cells.size() == 0,
	      ExcInternalError());
    }

  Assert (coarse_grid.n_levels() == 2, ExcInternalError());
  Assert (coarse_grid.n_active_cells() == 1<<dim, ExcInternalError());

				   // output the coordinates of the
				   // child cells
  GridOut().write_gnuplot (coarse_grid, deallog.get_file_stream());
}

int main ()
{
  std::ofstream logfile("distorted_cells_04/output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-8);

  check<2> ();
  check<3> ();
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2006-2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/file_storage.hpp" // for file_entry

namespace libtorrent
{

	file_pool::file_pool(int size)
		: m_size(size)
		, m_low_prio_io(true)
#if TORRENT_CLOSE_MAY_BLOCK
		, m_stop_thread(false)
		, m_closer_thread(boost::bind(&file_pool::closer_thread_fun, this))
#endif
	{
#ifdef TORRENT_DEBUG
		m_in_use = 1337;
#endif
	}

	file_pool::~file_pool()
	{
#ifdef TORRENT_DEBUG
		m_in_use = 0;
#endif
#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l(m_closer_mutex);
		m_stop_thread = true;
		l.unlock();
		// wait for hte closer thread to finish closing all files
		m_closer_thread.join();
#endif
	}

#if TORRENT_CLOSE_MAY_BLOCK
	void file_pool::closer_thread_fun()
	{
		for (;;)
		{
			mutex::scoped_lock l(m_closer_mutex);
			if (m_stop_thread)
			{
				l.unlock();
				m_queued_for_close.clear();
				return;
			}

			// find a file that doesn't have any other threads referencing
			// it. Since only those files can be closed in this thead
			std::vector<boost::intrusive_ptr<file> >::iterator i = std::find_if(
				m_queued_for_close.begin(), m_queued_for_close.end()
				, boost::bind(&file::refcount, boost::bind(&boost::intrusive_ptr<file>::get, _1)) == 1);

			if (i == m_queued_for_close.end())
			{
				l.unlock();
				// none of the files are ready to be closed yet
				// because they're still in use by other threads
				// hold off for a while
				sleep(100);
			}
			else
			{
				// ok, first pull the file out of the queue, release the mutex
				// (since closing the file may block) and then close it.
				boost::intrusive_ptr<file> f = *i;
				m_queued_for_close.erase(i);
				l.unlock();
				f->close();
			}
		}
	}
#endif

#ifdef TORRENT_WINDOWS
	void set_low_priority(boost::intrusive_ptr<file> const& f)
	{
		// file prio is only supported on vista and up
		// so load the functions dynamically
		typedef enum _FILE_INFO_BY_HANDLE_CLASS {
			FileBasicInfo,
			FileStandardInfo,
			FileNameInfo,
			FileRenameInfo,
			FileDispositionInfo,
			FileAllocationInfo,
			FileEndOfFileInfo,
			FileStreamInfo,
			FileCompressionInfo,
			FileAttributeTagInfo,
			FileIdBothDirectoryInfo,
			FileIdBothDirectoryRestartInfo,
			FileIoPriorityHintInfo,
			FileRemoteProtocolInfo,
			MaximumFileInfoByHandleClass
		} FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;

		typedef enum _PRIORITY_HINT {
			IoPriorityHintVeryLow = 0,
			IoPriorityHintLow,
			IoPriorityHintNormal,
			MaximumIoPriorityHintType
		} PRIORITY_HINT;

		typedef struct _FILE_IO_PRIORITY_HINT_INFO {
			PRIORITY_HINT PriorityHint;
		} FILE_IO_PRIORITY_HINT_INFO, *PFILE_IO_PRIORITY_HINT_INFO;

		typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
		static SetFileInformationByHandle_t SetFileInformationByHandle = NULL;

		static bool failed_kernel_load = false;

		if (failed_kernel_load) return;

		if (SetFileInformationByHandle == NULL)
		{
			HMODULE kernel32 = LoadLibraryA("kernel32.dll");
			if (kernel32 == NULL)
			{
				failed_kernel_load = true;
				return;
			}

			SetFileInformationByHandle = (SetFileInformationByHandle_t)GetProcAddress(kernel32, "SetFileInformationByHandle");
			if (SetFileInformationByHandle == NULL)
			{
				failed_kernel_load = true;
				return;
			}
		}

		TORRENT_ASSERT(SetFileInformationByHandle);

		FILE_IO_PRIORITY_HINT_INFO io_hint;
		io_hint.PriorityHint = IoPriorityHintLow;
		SetFileInformationByHandle(f->native_handle(),
			FileIoPriorityHintInfo, &io_hint, sizeof(io_hint));
	}
#endif // TORRENT_WINDOWS

	boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int file_index, file_storage const& fs, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(m_in_use == 1337);
		file_set::iterator i = m_files.find(std::make_pair(st, file_index));
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::intrusive_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if ((((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
				|| (e.mode & file::no_buffer) != (m & file::no_buffer)
				|| (e.mode & file::random_access) != (m & file::random_access))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr->refcount() == 1);

#if TORRENT_CLOSE_MAY_BLOCK
				mutex::scoped_lock l(m_closer_mutex);
				m_queued_for_close.push_back(e.file_ptr);
				l.unlock();
				e.file_ptr = new file;
#else
				e.file_ptr->close();
#endif
				std::string full_path = fs.file_path(file_index, p);
				if (!e.file_ptr->open(full_path, m, ec))
				{
					m_files.erase(i);
					return boost::intrusive_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
				if (m_low_prio_io)
					set_low_priority(e.file_ptr);
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		std::string full_path = fs.file_path(file_index, p);
		if (!e.file_ptr->open(full_path, m, ec))
			return boost::intrusive_ptr<file>();
#ifdef TORRENT_WINDOWS
		if (m_low_prio_io)
			set_low_priority(e.file_ptr);
#endif
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(std::make_pair(st, file_index), e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		TORRENT_ASSERT(m_in_use == 1337);

		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l_(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l_.unlock();
#endif
		m_files.erase(i);
	}

	void file_pool::release(void* st, int file_index)
	{
		mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(m_in_use == 1337);
		file_set::iterator i = m_files.find(std::make_pair(st, file_index));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l2(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l2.unlock();
#endif
		m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		TORRENT_ASSERT(m_in_use == 1337);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);

		TORRENT_ASSERT(m_in_use == 1337);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}

<commit_msg>fix mutex issue introduced in recent patch<commit_after>/*

Copyright (c) 2006-2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/file_storage.hpp" // for file_entry

namespace libtorrent
{

	file_pool::file_pool(int size)
		: m_size(size)
		, m_low_prio_io(true)
#if TORRENT_CLOSE_MAY_BLOCK
		, m_stop_thread(false)
		, m_closer_thread(boost::bind(&file_pool::closer_thread_fun, this))
#endif
	{
#ifdef TORRENT_DEBUG
		m_in_use = 1337;
#endif
	}

	file_pool::~file_pool()
	{
#ifdef TORRENT_DEBUG
		m_in_use = 0;
#endif
#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l(m_closer_mutex);
		m_stop_thread = true;
		l.unlock();
		// wait for hte closer thread to finish closing all files
		m_closer_thread.join();
#endif
	}

#if TORRENT_CLOSE_MAY_BLOCK
	void file_pool::closer_thread_fun()
	{
		for (;;)
		{
			mutex::scoped_lock l(m_closer_mutex);
			if (m_stop_thread)
			{
				l.unlock();
				m_queued_for_close.clear();
				return;
			}

			// find a file that doesn't have any other threads referencing
			// it. Since only those files can be closed in this thead
			std::vector<boost::intrusive_ptr<file> >::iterator i = std::find_if(
				m_queued_for_close.begin(), m_queued_for_close.end()
				, boost::bind(&file::refcount, boost::bind(&boost::intrusive_ptr<file>::get, _1)) == 1);

			if (i == m_queued_for_close.end())
			{
				l.unlock();
				// none of the files are ready to be closed yet
				// because they're still in use by other threads
				// hold off for a while
				sleep(100);
			}
			else
			{
				// ok, first pull the file out of the queue, release the mutex
				// (since closing the file may block) and then close it.
				boost::intrusive_ptr<file> f = *i;
				m_queued_for_close.erase(i);
				l.unlock();
				f->close();
			}
		}
	}
#endif

#ifdef TORRENT_WINDOWS
	void set_low_priority(boost::intrusive_ptr<file> const& f)
	{
		// file prio is only supported on vista and up
		// so load the functions dynamically
		typedef enum _FILE_INFO_BY_HANDLE_CLASS {
			FileBasicInfo,
			FileStandardInfo,
			FileNameInfo,
			FileRenameInfo,
			FileDispositionInfo,
			FileAllocationInfo,
			FileEndOfFileInfo,
			FileStreamInfo,
			FileCompressionInfo,
			FileAttributeTagInfo,
			FileIdBothDirectoryInfo,
			FileIdBothDirectoryRestartInfo,
			FileIoPriorityHintInfo,
			FileRemoteProtocolInfo,
			MaximumFileInfoByHandleClass
		} FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;

		typedef enum _PRIORITY_HINT {
			IoPriorityHintVeryLow = 0,
			IoPriorityHintLow,
			IoPriorityHintNormal,
			MaximumIoPriorityHintType
		} PRIORITY_HINT;

		typedef struct _FILE_IO_PRIORITY_HINT_INFO {
			PRIORITY_HINT PriorityHint;
		} FILE_IO_PRIORITY_HINT_INFO, *PFILE_IO_PRIORITY_HINT_INFO;

		typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
		static SetFileInformationByHandle_t SetFileInformationByHandle = NULL;

		static bool failed_kernel_load = false;

		if (failed_kernel_load) return;

		if (SetFileInformationByHandle == NULL)
		{
			HMODULE kernel32 = LoadLibraryA("kernel32.dll");
			if (kernel32 == NULL)
			{
				failed_kernel_load = true;
				return;
			}

			SetFileInformationByHandle = (SetFileInformationByHandle_t)GetProcAddress(kernel32, "SetFileInformationByHandle");
			if (SetFileInformationByHandle == NULL)
			{
				failed_kernel_load = true;
				return;
			}
		}

		TORRENT_ASSERT(SetFileInformationByHandle);

		FILE_IO_PRIORITY_HINT_INFO io_hint;
		io_hint.PriorityHint = IoPriorityHintLow;
		SetFileInformationByHandle(f->native_handle(),
			FileIoPriorityHintInfo, &io_hint, sizeof(io_hint));
	}
#endif // TORRENT_WINDOWS

	boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int file_index, file_storage const& fs, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(m_in_use == 1337);
		file_set::iterator i = m_files.find(std::make_pair(st, file_index));
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::intrusive_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if ((((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
				|| (e.mode & file::no_buffer) != (m & file::no_buffer)
				|| (e.mode & file::random_access) != (m & file::random_access))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr->refcount() == 1);

#if TORRENT_CLOSE_MAY_BLOCK
				mutex::scoped_lock l(m_closer_mutex);
				m_queued_for_close.push_back(e.file_ptr);
				l.unlock();
				e.file_ptr = new file;
#else
				e.file_ptr->close();
#endif
				std::string full_path = fs.file_path(file_index, p);
				if (!e.file_ptr->open(full_path, m, ec))
				{
					m_files.erase(i);
					return boost::intrusive_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
				if (m_low_prio_io)
					set_low_priority(e.file_ptr);
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		std::string full_path = fs.file_path(file_index, p);
		if (!e.file_ptr->open(full_path, m, ec))
			return boost::intrusive_ptr<file>();
#ifdef TORRENT_WINDOWS
		if (m_low_prio_io)
			set_low_priority(e.file_ptr);
#endif
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(std::make_pair(st, file_index), e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		TORRENT_ASSERT(m_in_use == 1337);

		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l_(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l_.unlock();
#endif
		m_files.erase(i);
	}

	void file_pool::release(void* st, int file_index)
	{
		mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(m_in_use == 1337);
		file_set::iterator i = m_files.find(std::make_pair(st, file_index));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l2(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l2.unlock();
#endif
		m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(m_in_use == 1337);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);

		TORRENT_ASSERT(m_in_use == 1337);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}

<|endoftext|>


<commit_before>//#include "fused.h"
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "microhttpd.h"
#include "String.h"
#include "JsonValue.h"
#include "JsonObject.h"
#include "JsonString.h"
#include "JsonArray.h"
#include "JsonNull.h"
#include "JsonNumber.h"
#include "SmartPointer.h"

using std::vector;

using lepcpplib::JsonValue;
using lepcpplib::JsonObject;
using lepcpplib::JsonString;
using lepcpplib::JsonArray;
using lepcpplib::JsonNull;
using lepcpplib::JsonNumber;
using lepcpplib::SmartPointer;
using lepcpplib::String;

const short int kPort = 8888;
const int kFileBlockSize = 32 * 1024 * 1024;
const String k404 = "<title>File not found</title>File not found";

int enqueue_404_response(MHD_Connection* connection)
{
    MHD_Response* response = MHD_create_response_from_buffer(k404.length(),
      (void*)k404.toCharArray(), MHD_RESPMEM_PERSISTENT);

    int result = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
    MHD_destroy_response(response);

    return result;
}

ssize_t file_server_callback(void *cls, uint64_t pos, char *buf, size_t max)
{
  FILE* f = (FILE*)cls;
  fseek(f, pos, SEEK_SET);
  return fread(buf, 1, max, f);
}

void file_server_free_callback(void* cls)
{
  fclose((FILE*)cls);
}

int serve_file(MHD_Connection* connection, String& filename)
{
  MHD_Response* response = NULL;
  struct stat filestats;
  int result = stat(filename.toCharArray(), &filestats);
  if (result != -1) {
    FILE* fp = fopen(filename.toCharArray(), "r");
    response = MHD_create_response_from_callback (filestats.st_size,
               kFileBlockSize, file_server_callback, fp, file_server_free_callback);
    result = MHD_queue_response(connection, MHD_HTTP_OK, response);
  }
  else {
    result = enqueue_404_response(connection);
  }

  MHD_destroy_response(response);
  return result;
}

int route_discover(void* cls, MHD_Connection* connection,
                   const char* url,
                   const char* method, const char* version,
                   const char* upload_data,
                   size_t* upload_data_size, void** con_cls,
                   vector<String>& tokens)
{
  MHD_Response* response;
  int result;
  String filename;
  if (tokens.size() == 2) {
    filename = "../www/html/discover.html";
  }
  else {
    filename = "../www/html";
    for (int i = 2; i < tokens.size(); ++i)
    {
      filename = filename + "/" + tokens[i];
    }
  }

  return serve_file(connection, filename);
}

int route_api(void* cls, MHD_Connection* connection,
              const char* url,
              const char* method, const char* version,
              const char* upload_data,
              size_t* upload_data_size, void** con_cls,
              vector<String>& tokens)
{
  SmartPointer<String> output;

  int token_count = tokens.size();
  if ((token_count >= 4) && (tokens[2] == "get") && (tokens[3] == "tags")) {
    JsonObject* j1 = new JsonObject();
    j1->Add(new JsonString("name"), new JsonString("root"));
    j1->Add(new JsonString("id"), new JsonNumber(0));
    j1->Add(new JsonString("parent"), new JsonNull());

    JsonObject* j2 = new JsonObject();
    j2->Add(new JsonString("name"), new JsonString("home"));
    j2->Add(new JsonString("id"), new JsonNumber(1));
    j2->Add(new JsonString("parent"), new JsonString("root"));

    JsonArray* a = new JsonArray();
    a->Add(j1);
    a->Add(j2);

    SmartPointer<JsonObject> j = new JsonObject();
    j->Add(new JsonString("tags"), a);

    output = j->ToString();
  }
  else if ((token_count >= 5) && (tokens[2] == "get") && (tokens[3] == "tag")) {
    int tag_id = String::toInt(tokens[4].toCharArray());

    if (tag_id == 0) {
      JsonObject* j1 = new JsonObject();
      j1->Add(new JsonString("name"), new JsonString("file1.txt"));
      j1->Add(new JsonString("id"), new JsonNumber(0));

      JsonObject* j2 = new JsonObject();
      j2->Add(new JsonString("name"), new JsonString("file2.jpg"));
      j2->Add(new JsonString("id"), new JsonNumber(1));

      JsonArray* a = new JsonArray();
      a->Add(j1);
      a->Add(j2);

      SmartPointer<JsonObject> j = new JsonObject();
      j->Add(new JsonString("files"), a);
      output = j->ToString();
    }
    else {
      JsonObject* j1 = new JsonObject();
      j1->Add(new JsonString("name"), new JsonString("file3.mp4"));
      j1->Add(new JsonString("id"), new JsonNumber(2));

      JsonObject* j2 = new JsonObject();
      j2->Add(new JsonString("name"), new JsonString("file4.mp3"));
      j2->Add(new JsonString("id"), new JsonNumber(3));

      JsonArray* a = new JsonArray();
      a->Add(j1);
      a->Add(j2);

      SmartPointer<JsonObject> j = new JsonObject();
      j->Add(new JsonString("files"), a);
      output = j->ToString();
    }
  }
  else {
    SmartPointer<JsonObject> j = new JsonObject();
    j->Add(new JsonString("error"), new JsonString("invalid api"));

    output = j->ToString();
  }

  MHD_Response* response = MHD_create_response_from_buffer(output->length(),
    (void*)output->toCharArray(), MHD_RESPMEM_MUST_COPY);

  int result = MHD_queue_response(connection, MHD_HTTP_OK, response);
  MHD_destroy_response(response);
  return result;
}

int client_processor(void* cls, MHD_Connection* connection,
                     const char* url,
                     const char* method, const char* version,
                     const char* upload_data,
                     size_t* upload_data_size, void** con_cls)
{
  vector<String> tokens;
  String::tokenize(url, '/', tokens);
  int result;

  if (tokens.size() >= 2) {
    if (tokens[1] == "discover") {
      result = route_discover(cls, connection, url, method, version,
        upload_data, upload_data_size, con_cls, tokens);
    }
    else if (tokens[1] == "api") {
      route_api(cls, connection, url, method, version,
        upload_data, upload_data_size, con_cls, tokens);
    }
    else {
      result = enqueue_404_response(connection);
    }
  }

  return result;
}

int main(int argc, char* argv[])
{
  MHD_Daemon* daemon;
  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, kPort, NULL, NULL,
    &client_processor, NULL, MHD_OPTION_END);

  if (daemon == NULL) {
    return 1;
  }

  getchar();

  MHD_stop_daemon(daemon);
  return 0;
}
<commit_msg>add api to get file metadata<commit_after>//#include "fused.h"
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "microhttpd.h"
#include "String.h"
#include "JsonValue.h"
#include "JsonObject.h"
#include "JsonString.h"
#include "JsonArray.h"
#include "JsonNull.h"
#include "JsonNumber.h"
#include "SmartPointer.h"

using std::vector;

using lepcpplib::JsonValue;
using lepcpplib::JsonObject;
using lepcpplib::JsonString;
using lepcpplib::JsonArray;
using lepcpplib::JsonNull;
using lepcpplib::JsonNumber;
using lepcpplib::SmartPointer;
using lepcpplib::String;

const short int kPort = 8888;
const int kFileBlockSize = 32 * 1024 * 1024;
const String k404 = "<title>File not found</title>File not found";

int enqueue_404_response(MHD_Connection* connection)
{
    MHD_Response* response = MHD_create_response_from_buffer(k404.length(),
      (void*)k404.toCharArray(), MHD_RESPMEM_PERSISTENT);

    int result = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
    MHD_destroy_response(response);

    return result;
}

ssize_t file_server_callback(void *cls, uint64_t pos, char *buf, size_t max)
{
  FILE* f = (FILE*)cls;
  fseek(f, pos, SEEK_SET);
  return fread(buf, 1, max, f);
}

void file_server_free_callback(void* cls)
{
  fclose((FILE*)cls);
}

int serve_file(MHD_Connection* connection, String& filename)
{
  MHD_Response* response = NULL;
  struct stat filestats;
  int result = stat(filename.toCharArray(), &filestats);
  if (result != -1) {
    FILE* fp = fopen(filename.toCharArray(), "r");
    response = MHD_create_response_from_callback (filestats.st_size,
               kFileBlockSize, file_server_callback, fp, file_server_free_callback);
    result = MHD_queue_response(connection, MHD_HTTP_OK, response);
  }
  else {
    result = enqueue_404_response(connection);
  }

  MHD_destroy_response(response);
  return result;
}

int route_discover(void* cls, MHD_Connection* connection,
                   const char* url,
                   const char* method, const char* version,
                   const char* upload_data,
                   size_t* upload_data_size, void** con_cls,
                   vector<String>& tokens)
{
  MHD_Response* response;
  int result;
  String filename;
  if (tokens.size() == 2) {
    filename = "../www/html/discover.html";
  }
  else {
    filename = "../www/html";
    for (int i = 2; i < tokens.size(); ++i)
    {
      filename = filename + "/" + tokens[i];
    }
  }

  return serve_file(connection, filename);
}

int route_api(void* cls, MHD_Connection* connection,
              const char* url,
              const char* method, const char* version,
              const char* upload_data,
              size_t* upload_data_size, void** con_cls,
              vector<String>& tokens)
{
  SmartPointer<String> output;

  int token_count = tokens.size();
  if ((token_count >= 4) && (tokens[2] == "get") && (tokens[3] == "tags")) {
    JsonObject* j1 = new JsonObject();
    j1->Add(new JsonString("name"), new JsonString("root"));
    j1->Add(new JsonString("id"), new JsonNumber(0));
    j1->Add(new JsonString("parent"), new JsonNull());

    JsonObject* j2 = new JsonObject();
    j2->Add(new JsonString("name"), new JsonString("home"));
    j2->Add(new JsonString("id"), new JsonNumber(1));
    j2->Add(new JsonString("parent"), new JsonString("root"));

    JsonArray* a = new JsonArray();
    a->Add(j1);
    a->Add(j2);

    SmartPointer<JsonObject> j = new JsonObject();
    j->Add(new JsonString("tags"), a);

    output = j->ToString();
  }
  else if ((token_count >= 5) && (tokens[2] == "get") && (tokens[3] == "tag")) {
    int tag_id = String::toInt(tokens[4].toCharArray());

    if (tag_id == 0) {
      JsonObject* j1 = new JsonObject();
      j1->Add(new JsonString("name"), new JsonString("file1.txt"));
      j1->Add(new JsonString("id"), new JsonNumber(0));

      JsonObject* j2 = new JsonObject();
      j2->Add(new JsonString("name"), new JsonString("file2.jpg"));
      j2->Add(new JsonString("id"), new JsonNumber(1));

      JsonArray* a = new JsonArray();
      a->Add(j1);
      a->Add(j2);

      SmartPointer<JsonObject> j = new JsonObject();
      j->Add(new JsonString("files"), a);
      output = j->ToString();
    }
    else {
      JsonObject* j1 = new JsonObject();
      j1->Add(new JsonString("name"), new JsonString("file3.mp4"));
      j1->Add(new JsonString("id"), new JsonNumber(2));

      JsonObject* j2 = new JsonObject();
      j2->Add(new JsonString("name"), new JsonString("file4.mp3"));
      j2->Add(new JsonString("id"), new JsonNumber(3));

      JsonArray* a = new JsonArray();
      a->Add(j1);
      a->Add(j2);

      SmartPointer<JsonObject> j = new JsonObject();
      j->Add(new JsonString("files"), a);
      output = j->ToString();
    }
  }
  else if ((token_count >= 5) && (tokens[2] == "get") && (tokens[3] == "file")) {
    int file_id = String::toInt(tokens[4].toCharArray());

    if (file_id == 0) {
      SmartPointer<JsonObject> j = new JsonObject();
      j->Add(new JsonString("name"), new JsonString("file1.txt"));
      j->Add(new JsonString("id"), new JsonNumber(0));
      j->Add(new JsonString("type"), new JsonString("Text document"));
      j->Add(new JsonString("last_modified"), new JsonString("Sat 14 Sep 2013 01:14:35 AM PDT"));

      JsonObject* j1 = new JsonObject();
      j1->Add(new JsonString("name"), new JsonString("anothertag1"));
      j1->Add(new JsonString("id"), new JsonNumber(3));

      JsonObject* j2 = new JsonObject();
      j2->Add(new JsonString("name"), new JsonString("anothertag2"));
      j2->Add(new JsonString("id"), new JsonNumber(4));

      JsonArray* a = new JsonArray();
      a->Add(j1);
      a->Add(j2);

      j->Add(new JsonString("tags"), a);
      output = j->ToString();
    }
    else {
      SmartPointer<JsonObject> j = new JsonObject();
      j->Add(new JsonString("name"), new JsonString("file2.jpg"));
      j->Add(new JsonString("id"), new JsonNumber(0));
      j->Add(new JsonString("type"), new JsonString("JPEG image"));
      j->Add(new JsonString("last_modified"), new JsonString("Sat 14 Sep 2013 01:14:35 AM PDT"));

      JsonObject* j1 = new JsonObject();
      j1->Add(new JsonString("name"), new JsonString("anothertag3"));
      j1->Add(new JsonString("id"), new JsonNumber(4));

      JsonObject* j2 = new JsonObject();
      j2->Add(new JsonString("name"), new JsonString("anothertag4"));
      j2->Add(new JsonString("id"), new JsonNumber(5));

      JsonArray* a = new JsonArray();
      a->Add(j1);
      a->Add(j2);

      j->Add(new JsonString("tags"), a);
      output = j->ToString();
    }
  }
  else {
    SmartPointer<JsonObject> j = new JsonObject();
    j->Add(new JsonString("error"), new JsonString("invalid api"));

    output = j->ToString();
  }

  MHD_Response* response = MHD_create_response_from_buffer(output->length(),
    (void*)output->toCharArray(), MHD_RESPMEM_MUST_COPY);

  int result = MHD_queue_response(connection, MHD_HTTP_OK, response);
  MHD_destroy_response(response);
  return result;
}

int client_processor(void* cls, MHD_Connection* connection,
                     const char* url,
                     const char* method, const char* version,
                     const char* upload_data,
                     size_t* upload_data_size, void** con_cls)
{
  vector<String> tokens;
  String::tokenize(url, '/', tokens);
  int result;

  if (tokens.size() >= 2) {
    if (tokens[1] == "discover") {
      result = route_discover(cls, connection, url, method, version,
        upload_data, upload_data_size, con_cls, tokens);
    }
    else if (tokens[1] == "api") {
      route_api(cls, connection, url, method, version,
        upload_data, upload_data_size, con_cls, tokens);
    }
    else {
      result = enqueue_404_response(connection);
    }
  }

  return result;
}

int main(int argc, char* argv[])
{
  MHD_Daemon* daemon;
  daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, kPort, NULL, NULL,
    &client_processor, NULL, MHD_OPTION_END);

  if (daemon == NULL) {
    return 1;
  }

  getchar();

  MHD_stop_daemon(daemon);
  return 0;
}
<|endoftext|>