<commit_before>#ifndef _SNARKFRONT_SHA_384_HPP_
#define _SNARKFRONT_SHA_384_HPP_

#include <array>
#include <cstdint>
#include "Alg.hpp"
#include "Alg_uint.hpp"
#include "AST.hpp"
#include "BitwiseOps.hpp"
#include "Lazy.hpp"
#include "SHA_512.hpp"

namespace snarkfront {

////////////////////////////////////////////////////////////////////////////////
// SHA-384
//

template <typename T, typename MSG, typename U, typename F>
class SHA_384 : public SHA_512<T, MSG, U, F>
{
public:
    typedef T WordType;
    typedef U ByteType;

    typedef std::array<T, 16> MsgType;
    typedef std::array<T, 6> DigType;
    typedef std::array<U, 16 * 8> PreType;

    SHA_384()
        : m_setDigest(false)
    {}

    // overrides base class SHA-512
    const std::array<T, 6>& digest() {
        if (m_setDigest) {
            for (std::size_t i = 0; i < 6; ++i) {
                m_Hleft384[i] = this->m_H[i];
            }

            m_setDigest = false;
        }

        return m_Hleft384;
    }

    // overrides base class SHA-512
    virtual void initHashValue() {
        // set initial hash value (NIST FIPS 180-4 section 5.3.4)
        const std::array<uint64_t, 8> a {
            0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
            0x9159015a3070dd17, 0x152fecd8f70e5939,

            0x67332667ffc00b31, 0x8eb44a8768581511,
            0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 };

        for (std::size_t i = 0; i < 8; ++i) {
            this->m_H[i] = F::constant(a[i]);
        }
    }

    virtual void afterHash() {
        m_setDigest = true;
    }

private:
    // truncated 384-bit message digest
    std::array<T, 6> m_Hleft384;

    bool m_setDigest;
};

////////////////////////////////////////////////////////////////////////////////
// typedefs
//

namespace zk {
    template <typename FR> using
    SHA384 = SHA_384<AST_Var<Alg_uint64<FR>>,
                     Lazy<AST_Var<Alg_uint64<FR>>, std::uint64_t>,
                     AST_Var<Alg_uint8<FR>>,
                     SHA_Functions<AST_Node<Alg_uint64<FR>>,
                                   AST_Op<Alg_uint64<FR>>,
                                   BitwiseAST<Alg_uint64<FR>, Alg_uint64<FR>>>>;
} // namespace zk

namespace eval {
typedef SHA_384<std::uint64_t,
                std::uint64_t,
                std::uint8_t,
                SHA_Functions<std::uint64_t,
                              std::uint64_t,
                              BitwiseINT<std::uint64_t, std::uint64_t>>>
    SHA384;
} // namespace eval

} // namespace snarkfront

#endif
<commit_msg>BitwiseOps templates<commit_after>#ifndef _SNARKFRONT_SHA_384_HPP_
#define _SNARKFRONT_SHA_384_HPP_

#include <array>
#include <cstdint>
#include "Alg.hpp"
#include "Alg_uint.hpp"
#include "AST.hpp"
#include "BitwiseOps.hpp"
#include "Lazy.hpp"
#include "SHA_512.hpp"

namespace snarkfront {

////////////////////////////////////////////////////////////////////////////////
// SHA-384
//

template <typename T, typename MSG, typename U, typename F>
class SHA_384 : public SHA_512<T, MSG, U, F>
{
public:
    typedef T WordType;
    typedef U ByteType;

    typedef std::array<T, 16> MsgType;
    typedef std::array<T, 6> DigType;
    typedef std::array<U, 16 * 8> PreType;

    SHA_384()
        : m_setDigest(false)
    {}

    // overrides base class SHA-512
    const std::array<T, 6>& digest() {
        if (m_setDigest) {
            for (std::size_t i = 0; i < 6; ++i) {
                m_Hleft384[i] = this->m_H[i];
            }

            m_setDigest = false;
        }

        return m_Hleft384;
    }

    // overrides base class SHA-512
    virtual void initHashValue() {
        // set initial hash value (NIST FIPS 180-4 section 5.3.4)
        const std::array<uint64_t, 8> a {
            0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
            0x9159015a3070dd17, 0x152fecd8f70e5939,

            0x67332667ffc00b31, 0x8eb44a8768581511,
            0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 };

        for (std::size_t i = 0; i < 8; ++i) {
            this->m_H[i] = F::constant(a[i]);
        }
    }

    virtual void afterHash() {
        m_setDigest = true;
    }

private:
    // truncated 384-bit message digest
    std::array<T, 6> m_Hleft384;

    bool m_setDigest;
};

////////////////////////////////////////////////////////////////////////////////
// typedefs
//

namespace zk {
    template <typename FR> using
    SHA384 = SHA_384<AST_Var<Alg_uint64<FR>>,
                     Lazy<AST_Var<Alg_uint64<FR>>, std::uint64_t>,
                     AST_Var<Alg_uint8<FR>>,
                     SHA_Functions<AST_Node<Alg_uint64<FR>>,
                                   AST_Op<Alg_uint64<FR>>,
                                   BitwiseAST<Alg_uint64<FR>>>>;
} // namespace zk

namespace eval {
typedef SHA_384<std::uint64_t,
                std::uint64_t,
                std::uint8_t,
                SHA_Functions<std::uint64_t,
                              std::uint64_t,
                              BitwiseINT<std::uint64_t>>>
    SHA384;
} // namespace eval

} // namespace snarkfront

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2016 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <nostalgia/core/core.hpp>

using namespace nostalgia;

static unsigned spriteX = 72;
static unsigned spriteY = 64;

static int eventHandler(core::Context *ctx) noexcept {
	if (core::buttonDown(core::GamePad_Right)) {
		spriteX += 2;
	} else if (core::buttonDown(core::GamePad_Left)) {
		spriteX -= 2;
	}
	if (core::buttonDown(core::GamePad_Down)) {
		spriteY += 2;
	} else if (core::buttonDown(core::GamePad_Up)) {
		spriteY -= 2;
	}
	constexpr auto s = "nostalgia";
	for (unsigned i = 0; s[i]; ++i) {
		const auto c = static_cast<unsigned>(s[i] - ('a' - 1));
		core::setSprite(ctx, i, spriteX + 8 * (i + 1), spriteY, c);
	}
	return 16;
}

ox::Error run(ox::FileSystem *fs) noexcept {
	oxRequireM(ctx, core::init(fs));
	constexpr auto TileSheetAddr = "/TileSheets/Charset.ng";
	constexpr auto PaletteAddr = "/Palettes/Charset.npal";
	oxReturnError(core::loadSpriteTileSheet(ctx.get(), 0, TileSheetAddr, PaletteAddr));
	oxReturnError(core::initConsole(ctx.get()));
	core::puts(ctx.get(), 10, 9, "DOPENESS!!!");
	core::setEventHandler(ctx.get(), eventHandler);
	oxReturnError(core::run(ctx.get()));
	oxReturnError(core::shutdownGfx(ctx.get()));
	return OxError(0);
}

<commit_msg>[nostalgia/player] Remove old shutdown function use<commit_after>/*
 * Copyright 2016 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <nostalgia/core/core.hpp>

using namespace nostalgia;

static unsigned spriteX = 72;
static unsigned spriteY = 64;

static int eventHandler(core::Context *ctx) noexcept {
	if (core::buttonDown(core::GamePad_Right)) {
		spriteX += 2;
	} else if (core::buttonDown(core::GamePad_Left)) {
		spriteX -= 2;
	}
	if (core::buttonDown(core::GamePad_Down)) {
		spriteY += 2;
	} else if (core::buttonDown(core::GamePad_Up)) {
		spriteY -= 2;
	}
	constexpr auto s = "nostalgia";
	for (unsigned i = 0; s[i]; ++i) {
		const auto c = static_cast<unsigned>(s[i] - ('a' - 1));
		core::setSprite(ctx, i, spriteX + 8 * (i + 1), spriteY, c);
	}
	return 16;
}

ox::Error run(ox::FileSystem *fs) noexcept {
	oxRequireM(ctx, core::init(fs));
	constexpr auto TileSheetAddr = "/TileSheets/Charset.ng";
	constexpr auto PaletteAddr = "/Palettes/Charset.npal";
	oxReturnError(core::loadSpriteTileSheet(ctx.get(), 0, TileSheetAddr, PaletteAddr));
	oxReturnError(core::initConsole(ctx.get()));
	core::puts(ctx.get(), 10, 9, "DOPENESS!!!");
	core::setEventHandler(ctx.get(), eventHandler);
	return core::run(ctx.get());
}

<|endoftext|>


<commit_before>//===-- X86ATTInstPrinter.cpp - AT&T assembly instruction printing --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file includes code for rendering MCInst instances as AT&T-style
// assembly.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "asm-printer"
#include "llvm/MC/MCInst.h"
#include "X86ATTAsmPrinter.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;

// Include the auto-generated portion of the assembly writer.
#define MachineInstr MCInst
#define NO_ASM_WRITER_BOILERPLATE
#include "X86GenAsmWriter.inc"
#undef MachineInstr

void X86ATTAsmPrinter::printSSECC(const MCInst *MI, unsigned Op) {
  switch (MI->getOperand(Op).getImm()) {
  default: llvm_unreachable("Invalid ssecc argument!");
  case 0: O << "eq"; break;
  case 1: O << "lt"; break;
  case 2: O << "le"; break;
  case 3: O << "unord"; break;
  case 4: O << "neq"; break;
  case 5: O << "nlt"; break;
  case 6: O << "nle"; break;
  case 7: O << "ord"; break;
  }
}

void X86ATTAsmPrinter::printPICLabel(const MCInst *MI, unsigned Op) {
  llvm_unreachable("This is only used for MOVPC32r,"
                   "should lower before asm printing!");
}

/// print_pcrel_imm - This is used to print an immediate value that ends up
/// being encoded as a pc-relative value.  These print slightly differently, for
/// example, a $ is not emitted.
void X86ATTAsmPrinter::print_pcrel_imm(const MCInst *MI, unsigned OpNo) {
  const MCOperand &Op = MI->getOperand(OpNo);

  if (Op.isImm())
    O << Op.getImm();
  else if (Op.isMBBLabel())
    // FIXME: Keep in sync with printBasicBlockLabel.  printBasicBlockLabel
    // should eventually call into this code, not the other way around.
    O << TAI->getPrivateGlobalPrefix() << "BB" << Op.getMBBLabelFunction()
      << '_' << Op.getMBBLabelBlock();
  else
    llvm_unreachable("Unknown pcrel immediate operand");
}

void X86ATTAsmPrinter::printOperand(const MCInst *MI, unsigned OpNo,
                                    const char *Modifier) {
  assert(Modifier == 0 && "Modifiers should not be used");

  const MCOperand &Op = MI->getOperand(OpNo);
  if (Op.isReg()) {
    O << '%';
    unsigned Reg = Op.getReg();
#if 0
    if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
      EVT VT = (strcmp(Modifier+6,"64") == 0) ?
      EVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? EVT::i32 :
                  ((strcmp(Modifier+6,"16") == 0) ? EVT::i16 : EVT::i8));
      Reg = getX86SubSuperRegister(Reg, VT);
    }
#endif
    O << TRI->getAsmName(Reg);
    return;
  } else if (Op.isImm()) {
    //if (!Modifier || (strcmp(Modifier, "debug") && strcmp(Modifier, "mem")))
    O << '$';
    O << Op.getImm();
    return;
  }

  O << "<<UNKNOWN OPERAND KIND>>";
}

void X86ATTAsmPrinter::printLeaMemReference(const MCInst *MI, unsigned Op) {

  const MCOperand &BaseReg  = MI->getOperand(Op);
  const MCOperand &IndexReg = MI->getOperand(Op+2);
  const MCOperand &DispSpec = MI->getOperand(Op+3);

  if (DispSpec.isImm()) {
    int64_t DispVal = DispSpec.getImm();
    if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg()))
      O << DispVal;
  } else {
    llvm_unreachable("non-immediate displacement for LEA?");
    //assert(DispSpec.isGlobal() || DispSpec.isCPI() ||
    //       DispSpec.isJTI() || DispSpec.isSymbol());
    //printOperand(MI, Op+3, "mem");
  }

  if (IndexReg.getReg() || BaseReg.getReg()) {
    // There are cases where we can end up with ESP/RSP in the indexreg slot.
    // If this happens, swap the base/index register to support assemblers that
    // don't work when the index is *SP.
    // FIXME: REMOVE THIS.
    assert(IndexReg.getReg() != X86::ESP && IndexReg.getReg() != X86::RSP);

    O << '(';
    if (BaseReg.getReg())
      printOperand(MI, Op);

    if (IndexReg.getReg()) {
      O << ',';
      printOperand(MI, Op+2);
      unsigned ScaleVal = MI->getOperand(Op+1).getImm();
      if (ScaleVal != 1)
        O << ',' << ScaleVal;
    }
    O << ')';
  }
}

void X86ATTAsmPrinter::printMemReference(const MCInst *MI, unsigned Op) {
  const MCOperand &Segment = MI->getOperand(Op+4);
  if (Segment.getReg()) {
    printOperand(MI, Op+4);
    O << ':';
  }
  printLeaMemReference(MI, Op);
}
<commit_msg>Add X86 instruction printer support for printing MCValue operands.<commit_after>//===-- X86ATTInstPrinter.cpp - AT&T assembly instruction printing --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file includes code for rendering MCInst instances as AT&T-style
// assembly.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "asm-printer"
#include "llvm/MC/MCInst.h"
#include "X86ATTAsmPrinter.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;

// Include the auto-generated portion of the assembly writer.
#define MachineInstr MCInst
#define NO_ASM_WRITER_BOILERPLATE
#include "X86GenAsmWriter.inc"
#undef MachineInstr

void X86ATTAsmPrinter::printSSECC(const MCInst *MI, unsigned Op) {
  switch (MI->getOperand(Op).getImm()) {
  default: llvm_unreachable("Invalid ssecc argument!");
  case 0: O << "eq"; break;
  case 1: O << "lt"; break;
  case 2: O << "le"; break;
  case 3: O << "unord"; break;
  case 4: O << "neq"; break;
  case 5: O << "nlt"; break;
  case 6: O << "nle"; break;
  case 7: O << "ord"; break;
  }
}

void X86ATTAsmPrinter::printPICLabel(const MCInst *MI, unsigned Op) {
  llvm_unreachable("This is only used for MOVPC32r,"
                   "should lower before asm printing!");
}

/// print_pcrel_imm - This is used to print an immediate value that ends up
/// being encoded as a pc-relative value.  These print slightly differently, for
/// example, a $ is not emitted.
void X86ATTAsmPrinter::print_pcrel_imm(const MCInst *MI, unsigned OpNo) {
  const MCOperand &Op = MI->getOperand(OpNo);

  if (Op.isImm())
    O << Op.getImm();
  else if (Op.isMCValue())
    Op.getMCValue().print(O);
  else if (Op.isMBBLabel())
    // FIXME: Keep in sync with printBasicBlockLabel.  printBasicBlockLabel
    // should eventually call into this code, not the other way around.
    O << TAI->getPrivateGlobalPrefix() << "BB" << Op.getMBBLabelFunction()
      << '_' << Op.getMBBLabelBlock();
  else
    llvm_unreachable("Unknown pcrel immediate operand");
}

void X86ATTAsmPrinter::printOperand(const MCInst *MI, unsigned OpNo,
                                    const char *Modifier) {
  assert(Modifier == 0 && "Modifiers should not be used");

  const MCOperand &Op = MI->getOperand(OpNo);
  if (Op.isReg()) {
    O << '%';
    unsigned Reg = Op.getReg();
#if 0
    if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
      EVT VT = (strcmp(Modifier+6,"64") == 0) ?
      EVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? EVT::i32 :
                  ((strcmp(Modifier+6,"16") == 0) ? EVT::i16 : EVT::i8));
      Reg = getX86SubSuperRegister(Reg, VT);
    }
#endif
    O << TRI->getAsmName(Reg);
    return;
  } else if (Op.isImm()) {
    //if (!Modifier || (strcmp(Modifier, "debug") && strcmp(Modifier, "mem")))
    O << '$';
    O << Op.getImm();
    return;
  } else if (Op.isMCValue()) {
    O << '$';
    Op.getMCValue().print(O);
    return;
  }

  O << "<<UNKNOWN OPERAND KIND>>";
}

void X86ATTAsmPrinter::printLeaMemReference(const MCInst *MI, unsigned Op) {

  const MCOperand &BaseReg  = MI->getOperand(Op);
  const MCOperand &IndexReg = MI->getOperand(Op+2);
  const MCOperand &DispSpec = MI->getOperand(Op+3);

  if (DispSpec.isImm()) {
    int64_t DispVal = DispSpec.getImm();
    if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg()))
      O << DispVal;
  } else if (DispSpec.isMCValue()) {
    DispSpec.getMCValue().print(O);
  } else {
    llvm_unreachable("non-immediate displacement for LEA?");
    //assert(DispSpec.isGlobal() || DispSpec.isCPI() ||
    //       DispSpec.isJTI() || DispSpec.isSymbol());
    //printOperand(MI, Op+3, "mem");
  }

  if (IndexReg.getReg() || BaseReg.getReg()) {
    // There are cases where we can end up with ESP/RSP in the indexreg slot.
    // If this happens, swap the base/index register to support assemblers that
    // don't work when the index is *SP.
    // FIXME: REMOVE THIS.
    assert(IndexReg.getReg() != X86::ESP && IndexReg.getReg() != X86::RSP);

    O << '(';
    if (BaseReg.getReg())
      printOperand(MI, Op);

    if (IndexReg.getReg()) {
      O << ',';
      printOperand(MI, Op+2);
      unsigned ScaleVal = MI->getOperand(Op+1).getImm();
      if (ScaleVal != 1)
        O << ',' << ScaleVal;
    }
    O << ')';
  }
}

void X86ATTAsmPrinter::printMemReference(const MCInst *MI, unsigned Op) {
  const MCOperand &Segment = MI->getOperand(Op+4);
  if (Segment.getReg()) {
    printOperand(MI, Op+4);
    O << ':';
  }
  printLeaMemReference(MI, Op);
}
<|endoftext|>


<commit_before>//===- ObjCARCAliasAnalysis.cpp - ObjC ARC Optimization -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines a simple ARC-aware AliasAnalysis using special knowledge
/// of Objective C to enhance other optimization passes which rely on the Alias
/// Analysis infrastructure.
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//

#include "ObjCARC.h"
#include "ObjCARCAliasAnalysis.h"
#include "llvm/IR/Instruction.h"
#include "llvm/InitializePasses.h"
#include "llvm/PassAnalysisSupport.h"
#include "llvm/PassSupport.h"

#define DEBUG_TYPE "objc-arc-aa"

namespace llvm {
  class Function;
  class Value;
}

using namespace llvm;
using namespace llvm::objcarc;

// Register this pass...
char ObjCARCAliasAnalysis::ID = 0;
INITIALIZE_AG_PASS(ObjCARCAliasAnalysis, AliasAnalysis, "objc-arc-aa",
                   "ObjC-ARC-Based Alias Analysis", false, true, false)

ImmutablePass *llvm::createObjCARCAliasAnalysisPass() {
  return new ObjCARCAliasAnalysis();
}

bool ObjCARCAliasAnalysis::doInitialization(Module &M) {
  InitializeAliasAnalysis(this, &M.getDataLayout());
  return true;
}

void
ObjCARCAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AliasAnalysis::getAnalysisUsage(AU);
}

AliasResult ObjCARCAliasAnalysis::alias(const MemoryLocation &LocA,
                                        const MemoryLocation &LocB) {
  if (!EnableARCOpts)
    return AliasAnalysis::alias(LocA, LocB);

  // First, strip off no-ops, including ObjC-specific no-ops, and try making a
  // precise alias query.
  const Value *SA = GetRCIdentityRoot(LocA.Ptr);
  const Value *SB = GetRCIdentityRoot(LocB.Ptr);
  AliasResult Result =
      AliasAnalysis::alias(MemoryLocation(SA, LocA.Size, LocA.AATags),
                           MemoryLocation(SB, LocB.Size, LocB.AATags));
  if (Result != MayAlias)
    return Result;

  // If that failed, climb to the underlying object, including climbing through
  // ObjC-specific no-ops, and try making an imprecise alias query.
  const Value *UA = GetUnderlyingObjCPtr(SA, *DL);
  const Value *UB = GetUnderlyingObjCPtr(SB, *DL);
  if (UA != SA || UB != SB) {
    Result = AliasAnalysis::alias(MemoryLocation(UA), MemoryLocation(UB));
    // We can't use MustAlias or PartialAlias results here because
    // GetUnderlyingObjCPtr may return an offsetted pointer value.
    if (Result == NoAlias)
      return NoAlias;
  }

  // If that failed, fail. We don't need to chain here, since that's covered
  // by the earlier precise query.
  return MayAlias;
}

bool ObjCARCAliasAnalysis::pointsToConstantMemory(const MemoryLocation &Loc,
                                                  bool OrLocal) {
  if (!EnableARCOpts)
    return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal);

  // First, strip off no-ops, including ObjC-specific no-ops, and try making
  // a precise alias query.
  const Value *S = GetRCIdentityRoot(Loc.Ptr);
  if (AliasAnalysis::pointsToConstantMemory(
          MemoryLocation(S, Loc.Size, Loc.AATags), OrLocal))
    return true;

  // If that failed, climb to the underlying object, including climbing through
  // ObjC-specific no-ops, and try making an imprecise alias query.
  const Value *U = GetUnderlyingObjCPtr(S, *DL);
  if (U != S)
    return AliasAnalysis::pointsToConstantMemory(MemoryLocation(U), OrLocal);

  // If that failed, fail. We don't need to chain here, since that's covered
  // by the earlier precise query.
  return false;
}

FunctionModRefBehavior
ObjCARCAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
  // We have nothing to do. Just chain to the next AliasAnalysis.
  return AliasAnalysis::getModRefBehavior(CS);
}

FunctionModRefBehavior
ObjCARCAliasAnalysis::getModRefBehavior(const Function *F) {
  if (!EnableARCOpts)
    return AliasAnalysis::getModRefBehavior(F);

  switch (GetFunctionClass(F)) {
  case ARCInstKind::NoopCast:
    return FMRB_DoesNotAccessMemory;
  default:
    break;
  }

  return AliasAnalysis::getModRefBehavior(F);
}

ModRefInfo ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS,
                                               const MemoryLocation &Loc) {
  if (!EnableARCOpts)
    return AliasAnalysis::getModRefInfo(CS, Loc);

  switch (GetBasicARCInstKind(CS.getInstruction())) {
  case ARCInstKind::Retain:
  case ARCInstKind::RetainRV:
  case ARCInstKind::Autorelease:
  case ARCInstKind::AutoreleaseRV:
  case ARCInstKind::NoopCast:
  case ARCInstKind::AutoreleasepoolPush:
  case ARCInstKind::FusedRetainAutorelease:
  case ARCInstKind::FusedRetainAutoreleaseRV:
    // These functions don't access any memory visible to the compiler.
    // Note that this doesn't include objc_retainBlock, because it updates
    // pointers when it copies block data.
    return MRI_NoModRef;
  default:
    break;
  }

  return AliasAnalysis::getModRefInfo(CS, Loc);
}

ModRefInfo ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS1,
                                               ImmutableCallSite CS2) {
  // TODO: Theoretically we could check for dependencies between objc_* calls
  // and FMRB_OnlyAccessesArgumentPointees calls or other well-behaved calls.
  return AliasAnalysis::getModRefInfo(CS1, CS2);
}
<commit_msg>[PM/AA] Don't bother forward declaring Function and Value, just include their headers.<commit_after>//===- ObjCARCAliasAnalysis.cpp - ObjC ARC Optimization -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines a simple ARC-aware AliasAnalysis using special knowledge
/// of Objective C to enhance other optimization passes which rely on the Alias
/// Analysis infrastructure.
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//

#include "ObjCARC.h"
#include "ObjCARCAliasAnalysis.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/PassAnalysisSupport.h"
#include "llvm/PassSupport.h"

#define DEBUG_TYPE "objc-arc-aa"

using namespace llvm;
using namespace llvm::objcarc;

// Register this pass...
char ObjCARCAliasAnalysis::ID = 0;
INITIALIZE_AG_PASS(ObjCARCAliasAnalysis, AliasAnalysis, "objc-arc-aa",
                   "ObjC-ARC-Based Alias Analysis", false, true, false)

ImmutablePass *llvm::createObjCARCAliasAnalysisPass() {
  return new ObjCARCAliasAnalysis();
}

bool ObjCARCAliasAnalysis::doInitialization(Module &M) {
  InitializeAliasAnalysis(this, &M.getDataLayout());
  return true;
}

void
ObjCARCAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AliasAnalysis::getAnalysisUsage(AU);
}

AliasResult ObjCARCAliasAnalysis::alias(const MemoryLocation &LocA,
                                        const MemoryLocation &LocB) {
  if (!EnableARCOpts)
    return AliasAnalysis::alias(LocA, LocB);

  // First, strip off no-ops, including ObjC-specific no-ops, and try making a
  // precise alias query.
  const Value *SA = GetRCIdentityRoot(LocA.Ptr);
  const Value *SB = GetRCIdentityRoot(LocB.Ptr);
  AliasResult Result =
      AliasAnalysis::alias(MemoryLocation(SA, LocA.Size, LocA.AATags),
                           MemoryLocation(SB, LocB.Size, LocB.AATags));
  if (Result != MayAlias)
    return Result;

  // If that failed, climb to the underlying object, including climbing through
  // ObjC-specific no-ops, and try making an imprecise alias query.
  const Value *UA = GetUnderlyingObjCPtr(SA, *DL);
  const Value *UB = GetUnderlyingObjCPtr(SB, *DL);
  if (UA != SA || UB != SB) {
    Result = AliasAnalysis::alias(MemoryLocation(UA), MemoryLocation(UB));
    // We can't use MustAlias or PartialAlias results here because
    // GetUnderlyingObjCPtr may return an offsetted pointer value.
    if (Result == NoAlias)
      return NoAlias;
  }

  // If that failed, fail. We don't need to chain here, since that's covered
  // by the earlier precise query.
  return MayAlias;
}

bool ObjCARCAliasAnalysis::pointsToConstantMemory(const MemoryLocation &Loc,
                                                  bool OrLocal) {
  if (!EnableARCOpts)
    return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal);

  // First, strip off no-ops, including ObjC-specific no-ops, and try making
  // a precise alias query.
  const Value *S = GetRCIdentityRoot(Loc.Ptr);
  if (AliasAnalysis::pointsToConstantMemory(
          MemoryLocation(S, Loc.Size, Loc.AATags), OrLocal))
    return true;

  // If that failed, climb to the underlying object, including climbing through
  // ObjC-specific no-ops, and try making an imprecise alias query.
  const Value *U = GetUnderlyingObjCPtr(S, *DL);
  if (U != S)
    return AliasAnalysis::pointsToConstantMemory(MemoryLocation(U), OrLocal);

  // If that failed, fail. We don't need to chain here, since that's covered
  // by the earlier precise query.
  return false;
}

FunctionModRefBehavior
ObjCARCAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
  // We have nothing to do. Just chain to the next AliasAnalysis.
  return AliasAnalysis::getModRefBehavior(CS);
}

FunctionModRefBehavior
ObjCARCAliasAnalysis::getModRefBehavior(const Function *F) {
  if (!EnableARCOpts)
    return AliasAnalysis::getModRefBehavior(F);

  switch (GetFunctionClass(F)) {
  case ARCInstKind::NoopCast:
    return FMRB_DoesNotAccessMemory;
  default:
    break;
  }

  return AliasAnalysis::getModRefBehavior(F);
}

ModRefInfo ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS,
                                               const MemoryLocation &Loc) {
  if (!EnableARCOpts)
    return AliasAnalysis::getModRefInfo(CS, Loc);

  switch (GetBasicARCInstKind(CS.getInstruction())) {
  case ARCInstKind::Retain:
  case ARCInstKind::RetainRV:
  case ARCInstKind::Autorelease:
  case ARCInstKind::AutoreleaseRV:
  case ARCInstKind::NoopCast:
  case ARCInstKind::AutoreleasepoolPush:
  case ARCInstKind::FusedRetainAutorelease:
  case ARCInstKind::FusedRetainAutoreleaseRV:
    // These functions don't access any memory visible to the compiler.
    // Note that this doesn't include objc_retainBlock, because it updates
    // pointers when it copies block data.
    return MRI_NoModRef;
  default:
    break;
  }

  return AliasAnalysis::getModRefInfo(CS, Loc);
}

ModRefInfo ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS1,
                                               ImmutableCallSite CS2) {
  // TODO: Theoretically we could check for dependencies between objc_* calls
  // and FMRB_OnlyAccessesArgumentPointees calls or other well-behaved calls.
  return AliasAnalysis::getModRefInfo(CS1, CS2);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 - 2014 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "AutoNetServer.h"
#include "Autowiring/Autowired.h"
#include "Autowiring/at_exit.h"
#include <iostream>

AutoNetServer::AutoNetServer():
  CoreThread("AutoNetServer"),
  m_Server(std::make_shared<websocketpp::server>(websocketpp::server::handler::ptr(new AutoNetServer::Handler(*this)))),
  m_Port(8000)
{
  m_Server->alog().unset_level(websocketpp::log::alevel::ALL);
  m_Server->elog().unset_level(websocketpp::log::elevel::ALL);

  for (auto type = g_pFirstEntry; type; type = type->pFlink) {
    if (type->IsEventReceiver())
      m_EventTypes.insert(type->NewTypeIdentifier());

    if (type->CanInject()){
      m_AllTypes[type->ti.name()] = [type]{
        std::cout
        << "Injecting "
        << type->ti.name()
        << " into "
        << AutoCurrentContext()->GetSigilType().name()
        << std::endl;
        type->Inject();
      };
    }
  }
}

AutoNetServer::~AutoNetServer(){}

//Core Thread methods
void AutoNetServer::Run(void){
  std::cout << "Starting Autonet server..." << std::endl;

  m_Server->start_listen(m_Port);

  auto teardown = MakeAtExit([this] {
    m_Server->close_all();
    m_Server->stop_listen(true);
  });

  PollCoreThreadUtilization(boost::chrono::milliseconds(1000));

  CoreThread::Run();
}

void AutoNetServer::OnStop(void){
  for (auto sub : m_Subscribers){
    SendMessage(sub, "Closing");
  }
  m_Server->stop();
}

// Websocket handlers
void AutoNetServer::OnOpen(connection_ptr p_connection){

  *this += [this, p_connection] {
    SendMessage(p_connection, "opened");
  };

}

void AutoNetServer::OnClose(connection_ptr p_connection){

  *this += [this, p_connection] {
    SendMessage(p_connection, "closed");
    m_Subscribers.erase(p_connection);
  };

}

void AutoNetServer::OnMessage(connection_ptr p_connection, message_ptr p_message){

  Jzon::Object msg;
  Jzon::Parser parser(msg, p_message->get_payload());
  if (!parser.Parse()) {
    std::cout << "Couldn't parse message" << std::endl;
    SendMessage(p_connection, "invalidMessage", "Couldn't parse message");
    return;
  }

  std::string msgType = msg.Get("type").ToString();
  Jzon::Array msgArgs = msg.Get("args");

  *this += [this, p_connection, msgType, msgArgs] {

    if (msgType == "subscribe") HandleSubscribe(p_connection);
    else if (msgType == "unsubscribe") HandleUnsubscribe(p_connection);
    else if (msgType == "terminateContext") HandleTerminateContext(msgArgs.Get(0).ToInt());
    else if (msgType == "injectContextMember") HandleInjectContextMember(msgArgs.Get(0).ToInt(), msgArgs.Get(1).ToString());
    else if (msgType == "resumeFromBreakpoint") HandleResumeFromBreakpoint(msgArgs.Get(0).ToString());
    else {
      SendMessage(p_connection, "invalidMessage", "Message type not recognized");
    };
  };
}

void AutoNetServer::Breakpoint(std::string name){
  boost::unique_lock<boost::mutex> lk(m_mutex);

  m_breakpoints.insert(name);

  *this += [this, name]{
    BroadcastMessage("breakpoint", name);
  };

  m_breakpoint_cv.wait(lk, [this, name]{
    return !m_breakpoints.count(name);
  });
}

// Update Functions
void AutoNetServer::NewContext(CoreContext& newCtxt){
  auto ctxt = newCtxt.shared_from_this();

  *this += [this, ctxt] {
    Jzon::Object context;
    context.Add("name", ctxt->GetSigilType().name());

    if (ctxt->GetParentContext()){
      context.Add("parent", ResolveContextID(ctxt->GetParentContext().get()));
    }

    BroadcastMessage("newContext", ResolveContextID(ctxt.get()), context);
  };
}

void AutoNetServer::ExpiredContext(CoreContext& oldCtxt){
  int id = ResolveContextID(&oldCtxt);
  *this += [this, id] {
    BroadcastMessage("expiredContext", id);
  };
}

void AutoNetServer::NewObject(CoreContext& ctxt, const AnySharedPointer& object){
  int contextID = ResolveContextID(&ctxt);

  *this += [this, object, contextID]{
    Jzon::Object objData;
    Jzon::Object types;
    std::shared_ptr<Object> objectPtr = *object;

    // Add object data
    objData.Add("name", typeid(*objectPtr).name());
    {
      Jzon::Array slots;
      for (auto slot = object->GetSlotInformation().pHead; slot; slot = slot->pFlink) {
        Jzon::Object slotData;
        slotData.Add("name", slot->type.name());
        slotData.Add("autoRequired", slot->autoRequired);
        slotData.Add("offset", int(slot->slotOffset));
        slots.Add(slotData);
      }
      objData.Add("slots", slots);
    }

    // Add type information
    auto member = leap::fast_pointer_cast<ContextMember>(objectPtr);
    if (member) {
      types.Add("contextMember", true);
    }

    auto runnable = leap::fast_pointer_cast<CoreRunnable>(objectPtr);
    if (runnable) {
      types.Add("coreRunnable", true);
    }

    auto thread = leap::fast_pointer_cast<CoreThread>(objectPtr);
    if (thread) {
      types.Add("coreThread", 0.0);
      m_CoreThreads[thread->GetSelf<CoreThread>()];
    }

    auto eventRcvr = leap::fast_pointer_cast<EventReceiver>(objectPtr);
    if (eventRcvr) {
      Jzon::Array listenerTypes;
      for (auto event : m_EventTypes) {
        if (event->Is(objectPtr.get()))
          listenerTypes.Add(event->Type().name());
      }

      types.Add("eventReceiver", listenerTypes);
    }

    auto filter = leap::fast_pointer_cast<ExceptionFilter>(objectPtr);
    if (filter) {
      types.Add("exceptionFilter", true);
    }

    auto bolt = leap::fast_pointer_cast<BoltBase>(objectPtr);
    if (bolt) {
      Jzon::Array sigils;
      for(auto cur = bolt->GetContextSigils(); *cur; cur++){
        sigils.Add((*cur)->name());
      }
      types.Add("bolt", sigils);
    }

    BroadcastMessage("newObject", contextID, types, objData);
  };

}

void AutoNetServer::EventFired(CoreContext& context, const std::type_info& info){
  int contextID = ResolveContextID(&context);
  std::string name = info.name();

  *this += [this, contextID, name] {
    Jzon::Object eventHash;
    eventHash.Add("name", name);

    BroadcastMessage("eventFired", contextID, eventHash);
  };
}

// Handler functions
void AutoNetServer::HandleSubscribe(connection_ptr p_connection){
  m_Subscribers.insert(p_connection);

  Jzon::Array types;
  for (auto type : m_AllTypes) {
    types.Add(type.first);
  }

  SendMessage(p_connection, "subscribed", types);
  AutoGlobalContext()->BuildCurrentState();

  // Send breakpoint message
  for (auto breakpoint : m_breakpoints) {
    SendMessage(p_connection, "breakpoint", breakpoint);
  }
}

void AutoNetServer::HandleUnsubscribe(connection_ptr p_connection){
  m_Subscribers.erase(p_connection);
  SendMessage(p_connection, "unsubscribed");
}

void AutoNetServer::HandleTerminateContext(int contextID) {
  ResolveContextID(contextID)->SignalShutdown();
}

void AutoNetServer::HandleInjectContextMember(int contextID, std::string typeName) {
  std::shared_ptr<CoreContext> ctxt = ResolveContextID(contextID)->shared_from_this();

  if (m_AllTypes.find(typeName) != m_AllTypes.end()) {
    CurrentContextPusher pshr(ctxt);
    m_AllTypes[typeName]();
  } else {
    // Type doesn't exist
    assert(false);
  }
}

void AutoNetServer::HandleResumeFromBreakpoint(std::string name){
  boost::unique_lock<boost::mutex> lk(m_mutex);

  m_breakpoints.erase(name);
  m_breakpoint_cv.notify_all();
}

//helper functions
int AutoNetServer::ResolveContextID(CoreContext* ctxt) {
  static int counter = 0;

  if ( m_ContextIDs.find(ctxt) == m_ContextIDs.end() ){
    m_ContextIDs[ctxt] = counter;
    m_ContextPtrs[counter] = ctxt;
    return counter++;
  } else {
    return m_ContextIDs[ctxt];
  }
}

CoreContext* AutoNetServer::ResolveContextID(int id) {
  return m_ContextPtrs.at(id);
}

void AutoNetServer::PollCoreThreadUtilization(boost::chrono::milliseconds period){
  *this += period, [this, period] {

    for(auto q = m_CoreThreads.begin(); q != m_CoreThreads.end();) {
      auto coreThread = q->first.lock();
      if(!coreThread) {
        q = m_CoreThreads.erase(q);
        continue;
      }

      // Decide whether to query creation time
      if(q->second.m_createTime == boost::chrono::system_clock::time_point::min()) {
        q->second.m_createTime = coreThread->GetCreationTime();
        if(q->second.m_createTime == boost::chrono::system_clock::time_point::min()) {
          // Thread still not running, circle around
          q++;
          continue;
        }
      }

      boost::chrono::nanoseconds runtimeKM, runtimeUM;
      coreThread->GetThreadTimes(runtimeKM, runtimeUM);

      // Determine the amount of time this thread has run since the last time we
      // asked it for its runtime.
      boost::chrono::duration<double> deltaRuntimeKM = runtimeKM - q->second.m_lastRuntimeKM;
      boost::chrono::duration<double> deltaRuntimeUM = runtimeUM - q->second.m_lastRuntimeUM;

      // Update timing values:
      q->second.m_lastRuntimeKM = runtimeKM;
      q->second.m_lastRuntimeUM = runtimeUM;

      // Broadcast current thread utilization
      int contextID = ResolveContextID(coreThread->GetContext().get());
      std::string name = typeid(*coreThread.get()).name();

      double utilization = 100 * deltaRuntimeKM / period;
      BroadcastMessage("coreThreadUtilization", contextID, name, utilization);

      // Next!
      q++;
    }

    // Poll again after "period" milliseconds
    PollCoreThreadUtilization(period);
  };
}
<commit_msg>Added user and kernal utilization bars<commit_after>// Copyright (c) 2010 - 2014 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "AutoNetServer.h"
#include "Autowiring/Autowired.h"
#include "Autowiring/at_exit.h"
#include <iostream>

AutoNetServer::AutoNetServer():
  CoreThread("AutoNetServer"),
  m_Server(std::make_shared<websocketpp::server>(websocketpp::server::handler::ptr(new AutoNetServer::Handler(*this)))),
  m_Port(8000)
{
  m_Server->alog().unset_level(websocketpp::log::alevel::ALL);
  m_Server->elog().unset_level(websocketpp::log::elevel::ALL);

  for (auto type = g_pFirstEntry; type; type = type->pFlink) {
    if (type->IsEventReceiver())
      m_EventTypes.insert(type->NewTypeIdentifier());

    if (type->CanInject()){
      m_AllTypes[type->ti.name()] = [type]{
        std::cout
        << "Injecting "
        << type->ti.name()
        << " into "
        << AutoCurrentContext()->GetSigilType().name()
        << std::endl;
        type->Inject();
      };
    }
  }
}

AutoNetServer::~AutoNetServer(){}

//Core Thread methods
void AutoNetServer::Run(void){
  std::cout << "Starting Autonet server..." << std::endl;

  m_Server->start_listen(m_Port);

  auto teardown = MakeAtExit([this] {
    m_Server->close_all();
    m_Server->stop_listen(true);
  });

  PollCoreThreadUtilization(boost::chrono::milliseconds(1000));

  CoreThread::Run();
}

void AutoNetServer::OnStop(void){
  for (auto sub : m_Subscribers){
    SendMessage(sub, "Closing");
  }
  m_Server->stop();
}

// Websocket handlers
void AutoNetServer::OnOpen(connection_ptr p_connection){

  *this += [this, p_connection] {
    SendMessage(p_connection, "opened");
  };

}

void AutoNetServer::OnClose(connection_ptr p_connection){

  *this += [this, p_connection] {
    SendMessage(p_connection, "closed");
    m_Subscribers.erase(p_connection);
  };

}

void AutoNetServer::OnMessage(connection_ptr p_connection, message_ptr p_message){

  Jzon::Object msg;
  Jzon::Parser parser(msg, p_message->get_payload());
  if (!parser.Parse()) {
    std::cout << "Couldn't parse message" << std::endl;
    SendMessage(p_connection, "invalidMessage", "Couldn't parse message");
    return;
  }

  std::string msgType = msg.Get("type").ToString();
  Jzon::Array msgArgs = msg.Get("args");

  *this += [this, p_connection, msgType, msgArgs] {

    if (msgType == "subscribe") HandleSubscribe(p_connection);
    else if (msgType == "unsubscribe") HandleUnsubscribe(p_connection);
    else if (msgType == "terminateContext") HandleTerminateContext(msgArgs.Get(0).ToInt());
    else if (msgType == "injectContextMember") HandleInjectContextMember(msgArgs.Get(0).ToInt(), msgArgs.Get(1).ToString());
    else if (msgType == "resumeFromBreakpoint") HandleResumeFromBreakpoint(msgArgs.Get(0).ToString());
    else {
      SendMessage(p_connection, "invalidMessage", "Message type not recognized");
    };
  };
}

void AutoNetServer::Breakpoint(std::string name){
  boost::unique_lock<boost::mutex> lk(m_mutex);

  m_breakpoints.insert(name);

  *this += [this, name]{
    BroadcastMessage("breakpoint", name);
  };

  m_breakpoint_cv.wait(lk, [this, name]{
    return !m_breakpoints.count(name);
  });
}

// Update Functions
void AutoNetServer::NewContext(CoreContext& newCtxt){
  auto ctxt = newCtxt.shared_from_this();

  *this += [this, ctxt] {
    Jzon::Object context;
    context.Add("name", ctxt->GetSigilType().name());

    if (ctxt->GetParentContext()){
      context.Add("parent", ResolveContextID(ctxt->GetParentContext().get()));
    }

    BroadcastMessage("newContext", ResolveContextID(ctxt.get()), context);
  };
}

void AutoNetServer::ExpiredContext(CoreContext& oldCtxt){
  int id = ResolveContextID(&oldCtxt);
  *this += [this, id] {
    BroadcastMessage("expiredContext", id);
  };
}

void AutoNetServer::NewObject(CoreContext& ctxt, const AnySharedPointer& object){
  int contextID = ResolveContextID(&ctxt);

  *this += [this, object, contextID]{
    Jzon::Object objData;
    Jzon::Object types;
    std::shared_ptr<Object> objectPtr = *object;

    // Add object data
    objData.Add("name", typeid(*objectPtr).name());
    {
      Jzon::Array slots;
      for (auto slot = object->GetSlotInformation().pHead; slot; slot = slot->pFlink) {
        Jzon::Object slotData;
        slotData.Add("name", slot->type.name());
        slotData.Add("autoRequired", slot->autoRequired);
        slotData.Add("offset", int(slot->slotOffset));
        slots.Add(slotData);
      }
      objData.Add("slots", slots);
    }

    // Add type information
    auto member = leap::fast_pointer_cast<ContextMember>(objectPtr);
    if (member) {
      types.Add("contextMember", true);
    }

    auto runnable = leap::fast_pointer_cast<CoreRunnable>(objectPtr);
    if (runnable) {
      types.Add("coreRunnable", true);
    }

    auto thread = leap::fast_pointer_cast<CoreThread>(objectPtr);
    if(thread) {
      m_CoreThreads[thread->GetSelf<CoreThread>()];

      Jzon::Object utilization;
      utilization.Add("kernel", 0.0);
      utilization.Add("user", 0.0);
      types.Add("coreThread", utilization);
    }

    auto eventRcvr = leap::fast_pointer_cast<EventReceiver>(objectPtr);
    if (eventRcvr) {
      Jzon::Array listenerTypes;
      for (auto event : m_EventTypes) {
        if (event->Is(objectPtr.get()))
          listenerTypes.Add(event->Type().name());
      }

      types.Add("eventReceiver", listenerTypes);
    }

    auto filter = leap::fast_pointer_cast<ExceptionFilter>(objectPtr);
    if (filter) {
      types.Add("exceptionFilter", true);
    }

    auto bolt = leap::fast_pointer_cast<BoltBase>(objectPtr);
    if (bolt) {
      Jzon::Array sigils;
      for(auto cur = bolt->GetContextSigils(); *cur; cur++){
        sigils.Add((*cur)->name());
      }
      types.Add("bolt", sigils);
    }

    BroadcastMessage("newObject", contextID, types, objData);
  };

}

void AutoNetServer::EventFired(CoreContext& context, const std::type_info& info){
  int contextID = ResolveContextID(&context);
  std::string name = info.name();

  *this += [this, contextID, name] {
    Jzon::Object eventHash;
    eventHash.Add("name", name);

    BroadcastMessage("eventFired", contextID, eventHash);
  };
}

// Handler functions
void AutoNetServer::HandleSubscribe(connection_ptr p_connection){
  m_Subscribers.insert(p_connection);

  Jzon::Array types;
  for (auto type : m_AllTypes) {
    types.Add(type.first);
  }

  SendMessage(p_connection, "subscribed", types);
  AutoGlobalContext()->BuildCurrentState();

  // Send breakpoint message
  for (auto breakpoint : m_breakpoints) {
    SendMessage(p_connection, "breakpoint", breakpoint);
  }
}

void AutoNetServer::HandleUnsubscribe(connection_ptr p_connection){
  m_Subscribers.erase(p_connection);
  SendMessage(p_connection, "unsubscribed");
}

void AutoNetServer::HandleTerminateContext(int contextID) {
  ResolveContextID(contextID)->SignalShutdown();
}

void AutoNetServer::HandleInjectContextMember(int contextID, std::string typeName) {
  std::shared_ptr<CoreContext> ctxt = ResolveContextID(contextID)->shared_from_this();

  if (m_AllTypes.find(typeName) != m_AllTypes.end()) {
    CurrentContextPusher pshr(ctxt);
    m_AllTypes[typeName]();
  } else {
    // Type doesn't exist
    assert(false);
  }
}

void AutoNetServer::HandleResumeFromBreakpoint(std::string name){
  boost::unique_lock<boost::mutex> lk(m_mutex);

  m_breakpoints.erase(name);
  m_breakpoint_cv.notify_all();
}

//helper functions
int AutoNetServer::ResolveContextID(CoreContext* ctxt) {
  static int counter = 0;

  if ( m_ContextIDs.find(ctxt) == m_ContextIDs.end() ){
    m_ContextIDs[ctxt] = counter;
    m_ContextPtrs[counter] = ctxt;
    return counter++;
  } else {
    return m_ContextIDs[ctxt];
  }
}

CoreContext* AutoNetServer::ResolveContextID(int id) {
  return m_ContextPtrs.at(id);
}

void AutoNetServer::PollCoreThreadUtilization(boost::chrono::milliseconds period){
  *this += period, [this, period] {

    for(auto q = m_CoreThreads.begin(); q != m_CoreThreads.end();) {
      auto coreThread = q->first.lock();
      if(!coreThread) {
        q = m_CoreThreads.erase(q);
        continue;
      }

      // Decide whether to query creation time
      if(q->second.m_createTime == boost::chrono::system_clock::time_point::min()) {
        q->second.m_createTime = coreThread->GetCreationTime();
        if(q->second.m_createTime == boost::chrono::system_clock::time_point::min()) {
          // Thread still not running, circle around
          q++;
          continue;
        }
      }

      boost::chrono::nanoseconds runtimeKM, runtimeUM;
      coreThread->GetThreadTimes(runtimeKM, runtimeUM);

      // Determine the amount of time this thread has run since the last time we
      // asked it for its runtime.
      boost::chrono::duration<double> deltaRuntimeKM = runtimeKM - q->second.m_lastRuntimeKM;
      boost::chrono::duration<double> deltaRuntimeUM = runtimeUM - q->second.m_lastRuntimeUM;

      // Update timing values:
      q->second.m_lastRuntimeKM = runtimeKM;
      q->second.m_lastRuntimeUM = runtimeUM;

      // Broadcast current thread utilization
      int contextID = ResolveContextID(coreThread->GetContext().get());
      std::string name = typeid(*coreThread.get()).name();

      double kmPercent = 100 * deltaRuntimeKM / period;
      double umPercent = 100 * deltaRuntimeUM / period;
      BroadcastMessage("coreThreadUtilization", contextID, name, kmPercent, umPercent);

      // Next!
      q++;
    }

    // Poll again after "period" milliseconds
    PollCoreThreadUtilization(period);
  };
}
<|endoftext|>


<commit_before>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <array>
#include <memory>
#include <string>
#include <vector>
#include <cassert>
#include <cstddef>
#include <exception>
#include <type_traits>

#include <windows.h>

#include "hadesmem/error.hpp"
#include "hadesmem/protect.hpp"
#include "hadesmem/detail/read_impl.hpp"
#include "hadesmem/detail/type_traits.hpp"
#include "hadesmem/detail/query_region.hpp"
#include "hadesmem/detail/protect_guard.hpp"
#include "hadesmem/detail/static_assert.hpp"

// NOTE: Reads which span across region boundaries are not explicitly handled
// or supported. They may work simply by chance (or if the user changes the
// memory page protections preemptively in preparation for the read), however
// this is not guaranteed to work, even in the aforementioned scenario.

namespace hadesmem
{

class Process;

namespace detail
{

template <typename T>
T ReadUnchecked(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  T data;
  ReadUnchecked(process, address, std::addressof(data), sizeof(data));
  return data;
}

}

template <typename T>
T Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  T data;
  detail::Read(process, address, std::addressof(data), sizeof(data));
  return data;
}

template <typename T, std::size_t N>
std::array<T, N> Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);

  std::array<T, N> data;
  detail::Read(process, address, data.data(), sizeof(T) * N);
  return data;
}

template <typename T>
std::basic_string<T> ReadString(Process const& process, PVOID address,
  std::size_t chunk_len = 128)
{
  HADESMEM_STATIC_ASSERT(detail::IsCharType<T>::value);

  assert(chunk_len != 0);

  detail::ProtectGuard protect_guard(&process, address,
    detail::ProtectGuardType::kRead);

  std::basic_string<T> data;

  MEMORY_BASIC_INFORMATION const mbi = detail::Query(process, address);
  PVOID const region_end = static_cast<PBYTE>(mbi.BaseAddress) +
    mbi.RegionSize;

  T* cur = static_cast<T*>(address);
  while (cur + 1 < region_end)
  {
    std::size_t const len_to_end = reinterpret_cast<DWORD_PTR>(region_end) -
      reinterpret_cast<DWORD_PTR>(cur);
    std::size_t const buf_len_bytes = (std::min)(chunk_len * sizeof(T),
      len_to_end);
    std::size_t const buf_len = buf_len_bytes / sizeof(T);

    std::vector<T> buf(buf_len);
    detail::ReadUnchecked(process, cur, buf.data(), buf.size() * sizeof(T));

    auto const iter = std::find(std::begin(buf), std::end(buf), T());
    std::copy(std::begin(buf), iter, std::back_inserter(data));

    if (iter != std::end(buf))
    {
      protect_guard.Restore();
      return data;
    }

    cur += buf_len;
  }

  BOOST_THROW_EXCEPTION(Error() <<
    ErrorString("Attempt to read across a region boundary."));
}

template <typename T>
std::vector<T> ReadVector(Process const& process, PVOID address,
  std::size_t size)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);

  std::vector<T> data(size);
  detail::Read(process, address, data.data(), sizeof(T) * size);
  return data;
}

}
<commit_msg>* Note to self.<commit_after>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <array>
#include <memory>
#include <string>
#include <vector>
#include <cassert>
#include <cstddef>
#include <exception>
#include <type_traits>

#include <windows.h>

#include "hadesmem/error.hpp"
#include "hadesmem/protect.hpp"
#include "hadesmem/detail/read_impl.hpp"
#include "hadesmem/detail/type_traits.hpp"
#include "hadesmem/detail/query_region.hpp"
#include "hadesmem/detail/protect_guard.hpp"
#include "hadesmem/detail/static_assert.hpp"

// NOTE: Reads which span across region boundaries are not explicitly handled
// or supported. They may work simply by chance (or if the user changes the
// memory page protections preemptively in preparation for the read), however
// this is not guaranteed to work, even in the aforementioned scenario.

namespace hadesmem
{

class Process;

namespace detail
{

template <typename T>
T ReadUnchecked(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  T data;
  ReadUnchecked(process, address, std::addressof(data), sizeof(data));
  return data;
}

}

template <typename T>
T Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  T data;
  detail::Read(process, address, std::addressof(data), sizeof(data));
  return data;
}

template <typename T, std::size_t N>
std::array<T, N> Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);

  std::array<T, N> data;
  detail::Read(process, address, data.data(), sizeof(T) * N);
  return data;
}

// TODO: Clean up this function.
template <typename T>
std::basic_string<T> ReadString(Process const& process, PVOID address,
  std::size_t chunk_len = 128)
{
  HADESMEM_STATIC_ASSERT(detail::IsCharType<T>::value);

  assert(chunk_len != 0);

  detail::ProtectGuard protect_guard(&process, address,
    detail::ProtectGuardType::kRead);

  std::basic_string<T> data;

  MEMORY_BASIC_INFORMATION const mbi = detail::Query(process, address);
  PVOID const region_end = static_cast<PBYTE>(mbi.BaseAddress) +
    mbi.RegionSize;

  T* cur = static_cast<T*>(address);
  while (cur + 1 < region_end)
  {
    std::size_t const len_to_end = reinterpret_cast<DWORD_PTR>(region_end) -
      reinterpret_cast<DWORD_PTR>(cur);
    std::size_t const buf_len_bytes = (std::min)(chunk_len * sizeof(T),
      len_to_end);
    std::size_t const buf_len = buf_len_bytes / sizeof(T);

    std::vector<T> buf(buf_len);
    detail::ReadUnchecked(process, cur, buf.data(), buf.size() * sizeof(T));

    auto const iter = std::find(std::begin(buf), std::end(buf), T());
    std::copy(std::begin(buf), iter, std::back_inserter(data));

    if (iter != std::end(buf))
    {
      protect_guard.Restore();
      return data;
    }

    cur += buf_len;
  }

  BOOST_THROW_EXCEPTION(Error() <<
    ErrorString("Attempt to read across a region boundary."));
}

template <typename T>
std::vector<T> ReadVector(Process const& process, PVOID address,
  std::size_t size)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);

  std::vector<T> data(size);
  detail::Read(process, address, data.data(), sizeof(T) * size);
  return data;
}

}
<|endoftext|>


<commit_before>//
// Copyright Antoine Leblanc 2010 - 2015
// Distributed under the MIT license.
//
// http://nauths.fr
// http://github.com/nicuveo
// mailto://antoine.jp.leblanc@gmail.com
//

#ifndef SAW_STATEMENT_HXX_
# define SAW_STATEMENT_HXX_

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Includes

# include <nauths/saw/statement.hh>

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Implementation

namespace saw
{

  // accessors

  inline bool
  Statement::busy() const
  {
    return empty() ? true : sqlite3_stmt_busy(raw_data()) != 0;
  }

  inline bool
  Statement::ready() const
  {
    return empty() ? false : sqlite3_stmt_busy(raw_data()) == 0;
  }

  inline bool
  Statement::empty() const
  {
    return not bool(*this);
  }

  inline Database
  Statement::database() const
  {
    return db_;
  }

  // parameter binding

  inline Statement::Proxy
  Statement::operator[](const ParameterKey& key)
  {
    using namespace std::placeholders;
    return Proxy(std::bind(static_cast<Statement& (Statement::*)(const ParameterKey&, const Value&)>(&Statement::bind), this, key, _1));
  }

  inline Statement::Proxy
  Statement::operator[](const ParameterName& name)
  {
    using namespace std::placeholders;
    return Proxy(std::bind(static_cast<Statement& (Statement::*)(const ParameterName&, const Value&)>(&Statement::bind), this, name, _1));
  }

  inline Statement::Proxy
  Statement::operator[](const ParameterIndex& index)
  {
    using namespace std::placeholders;
    return Proxy(std::bind(static_cast<Statement& (Statement::*)(const ParameterIndex&, const Value&)>(&Statement::bind), this, index, _1));
  }

  inline Statement&
  operator<<(Statement& stmt, const Parameter& p)
  {
    return stmt.bind(p);
  }

  inline Statement&
  operator<<(Statement& stmt, const Parameters& p)
  {
    return stmt.bind(p);
  }

  inline Statement&
  Statement::bind(const Parameter& p)
  {
    return bind(p.first, p.second);
  }

  // execution

  inline void
  Statement::exec(const RowCallback& rcb, const Parameters& ps)
  {
    return bind(ps).exec(rcb);
  }

}

#endif /* !SAW_STATEMENT_HXX_ */
<commit_msg>Fixed issue with placeholders.<commit_after>//
// Copyright Antoine Leblanc 2010 - 2015
// Distributed under the MIT license.
//
// http://nauths.fr
// http://github.com/nicuveo
// mailto://antoine.jp.leblanc@gmail.com
//

#ifndef SAW_STATEMENT_HXX_
# define SAW_STATEMENT_HXX_

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Includes

# include <nauths/saw/statement.hh>

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Implementation

namespace saw
{

  // accessors

  inline bool
  Statement::busy() const
  {
    return empty() ? true : sqlite3_stmt_busy(raw_data()) != 0;
  }

  inline bool
  Statement::ready() const
  {
    return empty() ? false : sqlite3_stmt_busy(raw_data()) == 0;
  }

  inline bool
  Statement::empty() const
  {
    return not bool(*this);
  }

  inline Database
  Statement::database() const
  {
    return db_;
  }

  // parameter binding

  inline Statement::Proxy
  Statement::operator[](const ParameterKey& key)
  {
    typedef Statement& (Statement::* Fun)(const ParameterKey&, const Value&);
    return Proxy(std::bind(static_cast<Fun>(&Statement::bind), this, key, std::placeholders::_1));
  }

  inline Statement::Proxy
  Statement::operator[](const ParameterName& name)
  {
    typedef Statement& (Statement::* Fun)(const ParameterName&, const Value&);
    return Proxy(std::bind(static_cast<Fun>(&Statement::bind), this, name, std::placeholders::_1));
  }

  inline Statement::Proxy
  Statement::operator[](const ParameterIndex& index)
  {
    typedef Statement& (Statement::* Fun)(const ParameterIndex&, const Value&);
    return Proxy(std::bind(static_cast<Fun>(&Statement::bind), this, index, std::placeholders::_1));
  }

  inline Statement&
  operator<<(Statement& stmt, const Parameter& p)
  {
    return stmt.bind(p);
  }

  inline Statement&
  operator<<(Statement& stmt, const Parameters& p)
  {
    return stmt.bind(p);
  }

  inline Statement&
  Statement::bind(const Parameter& p)
  {
    return bind(p.first, p.second);
  }

  // execution

  inline void
  Statement::exec(const RowCallback& rcb, const Parameters& ps)
  {
    return bind(ps).exec(rcb);
  }

}

#endif /* !SAW_STATEMENT_HXX_ */
<|endoftext|>


<commit_before><commit_msg>Change Windows ItoA calls into std::to_string() (#36)<commit_after><|endoftext|>


<commit_before>// Time:  O(n^4)
// Space: O(n^2)

class Solution {
public:
    vector<string> ambiguousCoordinates(string S) {
        vector<string> result;
        for (int i = 1; i < S.length() - 2; ++i) {
            const auto& lefts = make(S, 1, i);
            const auto& rights = make(S, i + 1, S.length() - 2 - i);
            for (const auto& left : lefts) {
                for (const auto& right : rights) {
                    string s;
                    s += "(";
                    s += left;
                    s += ", ";
                    s += right;
                    s += ")";
                    result.emplace_back(move(s));
                }
            }
        }
        return result;
    }

private:
    // Time:  O(n^2)
    // Space: O(n^2)
    vector<string> make(const string& S, int i, int n) {
        vector<string> result;
        for (int d = 1; d <= n; ++d) {
            const auto& left = S.substr(i, d);
            const auto& right = S.substr(i + d, n - d);
            if ((left.front() != '0' || left == "0") &&
                 right.back() != '0') {
                string s;
                s += left;
                s += (d < n ? "." : "");
                s += right;
                result.emplace_back(move(s));
            }
        }
        return result;
    }
};
<commit_msg>Update ambiguous-coordinates.cpp<commit_after>// Time:  O(n^4)
// Space: O(n^2)

class Solution {
public:
    vector<string> ambiguousCoordinates(string S) {
        vector<string> result;
        for (int i = 1; i < S.length() - 2; ++i) {
            const auto& lefts = make(S, 1, i);
            const auto& rights = make(S, i + 1, S.length() - 2 - i);
            for (const auto& left : lefts) {
                for (const auto& right : rights) {
                    string s;
                    s += "(";
                    s += left;
                    s += ", ";
                    s += right;
                    s += ")";
                    result.emplace_back(move(s));
                }
            }
        }
        return result;
    }

private:
    // Time:  O(n^2)
    // Space: O(n^2)
    vector<string> make(const string& S, int i, int n) {
        vector<string> result;
        for (int d = 1; d <= n; ++d) {
            const auto& left = S.substr(i, d);
            const auto& right = S.substr(i + d, n - d);
            if ((left.front() != '0' || left == "0") &&
                 right.back() != '0') {
                string s;
                s += left;
                s += (!right.empty() ? "." : "");
                s += right;
                result.emplace_back(move(s));
            }
        }
        return result;
    }
};
<|endoftext|>


<commit_before>// Time:  O(n!)
// Space: O(n)

class Solution {
public:
    vector<string> findItinerary(vector<pair<string, string>> tickets) {
        unordered_map<string, map<string, int>> graph;
        for (const auto& ticket : tickets) {
            ++graph[ticket.first][ticket.second];
        }
        const string start = "JFK";
        vector<string> ans{start};
        routeHelper(start, tickets.size(), &graph, &ans);
        return ans;
    }

private:
    bool routeHelper(const string& start, const int size,
             unordered_map<string, map<string, int>> *graph, vector<string> *ans) {

        if (size == 0) {
            return true;
        }

        for (const auto& neighbor : (*graph)[start]) {
            if ((*graph)[start][neighbor.first]) {
                --(*graph)[start][neighbor.first];
                ans->emplace_back(neighbor.first);
                if (dfs(neighbor.first, size - 1, graph, ans)) {
                    return true;
                }
                ans->pop_back();
                ++(*graph)[start][neighbor.first];
            }
        }
        return false;
    }
};
<commit_msg>Update reconstruct-itinerary.cpp<commit_after>// Time:  O(n!)
// Space: O(n)

class Solution {
public:
    vector<string> findItinerary(vector<pair<string, string>> tickets) {
        unordered_map<string, map<string, int>> graph;
        for (const auto& ticket : tickets) {
            ++graph[ticket.first][ticket.second];
        }
        const string start = "JFK";
        vector<string> ans{start};
        routeHelper(start, tickets.size(), &graph, &ans);
        return ans;
    }

private:
    bool routeHelper(const string& start, const int size,
             unordered_map<string, map<string, int>> *graph, vector<string> *ans) {

        if (size == 0) {
            return true;
        }

        for (const auto& neighbor : (*graph)[start]) {
            if ((*graph)[start][neighbor.first]) {
                --(*graph)[start][neighbor.first];
                ans->emplace_back(neighbor.first);
                if (routeHelper(neighbor.first, size - 1, graph, ans)) {
                    return true;
                }
                ans->pop_back();
                ++(*graph)[start][neighbor.first];
            }
        }
        return false;
    }
};
<|endoftext|>


<commit_before>#pragma once

#include "Communicator.hpp"
#include "CompletionEvent.hpp"
#include "Tasking.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "Delegate.hpp"
#include "Collective.hpp"
#include "Timestamp.hpp"
#include <type_traits>

namespace Grappa {

/// GlobalCompletionEvent (GCE):
/// Synchronization construct for determining when a global phase of asynchronous tasks have all completed.
/// For example, can be used to ensure that all tasks of a parallel loop have completed, including tasks or asynchronous delegates spawned during execution of the parallel loop.
///
/// A GlobalCompletionEvent must be replicated at the same address on all cores (the easiest way is to declare it as file-global or static storage).
///
/// Anyone calling "wait" after at least some work has been "enrolled" globally will block. When *all* work has been completed on all cores, all tasks waiting on the GCE will be woken.
///
/// To ensure consistent behavior and guarantee deadlock freedom, every "enroll" must be causally followed by "complete", so either must be completed from the same task that called "enroll" or from a task spawned (transitively) from the enrolling task.
class GlobalCompletionEvent : public CompletionEvent {
  // All nodes
  // (count)
  // (cv)
  bool event_in_progress;
  Core master_core;

  // Master barrier only
  Core cores_out;

  /// pointer to shared arg for loops that use a GCE
  const void * shared_ptr;

public:

  GlobalCompletionEvent(): master_core(0) { reset(); }

  inline void set_shared_ptr(const void* p) { shared_ptr = p; }
  template<typename T> inline const T* get_shared_ptr() { return reinterpret_cast<const T*>(shared_ptr); }

  /// SPMD (either all cores call this following a barrier, or use `reset_all` from one task,
  /// then spawn parallel work)
  void reset() {
    count = 0;
    cv.waiters_ = 0;
    cores_out = 0;
    event_in_progress = false;
  }

  /// Called from single task (probably `user_main`).
  void reset_all() {
    call_on_all_cores([this]{ reset(); });
  }

  /// Enroll more things that need to be completed before the global completion is, well, complete.
  /// This will send a cancel to the master if this core previously entered the cancellable barrier.
  ///
  /// Blocks until cancel completes (if it must cancel) to ensure correct ordering, therefore
  /// cannot be called from message handler (but I don't think we ever do).
  void enroll(int64_t inc = 1) {
    if (inc == 0) return;

    CHECK_GE(inc, 1);
    count += inc;

    // first one to have work here
    if (count == inc) { // count[0 -> inc]
      event_in_progress = true; // optimization to save checking in wait()
      // cancel barrier
      Core co = delegate::call(master_core, [this] {
        cores_out++;
        return cores_out;
      });
      // first one to cancel barrier should make sure other cores are ready to wait
      if (co == 1) { // cores_out[0 -> 1]
        event_in_progress = true;
        call_on_all_cores([this] {
          event_in_progress = true;
        });
        CHECK(event_in_progress);
      }
      // block until cancelled
      CHECK_GT(count, 0);
      VLOG(2) << "cores_out: " << co << ", count: " << count;
    }
  }

  /// Mark a certain number of things completed. When the global count on all cores goes to 0, all
  /// tasks waiting on the GCE will be woken.
  ///
  /// Note: this can be called in a message handler (e.g. remote completes from stolen tasks).
  void complete(int64_t dec = 1) {
    count -= dec;
    DVLOG(4) << "complete (" << count << ") -- " << this;

    // out of work here
    if (count == 0) { // count[dec -> 0]
      // enter cancellable barrier
      send_heap_message(master_core, [this] {
        cores_out--;

        // if all are in
        if (cores_out == 0) { // cores_out[1 -> 0]
          CHECK_EQ(count, 0);
          // notify everyone to wake
          for (Core c = 0; c < cores(); c++) {
            send_heap_message(c, [this] {
              CHECK_EQ(count, 0);
              broadcast(&cv); // wake anyone who was waiting here
              reset(); // reset, now anyone else calling `wait` should fall through
            });
          }
        }
      });
    }
  }

  void wait() {
    VLOG(3) << "wait(): event_in_progress: " << event_in_progress << ", count: " << count;
    if (event_in_progress) {
      Grappa::wait(&cv);
    } else {
      // conservative check, in case we're calling `wait` without calling `enroll`
      if (delegate::call(master_core, [this]{ return cores_out; }) > 0) {
//      if (delegate::call(master_core, [this]{ return event_in_progress; })) {
        Grappa::wait(&cv);
        VLOG(3) << "woke from conservative check";
      }
      VLOG(3) << "fell thru conservative check";
    }
    CHECK(!event_in_progress);
    CHECK_EQ(count, 0);
  }

};

} // namespace Grappa

/// Synchronizing delegates
namespace Grappa {
  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  template<typename TF>
  void privateTask(GlobalCompletionEvent * gce, TF tf) {
    gce->enroll();
    privateTask([gce,tf] {
      tf();
      gce->complete();
    });
  }

  /// Synchronizing public task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// sends `complete`  message when done (if GCE is non-null).
  template<GlobalCompletionEvent * GCE, typename TF>
  inline void publicTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    publicTask([origin,tf] {
      tf();
      if (GCE) complete(make_global(GCE,origin));
    });
  }
} // namespace Grappa
<commit_msg>Add templated version of privateTask spawn that syncs with GCE.<commit_after>#pragma once

#include "Communicator.hpp"
#include "CompletionEvent.hpp"
#include "Tasking.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "Delegate.hpp"
#include "Collective.hpp"
#include "Timestamp.hpp"
#include <type_traits>

namespace Grappa {

/// GlobalCompletionEvent (GCE):
/// Synchronization construct for determining when a global phase of asynchronous tasks have all completed.
/// For example, can be used to ensure that all tasks of a parallel loop have completed, including tasks or asynchronous delegates spawned during execution of the parallel loop.
///
/// A GlobalCompletionEvent must be replicated at the same address on all cores (the easiest way is to declare it as file-global or static storage).
///
/// Anyone calling "wait" after at least some work has been "enrolled" globally will block. When *all* work has been completed on all cores, all tasks waiting on the GCE will be woken.
///
/// To ensure consistent behavior and guarantee deadlock freedom, every "enroll" must be causally followed by "complete", so either must be completed from the same task that called "enroll" or from a task spawned (transitively) from the enrolling task.
class GlobalCompletionEvent : public CompletionEvent {
  // All nodes
  // (count)
  // (cv)
  bool event_in_progress;
  Core master_core;

  // Master barrier only
  Core cores_out;

  /// pointer to shared arg for loops that use a GCE
  const void * shared_ptr;

public:

  GlobalCompletionEvent(): master_core(0) { reset(); }

  inline void set_shared_ptr(const void* p) { shared_ptr = p; }
  template<typename T> inline const T* get_shared_ptr() { return reinterpret_cast<const T*>(shared_ptr); }

  /// SPMD (either all cores call this following a barrier, or use `reset_all` from one task,
  /// then spawn parallel work)
  void reset() {
    count = 0;
    cv.waiters_ = 0;
    cores_out = 0;
    event_in_progress = false;
  }

  /// Called from single task (probably `user_main`).
  void reset_all() {
    call_on_all_cores([this]{ reset(); });
  }

  /// Enroll more things that need to be completed before the global completion is, well, complete.
  /// This will send a cancel to the master if this core previously entered the cancellable barrier.
  ///
  /// Blocks until cancel completes (if it must cancel) to ensure correct ordering, therefore
  /// cannot be called from message handler (but I don't think we ever do).
  void enroll(int64_t inc = 1) {
    if (inc == 0) return;

    CHECK_GE(inc, 1);
    count += inc;

    // first one to have work here
    if (count == inc) { // count[0 -> inc]
      event_in_progress = true; // optimization to save checking in wait()
      // cancel barrier
      Core co = delegate::call(master_core, [this] {
        cores_out++;
        return cores_out;
      });
      // first one to cancel barrier should make sure other cores are ready to wait
      if (co == 1) { // cores_out[0 -> 1]
        event_in_progress = true;
        call_on_all_cores([this] {
          event_in_progress = true;
        });
        CHECK(event_in_progress);
      }
      // block until cancelled
      CHECK_GT(count, 0);
      VLOG(2) << "cores_out: " << co << ", count: " << count;
    }
  }

  /// Mark a certain number of things completed. When the global count on all cores goes to 0, all
  /// tasks waiting on the GCE will be woken.
  ///
  /// Note: this can be called in a message handler (e.g. remote completes from stolen tasks).
  void complete(int64_t dec = 1) {
    count -= dec;
    DVLOG(4) << "complete (" << count << ") -- " << this;

    // out of work here
    if (count == 0) { // count[dec -> 0]
      // enter cancellable barrier
      send_heap_message(master_core, [this] {
        cores_out--;

        // if all are in
        if (cores_out == 0) { // cores_out[1 -> 0]
          CHECK_EQ(count, 0);
          // notify everyone to wake
          for (Core c = 0; c < cores(); c++) {
            send_heap_message(c, [this] {
              CHECK_EQ(count, 0);
              broadcast(&cv); // wake anyone who was waiting here
              reset(); // reset, now anyone else calling `wait` should fall through
            });
          }
        }
      });
    }
  }

  void wait() {
    VLOG(3) << "wait(): event_in_progress: " << event_in_progress << ", count: " << count;
    if (event_in_progress) {
      Grappa::wait(&cv);
    } else {
      // conservative check, in case we're calling `wait` without calling `enroll`
      if (delegate::call(master_core, [this]{ return cores_out; }) > 0) {
//      if (delegate::call(master_core, [this]{ return event_in_progress; })) {
        Grappa::wait(&cv);
        VLOG(3) << "woke from conservative check";
      }
      VLOG(3) << "fell thru conservative check";
    }
    CHECK(!event_in_progress);
    CHECK_EQ(count, 0);
  }

};

} // namespace Grappa

/// Synchronizing delegates
namespace Grappa {
  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  template<typename TF>
  void privateTask(GlobalCompletionEvent * gce, TF tf) {
    gce->enroll();
    privateTask([gce,tf] {
      tf();
      gce->complete();
    });
  }

  template<GlobalCompletionEvent * GCE, typename TF>
  void privateTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    privateTask([tf] {
      tf();
      if (GCE) GCE->complete();
    });
  }

  /// Synchronizing public task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// sends `complete`  message when done (if GCE is non-null).
  template<GlobalCompletionEvent * GCE, typename TF>
  inline void publicTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    publicTask([origin,tf] {
      tf();
      if (GCE) complete(make_global(GCE,origin));
    });
  }

} // namespace Grappa
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "msg/SimpleMessenger.h"
#include "messages/MMonGetMap.h"
#include "messages/MMonMap.h"
#include "messages/MClientMount.h"

#include "include/nstring.h"

#include "messages/MClientMountAck.h"
#include "messages/MMonSubscribe.h"
#include "messages/MMonSubscribeAck.h"
#include "common/ConfUtils.h"

#include "MonClient.h"
#include "MonMap.h"

#include "config.h"

#define DOUT_SUBSYS monc
#undef dout_prefix
#define dout_prefix *_dout << dbeginl << "monclient: "

/*
 * build an initial monmap with any known monitor
 * addresses.
 */
int MonClient::build_initial_monmap()
{
  // file?
  if (g_conf.monmap) {
    const char *monmap_fn = g_conf.monmap;
    int r = monmap.read(monmap_fn);
    if (r >= 0)
      return 0;
    char buf[80];
    cerr << "unable to read monmap from " << monmap_fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl;
  }

  // -m foo?
  if (g_conf.mon_host) {
    vector<entity_addr_t> addrs;
    if (parse_ip_port_vec(g_conf.mon_host, addrs)) {
      for (unsigned i=0; i<addrs.size(); i++) {
	entity_inst_t inst;
	inst.name = entity_name_t::MON(i);
	inst.addr = addrs[i];
	monmap.add_mon(inst);
      }
      return 0;
    }
    cerr << "unable to parse addrs in '" << g_conf.mon_host << "'" << std::endl;
  }

  // config file?
  ConfFile a(g_conf.conf);
  ConfFile b("ceph.conf");
  ConfFile *c = 0;

  if (a.parse())
    c = &a;
  else if (b.parse())
    c = &b;
  if (c) {
    static string monstr;
    for (int i=0; i<15; i++) {
      char monname[20];
      char *val = 0;
      sprintf(monname, "mon%d", i);
      c->read(monname, "mon addr", &val, 0);
      if (!val || !val[0])
	break;

      entity_inst_t inst;
      if (!parse_ip_port(val, inst.addr)) {
	cerr << "unable to parse conf's addr for " << monname << " (" << val << ")" << std::endl;
	continue;
      }
      inst.name = entity_name_t::MON(monmap.mon_inst.size());
      monmap.add_mon(inst);
    }
    if (monmap.size())
      return 0;
    cerr << "unable to find any monitors in conf" << std::endl;
    return -EINVAL;
  }

  cerr << "please specify monitors via -m monaddr or -c ceph.conf" << std::endl;
  return -ENOENT;
}

int MonClient::get_monmap()
{
  dout(10) << "get_monmap" << dendl;
  Mutex::Locker l(monc_lock);

  want_monmap = true;
  if (cur_mon < 0)
    _reopen_session();

  while (want_monmap)
    map_cond.Wait(monc_lock);

  dout(10) << "get_monmap done" << dendl;

  return 0;
}

int MonClient::get_monmap_privately()
{
  dout(10) << "get_monmap_privately" << dendl;
  Mutex::Locker l(monc_lock);

  SimpleMessenger *rank = NULL;
  bool temp_msgr = false;
  if (!messenger) {
    rank = new SimpleMessenger;
    rank->bind();
    rank->set_policy(entity_name_t::TYPE_MON, SimpleMessenger::Policy::lossy_fast_fail());
    messenger = rank->register_entity(entity_name_t::CLIENT(-1));
    messenger->add_dispatcher_head(this);
    rank->start(true);  // do not daemonize!
    temp_msgr = true;
  }

  int attempt = 10;
  int i = 0;
  srand(getpid());

  dout(10) << "have " << monmap.epoch << dendl;

  while (monmap.epoch == 0) {
    i = rand() % monmap.mon_inst.size();
    dout(10) << "querying " << monmap.mon_inst[i] << dendl;
    messenger->send_message(new MMonGetMap, monmap.mon_inst[i]);

    if (--attempt == 0)
      break;

    utime_t interval(1, 0);
    map_cond.WaitInterval(monc_lock, interval);
  }

  if (temp_msgr) {
    messenger->shutdown();
    rank->wait();
    messenger->destroy();
    messenger = 0;
  }

  if (monmap.epoch)
    return 0;
  return -1;
}

bool MonClient::ms_dispatch(Message *m)
{
  dout(10) << "dispatch " << *m << dendl;

  if (my_addr == entity_addr_t())
    my_addr = messenger->get_myaddr();

  switch (m->get_type()) {
  case CEPH_MSG_MON_MAP:
    handle_monmap((MMonMap*)m);
    return true;

  case CEPH_MSG_CLIENT_MOUNT_ACK:
    handle_mount_ack((MClientMountAck*)m);
    return true;

  case CEPH_MSG_MON_SUBSCRIBE_ACK:
    handle_subscribe_ack((MMonSubscribeAck*)m);
    return true;
  }

  return false;
}

void MonClient::handle_monmap(MMonMap *m)
{
  dout(10) << "handle_monmap " << *m << dendl;
  monc_lock.Lock();

  _finish_hunting();

  bufferlist::iterator p = m->monmapbl.begin();
  ::decode(monmap, p);

  _sub_got("monmap", monmap.get_epoch());

  map_cond.Signal();
  want_monmap = false;

  monc_lock.Unlock();
  delete m;
}

// -------------------
// MOUNT

void MonClient::_send_mount()
{
  dout(10) << "_send_mount" << dendl;
  _send_mon_message(new MClientMount);
  mount_started = g_clock.now();
}

void MonClient::init()
{
  dout(10) << "init" << dendl;
  messenger->add_dispatcher_head(this);

  Mutex::Locker l(monc_lock);
  timer.add_event_after(10.0, new C_Tick(this));
}

void MonClient::shutdown()
{
  timer.cancel_all_events();
}

int MonClient::mount(double mount_timeout)
{
  Mutex::Locker lock(monc_lock);

  if (clientid >= 0) {
    dout(5) << "already mounted" << dendl;;
    return 0;
  }

  // only first mounter does the work
  mounting++;
  if (mounting == 1) {
    if (cur_mon < 0)
      _reopen_session();
    else
      _send_mount();
  }
  while (clientid < 0 && !mount_err)
    mount_cond.Wait(monc_lock);
  mounting--;

  if (clientid >= 0) {
    dout(5) << "mount success, client" << clientid << dendl;

    _sub_want("monmap", monmap.get_epoch());
  }

  return mount_err;
}

void MonClient::handle_mount_ack(MClientMountAck* m)
{
  dout(10) << "handle_mount_ack " << *m << dendl;

  _finish_hunting();

  if (m->result) {
    mount_err = m->result;
    dout(0) << "mount error " << m->result << " (" << m->result_msg << ")" << dendl;
  } else {
    // monmap
    bufferlist::iterator p = m->monmap_bl.begin();
    ::decode(monmap, p);

    clientid = m->client;
    messenger->set_myname(entity_name_t::CLIENT(m->client.v));
  }

  mount_cond.SignalAll();

  delete m;
}

// ---------

void MonClient::_send_mon_message(Message *m)
{
  assert(cur_mon >= 0);
  messenger->send_message(m, monmap.mon_inst[cur_mon]);
}

void MonClient::_pick_new_mon()
{
  if (cur_mon >= 0)
    messenger->mark_down(monmap.get_inst(cur_mon).addr);
  cur_mon = monmap.pick_mon(true);
  dout(10) << "_pick_new_mon picked mon" << cur_mon << dendl;
}

void MonClient::_reopen_session()
{
  dout(10) << "_reopen_session" << dendl;
  _pick_new_mon();
  if (mounting)
    _send_mount();
  if (!sub_have.empty())
    _renew_subs();
  if (!mounting && sub_have.empty()) {
    _send_mon_message(new MMonGetMap);
  }
}

bool MonClient::ms_handle_reset(Connection *con, const entity_addr_t& peer)
{
  dout(10) << "ms_handle_reset " << peer << dendl;
  if (hunting)
    return true;

  dout(0) << "hunting for new mon" << dendl;
  hunting = true;
  _reopen_session();
  return false;
}

void MonClient::_finish_hunting()
{
  if (hunting) {
    dout(0) << "found mon" << cur_mon << dendl;
    hunting = false;
  }
}

void MonClient::tick()
{
  dout(10) << "tick" << dendl;

  if (hunting) {
    dout(0) << "continuing hunt" << dendl;
    _reopen_session();
  } else {
    // just renew as needed
    utime_t now = g_clock.now();
    if (now > sub_renew_after)
      _renew_subs();

    int oldmon = monmap.pick_mon();
    messenger->send_keepalive(monmap.mon_inst[oldmon]);
  }

  timer.add_event_after(10.0, new C_Tick(this));
}

// ---------

void MonClient::_renew_subs()
{
  if (sub_have.empty()) {
    dout(10) << "renew_subs - empty" << dendl;
    return;
  }

  dout(10) << "renew_subs" << dendl;
  if (cur_mon < 0)
    _reopen_session();
  else {
    if (sub_renew_sent == utime_t())
      sub_renew_sent = g_clock.now();

    MMonSubscribe *m = new MMonSubscribe;
    m->what = sub_have;
    _send_mon_message(m);
  }
}

void MonClient::handle_subscribe_ack(MMonSubscribeAck *m)
{
  _finish_hunting();

  if (sub_renew_sent != utime_t()) {
    sub_renew_after = sub_renew_sent;
    sub_renew_after += m->interval / 2.0;
    dout(10) << "handle_subscribe_ack sent " << sub_renew_sent << " renew after " << sub_renew_after << dendl;
    sub_renew_sent = utime_t();
  } else {
    dout(10) << "handle_subscribe_ack sent " << sub_renew_sent << ", ignoring" << dendl;
  }
}

<commit_msg>monc: no msgr bind needed<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "msg/SimpleMessenger.h"
#include "messages/MMonGetMap.h"
#include "messages/MMonMap.h"
#include "messages/MClientMount.h"

#include "include/nstring.h"

#include "messages/MClientMountAck.h"
#include "messages/MMonSubscribe.h"
#include "messages/MMonSubscribeAck.h"
#include "common/ConfUtils.h"

#include "MonClient.h"
#include "MonMap.h"

#include "config.h"

#define DOUT_SUBSYS monc
#undef dout_prefix
#define dout_prefix *_dout << dbeginl << "monclient: "

/*
 * build an initial monmap with any known monitor
 * addresses.
 */
int MonClient::build_initial_monmap()
{
  // file?
  if (g_conf.monmap) {
    const char *monmap_fn = g_conf.monmap;
    int r = monmap.read(monmap_fn);
    if (r >= 0)
      return 0;
    char buf[80];
    cerr << "unable to read monmap from " << monmap_fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl;
  }

  // -m foo?
  if (g_conf.mon_host) {
    vector<entity_addr_t> addrs;
    if (parse_ip_port_vec(g_conf.mon_host, addrs)) {
      for (unsigned i=0; i<addrs.size(); i++) {
	entity_inst_t inst;
	inst.name = entity_name_t::MON(i);
	inst.addr = addrs[i];
	monmap.add_mon(inst);
      }
      return 0;
    }
    cerr << "unable to parse addrs in '" << g_conf.mon_host << "'" << std::endl;
  }

  // config file?
  ConfFile a(g_conf.conf);
  ConfFile b("ceph.conf");
  ConfFile *c = 0;

  if (a.parse())
    c = &a;
  else if (b.parse())
    c = &b;
  if (c) {
    static string monstr;
    for (int i=0; i<15; i++) {
      char monname[20];
      char *val = 0;
      sprintf(monname, "mon%d", i);
      c->read(monname, "mon addr", &val, 0);
      if (!val || !val[0])
	break;

      entity_inst_t inst;
      if (!parse_ip_port(val, inst.addr)) {
	cerr << "unable to parse conf's addr for " << monname << " (" << val << ")" << std::endl;
	continue;
      }
      inst.name = entity_name_t::MON(monmap.mon_inst.size());
      monmap.add_mon(inst);
    }
    if (monmap.size())
      return 0;
    cerr << "unable to find any monitors in conf" << std::endl;
    return -EINVAL;
  }

  cerr << "please specify monitors via -m monaddr or -c ceph.conf" << std::endl;
  return -ENOENT;
}

int MonClient::get_monmap()
{
  dout(10) << "get_monmap" << dendl;
  Mutex::Locker l(monc_lock);

  want_monmap = true;
  if (cur_mon < 0)
    _reopen_session();

  while (want_monmap)
    map_cond.Wait(monc_lock);

  dout(10) << "get_monmap done" << dendl;

  return 0;
}

int MonClient::get_monmap_privately()
{
  dout(10) << "get_monmap_privately" << dendl;
  Mutex::Locker l(monc_lock);

  SimpleMessenger *rank = NULL;
  bool temp_msgr = false;
  if (!messenger) {
    rank = new SimpleMessenger;
    rank->set_policy(entity_name_t::TYPE_MON, SimpleMessenger::Policy::lossy_fast_fail());
    messenger = rank->register_entity(entity_name_t::CLIENT(-1));
    messenger->add_dispatcher_head(this);
    rank->start(true);  // do not daemonize!
    temp_msgr = true;
  }

  int attempt = 10;
  int i = 0;
  srand(getpid());

  dout(10) << "have " << monmap.epoch << dendl;

  while (monmap.epoch == 0) {
    i = rand() % monmap.mon_inst.size();
    dout(10) << "querying " << monmap.mon_inst[i] << dendl;
    messenger->send_message(new MMonGetMap, monmap.mon_inst[i]);

    if (--attempt == 0)
      break;

    utime_t interval(1, 0);
    map_cond.WaitInterval(monc_lock, interval);
  }

  if (temp_msgr) {
    messenger->shutdown();
    rank->wait();
    messenger->destroy();
    messenger = 0;
  }

  if (monmap.epoch)
    return 0;
  return -1;
}

bool MonClient::ms_dispatch(Message *m)
{
  dout(10) << "dispatch " << *m << dendl;

  if (my_addr == entity_addr_t())
    my_addr = messenger->get_myaddr();

  switch (m->get_type()) {
  case CEPH_MSG_MON_MAP:
    handle_monmap((MMonMap*)m);
    return true;

  case CEPH_MSG_CLIENT_MOUNT_ACK:
    handle_mount_ack((MClientMountAck*)m);
    return true;

  case CEPH_MSG_MON_SUBSCRIBE_ACK:
    handle_subscribe_ack((MMonSubscribeAck*)m);
    return true;
  }

  return false;
}

void MonClient::handle_monmap(MMonMap *m)
{
  dout(10) << "handle_monmap " << *m << dendl;
  monc_lock.Lock();

  _finish_hunting();

  bufferlist::iterator p = m->monmapbl.begin();
  ::decode(monmap, p);

  _sub_got("monmap", monmap.get_epoch());

  map_cond.Signal();
  want_monmap = false;

  monc_lock.Unlock();
  delete m;
}

// -------------------
// MOUNT

void MonClient::_send_mount()
{
  dout(10) << "_send_mount" << dendl;
  _send_mon_message(new MClientMount);
  mount_started = g_clock.now();
}

void MonClient::init()
{
  dout(10) << "init" << dendl;
  messenger->add_dispatcher_head(this);

  Mutex::Locker l(monc_lock);
  timer.add_event_after(10.0, new C_Tick(this));
}

void MonClient::shutdown()
{
  timer.cancel_all_events();
}

int MonClient::mount(double mount_timeout)
{
  Mutex::Locker lock(monc_lock);

  if (clientid >= 0) {
    dout(5) << "already mounted" << dendl;;
    return 0;
  }

  // only first mounter does the work
  mounting++;
  if (mounting == 1) {
    if (cur_mon < 0)
      _reopen_session();
    else
      _send_mount();
  }
  while (clientid < 0 && !mount_err)
    mount_cond.Wait(monc_lock);
  mounting--;

  if (clientid >= 0) {
    dout(5) << "mount success, client" << clientid << dendl;

    _sub_want("monmap", monmap.get_epoch());
  }

  return mount_err;
}

void MonClient::handle_mount_ack(MClientMountAck* m)
{
  dout(10) << "handle_mount_ack " << *m << dendl;

  _finish_hunting();

  if (m->result) {
    mount_err = m->result;
    dout(0) << "mount error " << m->result << " (" << m->result_msg << ")" << dendl;
  } else {
    // monmap
    bufferlist::iterator p = m->monmap_bl.begin();
    ::decode(monmap, p);

    clientid = m->client;
    messenger->set_myname(entity_name_t::CLIENT(m->client.v));
  }

  mount_cond.SignalAll();

  delete m;
}

// ---------

void MonClient::_send_mon_message(Message *m)
{
  assert(cur_mon >= 0);
  messenger->send_message(m, monmap.mon_inst[cur_mon]);
}

void MonClient::_pick_new_mon()
{
  if (cur_mon >= 0)
    messenger->mark_down(monmap.get_inst(cur_mon).addr);
  cur_mon = monmap.pick_mon(true);
  dout(10) << "_pick_new_mon picked mon" << cur_mon << dendl;
}

void MonClient::_reopen_session()
{
  dout(10) << "_reopen_session" << dendl;
  _pick_new_mon();
  if (mounting)
    _send_mount();
  if (!sub_have.empty())
    _renew_subs();
  if (!mounting && sub_have.empty()) {
    _send_mon_message(new MMonGetMap);
  }
}

bool MonClient::ms_handle_reset(Connection *con, const entity_addr_t& peer)
{
  dout(10) << "ms_handle_reset " << peer << dendl;
  if (hunting)
    return true;

  dout(0) << "hunting for new mon" << dendl;
  hunting = true;
  _reopen_session();
  return false;
}

void MonClient::_finish_hunting()
{
  if (hunting) {
    dout(0) << "found mon" << cur_mon << dendl;
    hunting = false;
  }
}

void MonClient::tick()
{
  dout(10) << "tick" << dendl;

  if (hunting) {
    dout(0) << "continuing hunt" << dendl;
    _reopen_session();
  } else {
    // just renew as needed
    utime_t now = g_clock.now();
    if (now > sub_renew_after)
      _renew_subs();

    int oldmon = monmap.pick_mon();
    messenger->send_keepalive(monmap.mon_inst[oldmon]);
  }

  timer.add_event_after(10.0, new C_Tick(this));
}

// ---------

void MonClient::_renew_subs()
{
  if (sub_have.empty()) {
    dout(10) << "renew_subs - empty" << dendl;
    return;
  }

  dout(10) << "renew_subs" << dendl;
  if (cur_mon < 0)
    _reopen_session();
  else {
    if (sub_renew_sent == utime_t())
      sub_renew_sent = g_clock.now();

    MMonSubscribe *m = new MMonSubscribe;
    m->what = sub_have;
    _send_mon_message(m);
  }
}

void MonClient::handle_subscribe_ack(MMonSubscribeAck *m)
{
  _finish_hunting();

  if (sub_renew_sent != utime_t()) {
    sub_renew_after = sub_renew_sent;
    sub_renew_after += m->interval / 2.0;
    dout(10) << "handle_subscribe_ack sent " << sub_renew_sent << " renew after " << sub_renew_after << dendl;
    sub_renew_sent = utime_t();
  } else {
    dout(10) << "handle_subscribe_ack sent " << sub_renew_sent << ", ignoring" << dendl;
  }
}

<|endoftext|>