<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/hwpf/fapi2/include/error_scope.H $                 */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 * @file error_scope.H
 * @brief definitions which create a scope for automatic error handling
 */

#ifndef __FAPI2_ERROR_SCOPE__
#define __FAPI2_ERROR_SCOPE__

#include <stdint.h>
#include <thread>
#include <stdio.h>
#include <return_code.H>

/// @cond
#define FAPI_VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define FAPI_VA_NARGS(...) FAPI_VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

#define FAPI_TRY_IMPL2(count, ...) FAPI_TRY ## count (__VA_ARGS__)
#define FAPI_TRY_IMPL(count, ...) FAPI_TRY_IMPL2(count, __VA_ARGS__)

#define FAPI_TRY_NO_TRACE( __operation__ )                              \
    if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) \
    {                                                                   \
        goto clean_up;                                                  \
    }

// Why debug? Because this isn't a mechanism to gather FFDC
// one should be using FAPI_ASSERT. However, it is nice to
// have a conditional trace in the event of a failure in the
// operation, so that's why this is here.
#define FAPI_TRY_TRACE( __operation__, ... )                            \
    if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) \
    {                                                                   \
        FAPI_DBG(__VA_ARGS__);                                          \
        goto clean_up;                                                  \
    }

#define FAPI_TRY1 FAPI_TRY_NO_TRACE
#define FAPI_TRY2 FAPI_TRY_TRACE
#define FAPI_TRY3 FAPI_TRY_TRACE
#define FAPI_TRY4 FAPI_TRY_TRACE
#define FAPI_TRY5 FAPI_TRY_TRACE
/// @endcond

///
/// @brief Wrapper to check an operation for an error state
/// and jump to the label cleam_up if there is an error.
/// @param[in] __operation__ an operation which returns a fapi::ReturnCode
/// @param[in] Optional vararg format/agruments for trace output.
/// @note This implementation does not support PIB error masks or
/// FSP operational states.
/// @warning The trace information is only going to be seen during
/// debug, it's not an error or informational trace. This is because
/// traces might not be seen in the field. If you want information
/// you will see on a field error, use FAPI_ASSERT.
///
#ifdef DOXYGEN
#define FAPI_TRY(__operation__, ...) FAPI_TRY_IMPL
#else
#define FAPI_TRY(...) FAPI_TRY_IMPL(FAPI_VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#endif

///
/// @brief Assert a conditional is true.
/// If it is not, the FFDC gathering function is called and the
/// trace is output as a FAPI error trace.
/// @param[in] __conditional__ the condition to assert
/// @param[in] __ffdc__ the FFDC gathering function
/// @param[in] ... varargs, as input to FAPI_ERR
///
#define FAPI_ASSERT( __conditional__, __ffdc__, ... )   \
    if (! (__conditional__))                            \
    {                                                   \
        (__ffdc__).execute();                           \
        FAPI_ERR(__VA_ARGS__);                          \
        goto clean_up;                                  \
    }

#endif
<commit_msg>Add doxygen fapi2 tooling, doc clean up<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/hwpf/fapi2/include/error_scope.H $                 */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 * @file error_scope.H
 * @brief definitions which create a scope for automatic error handling
 */

#ifndef __FAPI2_ERROR_SCOPE__
#define __FAPI2_ERROR_SCOPE__

#include <stdint.h>
#include <thread>
#include <stdio.h>
#include <return_code.H>

/// @cond
#define FAPI_VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define FAPI_VA_NARGS(...) FAPI_VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

#define FAPI_TRY_IMPL2(count, ...) FAPI_TRY ## count (__VA_ARGS__)
#define FAPI_TRY_IMPL(count, ...) FAPI_TRY_IMPL2(count, __VA_ARGS__)

#define FAPI_TRY_NO_TRACE( __operation__ )                              \
    if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) \
    {                                                                   \
        goto clean_up;                                                  \
    }

// Why debug? Because this isn't a mechanism to gather FFDC
// one should be using FAPI_ASSERT. However, it is nice to
// have a conditional trace in the event of a failure in the
// operation, so that's why this is here.
#define FAPI_TRY_TRACE( __operation__, ... )                            \
    if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) \
    {                                                                   \
        FAPI_DBG(__VA_ARGS__);                                          \
        goto clean_up;                                                  \
    }

#define FAPI_TRY1 FAPI_TRY_NO_TRACE
#define FAPI_TRY2 FAPI_TRY_TRACE
#define FAPI_TRY3 FAPI_TRY_TRACE
#define FAPI_TRY4 FAPI_TRY_TRACE
#define FAPI_TRY5 FAPI_TRY_TRACE
/// @endcond

///
/// @brief Wrapper to check an operation for an error state
/// and jump to the label cleam_up if there is an error.
/// @param[in] __operation__ an operation which returns a fapi::ReturnCode
/// @param[in] ... vararg format/agruments for trace output (optional)
/// @note This implementation does not support PIB error masks or
/// FSP operational states.
/// @warning The trace information is only going to be seen during
/// debug, it's not an error or informational trace. This is because
/// traces might not be seen in the field. If you want information
/// you will see on a field error, use FAPI_ASSERT.
///
#ifdef DOXYGEN
#define FAPI_TRY(__operation__, ...) FAPI_TRY_IMPL
#else
#define FAPI_TRY(...) FAPI_TRY_IMPL(FAPI_VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#endif

///
/// @brief Assert a conditional is true.
/// If it is not, the FFDC gathering function is called and the
/// trace is output as a FAPI error trace.
/// @param[in] __conditional__ the condition to assert
/// @param[in] __ffdc__ the FFDC gathering function
/// @param[in] ... varargs, as input to FAPI_ERR
///
#define FAPI_ASSERT( __conditional__, __ffdc__, ... )   \
    if (! (__conditional__))                            \
    {                                                   \
        (__ffdc__).execute();                           \
        FAPI_ERR(__VA_ARGS__);                          \
        goto clean_up;                                  \
    }

#endif
<|endoftext|>


<commit_before>//===-- SIAddIMGInit.cpp - Add any required IMG inits ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// Any MIMG instructions that use tfe or lwe require an initialization of the
/// result register that will be written in the case of a memory access failure
/// The required code is also added to tie this init code to the result of the
/// img instruction
///
//===----------------------------------------------------------------------===//
//

#define DEBUG_TYPE "si-img-init"
#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "Utils/AMDGPULaneDominator.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

namespace {

class SIAddIMGInit : public MachineFunctionPass {
public:
  static char ID;

public:
  SIAddIMGInit() : MachineFunctionPass(ID) {
    initializeSIAddIMGInitPass(*PassRegistry::getPassRegistry());
  }

  bool runOnMachineFunction(MachineFunction &MF) override;

  StringRef getPassName() const override { return "SI Add IMG init"; }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

} // End anonymous namespace.

INITIALIZE_PASS(SIAddIMGInit, DEBUG_TYPE,
                "SI Add IMG Init", false, false)

char SIAddIMGInit::ID = 0;

char &llvm::SIAddIMGInitID = SIAddIMGInit::ID;

FunctionPass *llvm::createSIAddIMGInitPass() {
  return new SIAddIMGInit();
}

bool SIAddIMGInit::runOnMachineFunction(MachineFunction &MF) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
  const SIInstrInfo *TII = ST.getInstrInfo();
  const SIRegisterInfo *RI = ST.getRegisterInfo();
  bool Changed = false;

  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
                                                  BI != BE; ++BI) {
    MachineBasicBlock &MBB = *BI;
    MachineBasicBlock::iterator I, Next;
    for (I = MBB.begin(); I != MBB.end(); I = Next) {
      Next = std::next(I);
      MachineInstr &MI = *I;

      auto Opcode = MI.getOpcode();
      if (TII->isMIMG(Opcode) && !TII->get(Opcode).mayStore()) {
        MachineOperand *tfe = TII->getNamedOperand(MI, AMDGPU::OpName::tfe);
        MachineOperand *lwe = TII->getNamedOperand(MI, AMDGPU::OpName::lwe);
        MachineOperand *d16 = TII->getNamedOperand(MI, AMDGPU::OpName::d16);

        // Abandon attempts for instructions that don't have tfe or lwe fields
        // Shouldn't be any at this point, but this will allow for future
        // variants.
        if (!tfe && !lwe)
          continue;

        unsigned tfeVal = tfe->getImm();
        unsigned lweVal = lwe->getImm();
        unsigned d16Val = d16 ? d16->getImm() : 0;

        if (tfeVal || lweVal) {
          // At least one of TFE or LWE are non-zero
          // We have to insert a suitable initialization of the result value and
          // tie this to the dest of the image instruction.

          const DebugLoc &DL = MI.getDebugLoc();

          int dstIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
                                                  AMDGPU::OpName::vdata);

          // Calculate which dword we have to initialize to 0.
          MachineOperand *MO_Dmask =
            TII->getNamedOperand(MI, AMDGPU::OpName::dmask);
          // Abandon attempt if no dmask operand is found.
          if (!MO_Dmask) continue;

          unsigned dmask = MO_Dmask->getImm();
          // Determine the number of active lanes taking into account the
          // Gather4 special case
          unsigned activeLanes =
            TII->isGather4(Opcode) ? 4 : countPopulation(dmask);
          // Subreg indices are counted from 1
          // When D16 then we want next whole VGPR after write data.
          bool Packed = !ST.hasUnpackedD16VMem();
          unsigned initIdx =
            d16Val && Packed ? ((activeLanes + 1) >> 1) + 1
                             : activeLanes + 1;

          // Abandon attempt if the dst size isn't large enough
          // - this is in fact an error but this is picked up elsewhere and
          // reported correctly.
          uint32_t dstSize =
            RI->getRegSizeInBits(*TII->getOpRegClass(MI, dstIdx)) / 32;
          if (dstSize < initIdx) continue;

          // Create a register for the intialization value.
          unsigned prevDst =
            MRI.createVirtualRegister(TII->getOpRegClass(MI, dstIdx));
          BuildMI(MBB, MI, DL, TII->get(AMDGPU::IMPLICIT_DEF), prevDst);

          unsigned newDst = 0; // Final initialized value will be in here

          // If PRTStrictNull feature is enabled (the default) then initialize
          // all the result registers to 0, otherwise just the error indication
          // register (VGPRn+1)
          unsigned sizeLeft = ST.usePRTStrictNull() ? initIdx : 1;
          unsigned currIdx = ST.usePRTStrictNull() ? 1 : initIdx;

          for ( ; sizeLeft ; sizeLeft--, currIdx++ ) {
            newDst = MRI.createVirtualRegister(TII->getOpRegClass(MI, dstIdx));
            // Initialize dword
            unsigned subReg =
                MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
            BuildMI(MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), subReg)
              .addImm(0);
            // Insert into the super-reg
            BuildMI(MBB, I, DL, TII->get(TargetOpcode::INSERT_SUBREG), newDst)
              .addReg(prevDst)
              .addReg(subReg)
              .addImm(currIdx);

            prevDst = newDst;
          }

          // Add as an implicit operand
          MachineInstrBuilder(MF,MI).addReg(newDst, RegState::Implicit);

          // Tie the just added implicit operand to the dst
          MI.tieOperands(dstIdx, MI.getNumOperands() - 1);

          Changed = true;
        }
      }
    }
  }

  return Changed;
}
<commit_msg>[AMDGPU] Fixes in the image instruction init pass<commit_after>//===-- SIAddIMGInit.cpp - Add any required IMG inits ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// Any MIMG instructions that use tfe or lwe require an initialization of the
/// result register that will be written in the case of a memory access failure
/// The required code is also added to tie this init code to the result of the
/// img instruction
///
//===----------------------------------------------------------------------===//
//

#define DEBUG_TYPE "si-img-init"
#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "Utils/AMDGPULaneDominator.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

namespace {

class SIAddIMGInit : public MachineFunctionPass {
public:
  static char ID;

public:
  SIAddIMGInit() : MachineFunctionPass(ID) {
    initializeSIAddIMGInitPass(*PassRegistry::getPassRegistry());
  }

  bool runOnMachineFunction(MachineFunction &MF) override;

  StringRef getPassName() const override { return "SI Add IMG init"; }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

} // End anonymous namespace.

INITIALIZE_PASS(SIAddIMGInit, DEBUG_TYPE,
                "SI Add IMG Init", false, false)

char SIAddIMGInit::ID = 0;

char &llvm::SIAddIMGInitID = SIAddIMGInit::ID;

FunctionPass *llvm::createSIAddIMGInitPass() {
  return new SIAddIMGInit();
}

bool SIAddIMGInit::runOnMachineFunction(MachineFunction &MF) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
  const SIInstrInfo *TII = ST.getInstrInfo();
  const SIRegisterInfo *RI = ST.getRegisterInfo();
  bool Changed = false;

  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
                                                  BI != BE; ++BI) {
    MachineBasicBlock &MBB = *BI;
    MachineBasicBlock::iterator I, Next;
    for (I = MBB.begin(); I != MBB.end(); I = Next) {
      Next = std::next(I);
      MachineInstr &MI = *I;

      auto Opcode = MI.getOpcode();
      if (TII->isMIMG(Opcode) && !TII->get(Opcode).mayStore()) {
        MachineOperand *tfe = TII->getNamedOperand(MI, AMDGPU::OpName::tfe);
        MachineOperand *lwe = TII->getNamedOperand(MI, AMDGPU::OpName::lwe);
        MachineOperand *d16 = TII->getNamedOperand(MI, AMDGPU::OpName::d16);

        // Abandon attempts for instructions that don't have tfe or lwe fields
        // Shouldn't be any at this point, but this will allow for future
        // variants.
        if (!tfe && !lwe)
          continue;

        unsigned tfeVal = tfe->getImm();
        unsigned lweVal = lwe->getImm();
        unsigned d16Val = d16 ? d16->getImm() : 0;

        if (tfeVal || lweVal) {
          // At least one of TFE or LWE are non-zero
          // We have to insert a suitable initialization of the result value and
          // tie this to the dest of the image instruction.

          const DebugLoc &DL = MI.getDebugLoc();

          int dstIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
                                                  AMDGPU::OpName::vdata);

          // Calculate which dword we have to initialize to 0.
          MachineOperand *MO_Dmask =
            TII->getNamedOperand(MI, AMDGPU::OpName::dmask);
          // Abandon attempt if no dmask operand is found.
          if (!MO_Dmask) continue;

          unsigned dmask = MO_Dmask->getImm();
          // Determine the number of active lanes taking into account the
          // Gather4 special case
          unsigned activeLanes =
            TII->isGather4(Opcode) ? 4 : countPopulation(dmask);
          // Subreg indices are counted from 1
          // When D16 then we want next whole VGPR after write data.
          bool Packed = !ST.hasUnpackedD16VMem();
          unsigned initIdx =
            d16Val && Packed ? ((activeLanes + 1) >> 1) + 1
                             : activeLanes + 1;

          // Abandon attempt if the dst size isn't large enough
          // - this is in fact an error but this is picked up elsewhere and
          // reported correctly.
          uint32_t dstSize =
            RI->getRegSizeInBits(*TII->getOpRegClass(MI, dstIdx)) / 32;
          if (dstSize < initIdx) continue;

          // Create a register for the intialization value.
          unsigned prevDst =
            MRI.createVirtualRegister(TII->getOpRegClass(MI, dstIdx));
          unsigned newDst = 0; // Final initialized value will be in here

          // If PRTStrictNull feature is enabled (the default) then initialize
          // all the result registers to 0, otherwise just the error indication
          // register (VGPRn+1)
          unsigned sizeLeft = ST.usePRTStrictNull() ? initIdx : 1;
          unsigned currIdx = ST.usePRTStrictNull() ? 1 : initIdx;

          if (dstSize == 1) {
            // In this case we can just initialize the result directly
            BuildMI(MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), prevDst)
                .addImm(0);
            newDst = prevDst;
          } else {
            BuildMI(MBB, MI, DL, TII->get(AMDGPU::IMPLICIT_DEF), prevDst);
            for (; sizeLeft; sizeLeft--, currIdx++) {
              newDst =
                  MRI.createVirtualRegister(TII->getOpRegClass(MI, dstIdx));
              // Initialize dword
              unsigned subReg =
                  MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
              BuildMI(MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), subReg)
                  .addImm(0);
              // Insert into the super-reg
              BuildMI(MBB, I, DL, TII->get(TargetOpcode::INSERT_SUBREG), newDst)
                  .addReg(prevDst)
                  .addReg(subReg)
                  .addImm(currIdx);

              prevDst = newDst;
            }
          }

          // Add as an implicit operand
          MachineInstrBuilder(MF,MI).addReg(newDst, RegState::Implicit);

          // Tie the just added implicit operand to the dst
          MI.tieOperands(dstIdx, MI.getNumOperands() - 1);

          Changed = true;
        }
      }
    }
  }

  return Changed;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/gamepad_shared_memory_reader.h"

#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
#include "content/common/gamepad_messages.h"
#include "content/public/renderer/render_thread.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "ipc/ipc_sync_message_filter.h"

namespace content {

GamepadSharedMemoryReader::GamepadSharedMemoryReader() {
  memset(ever_interacted_with_, 0, sizeof(ever_interacted_with_));
  CHECK(RenderThread::Get()->Send(new GamepadHostMsg_StartPolling(
      &renderer_shared_memory_handle_)));
  // If we don't get a valid handle from the browser, don't try to Map (we're
  // probably out of memory or file handles).
  bool valid_handle = base::SharedMemory::IsHandleValid(
      renderer_shared_memory_handle_);
  UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", valid_handle);
  if (!valid_handle)
    return;
  renderer_shared_memory_.reset(
      new base::SharedMemory(renderer_shared_memory_handle_, true));
  CHECK(renderer_shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
  void *memory = renderer_shared_memory_->memory();
  CHECK(memory);
  gamepad_hardware_buffer_ =
      static_cast<GamepadHardwareBuffer*>(memory);
}

void GamepadSharedMemoryReader::SampleGamepads(WebKit::WebGamepads& gamepads) {
  WebKit::WebGamepads read_into;
  TRACE_EVENT0("GAMEPAD", "SampleGamepads");

  if (!base::SharedMemory::IsHandleValid(renderer_shared_memory_handle_))
    return;

  // Only try to read this many times before failing to avoid waiting here
  // very long in case of contention with the writer. TODO(scottmg) Tune this
  // number (as low as 1?) if histogram shows distribution as mostly
  // 0-and-maximum.
  const int kMaximumContentionCount = 10;
  int contention_count = -1;
  base::subtle::Atomic32 version;
  do {
    version = gamepad_hardware_buffer_->sequence.ReadBegin();
    memcpy(&read_into, &gamepad_hardware_buffer_->buffer, sizeof(read_into));
    ++contention_count;
    if (contention_count == kMaximumContentionCount)
      break;
  } while (gamepad_hardware_buffer_->sequence.ReadRetry(version));
  UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count);

  if (contention_count >= kMaximumContentionCount) {
      // We failed to successfully read, presumably because the hardware
      // thread was taking unusually long. Don't copy the data to the output
      // buffer, and simply leave what was there before.
      return;
  }

  // New data was read successfully, copy it into the output buffer.
  memcpy(&gamepads, &read_into, sizeof(gamepads));

  // Override the "connected" with false until the user has interacted
  // with the gamepad. This is to prevent fingerprinting on drive-by pages.
  for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i) {
    WebKit::WebGamepad& pad = gamepads.items[i];
    // If the device is physically connected, then check if we should
    // keep it disabled. We track if any of the primary 4 buttons have been
    // pressed to determine a reasonable intentional interaction from the user.
    if (pad.connected) {
      if (ever_interacted_with_[i])
        continue;
      const unsigned kPrimaryInteractionButtons = 4;
      for (unsigned j = 0; j < kPrimaryInteractionButtons; ++j)
        ever_interacted_with_[i] |= pad.buttons[j] > 0.5f;
      // If we've not previously set, and the user still hasn't touched
      // these buttons, then don't pass the data on to the Chromium port.
      if (!ever_interacted_with_[i])
        pad.connected = false;
    }
  }
}

GamepadSharedMemoryReader::~GamepadSharedMemoryReader() {
  RenderThread::Get()->Send(new GamepadHostMsg_StopPolling());
}

} // namespace content
<commit_msg>Coverity: Initialize a member variable.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/gamepad_shared_memory_reader.h"

#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
#include "content/common/gamepad_messages.h"
#include "content/public/renderer/render_thread.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "ipc/ipc_sync_message_filter.h"

namespace content {

GamepadSharedMemoryReader::GamepadSharedMemoryReader()
    : gamepad_hardware_buffer_(NULL) {
  memset(ever_interacted_with_, 0, sizeof(ever_interacted_with_));
  CHECK(RenderThread::Get()->Send(new GamepadHostMsg_StartPolling(
      &renderer_shared_memory_handle_)));
  // If we don't get a valid handle from the browser, don't try to Map (we're
  // probably out of memory or file handles).
  bool valid_handle = base::SharedMemory::IsHandleValid(
      renderer_shared_memory_handle_);
  UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", valid_handle);
  if (!valid_handle)
    return;
  renderer_shared_memory_.reset(
      new base::SharedMemory(renderer_shared_memory_handle_, true));
  CHECK(renderer_shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
  void *memory = renderer_shared_memory_->memory();
  CHECK(memory);
  gamepad_hardware_buffer_ =
      static_cast<GamepadHardwareBuffer*>(memory);
}

void GamepadSharedMemoryReader::SampleGamepads(WebKit::WebGamepads& gamepads) {
  WebKit::WebGamepads read_into;
  TRACE_EVENT0("GAMEPAD", "SampleGamepads");

  if (!base::SharedMemory::IsHandleValid(renderer_shared_memory_handle_))
    return;

  // Only try to read this many times before failing to avoid waiting here
  // very long in case of contention with the writer. TODO(scottmg) Tune this
  // number (as low as 1?) if histogram shows distribution as mostly
  // 0-and-maximum.
  const int kMaximumContentionCount = 10;
  int contention_count = -1;
  base::subtle::Atomic32 version;
  do {
    version = gamepad_hardware_buffer_->sequence.ReadBegin();
    memcpy(&read_into, &gamepad_hardware_buffer_->buffer, sizeof(read_into));
    ++contention_count;
    if (contention_count == kMaximumContentionCount)
      break;
  } while (gamepad_hardware_buffer_->sequence.ReadRetry(version));
  UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count);

  if (contention_count >= kMaximumContentionCount) {
      // We failed to successfully read, presumably because the hardware
      // thread was taking unusually long. Don't copy the data to the output
      // buffer, and simply leave what was there before.
      return;
  }

  // New data was read successfully, copy it into the output buffer.
  memcpy(&gamepads, &read_into, sizeof(gamepads));

  // Override the "connected" with false until the user has interacted
  // with the gamepad. This is to prevent fingerprinting on drive-by pages.
  for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i) {
    WebKit::WebGamepad& pad = gamepads.items[i];
    // If the device is physically connected, then check if we should
    // keep it disabled. We track if any of the primary 4 buttons have been
    // pressed to determine a reasonable intentional interaction from the user.
    if (pad.connected) {
      if (ever_interacted_with_[i])
        continue;
      const unsigned kPrimaryInteractionButtons = 4;
      for (unsigned j = 0; j < kPrimaryInteractionButtons; ++j)
        ever_interacted_with_[i] |= pad.buttons[j] > 0.5f;
      // If we've not previously set, and the user still hasn't touched
      // these buttons, then don't pass the data on to the Chromium port.
      if (!ever_interacted_with_[i])
        pad.connected = false;
    }
  }
}

GamepadSharedMemoryReader::~GamepadSharedMemoryReader() {
  RenderThread::Get()->Send(new GamepadHostMsg_StopPolling());
}

} // namespace content
<|endoftext|>


<commit_before>/** \copyright
 *
 *    Copyright (C) 2018  Robert Heller D/B/A Deepwoods Software
 *			51 Locke Hill Road
 *			Wendell, MA 01379-9728
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * \file LinuxGpio.hxx
 *
 * Defines GPIO pins using the Linux sysfs ABI.
 *
 * \section HOWTOUSE How to use
 *
 * You need to use the GPIO_PIN macro at the bottom, like this:
 *
 * GPIO_PIN(LED1, GpioOutputSafeLow, 27);  // Defines LED1_Pin, for GPIO 27, initialized low.
 * GPIO_PIN(CSLow, GpioOutputSafeHighInvert, 5);  // Defines CSLow_Pin, for GPIO 5, initialized high, with the set logic inverted.
 * GPIO_PIN(Button1, GpioInputActiveLow, 20);  // Defines Button1_Pin, for GPIO 20, avtive low -- return true when shorted to ground.
 *
 * Classes available for the second macro parameter are:
 *
 *   - GpioOutputSafeLow        Output initialized low, true = high
 *   - GpioOutputSafeLowInvert  Output initialized low, true = low
 *   - GpioOutputSafeHigh       Output initialized high, true = high
 *   - GpioOutputSafeHighInvert Output initialized high, true = high
 *   - GpioInputActiveHigh      Input, high = true
 *   - GpioInputActiveLow       Input, low  = true
 *
 * Be sure to use GpioInitializer to create an Initializer class:
 *
 * typedef GpioInitializer<LED1_Pin, CSLow_Pin, Button1_Pin> GpioInit;
 *
 * somewhere in main.cxx, and then in appl_main():
 *
 * GpioInit::hw_init();
 *
 * This makes sure the GPIO pins are properly set up (eg exported to /sys/class/gpio/).
 * Also, the process running the node needs to be in group gpio.
 *
 * @author Robert Heller
 * @date 10 October 2018
 */

#ifndef __LINUXGPIO_HXX
#define __LINUXGPIO_HXX

#include "freertos_drivers/common/GpioWrapper.hxx"
#include "os/Gpio.hxx"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

/// Defines a GPIO output pin. Writes to this structure will change the output
/// level of the pin. Reads will return the pin's current level.
/// Uses Linux sysfs ABI
///
/// The pin is set to output at initialization time, with the level defined by
/// `SAFE_VALUE'.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <int PIN_NUM> class LinuxGpio
{
public:
    /// Number of the pin
    static constexpr const uint32_t PIN = PIN_NUM;

    /// Export pin
    static void export_pin()
    {
        FILE *fp = fopen("/sys/class/gpio/export","w");
        fprintf(fp,"%d\n",PIN);
        fclose(fp);
        // 50ms delay IS needed while kernel changes ownership of created GPIO directory
        usleep(50000);
    }

    /// Sets pin to output.
    static void set_output()
    {
        char dirname[40];
        snprintf(dirname,sizeof(dirname),"/sys/class/gpio/gpio%d/direction",PIN);
        int dfd = open(dirname,O_WRONLY);
        write(dfd,"out\n",4);
        close(dfd);
    }
    /// Sets pin to input.
    static void set_input()
    {
        char dirname[40];
        snprintf(dirname,sizeof(dirname),"/sys/class/gpio/gpio%d/direction",PIN);
        int dfd = open(dirname,O_WRONLY);
        write(dfd,"in\n",3);
        close(dfd);
    }
    /// Sets output to HIGH.
    static void set_on()
    {
        char valname[40];
        snprintf(valname,sizeof(valname),"/sys/class/gpio/gpio%d/value",PIN);
        int vfd = open(valname,O_WRONLY);
        write(vfd,"1\n",2);
        close(vfd);
    }
    /// Sets output to LOW.
    static void set_off()
    {
        char valname[40];
        snprintf(valname,sizeof(valname),"/sys/class/gpio/gpio%d/value",PIN);
        int vfd = open(valname,O_WRONLY);
        write(vfd,"0\n",2);
        close(vfd);
    }
    /// @return input pin level.
    static bool get()
    {
        char valname[40], c;
        snprintf(valname,sizeof(valname),"/sys/class/gpio/gpio%d/value",PIN);
        int vfd = open(valname,O_RDONLY);
        read(vfd,&c,1);
        close(vfd);
        return (c != '0');
    }
    /// Set output pin level. @param value is the level to set to.
    static void set(bool value)
    {
        if (value)
        {
            set_on();
        }
        else
        {
            set_off();
        }
    }

    /// Toggles output pin value.
    static void toggle()
    {
        set(!get());
    }

    /// @return true if pin is configured as an output pin.
    static bool is_output()
    {
        char dirname[40], c;
        snprintf(dirname,sizeof(dirname),"/sys/class/gpio/gpio%d/direction",PIN);
        int dfd = open(dirname,O_RDONLY);
        read(dfd,&c,1);
        close(dfd);
        return (c == 'o');
    }
};

/// Generic output pin
template <class Base, bool SAFE_VALUE, bool INVERT = false>
struct GpioOutputPin : public Base
{
public:
    /// Initializes the hardware pin.
    static void hw_init()
    {
        Base::export_pin();
        Base::set_output();
        Base::set(SAFE_VALUE);
    }
    /// Sets the hardware pin to a safe value.
    static void hw_set_to_safe()
    {
        Base::set(SAFE_VALUE);
    }
    /// Sets the output pinm @param value if true, output is set to HIGH, if
    /// false, output is set to LOW.
    static void set(bool value)
    {
        if (INVERT)
        {
            Base::set(!value);
        }
        else
        {
            Base::set(value);
        }
    }
    /// @return the static Gpio instance.
    static constexpr const Gpio *instance()
    {
        return GpioWrapper<GpioOutputPin<Base,SAFE_VALUE,INVERT>>::instance();
    }
};

/// Defines a GPIO output pin, initialized to be an output pin with low level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with low
/// level. All set() commands are acted upon by inverting the value.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLowInvert : public GpioOutputPin<Defs, false, true>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high
/// level. All set() commands are acted upon by inverting the value.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHighInvert : public GpioOutputPin<Defs, true, true>
{
};
/// Generic input pin
template <class Base, bool ACTIVE_HIGH = true>
struct GpioInputPin : public Base
{
public:
    /// Initializes the hardware pin.
    static void hw_init()
    {
        Base::export_pin();
        Base::set_input();
    }
    /// Sets the hardware pin to a safe state.
    static void hw_set_to_safe()
    {
        hw_init();
    }
    /// @return the static Gpio instance.
    static const Gpio *instance()
    {
        return GpioWrapper<GpioInputPin<Base>>::instance();
    }
    static bool get()
    {
        if (ACTIVE_HIGH)
        {
            return Base::get();
        }
        else
        {
            return !Base::get();
        }
    }
};

/// Defines a GPIO input pin, Active High (High == true).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputActiveHigh : public GpioInputPin<Defs, true>
{
};

/// Defines a GPIO input pin, Active Low (Low == true).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputActiveLow : public GpioInputPin<Defs, false>
{
};

/// Helper macro for defining GPIO pins on Linux-based microcontrollers (like the Raspberry Pi or Bagle Bone.
///
/// @param NAME is the basename of the declaration. For NAME==FOO the macro
/// declared FOO_Pin as a structure on which the read-write functions will be
/// available.
///
/// @param BaseClass is the initialization structure, such as @ref LedPin, or
/// @ref GpioOutputSafeHigh or @ref GpioOutputSafeLow.
///
/// @param NUM is the pin number, such as 3
///
/// Example:
///  GPIO_PIN(FOO, GpioOutputSafeLow, 3);
///  ...
///  FOO_Pin::set(true);
#define GPIO_PIN(NAME, BaseClass, NUM) \
    typedef BaseClass<LinuxGpio<NUM>> NAME##_Pin

#endif // __LINUXGPIO_HXX

<commit_msg>Updates to LinuxGPIO.hxx to handle slower Linux ARM boards, like the Beagles. (#299)<commit_after>/** \copyright
 *
 *    Copyright (C) 2018  Robert Heller D/B/A Deepwoods Software
 *			51 Locke Hill Road
 *			Wendell, MA 01379-9728
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * \file LinuxGpio.hxx
 *
 * Defines GPIO pins using the Linux sysfs ABI.
 *
 * \section HOWTOUSE How to use
 *
 * You need to use the GPIO_PIN macro at the bottom, like this:
 *
 * GPIO_PIN(LED1, GpioOutputSafeLow, 27);  // Defines LED1_Pin, for GPIO 27, initialized low.
 * GPIO_PIN(CSLow, GpioOutputSafeHighInvert, 5);  // Defines CSLow_Pin, for GPIO 5, initialized high, with the set logic inverted.
 * GPIO_PIN(Button1, GpioInputActiveLow, 20);  // Defines Button1_Pin, for GPIO 20, avtive low -- return true when shorted to ground.
 *
 * Classes available for the second macro parameter are:
 *
 *   - GpioOutputSafeLow        Output initialized low, true = high
 *   - GpioOutputSafeLowInvert  Output initialized low, true = low
 *   - GpioOutputSafeHigh       Output initialized high, true = high
 *   - GpioOutputSafeHighInvert Output initialized high, true = high
 *   - GpioInputActiveHigh      Input, high = true
 *   - GpioInputActiveLow       Input, low  = true
 *
 * Be sure to use GpioInitializer to create an Initializer class:
 *
 * typedef GpioInitializer<LED1_Pin, CSLow_Pin, Button1_Pin> GpioInit;
 *
 * somewhere in main.cxx, and then in appl_main():
 *
 * GpioInit::hw_init();
 *
 * This makes sure the GPIO pins are properly set up (eg exported to /sys/class/gpio/).
 * Also, the process running the node needs to be in group gpio.
 *
 * @author Robert Heller
 * @date 10 October 2018
 */

#ifndef __LINUXGPIO_HXX
#define __LINUXGPIO_HXX

#include "freertos_drivers/common/GpioWrapper.hxx"
#include "os/Gpio.hxx"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

/// Defines a GPIO output pin. Writes to this structure will change the output
/// level of the pin. Reads will return the pin's current level.
/// Uses Linux sysfs ABI
///
/// The pin is set to output at initialization time, with the level defined by
/// `SAFE_VALUE'.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <int PIN_NUM> class LinuxGpio
{
public:
    /// Number of the pin
    static constexpr const uint32_t PIN = PIN_NUM;

    /// Export pin
    static void export_pin()
    {
        FILE *fp = fopen("/sys/class/gpio/export","w");
        fprintf(fp,"%d\n",PIN);
        fclose(fp);
        // 50ms delay IS needed while kernel changes ownership of created GPIO directory
        usleep(50000);
    }

    /// Sets pin to output.
    static void set_output()
    {
        char dirname[40];
        snprintf(dirname,sizeof(dirname),"/sys/class/gpio/gpio%d/direction",PIN);
        int dfd = -1;
        while ((dfd = open(dirname,O_WRONLY)) < 0) {
            export_pin();
        }
        write(dfd,"out\n",4);
        close(dfd);
    }
    /// Sets pin to input.
    static void set_input()
    {
        char dirname[40];
        snprintf(dirname,sizeof(dirname),"/sys/class/gpio/gpio%d/direction",PIN);
        int dfd = -1;
        while ((dfd = open(dirname,O_WRONLY)) < 0) {
            export_pin();
        }
        write(dfd,"in\n",3);
        close(dfd);
    }
    /// Sets output to HIGH.
    static void set_on()
    {
        char valname[40];
        snprintf(valname,sizeof(valname),"/sys/class/gpio/gpio%d/value",PIN);
        int vfd = open(valname,O_WRONLY);
        write(vfd,"1\n",2);
        close(vfd);
    }
    /// Sets output to LOW.
    static void set_off()
    {
        char valname[40];
        snprintf(valname,sizeof(valname),"/sys/class/gpio/gpio%d/value",PIN);
        int vfd = open(valname,O_WRONLY);
        write(vfd,"0\n",2);
        close(vfd);
    }
    /// @return input pin level.
    static bool get()
    {
        char valname[40], c;
        snprintf(valname,sizeof(valname),"/sys/class/gpio/gpio%d/value",PIN);
        int vfd = open(valname,O_RDONLY);
        read(vfd,&c,1);
        close(vfd);
        return (c != '0');
    }
    /// Set output pin level. @param value is the level to set to.
    static void set(bool value)
    {
        if (value)
        {
            set_on();
        }
        else
        {
            set_off();
        }
    }

    /// Toggles output pin value.
    static void toggle()
    {
        set(!get());
    }

    /// @return true if pin is configured as an output pin.
    static bool is_output()
    {
        char dirname[40], c;
        snprintf(dirname,sizeof(dirname),"/sys/class/gpio/gpio%d/direction",PIN);
        int dfd = open(dirname,O_RDONLY);
        read(dfd,&c,1);
        close(dfd);
        return (c == 'o');
    }
};

/// Generic output pin
template <class Base, bool SAFE_VALUE, bool INVERT = false>
struct GpioOutputPin : public Base
{
public:
    /// Initializes the hardware pin.
    static void hw_init()
    {
        Base::export_pin();
        Base::set_output();
        Base::set(SAFE_VALUE);
    }
    /// Sets the hardware pin to a safe value.
    static void hw_set_to_safe()
    {
        Base::set(SAFE_VALUE);
    }
    /// Sets the output pinm @param value if true, output is set to HIGH, if
    /// false, output is set to LOW.
    static void set(bool value)
    {
        if (INVERT)
        {
            Base::set(!value);
        }
        else
        {
            Base::set(value);
        }
    }
    /// @return the static Gpio instance.
    static constexpr const Gpio *instance()
    {
        return GpioWrapper<GpioOutputPin<Base,SAFE_VALUE,INVERT>>::instance();
    }
};

/// Defines a GPIO output pin, initialized to be an output pin with low level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with low
/// level. All set() commands are acted upon by inverting the value.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLowInvert : public GpioOutputPin<Defs, false, true>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high
/// level. All set() commands are acted upon by inverting the value.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHighInvert : public GpioOutputPin<Defs, true, true>
{
};
/// Generic input pin
template <class Base, bool ACTIVE_HIGH = true>
struct GpioInputPin : public Base
{
public:
    /// Initializes the hardware pin.
    static void hw_init()
    {
        Base::export_pin();
        Base::set_input();
    }
    /// Sets the hardware pin to a safe state.
    static void hw_set_to_safe()
    {
        hw_init();
    }
    /// @return the static Gpio instance.
    static const Gpio *instance()
    {
        return GpioWrapper<GpioInputPin<Base>>::instance();
    }
    static bool get()
    {
        if (ACTIVE_HIGH)
        {
            return Base::get();
        }
        else
        {
            return !Base::get();
        }
    }
};

/// Defines a GPIO input pin, Active High (High == true).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputActiveHigh : public GpioInputPin<Defs, true>
{
};

/// Defines a GPIO input pin, Active Low (Low == true).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputActiveLow : public GpioInputPin<Defs, false>
{
};

/// Helper macro for defining GPIO pins on Linux-based microcontrollers (like the Raspberry Pi or Bagle Bone.
///
/// @param NAME is the basename of the declaration. For NAME==FOO the macro
/// declared FOO_Pin as a structure on which the read-write functions will be
/// available.
///
/// @param BaseClass is the initialization structure, such as @ref LedPin, or
/// @ref GpioOutputSafeHigh or @ref GpioOutputSafeLow.
///
/// @param NUM is the pin number, such as 3
///
/// Example:
///  GPIO_PIN(FOO, GpioOutputSafeLow, 3);
///  ...
///  FOO_Pin::set(true);
#define GPIO_PIN(NAME, BaseClass, NUM) \
    typedef BaseClass<LinuxGpio<NUM>> NAME##_Pin

#endif // __LINUXGPIO_HXX

<|endoftext|>


<commit_before>#include "LogConfigReader.hpp"
#include "LogManager.hpp"
#include "LogRotationManager.hpp"
#include <yaml-cpp/yaml.h>
#include <fmt/format.h>

static const std::string CONFIG_FILE_NAME = "log-config.yml";

bool ParseLogLevel(YAML::Node const &level_node, LogLevel &dest, std::string const &error_msg)
{
	static const std::unordered_map<std::string, LogLevel> loglevel_str_map = {
		{ "Debug",   LogLevel::DEBUG },
		{ "Info",    LogLevel::INFO },
		{ "Warning", LogLevel::WARNING },
		{ "Error",   LogLevel::ERROR },
		{ "Fatal",   LogLevel::FATAL },
		{ "Verbose", LogLevel::VERBOSE },
		{ "All",     LogLevel::ALL }
	};

	auto const &level_str = level_node.as<std::string>(std::string());
	if (level_str.empty())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level specified", error_msg));
		return false;
	}

	auto const &it = loglevel_str_map.find(level_str);
	if (it == loglevel_str_map.end())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level '{}'", error_msg, level_str));
		return false;
	}

	dest |= (*it).second;
	return true;
}

bool ParseDuration(std::string duration, LogRotationTimeType &dest)
{
	std::transform(duration.begin(), duration.end(), duration.begin(), tolower);
	if (duration == "daily")
		dest = LogRotationTimeType::DAILY;
	else if (duration == "weekly")
		dest = LogRotationTimeType::WEEKLY;
	else if (duration == "monthly")
		dest = LogRotationTimeType::MONTHLY;
	else
		return false;

	return true;
}

bool ParseFileSize(std::string const &size, unsigned int &dest_in_kb)
{
	auto type_idx = size.find_first_not_of("0123456789");
	if (type_idx == std::string::npos || type_idx == 0)
		return false;

	int size_val = std::stoi(size); // works as long as the string starts with a number
	if (size.length() != (type_idx + 2) || tolower(size.at(type_idx + 1)) != 'b')
		return false;

	switch (tolower(size.at(type_idx)))
	{
	case 'k':
		dest_in_kb = size_val;
		break;
	case 'm':
		dest_in_kb = size_val * 1000;
		break;
	case 'g':
		dest_in_kb = size_val * 1000 * 1000;
		break;
	default:
		return false;
	}

	return true;
}

LoggerConfig GetInternalLogConfig()
{
	LoggerConfig config;
	config.Level = LogLevel::ALL;
	config.PrintToConsole = true;
	return config;
}

void LogConfig::ParseConfigFile()
{
	YAML::Node root;
	try
	{
		root = YAML::LoadFile(CONFIG_FILE_NAME);
	}
	catch (const YAML::ParserException& e)
	{
		LogManager::Get()->LogInternal(LogLevel::ERROR,
			fmt::format("could not parse log config file: {}", e.what()));
		return;
	}
	catch (const YAML::BadFile&)
	{
		// file likely doesn't exist, ignore
		return;
	}

	std::lock_guard<std::mutex> lock(_configLock);

	_loggerConfigs.clear();

	// default settings for log-core logger
	_loggerConfigs.emplace("log-core", GetInternalLogConfig());

	YAML::Node const &loggers = root["Logger"];
	for (YAML::const_iterator y_it = loggers.begin(); y_it != loggers.end(); ++y_it)
	{
		auto module_name = y_it->first.as<std::string>(std::string());
		if (module_name.empty() || module_name == "log-core")
		{
			LogManager::Get()->LogInternal(LogLevel::ERROR,
				fmt::format("could not parse logger config: invalid logger name"));
			continue;
		}
		LoggerConfig config;

		std::string const error_msg_loglevel = fmt::format(
			"could not parse log level setting for logger '{}'", module_name);
		YAML::Node const &log_levels = y_it->second["LogLevel"];
		if (log_levels && !log_levels.IsNull()) // log level is specified, remove default log level
			config.Level = LogLevel::NONE;

		if (log_levels.IsSequence())
		{
			for (YAML::const_iterator y_it_level = log_levels.begin();
				y_it_level != log_levels.end(); ++y_it_level)
			{
				ParseLogLevel(*y_it_level, config.Level, error_msg_loglevel);
			}
		}
		else
		{
			ParseLogLevel(log_levels, config.Level, error_msg_loglevel);
		}

		YAML::Node const &log_rotation = y_it->second["LogRotation"];
		if (log_rotation)
		{
			YAML::Node const
				&type = log_rotation["Type"],
				&trigger = log_rotation["Trigger"];
			if (type && trigger)
			{
				static const std::unordered_map<std::string, LogRotationType>
					logrotation_type_str_map = {
					{ "Date", LogRotationType::DATE },
					{ "Size", LogRotationType::SIZE }
				};
				auto const &type_str = type.as<std::string>();
				auto const &it = logrotation_type_str_map.find(type_str);
				if (it != logrotation_type_str_map.end())
				{
					config.Rotation.Type = it->second;
					switch (config.Rotation.Type)
					{
						case LogRotationType::DATE:
						{
							auto time_str = trigger.as<std::string>("Daily");
							if (!ParseDuration(time_str, config.Rotation.Value.Date))
							{
								config.Rotation.Value.Date = LogRotationTimeType::DAILY;
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse date log rotation duration " \
										"for logger '{}': invalid duration \"{}\"",
										module_name, time_str));
							}
						} break;
						case LogRotationType::SIZE:
						{
							auto size_str = trigger.as<std::string>("100MB");
							if (!ParseFileSize(size_str, config.Rotation.Value.FileSize))
							{
								config.Rotation.Value.FileSize = 100;
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse file log rotation size " \
										"for logger '{}': invalid size \"{}\"",
										module_name, size_str));
							}
						} break;
					}

					YAML::Node const &backup_count = log_rotation["BackupCount"];
					if (backup_count && backup_count.IsScalar())
						config.Rotation.BackupCount = backup_count.as<int>(config.Rotation.BackupCount);
				}
				else
				{
					LogManager::Get()->LogInternal(LogLevel::WARNING,
						fmt::format(
							"could not parse log rotation setting for logger '{}': " \
							"invalid log rotation type '{}'",
							module_name, type_str));
				}
			}
			else
			{
				LogManager::Get()->LogInternal(LogLevel::WARNING,
					fmt::format(
						"could not parse log rotation setting for logger '{}': " \
						"log rotation not completely specified",
						module_name));
			}
		}

		YAML::Node const &console_print = y_it->second["PrintToConsole"];
		if (console_print && console_print.IsScalar())
			config.PrintToConsole = console_print.as<bool>(config.PrintToConsole);

		YAML::Node const &append_logs = y_it->second["Append"];
		if (append_logs && append_logs.IsScalar())
			config.Append = append_logs.as<bool>(config.Append);

		_loggerConfigs.emplace(module_name, std::move(config));
	}

	_levelConfigs.clear();
	YAML::Node const &levels = root["LogLevel"];
	for (YAML::const_iterator y_it = levels.begin(); y_it != levels.end(); ++y_it)
	{
		LogLevel level = static_cast<LogLevel>(0); // initialize to zero as ParseLogLevel OR's levels
		if (!ParseLogLevel(y_it->first, level, "could not parse log level setting"))
			continue;

		LogLevelConfig config;
		YAML::Node const &console_print_opt = y_it->second["PrintToConsole"];
		if (console_print_opt && console_print_opt.IsScalar())
			config.PrintToConsole = console_print_opt.as<bool>(config.PrintToConsole);

		_levelConfigs.emplace(level, std::move(config));
	}

	//global config settings
	_globalConfig = GlobalConfig();
	YAML::Node const &logtime_format = root["LogTimeFormat"];
	if (logtime_format && logtime_format.IsScalar())
		_globalConfig.LogTimeFormat = logtime_format.as<std::string>(_globalConfig.LogTimeFormat);

	YAML::Node const &enable_colors = root["EnableColors"];
	if (enable_colors && enable_colors.IsScalar())
		_globalConfig.EnableColors = enable_colors.as<bool>(_globalConfig.EnableColors);

	YAML::Node const &disable_debug = root["DisableDebugInfo"];
	if (disable_debug && disable_debug.IsScalar())
		_globalConfig.DisableDebugInfo = disable_debug.as<bool>(_globalConfig.DisableDebugInfo);
}

void LogConfig::Initialize()
{
	ParseConfigFile();
	_fileWatcher.reset(new FileChangeDetector(CONFIG_FILE_NAME, [this]()
	{
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"config file change detected, reloading...");
		ParseConfigFile();
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"reloading finished");
	}));
}
<commit_msg>validate log time format string<commit_after>#include "LogConfigReader.hpp"
#include "LogManager.hpp"
#include "LogRotationManager.hpp"
#include <yaml-cpp/yaml.h>
#include <fmt/format.h>

static const std::string CONFIG_FILE_NAME = "log-config.yml";

bool ParseLogLevel(YAML::Node const &level_node, LogLevel &dest, std::string const &error_msg)
{
	static const std::unordered_map<std::string, LogLevel> loglevel_str_map = {
		{ "Debug",   LogLevel::DEBUG },
		{ "Info",    LogLevel::INFO },
		{ "Warning", LogLevel::WARNING },
		{ "Error",   LogLevel::ERROR },
		{ "Fatal",   LogLevel::FATAL },
		{ "Verbose", LogLevel::VERBOSE },
		{ "All",     LogLevel::ALL }
	};

	auto const &level_str = level_node.as<std::string>(std::string());
	if (level_str.empty())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level specified", error_msg));
		return false;
	}

	auto const &it = loglevel_str_map.find(level_str);
	if (it == loglevel_str_map.end())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level '{}'", error_msg, level_str));
		return false;
	}

	dest |= (*it).second;
	return true;
}

bool ParseDuration(std::string duration, LogRotationTimeType &dest)
{
	std::transform(duration.begin(), duration.end(), duration.begin(), tolower);
	if (duration == "daily")
		dest = LogRotationTimeType::DAILY;
	else if (duration == "weekly")
		dest = LogRotationTimeType::WEEKLY;
	else if (duration == "monthly")
		dest = LogRotationTimeType::MONTHLY;
	else
		return false;

	return true;
}

bool ParseFileSize(std::string const &size, unsigned int &dest_in_kb)
{
	auto type_idx = size.find_first_not_of("0123456789");
	if (type_idx == std::string::npos || type_idx == 0)
		return false;

	int size_val = std::stoi(size); // works as long as the string starts with a number
	if (size.length() != (type_idx + 2) || tolower(size.at(type_idx + 1)) != 'b')
		return false;

	switch (tolower(size.at(type_idx)))
	{
	case 'k':
		dest_in_kb = size_val;
		break;
	case 'm':
		dest_in_kb = size_val * 1000;
		break;
	case 'g':
		dest_in_kb = size_val * 1000 * 1000;
		break;
	default:
		return false;
	}

	return true;
}

LoggerConfig GetInternalLogConfig()
{
	LoggerConfig config;
	config.Level = LogLevel::ALL;
	config.PrintToConsole = true;
	return config;
}

bool ValidateTimeFormat(std::string const &format)
{
	size_t idx = 0;
	while (idx < format.size())
	{
		if (format.at(idx++) != '%')
			continue;

		switch (format.at(idx++))
		{
		case 'a':
		case 'A':
		case 'b':
		case 'B':
		case 'c':
		case 'C':
		case 'd':
		case 'D':
		case 'e':
		case 'F':
		case 'g':
		case 'G':
		case 'h':
		case 'H':
		case 'I':
		case 'j':
		case 'm':
		case 'M':
		case 'n':
		case 'p':
		case 'r':
		case 'R':
		case 'S':
		case 't':
		case 'T':
		case 'u':
		case 'U':
		case 'V':
		case 'w':
		case 'W':
		case 'x':
		case 'X':
		case 'y':
		case 'Y':
		case 'z':
		case 'Z':
		case '%':
			continue;
		default:
			return false;
		}
	}
	return true;
}

void LogConfig::ParseConfigFile()
{
	YAML::Node root;
	try
	{
		root = YAML::LoadFile(CONFIG_FILE_NAME);
	}
	catch (const YAML::ParserException& e)
	{
		LogManager::Get()->LogInternal(LogLevel::ERROR,
			fmt::format("could not parse log config file: {}", e.what()));
		return;
	}
	catch (const YAML::BadFile&)
	{
		// file likely doesn't exist, ignore
		return;
	}

	std::lock_guard<std::mutex> lock(_configLock);

	_loggerConfigs.clear();

	// default settings for log-core logger
	_loggerConfigs.emplace("log-core", GetInternalLogConfig());

	YAML::Node const &loggers = root["Logger"];
	for (YAML::const_iterator y_it = loggers.begin(); y_it != loggers.end(); ++y_it)
	{
		auto module_name = y_it->first.as<std::string>(std::string());
		if (module_name.empty() || module_name == "log-core")
		{
			LogManager::Get()->LogInternal(LogLevel::ERROR,
				fmt::format("could not parse logger config: invalid logger name"));
			continue;
		}
		LoggerConfig config;

		std::string const error_msg_loglevel = fmt::format(
			"could not parse log level setting for logger '{}'", module_name);
		YAML::Node const &log_levels = y_it->second["LogLevel"];
		if (log_levels && !log_levels.IsNull()) // log level is specified, remove default log level
			config.Level = LogLevel::NONE;

		if (log_levels.IsSequence())
		{
			for (YAML::const_iterator y_it_level = log_levels.begin();
				y_it_level != log_levels.end(); ++y_it_level)
			{
				ParseLogLevel(*y_it_level, config.Level, error_msg_loglevel);
			}
		}
		else
		{
			ParseLogLevel(log_levels, config.Level, error_msg_loglevel);
		}

		YAML::Node const &log_rotation = y_it->second["LogRotation"];
		if (log_rotation)
		{
			YAML::Node const
				&type = log_rotation["Type"],
				&trigger = log_rotation["Trigger"];
			if (type && trigger)
			{
				static const std::unordered_map<std::string, LogRotationType>
					logrotation_type_str_map = {
					{ "Date", LogRotationType::DATE },
					{ "Size", LogRotationType::SIZE }
				};
				auto const &type_str = type.as<std::string>();
				auto const &it = logrotation_type_str_map.find(type_str);
				if (it != logrotation_type_str_map.end())
				{
					config.Rotation.Type = it->second;
					switch (config.Rotation.Type)
					{
						case LogRotationType::DATE:
						{
							auto time_str = trigger.as<std::string>("Daily");
							if (!ParseDuration(time_str, config.Rotation.Value.Date))
							{
								config.Rotation.Value.Date = LogRotationTimeType::DAILY;
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse date log rotation duration " \
										"for logger '{}': invalid duration \"{}\"",
										module_name, time_str));
							}
						} break;
						case LogRotationType::SIZE:
						{
							auto size_str = trigger.as<std::string>("100MB");
							if (!ParseFileSize(size_str, config.Rotation.Value.FileSize))
							{
								config.Rotation.Value.FileSize = 100;
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse file log rotation size " \
										"for logger '{}': invalid size \"{}\"",
										module_name, size_str));
							}
						} break;
					}

					YAML::Node const &backup_count = log_rotation["BackupCount"];
					if (backup_count && backup_count.IsScalar())
						config.Rotation.BackupCount = backup_count.as<int>(config.Rotation.BackupCount);
				}
				else
				{
					LogManager::Get()->LogInternal(LogLevel::WARNING,
						fmt::format(
							"could not parse log rotation setting for logger '{}': " \
							"invalid log rotation type '{}'",
							module_name, type_str));
				}
			}
			else
			{
				LogManager::Get()->LogInternal(LogLevel::WARNING,
					fmt::format(
						"could not parse log rotation setting for logger '{}': " \
						"log rotation not completely specified",
						module_name));
			}
		}

		YAML::Node const &console_print = y_it->second["PrintToConsole"];
		if (console_print && console_print.IsScalar())
			config.PrintToConsole = console_print.as<bool>(config.PrintToConsole);

		YAML::Node const &append_logs = y_it->second["Append"];
		if (append_logs && append_logs.IsScalar())
			config.Append = append_logs.as<bool>(config.Append);

		_loggerConfigs.emplace(module_name, std::move(config));
	}

	_levelConfigs.clear();
	YAML::Node const &levels = root["LogLevel"];
	for (YAML::const_iterator y_it = levels.begin(); y_it != levels.end(); ++y_it)
	{
		LogLevel level = static_cast<LogLevel>(0); // initialize to zero as ParseLogLevel OR's levels
		if (!ParseLogLevel(y_it->first, level, "could not parse log level setting"))
			continue;

		LogLevelConfig config;
		YAML::Node const &console_print_opt = y_it->second["PrintToConsole"];
		if (console_print_opt && console_print_opt.IsScalar())
			config.PrintToConsole = console_print_opt.as<bool>(config.PrintToConsole);

		_levelConfigs.emplace(level, std::move(config));
	}

	//global config settings
	_globalConfig = GlobalConfig();
	YAML::Node const &logtime_format = root["LogTimeFormat"];
	if (logtime_format && logtime_format.IsScalar())
	{
		auto const time_format = logtime_format.as<std::string>(_globalConfig.LogTimeFormat);
		if (ValidateTimeFormat(time_format))
		{
			_globalConfig.LogTimeFormat = time_format;
		}
		else
		{
			LogManager::Get()->LogInternal(LogLevel::WARNING, fmt::format(
				"could not parse log time format: '{:s}' " \
				"is not a valid time format string", time_format));
		}
	}

	YAML::Node const &enable_colors = root["EnableColors"];
	if (enable_colors && enable_colors.IsScalar())
		_globalConfig.EnableColors = enable_colors.as<bool>(_globalConfig.EnableColors);

	YAML::Node const &disable_debug = root["DisableDebugInfo"];
	if (disable_debug && disable_debug.IsScalar())
		_globalConfig.DisableDebugInfo = disable_debug.as<bool>(_globalConfig.DisableDebugInfo);
}

void LogConfig::Initialize()
{
	ParseConfigFile();
	_fileWatcher.reset(new FileChangeDetector(CONFIG_FILE_NAME, [this]()
	{
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"config file change detected, reloading...");
		ParseConfigFile();
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"reloading finished");
	}));
}
<|endoftext|>


<commit_before>#include "pch.h"
#include "jnc_ct_ScheduleLauncherFunction.h"
#include "jnc_ct_Module.h"

namespace jnc {
namespace ct {

//.............................................................................

bool
ScheduleLauncherFunction::compile ()
{
	bool result;

	size_t argCount = m_type->getArgArray ().getCount ();

	char buffer [256];
	sl::Array <Value> argValueArray (ref::BufKind_Stack, buffer, sizeof (buffer));
	argValueArray.setCount (argCount);

	m_module->m_functionMgr.internalPrologue (this, argValueArray, argCount);

	Value functionPtrValue = argValueArray [0];
	Value schedulerValue = argValueArray [1];
	Value scheduleValue;

	result = m_module->m_operatorMgr.memberOperator (schedulerValue, "schedule", &scheduleValue);
	if (!result)
		return false;

	if (argCount > 2)
	{
		sl::BoxList <Value> argList;
		for (size_t i = 2; i < argCount; i++)
			argList.insertTail (argValueArray [i]);

		result = m_module->m_operatorMgr.closureOperator (&functionPtrValue, &argList);
		if (!result)
			return false;
	}

	result = m_module->m_operatorMgr.callOperator (scheduleValue, functionPtrValue);
	if (!result)
		return false;

	m_module->m_functionMgr.internalEpilogue ();
	return true;
}

//.............................................................................

} // namespace ct
} // namespace jnc
<commit_msg>[jancy] critical update: schedule launcher functions should mark gc-root arguments (otherwise it's extremely error-prone when calling scheduled function pointers from C++)<commit_after>#include "pch.h"
#include "jnc_ct_ScheduleLauncherFunction.h"
#include "jnc_ct_Module.h"

namespace jnc {
namespace ct {

//.............................................................................

bool
ScheduleLauncherFunction::compile ()
{
	bool result;

	size_t argCount = m_type->getArgArray ().getCount ();

	char buffer [256];
	sl::Array <Value> argValueArray (ref::BufKind_Stack, buffer, sizeof (buffer));
	argValueArray.setCount (argCount);

	m_module->m_functionMgr.internalPrologue (this, argValueArray, argCount);

	Value functionPtrValue = argValueArray [0];
	Value schedulerValue = argValueArray [1];
	Value scheduleValue;

	result = m_module->m_operatorMgr.memberOperator (schedulerValue, "schedule", &scheduleValue);
	if (!result)
		return false;

	if (argCount > 2)
	{
		sl::BoxList <Value> argList;
		for (size_t i = 2; i < argCount; i++)
		{
			Value argValue = argValueArray [i];
			argList.insertTail (argValue);

			Type* argType = argValue.getType ();
			if (argType->getFlags () & TypeFlag_GcRoot)
			{
				Value argVariable;
				m_module->m_llvmIrBuilder.createAlloca (argType, "gcRoot", NULL, &argVariable);
				m_module->m_llvmIrBuilder.createStore (argValue, argVariable);
				m_module->m_gcShadowStackMgr.markGcRoot (argVariable, argType);
			}
		}

		result = m_module->m_operatorMgr.closureOperator (&functionPtrValue, &argList);
		if (!result)
			return false;
	}

	result = m_module->m_operatorMgr.callOperator (scheduleValue, functionPtrValue);
	if (!result)
		return false;

	m_module->m_functionMgr.internalEpilogue ();
	return true;
}

//.............................................................................

} // namespace ct
} // namespace jnc
<|endoftext|>


<commit_before>// Copyright (c) 2014, Facebook, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.

#include "port/likely.h"
#include "util/mutexlock.h"
#include "util/thread_status_impl.h"

namespace rocksdb {

ThreadStatusImpl thread_local_status;

#if ROCKSDB_USING_THREAD_STATUS
__thread ThreadStatusData* ThreadStatusImpl::thread_status_data_ = nullptr;
std::mutex ThreadStatusImpl::thread_list_mutex_;
std::unordered_set<ThreadStatusData*> ThreadStatusImpl::thread_data_set_;
std::unordered_map<const void*, ConstantColumnFamilyInfo*>
    ThreadStatusImpl::cf_info_map_;
std::unordered_map<const void*, std::unordered_set<const void*>>
    ThreadStatusImpl::db_key_map_;

ThreadStatusImpl::~ThreadStatusImpl() {
  assert(thread_data_set_.size() == 0);
}

void ThreadStatusImpl::UnregisterThread() {
  if (thread_status_data_ != nullptr) {
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.erase(thread_status_data_);
    delete thread_status_data_;
    thread_status_data_ = nullptr;
  }
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
  auto* data = InitAndGet();
  data->thread_type.store(ttype, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
  auto* data = InitAndGet();
  data->cf_key.store(cf_key, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
  auto* data = InitAndGet();
  data->event_info.store(event_info, std::memory_order_relaxed);
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  thread_list->clear();
  std::vector<std::shared_ptr<ThreadStatusData>> valid_list;

  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  for (auto* thread_data : thread_data_set_) {
    assert(thread_data);
    auto thread_type = thread_data->thread_type.load(
        std::memory_order_relaxed);
    auto cf_key = thread_data->cf_key.load(
        std::memory_order_relaxed);
    auto iter = cf_info_map_.find(cf_key);
    assert(cf_key == 0 || iter != cf_info_map_.end());
    auto* cf_info = iter != cf_info_map_.end() ?
        iter->second : nullptr;
    auto* event_info = thread_data->event_info.load(
        std::memory_order_relaxed);
    const std::string* db_name = nullptr;
    const std::string* cf_name = nullptr;
    const std::string* event_name = nullptr;
    if (cf_info != nullptr) {
      db_name = &cf_info->db_name;
      cf_name = &cf_info->cf_name;
      // display lower-level info only when higher-level info is available.
      if (event_info != nullptr) {
        event_name = &event_info->event_name;
      }
    }
    thread_list->emplace_back(
        thread_data->thread_id, thread_type,
        db_name ? *db_name : "",
        cf_name ? *cf_name : "",
        event_name ? *event_name : "");
  }

  return Status::OK();
}

ThreadStatusData* ThreadStatusImpl::InitAndGet() {
  if (UNLIKELY(thread_status_data_ == nullptr)) {
    thread_status_data_ = new ThreadStatusData();
    thread_status_data_->thread_id = reinterpret_cast<uint64_t>(
        thread_status_data_);
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.insert(thread_status_data_);
  }
  return thread_status_data_;
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);

  cf_info_map_[cf_key] = new ConstantColumnFamilyInfo(db_key, db_name, cf_name);
  db_key_map_[db_key].insert(cf_key);
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto cf_pair = cf_info_map_.find(cf_key);
  assert(cf_pair != cf_info_map_.end());

  auto* cf_info = cf_pair->second;
  assert(cf_info);

  // Remove its entry from db_key_map_ by the following steps:
  // 1. Obtain the entry in db_key_map_ whose set contains cf_key
  // 2. Remove it from the set.
  auto db_pair = db_key_map_.find(cf_info->db_key);
  assert(db_pair != db_key_map_.end());
  size_t result __attribute__((unused)) = db_pair->second.erase(cf_key);
  assert(result);

  delete cf_info;
  result = cf_info_map_.erase(cf_key);
  assert(result);
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto db_pair = db_key_map_.find(db_key);
  if (UNLIKELY(db_pair == db_key_map_.end())) {
    // In some occasional cases such as DB::Open fails, we won't
    // register ColumnFamilyInfo for a db.
    return;
  }

  size_t result __attribute__((unused)) = 0;
  for (auto cf_key : db_pair->second) {
    auto cf_pair = cf_info_map_.find(cf_key);
    assert(cf_pair != cf_info_map_.end());
    delete cf_pair->second;
    result = cf_info_map_.erase(cf_key);
    assert(result);
  }
  db_key_map_.erase(db_key);
}

#else

ThreadStatusImpl::~ThreadStatusImpl() {
}

void ThreadStatusImpl::UnregisterThread() {
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  return Status::NotSupported(
      "GetThreadList is not supported in the current running environment.");
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
}

#endif  // ROCKSDB_USING_THREAD_STATUS
}  // namespace rocksdb
<commit_msg>Fixed the destruction order of static variables in ThreadStatusImpl.<commit_after>// Copyright (c) 2014, Facebook, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.

#include "port/likely.h"
#include "util/mutexlock.h"
#include "util/thread_status_impl.h"

namespace rocksdb {

#if ROCKSDB_USING_THREAD_STATUS
__thread ThreadStatusData* ThreadStatusImpl::thread_status_data_ = nullptr;
std::mutex ThreadStatusImpl::thread_list_mutex_;
std::unordered_set<ThreadStatusData*> ThreadStatusImpl::thread_data_set_;
std::unordered_map<const void*, ConstantColumnFamilyInfo*>
    ThreadStatusImpl::cf_info_map_;
std::unordered_map<const void*, std::unordered_set<const void*>>
    ThreadStatusImpl::db_key_map_;

ThreadStatusImpl thread_local_status;

ThreadStatusImpl::~ThreadStatusImpl() {
  assert(thread_data_set_.size() == 0);
}

void ThreadStatusImpl::UnregisterThread() {
  if (thread_status_data_ != nullptr) {
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.erase(thread_status_data_);
    delete thread_status_data_;
    thread_status_data_ = nullptr;
  }
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
  auto* data = InitAndGet();
  data->thread_type.store(ttype, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
  auto* data = InitAndGet();
  data->cf_key.store(cf_key, std::memory_order_relaxed);
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
  auto* data = InitAndGet();
  data->event_info.store(event_info, std::memory_order_relaxed);
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  thread_list->clear();
  std::vector<std::shared_ptr<ThreadStatusData>> valid_list;

  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  for (auto* thread_data : thread_data_set_) {
    assert(thread_data);
    auto thread_type = thread_data->thread_type.load(
        std::memory_order_relaxed);
    auto cf_key = thread_data->cf_key.load(
        std::memory_order_relaxed);
    auto iter = cf_info_map_.find(cf_key);
    assert(cf_key == 0 || iter != cf_info_map_.end());
    auto* cf_info = iter != cf_info_map_.end() ?
        iter->second : nullptr;
    auto* event_info = thread_data->event_info.load(
        std::memory_order_relaxed);
    const std::string* db_name = nullptr;
    const std::string* cf_name = nullptr;
    const std::string* event_name = nullptr;
    if (cf_info != nullptr) {
      db_name = &cf_info->db_name;
      cf_name = &cf_info->cf_name;
      // display lower-level info only when higher-level info is available.
      if (event_info != nullptr) {
        event_name = &event_info->event_name;
      }
    }
    thread_list->emplace_back(
        thread_data->thread_id, thread_type,
        db_name ? *db_name : "",
        cf_name ? *cf_name : "",
        event_name ? *event_name : "");
  }

  return Status::OK();
}

ThreadStatusData* ThreadStatusImpl::InitAndGet() {
  if (UNLIKELY(thread_status_data_ == nullptr)) {
    thread_status_data_ = new ThreadStatusData();
    thread_status_data_->thread_id = reinterpret_cast<uint64_t>(
        thread_status_data_);
    std::lock_guard<std::mutex> lck(thread_list_mutex_);
    thread_data_set_.insert(thread_status_data_);
  }
  return thread_status_data_;
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);

  cf_info_map_[cf_key] = new ConstantColumnFamilyInfo(db_key, db_name, cf_name);
  db_key_map_[db_key].insert(cf_key);
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto cf_pair = cf_info_map_.find(cf_key);
  assert(cf_pair != cf_info_map_.end());

  auto* cf_info = cf_pair->second;
  assert(cf_info);

  // Remove its entry from db_key_map_ by the following steps:
  // 1. Obtain the entry in db_key_map_ whose set contains cf_key
  // 2. Remove it from the set.
  auto db_pair = db_key_map_.find(cf_info->db_key);
  assert(db_pair != db_key_map_.end());
  size_t result __attribute__((unused)) = db_pair->second.erase(cf_key);
  assert(result);

  delete cf_info;
  result = cf_info_map_.erase(cf_key);
  assert(result);
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
  std::lock_guard<std::mutex> lck(thread_list_mutex_);
  auto db_pair = db_key_map_.find(db_key);
  if (UNLIKELY(db_pair == db_key_map_.end())) {
    // In some occasional cases such as DB::Open fails, we won't
    // register ColumnFamilyInfo for a db.
    return;
  }

  size_t result __attribute__((unused)) = 0;
  for (auto cf_key : db_pair->second) {
    auto cf_pair = cf_info_map_.find(cf_key);
    assert(cf_pair != cf_info_map_.end());
    delete cf_pair->second;
    result = cf_info_map_.erase(cf_key);
    assert(result);
  }
  db_key_map_.erase(db_key);
}

#else

ThreadStatusImpl::~ThreadStatusImpl() {
}

void ThreadStatusImpl::UnregisterThread() {
}

void ThreadStatusImpl::SetThreadType(
    ThreadStatus::ThreadType ttype) {
}

void ThreadStatusImpl::SetColumnFamilyInfoKey(
    const void* cf_key) {
}

void ThreadStatusImpl::SetEventInfoPtr(
    const ThreadEventInfo* event_info) {
}

Status ThreadStatusImpl::GetThreadList(
    std::vector<ThreadStatus>* thread_list) const {
  return Status::NotSupported(
      "GetThreadList is not supported in the current running environment.");
}

void ThreadStatusImpl::NewColumnFamilyInfo(
    const void* db_key, const std::string& db_name,
    const void* cf_key, const std::string& cf_name) {
}

void ThreadStatusImpl::EraseColumnFamilyInfo(const void* cf_key) {
}

void ThreadStatusImpl::EraseDatabaseInfo(const void* db_key) {
}

ThreadStatusImpl thread_local_status;
#endif  // ROCKSDB_USING_THREAD_STATUS
}  // namespace rocksdb
<|endoftext|>


<commit_before>#include "SimpleAudioEngine.h"
#include "AppDelegate.h"
#include "MenuScene.h"
#include "Path.h"

USING_NS_CC;
using CocosDenshion::SimpleAudioEngine;

AppDelegate::AppDelegate() { }

AppDelegate::~AppDelegate() { }

//if you want a different context,just modify the value of glContextAttrs
//it will takes effect on all platforms
void AppDelegate::initGLContextAttrs()
{
    //set OpenGL context attributions,now can only set six attributions:
    //red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

// If you want to use packages manager to install more packages,
// don't modify or remove this function
static int register_all_packages()
{
    return 0; //flag for packages manager
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLViewImpl::create("Flappy Bird");
        glview->setFrameSize(360, 640);
        director->setOpenGLView(glview);
    }

    glview->setDesignResolutionSize(288, 512, ResolutionPolicy::NO_BORDER);

    // turn on display FPS
    director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    register_all_packages();

    srand(time(NULL));

    preloadSFX();

    // create a scene. it's an autorelease object
    auto scene = MenuScene::createScene();

    // run
    director->runWithScene(scene);

    return true;
}
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground()
{
    Director::getInstance()->stopAnimation();

    // if you use SimpleAudioEngine, it must be pause
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
    Director::getInstance()->startAnimation();

    // if you use SimpleAudioEngine, it must resume here
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}

void AppDelegate::preloadSFX()
{
    auto audioEngine = SimpleAudioEngine::getInstance();

    audioEngine->preloadEffect(SFX_DIE);
    audioEngine->preloadEffect(SFX_HIT);
    audioEngine->preloadEffect(SFX_POINT);
    audioEngine->preloadEffect(SFX_SWOOSHING);
    audioEngine->preloadEffect(SFX_WING);

    audioEngine->setEffectsVolume(0.4f);
}

<commit_msg>Turn off display FPS<commit_after>#include "SimpleAudioEngine.h"
#include "AppDelegate.h"
#include "MenuScene.h"
#include "Path.h"

USING_NS_CC;
using CocosDenshion::SimpleAudioEngine;

AppDelegate::AppDelegate() { }

AppDelegate::~AppDelegate() { }

//if you want a different context,just modify the value of glContextAttrs
//it will takes effect on all platforms
void AppDelegate::initGLContextAttrs()
{
    //set OpenGL context attributions,now can only set six attributions:
    //red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

// If you want to use packages manager to install more packages,
// don't modify or remove this function
static int register_all_packages()
{
    return 0; //flag for packages manager
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLViewImpl::create("Flappy Bird");
        glview->setFrameSize(360, 640);
        director->setOpenGLView(glview);
    }

    glview->setDesignResolutionSize(288, 512, ResolutionPolicy::NO_BORDER);

    // turn on display FPS
    director->setDisplayStats(false);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    register_all_packages();

    srand(time(NULL));

    preloadSFX();

    // create a scene. it's an autorelease object
    auto scene = MenuScene::createScene();

    // run
    director->runWithScene(scene);

    return true;
}
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground()
{
    Director::getInstance()->stopAnimation();

    // if you use SimpleAudioEngine, it must be pause
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
    Director::getInstance()->startAnimation();

    // if you use SimpleAudioEngine, it must resume here
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}

void AppDelegate::preloadSFX()
{
    auto audioEngine = SimpleAudioEngine::getInstance();

    audioEngine->preloadEffect(SFX_DIE);
    audioEngine->preloadEffect(SFX_HIT);
    audioEngine->preloadEffect(SFX_POINT);
    audioEngine->preloadEffect(SFX_SWOOSHING);
    audioEngine->preloadEffect(SFX_WING);

    audioEngine->setEffectsVolume(0.4f);
}

<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include "floppy.h"

using namespace Device;

void Floppy::Open(const std::string &fname){
	std::stringstream ss;
	fs.open(fname, std::ios::in | std::ios::out |std::ios::binary);
	if(fs.fail()){
		ss << "Floppy: cannot open file \'"
			<<fname
			<<"\'";
		throw ss.str();
	}

	// ファイルサイズのチェック
	size_t size;
	{
		fs.seekg(0, std::fstream::end);
		auto end = fs.tellg();
		fs.clear();
		fs.seekg(0, std::fstream::beg);
		auto start = fs.tellg();
		size = end - start;
	}
	DOUT("Floppy: file size="<<size/KB<<"KB"<<std::endl);
	if(size/KB != 1440) throw "Floppy: file size is not 1440KB";
}

bool Floppy::Seek(const Floppy::Setting &set){
	if(set.cylinder > 79){
		DOUT("Floppy: cylinder error: "<<static_cast<uint32_t>(set.cylinder)<<std::endl);
		return false;
	}
	if(set.sector==0 || set.sector > 18){
		DOUT("Floppy: sector error: "<<static_cast<uint32_t>(set.sector)<<std::endl);
		return false;
	}

	DOUT("Floppy: Seek: drive="<<std::dec<<static_cast<uint32_t>(set.drive)
			<<", head="<<set.head
			<<", cylinder="<<static_cast<uint32_t>(set.cylinder)
			<<", sector="<<static_cast<uint32_t>(set.sector)
			<<std::endl);
	this->set = set;

	fs.seekg(0, std::fstream::beg);
	if(set.head)
		fs.seekg(512*18, std::fstream::cur);
	if(set.cylinder)
		fs.seekg(set.cylinder*512*36, std::fstream::cur);
	fs.seekg(512*(set.sector-1), std::fstream::cur);
//	std::cout<<set.head*18 + set.cylinder*36 + (set.sector -1)<<std::endl;
	if(fs.fail()) return false;
	return true;
}

bool Floppy::Read(Memory *mem, uint32_t addr, uint8_t sector_num){
	DOUT("Floppy: Read: sector num="<<static_cast<uint32_t>(sector_num)<<std::endl);
	Load(mem, addr, 512*sector_num);
	return true;
}

void Floppy::Load(Memory *mem, uint32_t addr, uint32_t size){
	DOUT("Floppy: loading to memory... addr=0x"<<std::hex<<addr<<", size=0x"<<size<<std::endl);
	fs.read((char*)&mem->GetRaw()[addr], size);
}
<commit_msg>[UPDATE]<commit_after>#include <iostream>
#include <sstream>
#include "floppy.h"

using namespace Device;

void Floppy::Open(const std::string &fname){
	std::stringstream ss;
	fs.open(fname, std::ios::in | std::ios::out |std::ios::binary);
	if(fs.fail()){
		ss << "Floppy: cannot open file \'"
			<<fname
			<<"\'";
		throw ss.str();
	}

	// ファイルサイズのチェック
	size_t size;
	{
		fs.seekg(0, std::fstream::end);
		auto end = fs.tellg();
		fs.clear();
		fs.seekg(0, std::fstream::beg);
		auto start = fs.tellg();
		size = end - start;
	}
	DOUT("Floppy: file size="<<size/KB<<"KB"<<std::endl);
	if(size != 1440 * KB)
		std::cerr<<"warning: Floppy: file size is not 1440KB"<<std::endl;
}

bool Floppy::Seek(const Floppy::Setting &set){
	if(set.cylinder > 79){
		DOUT("Floppy: cylinder error: "<<static_cast<uint32_t>(set.cylinder)<<std::endl);
		return false;
	}
	if(set.sector==0 || set.sector > 18){
		DOUT("Floppy: sector error: "<<static_cast<uint32_t>(set.sector)<<std::endl);
		return false;
	}

	DOUT("Floppy: Seek: drive="<<std::dec<<static_cast<uint32_t>(set.drive)
			<<", head="<<set.head
			<<", cylinder="<<static_cast<uint32_t>(set.cylinder)
			<<", sector="<<static_cast<uint32_t>(set.sector)
			<<std::endl);
	this->set = set;

	fs.seekg(0, std::fstream::beg);
	if(set.head)
		fs.seekg(512*18, std::fstream::cur);
	if(set.cylinder)
		fs.seekg(set.cylinder*512*36, std::fstream::cur);
	fs.seekg(512*(set.sector-1), std::fstream::cur);
//	std::cout<<set.head*18 + set.cylinder*36 + (set.sector -1)<<std::endl;
	if(fs.fail()) return false;
	return true;
}

bool Floppy::Read(Memory *mem, uint32_t addr, uint8_t sector_num){
	DOUT("Floppy: Read: sector num="<<static_cast<uint32_t>(sector_num)<<std::endl);
	Load(mem, addr, 512*sector_num);
	return true;
}

void Floppy::Load(Memory *mem, uint32_t addr, uint32_t size){
	DOUT("Floppy: loading to memory... addr=0x"<<std::hex<<addr<<", size=0x"<<size<<std::endl);
	fs.read((char*)&mem->GetRaw()[addr], size);
}
<|endoftext|>