<commit_before>//===-- ExternalCommand.cpp -----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "llbuild/BuildSystem/ExternalCommand.h"

#include "llbuild/Basic/Hashing.h"
#include "llbuild/Basic/ExecutionQueue.h"
#include "llbuild/Basic/FileSystem.h"
#include "llbuild/BuildSystem/BuildFile.h"
#include "llbuild/BuildSystem/BuildKey.h"
#include "llbuild/BuildSystem/BuildNode.h"
#include "llbuild/BuildSystem/BuildSystemCommandInterface.h"
#include "llbuild/BuildSystem/BuildValue.h"

#include "llbuild/Basic/FileInfo.h"
#include "llbuild/Basic/LLVM.h"

#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace llbuild;
using namespace llbuild::basic;
using namespace llbuild::buildsystem;

CommandSignature ExternalCommand::getSignature() const {
  CommandSignature code(getName());
  for (const auto* input: inputs) {
    code = code.combine(input->getName());
  }
  for (const auto* output: outputs) {
    code = code.combine(output->getName());
  }
  return code
      .combine(allowMissingInputs)
      .combine(allowModifiedOutputs)
      .combine(alwaysOutOfDate);
}

void ExternalCommand::configureDescription(const ConfigureContext&,
                                           StringRef value) {
  description = value;
}

void ExternalCommand::
configureInputs(const ConfigureContext&,
                const std::vector<Node*>& value) {
  inputs.reserve(value.size());
  for (auto* node: value) {
    inputs.emplace_back(static_cast<BuildNode*>(node));
  }
}

void ExternalCommand::
configureOutputs(const ConfigureContext&, const std::vector<Node*>& value) {
  outputs.reserve(value.size());
  for (auto* node: value) {
    outputs.emplace_back(static_cast<BuildNode*>(node));
  }
}

bool ExternalCommand::
configureAttribute(const ConfigureContext& ctx, StringRef name,
                   StringRef value) {
  if (name == "allow-missing-inputs") {
    if (value != "true" && value != "false") {
      ctx.error("invalid value: '" + value + "' for attribute '" +
                name + "'");
      return false;
    }
    allowMissingInputs = value == "true";
    return true;
  } else if (name == "allow-modified-outputs") {
    if (value != "true" && value != "false") {
      ctx.error("invalid value: '" + value + "' for attribute '" +
                name + "'");
      return false;
    }
    allowModifiedOutputs = value == "true";
    return true;
  } else if (name == "always-out-of-date") {
    if (value != "true" && value != "false") {
      ctx.error("invalid value: '" + value + "' for attribute '" +
                name + "'");
      return false;
    }
    alwaysOutOfDate = value == "true";
    return true;
  } else {
    ctx.error("unexpected attribute: '" + name + "'");
    return false;
  }
}
bool ExternalCommand::
configureAttribute(const ConfigureContext& ctx, StringRef name,
                   ArrayRef<StringRef> values) {
  ctx.error("unexpected attribute: '" + name + "'");
  return false;
}
bool ExternalCommand::configureAttribute(
    const ConfigureContext& ctx, StringRef name,
    ArrayRef<std::pair<StringRef, StringRef>> values) {
  ctx.error("unexpected attribute: '" + name + "'");
  return false;
}

BuildValue ExternalCommand::
getResultForOutput(Node* node, const BuildValue& value) {
  // If the value was a failed or cancelled command, propagate the failure.
  if (value.isFailedCommand() || value.isPropagatedFailureCommand() ||
      value.isCancelledCommand())
    return BuildValue::makeFailedInput();
  if (value.isSkippedCommand())
      return BuildValue::makeSkippedCommand();

  // Otherwise, we should have a successful command -- return the actual
  // result for the output.
  assert(value.isSuccessfulCommand());

  // If the node is virtual, the output is always a virtual input value.
  //
  // FIXME: Eliminate this, and make the build value array contain an array of
  // build values.
  auto buildNode = static_cast<BuildNode*>(node);
  if (buildNode->isVirtual() && !buildNode->isCommandTimestamp()) {
    return BuildValue::makeVirtualInput();
  }

  // Find the index of the output node.
  //
  // FIXME: This is O(N). We don't expect N to be large in practice, but it
  // could be.
  auto it = std::find(outputs.begin(), outputs.end(), node);
  assert(it != outputs.end());

  auto idx = it - outputs.begin();
  assert(idx < value.getNumOutputs());

  auto& info = value.getNthOutputInfo(idx);
  if (info.isMissing())
    return BuildValue::makeMissingOutput();

  return BuildValue::makeExistingInput(info);
}

bool ExternalCommand::isResultValid(BuildSystem& system,
                                    const BuildValue& value) {
  // Treat the command as always out-of-date, if requested.
  if (alwaysOutOfDate)
    return false;

  // If the prior value wasn't for a successful command, recompute.
  if (!value.isSuccessfulCommand())
    return false;

  // Check the timestamps on each of the outputs.
  for (unsigned i = 0, e = outputs.size(); i != e; ++i) {
    auto* node = outputs[i];

    // Ignore virtual outputs.
    if (node->isVirtual())
      continue;

    // Rebuild if the output information has changed.
    //
    // We intentionally allow missing outputs here, as long as they haven't
    // changed. This is under the assumption that the commands themselves are
    // behaving correctly when they exit successfully, and that downstream
    // commands would diagnose required missing inputs.
    //
    // FIXME: CONSISTENCY: One consistency issue in this model currently is that
    // if the output was missing, then appears, nothing will remove it; that
    // results in an inconsistent build. What would be nice if we supported
    // per-edge annotations on whether an output was optional -- in that case we
    // could enforce and error on the missing output if not annotated, and we
    // could enable behavior to remove such output files if annotated prior to
    // running the command.
    auto info = node->getFileInfo(system.getFileSystem());

    // If this output is mutated by the build, we can't rely on equivalence,
    // only existence.
    if (node->isMutated()) {
      if (value.getNthOutputInfo(i).isMissing() != info.isMissing())
        return false;
      continue;
    }

    if (value.getNthOutputInfo(i) != info)
      return false;
  }

  // Otherwise, the result is ok.
  return true;
}

void ExternalCommand::start(BuildSystemCommandInterface& bsci,
                            core::Task* task) {
  // Initialize the build state.
  skipValue = llvm::None;
  missingInputNodes.clear();

  // Request all of the inputs.
  unsigned id = 0;
  for (auto it = inputs.begin(), ie = inputs.end(); it != ie; ++it, ++id) {
    bsci.taskNeedsInput(task, BuildKey::makeNode(*it), id);
  }

  // Delegate to the subclass in case it needs more custom inputs.
  startExternalCommand(bsci, task);
}

void ExternalCommand::providePriorValue(BuildSystemCommandInterface&,
                                        core::Task*,
                                        const BuildValue& value) {
  if (value.isSuccessfulCommand()) {
    hasPriorResult = true;
  }
}

void ExternalCommand::provideValue(BuildSystemCommandInterface& bsci,
                                   core::Task* task,
                                   uintptr_t inputID,
                                   const BuildValue& value) {
  if (value.isSuccessfulCommand() || value.isFailedCommand()) {
    // If the value is a successful command, it must probably be a value that was requested for a custom task, so
    // skip the input processing and invoke the subclass instead to process it accordingly.
    provideValueExternalCommand(bsci, task, inputID, value);
    return;
  }

  // All direct inputs should be individual node values.
  assert(!value.hasMultipleOutputs());
  assert(value.isExistingInput() || value.isMissingInput() ||
         value.isMissingOutput() || value.isFailedInput() ||
         value.isVirtualInput()  || value.isSkippedCommand() ||
         value.isDirectoryTreeSignature() ||
         value.isDirectoryTreeStructureSignature() ||
         value.isStaleFileRemoval());

  // If the input should cause this command to skip, how should it skip?
  auto getSkipValueForInput = [&]() -> llvm::Optional<BuildValue> {
    // If the value is an signature, existing, or virtual input, we are always
    // good.
    if (value.isDirectoryTreeSignature() ||
        value.isDirectoryTreeStructureSignature() ||
        value.isExistingInput() ||
        value.isVirtualInput() || value.isStaleFileRemoval())
      return llvm::None;

    // We explicitly allow running the command against a missing output, under
    // the expectation that responsibility for reporting this situation falls to
    // the command.
    //
    // FIXME: Eventually, it might be nice to harden the format so that we know
    // when an output was actually required versus optional.
    if (value.isMissingOutput())
      return llvm::None;

    // If the value is a missing input, but those are allowed, it is ok.
    if (value.isMissingInput()) {
      if (allowMissingInputs)
        return llvm::None;
      else
        return BuildValue::makePropagatedFailureCommand();
    }

    // Propagate failure.
    if (value.isFailedInput())
      return BuildValue::makePropagatedFailureCommand();

    // A skipped dependency doesn't cause this command to skip.
    if (value.isSkippedCommand())
        return llvm::None;

    llvm_unreachable("unexpected input");
  };

  // Check if we need to skip the command because of this input.
  auto skipValueForInput = getSkipValueForInput();
  if (skipValueForInput.hasValue()) {
    skipValue = std::move(skipValueForInput);
    if (value.isMissingInput()) {
      missingInputNodes.insert(inputs[inputID]);
    }
  } else {
    // If there is a missing input file (from a successful command), we always
    // need to run the command.
    if (value.isMissingOutput())
      canUpdateIfNewer = false;
  }
}

bool ExternalCommand::canUpdateIfNewerWithResult(const BuildValue& result) {
  // Unless `allowModifiedOutputs` is specified, we always need to update if
  // ran.
  if (!allowModifiedOutputs)
    return false;

  // If it was specified, then we can update if all of our outputs simply exist.
  for (unsigned i = 0, e = result.getNumOutputs(); i != e; ++i) {
    const FileInfo& outputInfo = result.getNthOutputInfo(i);

    // If the output is missing, we need to rebuild.
    if (outputInfo.isMissing())
      return false;
  }
  return true;
}

BuildValue
ExternalCommand::computeCommandResult(BuildSystemCommandInterface& bsci) {
  // Capture the file information for each of the output nodes.
  //
  // FIXME: We need to delegate to the node here.
  SmallVector<FileInfo, 8> outputInfos;
  for (auto* node: outputs) {
    if (node->isCommandTimestamp()) {
      // FIXME: We currently have to shoehorn the timestamp into a fake file
      // info, but need to refactor the command result to just store the node
      // subvalues instead.
      FileInfo info{};
      info.size = bsci.getBuildEngine().getCurrentEpoch();
      outputInfos.push_back(info);
    } else if (node->isVirtual()) {
      outputInfos.push_back(FileInfo{});
    } else {
      outputInfos.push_back(node->getFileInfo(
                                bsci.getFileSystem()));
    }
  }

  // FIXME: If the outputs are empty, it might mean that this instance is for a custom task, which does not
  // currently have any hooks for specifying what the outputs are. It might make sense to create a new BuildValue
  // for a successful command with custom data, so that we can avoid the file system for commands that don't require
  // the filesystem. For now, hackily insert the timestamp just to differentiate between 2 build values that ran at
  // different times.
  if (outputs.size() == 0) {
    FileInfo info{};
    info.size = bsci.getBuildEngine().getCurrentEpoch();
    outputInfos.push_back(info);
  }

  return BuildValue::makeSuccessfulCommand(outputInfos);
}

void ExternalCommand::execute(BuildSystemCommandInterface& bsci,
                              core::Task* task,
                              QueueJobContext* context,
                              ResultFn resultFn) {
  // If this command should be skipped, do nothing.
  if (skipValue.hasValue()) {
    // If this command had a failed input, treat it as having failed.
    if (!missingInputNodes.empty()) {
      bsci.getDelegate().commandCannotBuildOutputDueToMissingInputs(this,
                         outputs[0], missingInputNodes);

      // Report the command failure.
      bsci.getDelegate().hadCommandFailure();
    }

    resultFn(std::move(skipValue.getValue()));
    return;
  }
  assert(missingInputNodes.empty());

  // If it is legal to simply update the command, then see if we can do so.
  if (canUpdateIfNewer && hasPriorResult) {
    BuildValue result = computeCommandResult(bsci);
    if (canUpdateIfNewerWithResult(result)) {
      resultFn(std::move(result));
      return;
    }
  }

  // Create the directories for the directories containing file outputs.
  //
  // FIXME: Implement a shared cache for this, to reduce the number of
  // syscalls required to make this happen.
  for (auto* node: outputs) {
    if (!node->isVirtual()) {
      // Attempt to create the directory; we ignore errors here under the
      // assumption the command will diagnose the situation if necessary.
      //
      // FIXME: Need to use the filesystem interfaces.
      auto parent = llvm::sys::path::parent_path(node->getName());
      if (!parent.empty()) {
        (void) bsci.getFileSystem().createDirectories(parent);
      }
    }
  }

  // Invoke the external command.
  bsci.getDelegate().commandStarted(this);
  executeExternalCommand(bsci, task, context, {[this, &bsci, resultFn](ProcessResult result){
    bsci.getDelegate().commandFinished(this, result.status);

    // Process the result.
    switch (result.status) {
    case ProcessStatus::Failed:
      resultFn(BuildValue::makeFailedCommand());
      return;
    case ProcessStatus::Cancelled:
      resultFn(BuildValue::makeCancelledCommand());
      return;
    case ProcessStatus::Succeeded:
      resultFn(computeCommandResult(bsci));
      return;
    case ProcessStatus::Skipped:
      // It is illegal to get skipped result at this point.
      break;
    }
    llvm::report_fatal_error("unknown result");
  }});
}
<commit_msg>Add ExternalCommand workaround for dynamic dependencies<commit_after>//===-- ExternalCommand.cpp -----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "llbuild/BuildSystem/ExternalCommand.h"

#include "llbuild/Basic/Hashing.h"
#include "llbuild/Basic/ExecutionQueue.h"
#include "llbuild/Basic/FileSystem.h"
#include "llbuild/BuildSystem/BuildFile.h"
#include "llbuild/BuildSystem/BuildKey.h"
#include "llbuild/BuildSystem/BuildNode.h"
#include "llbuild/BuildSystem/BuildSystemCommandInterface.h"
#include "llbuild/BuildSystem/BuildValue.h"

#include "llbuild/Basic/FileInfo.h"
#include "llbuild/Basic/LLVM.h"

#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace llbuild;
using namespace llbuild::basic;
using namespace llbuild::buildsystem;

CommandSignature ExternalCommand::getSignature() const {
  CommandSignature code(getName());
  for (const auto* input: inputs) {
    code = code.combine(input->getName());
  }
  for (const auto* output: outputs) {
    code = code.combine(output->getName());
  }
  return code
      .combine(allowMissingInputs)
      .combine(allowModifiedOutputs)
      .combine(alwaysOutOfDate);
}

void ExternalCommand::configureDescription(const ConfigureContext&,
                                           StringRef value) {
  description = value;
}

void ExternalCommand::
configureInputs(const ConfigureContext&,
                const std::vector<Node*>& value) {
  inputs.reserve(value.size());
  for (auto* node: value) {
    inputs.emplace_back(static_cast<BuildNode*>(node));
  }
}

void ExternalCommand::
configureOutputs(const ConfigureContext&, const std::vector<Node*>& value) {
  outputs.reserve(value.size());
  for (auto* node: value) {
    outputs.emplace_back(static_cast<BuildNode*>(node));
  }
}

bool ExternalCommand::
configureAttribute(const ConfigureContext& ctx, StringRef name,
                   StringRef value) {
  if (name == "allow-missing-inputs") {
    if (value != "true" && value != "false") {
      ctx.error("invalid value: '" + value + "' for attribute '" +
                name + "'");
      return false;
    }
    allowMissingInputs = value == "true";
    return true;
  } else if (name == "allow-modified-outputs") {
    if (value != "true" && value != "false") {
      ctx.error("invalid value: '" + value + "' for attribute '" +
                name + "'");
      return false;
    }
    allowModifiedOutputs = value == "true";
    return true;
  } else if (name == "always-out-of-date") {
    if (value != "true" && value != "false") {
      ctx.error("invalid value: '" + value + "' for attribute '" +
                name + "'");
      return false;
    }
    alwaysOutOfDate = value == "true";
    return true;
  } else {
    ctx.error("unexpected attribute: '" + name + "'");
    return false;
  }
}
bool ExternalCommand::
configureAttribute(const ConfigureContext& ctx, StringRef name,
                   ArrayRef<StringRef> values) {
  ctx.error("unexpected attribute: '" + name + "'");
  return false;
}
bool ExternalCommand::configureAttribute(
    const ConfigureContext& ctx, StringRef name,
    ArrayRef<std::pair<StringRef, StringRef>> values) {
  ctx.error("unexpected attribute: '" + name + "'");
  return false;
}

BuildValue ExternalCommand::
getResultForOutput(Node* node, const BuildValue& value) {
  // If the value was a failed or cancelled command, propagate the failure.
  if (value.isFailedCommand() || value.isPropagatedFailureCommand() ||
      value.isCancelledCommand())
    return BuildValue::makeFailedInput();
  if (value.isSkippedCommand())
      return BuildValue::makeSkippedCommand();

  // Otherwise, we should have a successful command -- return the actual
  // result for the output.
  assert(value.isSuccessfulCommand());

  // If the node is virtual, the output is always a virtual input value.
  //
  // FIXME: Eliminate this, and make the build value array contain an array of
  // build values.
  auto buildNode = static_cast<BuildNode*>(node);
  if (buildNode->isVirtual() && !buildNode->isCommandTimestamp()) {
    return BuildValue::makeVirtualInput();
  }

  // Find the index of the output node.
  //
  // FIXME: This is O(N). We don't expect N to be large in practice, but it
  // could be.
  auto it = std::find(outputs.begin(), outputs.end(), node);
  assert(it != outputs.end());

  auto idx = it - outputs.begin();
  assert(idx < value.getNumOutputs());

  auto& info = value.getNthOutputInfo(idx);
  if (info.isMissing())
    return BuildValue::makeMissingOutput();

  return BuildValue::makeExistingInput(info);
}

bool ExternalCommand::isResultValid(BuildSystem& system,
                                    const BuildValue& value) {
  // Treat the command as always out-of-date, if requested.
  if (alwaysOutOfDate)
    return false;

  // If the prior value wasn't for a successful command, recompute.
  if (!value.isSuccessfulCommand())
    return false;

  // Check the timestamps on each of the outputs.
  for (unsigned i = 0, e = outputs.size(); i != e; ++i) {
    auto* node = outputs[i];

    // Ignore virtual outputs.
    if (node->isVirtual())
      continue;

    // Rebuild if the output information has changed.
    //
    // We intentionally allow missing outputs here, as long as they haven't
    // changed. This is under the assumption that the commands themselves are
    // behaving correctly when they exit successfully, and that downstream
    // commands would diagnose required missing inputs.
    //
    // FIXME: CONSISTENCY: One consistency issue in this model currently is that
    // if the output was missing, then appears, nothing will remove it; that
    // results in an inconsistent build. What would be nice if we supported
    // per-edge annotations on whether an output was optional -- in that case we
    // could enforce and error on the missing output if not annotated, and we
    // could enable behavior to remove such output files if annotated prior to
    // running the command.
    auto info = node->getFileInfo(system.getFileSystem());

    // If this output is mutated by the build, we can't rely on equivalence,
    // only existence.
    if (node->isMutated()) {
      if (value.getNthOutputInfo(i).isMissing() != info.isMissing())
        return false;
      continue;
    }

    if (value.getNthOutputInfo(i) != info)
      return false;
  }

  // Otherwise, the result is ok.
  return true;
}

void ExternalCommand::start(BuildSystemCommandInterface& bsci,
                            core::Task* task) {
  // Initialize the build state.
  skipValue = llvm::None;
  missingInputNodes.clear();

  // Request all of the inputs.
  unsigned id = 0;
  for (auto it = inputs.begin(), ie = inputs.end(); it != ie; ++it, ++id) {
    bsci.taskNeedsInput(task, BuildKey::makeNode(*it), id);
  }

  // Delegate to the subclass in case it needs more custom inputs.
  startExternalCommand(bsci, task);
}

void ExternalCommand::providePriorValue(BuildSystemCommandInterface&,
                                        core::Task*,
                                        const BuildValue& value) {
  if (value.isSuccessfulCommand()) {
    hasPriorResult = true;
  }
}

void ExternalCommand::provideValue(BuildSystemCommandInterface& bsci,
                                   core::Task* task,
                                   uintptr_t inputID,
                                   const BuildValue& value) {
  if (value.isSuccessfulCommand() || value.isFailedCommand() || value.isPropagatedFailureCommand()) {
    // If the value is a successful command, it must probably be a value that was requested for a custom task, so
    // skip the input processing and invoke the subclass instead to process it accordingly.
    provideValueExternalCommand(bsci, task, inputID, value);
    return;
  }

  // All direct inputs should be individual node values.
  assert(!value.hasMultipleOutputs());
  assert(value.isExistingInput() || value.isMissingInput() ||
         value.isMissingOutput() || value.isFailedInput() ||
         value.isVirtualInput()  || value.isSkippedCommand() ||
         value.isDirectoryTreeSignature() ||
         value.isDirectoryTreeStructureSignature() ||
         value.isStaleFileRemoval());

  // If the input should cause this command to skip, how should it skip?
  auto getSkipValueForInput = [&]() -> llvm::Optional<BuildValue> {
    // If the value is an signature, existing, or virtual input, we are always
    // good.
    if (value.isDirectoryTreeSignature() ||
        value.isDirectoryTreeStructureSignature() ||
        value.isExistingInput() ||
        value.isVirtualInput() || value.isStaleFileRemoval())
      return llvm::None;

    // We explicitly allow running the command against a missing output, under
    // the expectation that responsibility for reporting this situation falls to
    // the command.
    //
    // FIXME: Eventually, it might be nice to harden the format so that we know
    // when an output was actually required versus optional.
    if (value.isMissingOutput())
      return llvm::None;

    // If the value is a missing input, but those are allowed, it is ok.
    if (value.isMissingInput()) {
      if (allowMissingInputs)
        return llvm::None;
      else
        return BuildValue::makePropagatedFailureCommand();
    }

    // Propagate failure.
    if (value.isFailedInput())
      return BuildValue::makePropagatedFailureCommand();

    // A skipped dependency doesn't cause this command to skip.
    if (value.isSkippedCommand())
        return llvm::None;

    llvm_unreachable("unexpected input");
  };

  // Check if we need to skip the command because of this input.
  auto skipValueForInput = getSkipValueForInput();
  if (skipValueForInput.hasValue()) {
    skipValue = std::move(skipValueForInput);
    if (value.isMissingInput()) {
      // FIXME: This should also account for dependencies that were added dynamically.
      if (inputs.size() > inputID) {
        missingInputNodes.insert(inputs[inputID]);
      }
    }
  } else {
    // If there is a missing input file (from a successful command), we always
    // need to run the command.
    if (value.isMissingOutput())
      canUpdateIfNewer = false;
  }
}

bool ExternalCommand::canUpdateIfNewerWithResult(const BuildValue& result) {
  // Unless `allowModifiedOutputs` is specified, we always need to update if
  // ran.
  if (!allowModifiedOutputs)
    return false;

  // If it was specified, then we can update if all of our outputs simply exist.
  for (unsigned i = 0, e = result.getNumOutputs(); i != e; ++i) {
    const FileInfo& outputInfo = result.getNthOutputInfo(i);

    // If the output is missing, we need to rebuild.
    if (outputInfo.isMissing())
      return false;
  }
  return true;
}

BuildValue
ExternalCommand::computeCommandResult(BuildSystemCommandInterface& bsci) {
  // Capture the file information for each of the output nodes.
  //
  // FIXME: We need to delegate to the node here.
  SmallVector<FileInfo, 8> outputInfos;
  for (auto* node: outputs) {
    if (node->isCommandTimestamp()) {
      // FIXME: We currently have to shoehorn the timestamp into a fake file
      // info, but need to refactor the command result to just store the node
      // subvalues instead.
      FileInfo info{};
      info.size = bsci.getBuildEngine().getCurrentEpoch();
      outputInfos.push_back(info);
    } else if (node->isVirtual()) {
      outputInfos.push_back(FileInfo{});
    } else {
      outputInfos.push_back(node->getFileInfo(
                                bsci.getFileSystem()));
    }
  }

  // FIXME: If the outputs are empty, it might mean that this instance is for a custom task, which does not
  // currently have any hooks for specifying what the outputs are. It might make sense to create a new BuildValue
  // for a successful command with custom data, so that we can avoid the file system for commands that don't require
  // the filesystem. For now, hackily insert the timestamp just to differentiate between 2 build values that ran at
  // different times.
  if (outputs.size() == 0) {
    FileInfo info{};
    info.size = bsci.getBuildEngine().getCurrentEpoch();
    outputInfos.push_back(info);
  }

  return BuildValue::makeSuccessfulCommand(outputInfos);
}

void ExternalCommand::execute(BuildSystemCommandInterface& bsci,
                              core::Task* task,
                              QueueJobContext* context,
                              ResultFn resultFn) {
  // If this command should be skipped, do nothing.
  if (skipValue.hasValue()) {
    // If this command had a failed input, treat it as having failed.
    if (!missingInputNodes.empty()) {
      bsci.getDelegate().commandCannotBuildOutputDueToMissingInputs(this,
                         outputs[0], missingInputNodes);

      // Report the command failure.
      bsci.getDelegate().hadCommandFailure();
    }

    resultFn(std::move(skipValue.getValue()));
    return;
  }
  assert(missingInputNodes.empty());

  // If it is legal to simply update the command, then see if we can do so.
  if (canUpdateIfNewer && hasPriorResult) {
    BuildValue result = computeCommandResult(bsci);
    if (canUpdateIfNewerWithResult(result)) {
      resultFn(std::move(result));
      return;
    }
  }

  // Create the directories for the directories containing file outputs.
  //
  // FIXME: Implement a shared cache for this, to reduce the number of
  // syscalls required to make this happen.
  for (auto* node: outputs) {
    if (!node->isVirtual()) {
      // Attempt to create the directory; we ignore errors here under the
      // assumption the command will diagnose the situation if necessary.
      //
      // FIXME: Need to use the filesystem interfaces.
      auto parent = llvm::sys::path::parent_path(node->getName());
      if (!parent.empty()) {
        (void) bsci.getFileSystem().createDirectories(parent);
      }
    }
  }

  // Invoke the external command.
  bsci.getDelegate().commandStarted(this);
  executeExternalCommand(bsci, task, context, {[this, &bsci, resultFn](ProcessResult result){
    bsci.getDelegate().commandFinished(this, result.status);

    // Process the result.
    switch (result.status) {
    case ProcessStatus::Failed:
      resultFn(BuildValue::makeFailedCommand());
      return;
    case ProcessStatus::Cancelled:
      resultFn(BuildValue::makeCancelledCommand());
      return;
    case ProcessStatus::Succeeded:
      resultFn(computeCommandResult(bsci));
      return;
    case ProcessStatus::Skipped:
      // It is illegal to get skipped result at this point.
      break;
    }
    llvm::report_fatal_error("unknown result");
  }});
}
<|endoftext|>


<commit_before>/// @file
/// @version 3.5
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause

#ifdef _DIRECTX11
#include <hltypes/hlog.h>
#include <hltypes/hstring.h>

#include "april.h"
#include "DirectX11_RenderSystem.h"
#include "DirectX11_Texture.h"
#include "Image.h"

#define APRIL_D3D_DEVICE (((DirectX11_RenderSystem*)april::rendersys)->d3dDevice)
#define APRIL_D3D_DEVICE_CONTEXT (((DirectX11_RenderSystem*)april::rendersys)->d3dDeviceContext)

namespace april
{
	DirectX11_Texture::DirectX11_Texture(bool fromResource) : DirectX_Texture(fromResource), dxgiFormat(DXGI_FORMAT_UNKNOWN)
	{
		this->d3dTexture = nullptr;
		this->d3dView = nullptr;
		this->d3dRenderTargetView = nullptr;
	}

	DirectX11_Texture::~DirectX11_Texture()
	{
		this->unload();
	}

	bool DirectX11_Texture::_createInternalTexture(unsigned char* data, int size, Type type)
	{
		this->internalType = type;
		int bpp = Image::getFormatBpp(this->format);
		D3D11_SUBRESOURCE_DATA textureSubresourceData = {0};
		textureSubresourceData.pSysMem = data;
		this->firstUpload = true;
		if (data != NULL)
		{
			Image::Format nativeFormat = april::rendersys->getNativeTextureFormat(this->format);
			if (Image::needsConversion(this->format, nativeFormat))
			{
				textureSubresourceData.pSysMem = NULL;
				Image::convertToFormat(this->width, this->height, data, this->format, (unsigned char**)&textureSubresourceData.pSysMem, nativeFormat);
				bpp = Image::getFormatBpp(nativeFormat);
			}
			this->firstUpload = false;
		}
		else
		{
			int dummySize = this->width * this->height * bpp;
			textureSubresourceData.pSysMem = new unsigned char[dummySize];
			memset((unsigned char*)textureSubresourceData.pSysMem, 0, dummySize);
		}
		// texture
		textureSubresourceData.SysMemPitch = this->width * bpp;
		textureSubresourceData.SysMemSlicePitch = 0;
		D3D11_TEXTURE2D_DESC textureDesc = {0};
		textureDesc.Width = this->width;
		textureDesc.Height = this->height;
		if (type == TYPE_IMMUTABLE)
		{
			textureDesc.Usage = D3D11_USAGE_IMMUTABLE;
			textureDesc.CPUAccessFlags = 0;
		}
		else if (type == TYPE_VOLATILE)
		{
			textureDesc.Usage = D3D11_USAGE_DYNAMIC;
			textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		}
		else
		{
			textureDesc.Usage = D3D11_USAGE_DEFAULT;
			textureDesc.CPUAccessFlags = 0;
		}
		if (type == TYPE_RENDER_TARGET)
		{
			textureDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
		}
		textureDesc.MiscFlags = 0;
		textureDesc.MipLevels = 1;
		textureDesc.ArraySize = 1;
		textureDesc.SampleDesc.Count = 1;
		textureDesc.SampleDesc.Quality = 0;
		textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		textureDesc.Format = this->dxgiFormat;
		HRESULT hr = APRIL_D3D_DEVICE->CreateTexture2D(&textureDesc, &textureSubresourceData, &this->d3dTexture);
		if (textureSubresourceData.pSysMem != data)
		{
			delete [] (unsigned char*)textureSubresourceData.pSysMem;
		}
		if (FAILED(hr))
		{
			hlog::error(april::logTag, "Failed to create DX11 texture!");
			return false;
		}
		if (this->type == TYPE_RENDER_TARGET)
		{
			D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
			renderTargetViewDesc.Format = textureDesc.Format;
			renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
			renderTargetViewDesc.Texture2D.MipSlice = 0;
			hr = APRIL_D3D_DEVICE->CreateRenderTargetView(this->d3dTexture.Get(),
				&renderTargetViewDesc, &this->d3dRenderTargetView);
			if (FAILED(hr))
			{
				hlog::error(april::logTag, "Failed to create render target view for texture with render-to-texture!");
				return false;
			}
		}
		// shader resource
		D3D11_SHADER_RESOURCE_VIEW_DESC textureViewDesc;
		memset(&textureViewDesc, 0, sizeof(textureViewDesc));
		textureViewDesc.Format = textureDesc.Format;
		textureViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		textureViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
		textureViewDesc.Texture2D.MostDetailedMip = 0;
		hr = APRIL_D3D_DEVICE->CreateShaderResourceView(this->d3dTexture.Get(), &textureViewDesc, &this->d3dView);
		if (FAILED(hr))
		{
			hlog::error(april::logTag, "Failed to create DX11 texture view!");
			return false;
		}
		return true;
	}

	void DirectX11_Texture::_assignFormat()
	{
		Image::Format nativeFormat = april::rendersys->getNativeTextureFormat(this->format);
		switch (nativeFormat)
		{
		case Image::FORMAT_BGRA:
			this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
			break;
		case Image::FORMAT_BGRX:
			this->dxgiFormat = DXGI_FORMAT_B8G8R8X8_UNORM;
			break;
		case Image::FORMAT_ALPHA:
			this->dxgiFormat = DXGI_FORMAT_R8_UNORM;
			break;
		case Image::FORMAT_GRAYSCALE:
			this->dxgiFormat = DXGI_FORMAT_R8_UNORM;
			break;
		case Image::FORMAT_PALETTE: // TODOaa - needs changing
			this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
			break;
		default:
			this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
			break;
		}
	}

	void DirectX11_Texture::unload()
	{
		if (this->d3dTexture != nullptr)
		{
			hlog::write(april::logTag, "Unloading texture: " + this->_getInternalName());
			this->d3dTexture = nullptr;
			this->d3dView = nullptr;
			this->d3dRenderTargetView = nullptr;
		}
	}

	bool DirectX11_Texture::isLoaded()
	{
		return (this->d3dTexture != nullptr);
	}

	Texture::Lock DirectX11_Texture::_tryLockSystem(int x, int y, int w, int h)
	{
		Lock lock;
		Image::Format nativeFormat = april::rendersys->getNativeTextureFormat(this->format);
		int gpuBpp = Image::getFormatBpp(nativeFormat);
		if (this->type == TYPE_VOLATILE)
		{
			D3D11_MAPPED_SUBRESOURCE* mappedSubResource = new D3D11_MAPPED_SUBRESOURCE();
			memset(mappedSubResource, 0, sizeof(D3D11_MAPPED_SUBRESOURCE));
			// TODOa - maybe there is a good way to lock only part of the resource
			HRESULT hr = APRIL_D3D_DEVICE_CONTEXT->Map(this->d3dTexture.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, mappedSubResource);
			if (!FAILED(hr))
			{
				lock.systemBuffer = mappedSubResource;
				lock.activateLock(x, y, w, h, x, y, (unsigned char*)mappedSubResource->pData, mappedSubResource->RowPitch / gpuBpp, this->height, nativeFormat);
			}
		}
		else
		{
			lock.activateLock(0, 0, w, h, x, y, new unsigned char[w * h * gpuBpp], w, h, nativeFormat);
			lock.systemBuffer = lock.data;
		}
		return lock;
	}

	bool DirectX11_Texture::_unlockSystem(Lock& lock, bool update)
	{
		if (lock.systemBuffer == NULL)
		{
			return false;
		}
		if (update)
		{
			if (lock.locked)
			{
				if (this->internalType == TYPE_VOLATILE)
				{
					APRIL_D3D_DEVICE_CONTEXT->Unmap(this->d3dTexture.Get(), 0);
				}
				else
				{
					int bpp = Image::getFormatBpp(lock.format);
					D3D11_BOX box;
					box.left = lock.dx;
					box.right = lock.dx + lock.w;
					box.top = lock.dy;
					box.bottom = lock.dy + lock.h;
					box.front = 0;
					box.back = 1;
					// using UpdateSubresource1() because UpdateSubresource() has problems with deferred contexts and non-NULL boxes
					APRIL_D3D_DEVICE_CONTEXT->UpdateSubresource1(this->d3dTexture.Get(), 0, &box, lock.data, lock.w * bpp, 0, D3D11_COPY_DISCARD);
				}
			}
			else if (lock.renderTarget)
			{
				// TODOaa - implement
			}
			this->firstUpload = false;
		}
		if (this->internalType == TYPE_VOLATILE)
		{
			delete (D3D11_MAPPED_SUBRESOURCE*)lock.systemBuffer;
		}
		else
		{
			delete [] lock.data;
		}
		return update;
	}

}
#endif
<commit_msg>- fixed texture flicker problem on some Windows 8 graphics drivers<commit_after>/// @file
/// @version 3.5
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause

#ifdef _DIRECTX11
#include <hltypes/hlog.h>
#include <hltypes/hstring.h>

#include "april.h"
#include "DirectX11_RenderSystem.h"
#include "DirectX11_Texture.h"
#include "Image.h"

#define APRIL_D3D_DEVICE (((DirectX11_RenderSystem*)april::rendersys)->d3dDevice)
#define APRIL_D3D_DEVICE_CONTEXT (((DirectX11_RenderSystem*)april::rendersys)->d3dDeviceContext)

namespace april
{
	DirectX11_Texture::DirectX11_Texture(bool fromResource) : DirectX_Texture(fromResource), dxgiFormat(DXGI_FORMAT_UNKNOWN)
	{
		this->d3dTexture = nullptr;
		this->d3dView = nullptr;
		this->d3dRenderTargetView = nullptr;
	}

	DirectX11_Texture::~DirectX11_Texture()
	{
		this->unload();
	}

	bool DirectX11_Texture::_createInternalTexture(unsigned char* data, int size, Type type)
	{
		this->internalType = type;
		int bpp = Image::getFormatBpp(this->format);
		D3D11_SUBRESOURCE_DATA textureSubresourceData = {0};
		textureSubresourceData.pSysMem = data;
		this->firstUpload = true;
		if (data != NULL)
		{
			Image::Format nativeFormat = april::rendersys->getNativeTextureFormat(this->format);
			if (Image::needsConversion(this->format, nativeFormat))
			{
				textureSubresourceData.pSysMem = NULL;
				Image::convertToFormat(this->width, this->height, data, this->format, (unsigned char**)&textureSubresourceData.pSysMem, nativeFormat);
				bpp = Image::getFormatBpp(nativeFormat);
			}
			this->firstUpload = false;
		}
		else
		{
			int dummySize = this->width * this->height * bpp;
			textureSubresourceData.pSysMem = new unsigned char[dummySize];
			memset((unsigned char*)textureSubresourceData.pSysMem, 0, dummySize);
		}
		// texture
		textureSubresourceData.SysMemPitch = this->width * bpp;
		textureSubresourceData.SysMemSlicePitch = 0;
		D3D11_TEXTURE2D_DESC textureDesc = {0};
		textureDesc.Width = this->width;
		textureDesc.Height = this->height;
		if (type == TYPE_IMMUTABLE)
		{
			textureDesc.Usage = D3D11_USAGE_IMMUTABLE;
			textureDesc.CPUAccessFlags = 0;
		}
		else
		{
			textureDesc.Usage = D3D11_USAGE_DYNAMIC;
			textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		}
		if (type == TYPE_RENDER_TARGET)
		{
			textureDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
		}
		textureDesc.MiscFlags = 0;
		textureDesc.MipLevels = 1;
		textureDesc.ArraySize = 1;
		textureDesc.SampleDesc.Count = 1;
		textureDesc.SampleDesc.Quality = 0;
		textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		textureDesc.Format = this->dxgiFormat;
		HRESULT hr = APRIL_D3D_DEVICE->CreateTexture2D(&textureDesc, &textureSubresourceData, &this->d3dTexture);
		if (textureSubresourceData.pSysMem != data)
		{
			delete [] (unsigned char*)textureSubresourceData.pSysMem;
		}
		if (FAILED(hr))
		{
			hlog::error(april::logTag, "Failed to create DX11 texture!");
			return false;
		}
		if (this->type == TYPE_RENDER_TARGET)
		{
			D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
			renderTargetViewDesc.Format = textureDesc.Format;
			renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
			renderTargetViewDesc.Texture2D.MipSlice = 0;
			hr = APRIL_D3D_DEVICE->CreateRenderTargetView(this->d3dTexture.Get(),
				&renderTargetViewDesc, &this->d3dRenderTargetView);
			if (FAILED(hr))
			{
				hlog::error(april::logTag, "Failed to create render target view for texture with render-to-texture!");
				return false;
			}
		}
		// shader resource
		D3D11_SHADER_RESOURCE_VIEW_DESC textureViewDesc;
		memset(&textureViewDesc, 0, sizeof(textureViewDesc));
		textureViewDesc.Format = textureDesc.Format;
		textureViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		textureViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
		textureViewDesc.Texture2D.MostDetailedMip = 0;
		hr = APRIL_D3D_DEVICE->CreateShaderResourceView(this->d3dTexture.Get(), &textureViewDesc, &this->d3dView);
		if (FAILED(hr))
		{
			hlog::error(april::logTag, "Failed to create DX11 texture view!");
			return false;
		}
		return true;
	}

	void DirectX11_Texture::_assignFormat()
	{
		Image::Format nativeFormat = april::rendersys->getNativeTextureFormat(this->format);
		switch (nativeFormat)
		{
		case Image::FORMAT_BGRA:
			this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
			break;
		case Image::FORMAT_BGRX:
			this->dxgiFormat = DXGI_FORMAT_B8G8R8X8_UNORM;
			break;
		case Image::FORMAT_ALPHA:
			this->dxgiFormat = DXGI_FORMAT_R8_UNORM;
			break;
		case Image::FORMAT_GRAYSCALE:
			this->dxgiFormat = DXGI_FORMAT_R8_UNORM;
			break;
		case Image::FORMAT_PALETTE: // TODOaa - needs changing
			this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
			break;
		default:
			this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
			break;
		}
	}

	void DirectX11_Texture::unload()
	{
		if (this->d3dTexture != nullptr)
		{
			hlog::write(april::logTag, "Unloading texture: " + this->_getInternalName());
			this->d3dTexture = nullptr;
			this->d3dView = nullptr;
			this->d3dRenderTargetView = nullptr;
		}
	}

	bool DirectX11_Texture::isLoaded()
	{
		return (this->d3dTexture != nullptr);
	}

	Texture::Lock DirectX11_Texture::_tryLockSystem(int x, int y, int w, int h)
	{
		Lock lock;
		Image::Format nativeFormat = april::rendersys->getNativeTextureFormat(this->format);
		int gpuBpp = Image::getFormatBpp(nativeFormat);
		D3D11_MAPPED_SUBRESOURCE* mappedSubResource = new D3D11_MAPPED_SUBRESOURCE();
		memset(mappedSubResource, 0, sizeof(D3D11_MAPPED_SUBRESOURCE));
		// Map() is being used for all, because UpdateSubResource() / UpdateSubResource1() seems to use Map() internally somewhere and the memory pointer can change
		HRESULT hr = APRIL_D3D_DEVICE_CONTEXT->Map(this->d3dTexture.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, mappedSubResource);
		if (!FAILED(hr))
		{
			lock.systemBuffer = mappedSubResource;
			lock.activateLock(x, y, w, h, x, y, (unsigned char*)mappedSubResource->pData, mappedSubResource->RowPitch / gpuBpp, this->height, nativeFormat);
		}
		return lock;
	}

	bool DirectX11_Texture::_unlockSystem(Lock& lock, bool update)
	{
		if (lock.systemBuffer == NULL)
		{
			return false;
		}
		if (update)
		{
			if (lock.locked)
			{
				// this special hack is required because Map() with D3D11_MAP_WRITE_DISCARD can allocate any piece of memory
				if (this->data != NULL && this->data != lock.data)
				{
					Image::write(0, 0, this->width, this->height, 0, 0, this->data, this->width, this->height, this->format, lock.data, lock.dataWidth, lock.dataHeight, lock.format);
				}
				APRIL_D3D_DEVICE_CONTEXT->Unmap(this->d3dTexture.Get(), 0);
			}
			else if (lock.renderTarget)
			{
				// TODOaa - implement
			}
			this->firstUpload = false;
		}
		delete (D3D11_MAPPED_SUBRESOURCE*)lock.systemBuffer;
		return update;
	}

}
#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry(): m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(data_type t): m_type(t)
	{
		construct(t);
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(const entry& e)
	{
		copy(e);
#ifndef NDEBUG
		m_type_queried = e.m_type_queried;
#endif
	}

	entry::entry(dictionary_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		m_type = t;
		switch(m_type)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			m_type = undefined_t;
		}
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::copy(entry const& e)
	{
		m_type = e.type();
		switch(m_type)
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			m_type = undefined_t;
		}
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
#ifndef NDEBUG
		m_type_queried = false;
#endif
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<commit_msg>exception safety fixes to entry.cpp<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry()
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(data_type t)
		: m_type(undefined_t)
	{
		construct(t);
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(const entry& e)
		: m_type(undefined_t)
	{
		copy(e);
#ifndef NDEBUG
		m_type_queried = e.m_type_queried;
#endif
	}

	entry::entry(dictionary_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		switch(t)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(t == undefined_t);
		}
		m_type = t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::copy(entry const& e)
	{
		switch (e.type())
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			TORRENT_ASSERT(e.type() == undefined_t);
		}
		m_type = e.type();
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
		m_type = undefined_t;
#ifndef NDEBUG
		m_type_queried = false;
#endif
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <cassert>
#include <chrono>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <sstream>

#include <sys/signal.h>

#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/histogram.h>
#include <grpc/support/log.h>
#include <grpc/support/host_port.h>
#include <gflags/gflags.h>
#include <grpc++/client_context.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include <gtest/gtest.h>
#include "test/cpp/util/create_test_channel.h"
#include "test/cpp/qps/client.h"
#include "test/cpp/qps/qpstest.grpc.pb.h"
#include "test/cpp/qps/histogram.h"
#include "test/cpp/qps/interarrival.h"
#include "test/cpp/qps/timer.h"

namespace grpc {
namespace testing {

class SynchronousClient : public Client {
 public:
  SynchronousClient(const ClientConfig& config) : Client(config) {
    num_threads_ =
      config.outstanding_rpcs_per_channel() * config.client_channels();
    responses_.resize(num_threads_);
    SetupLoadTest(config, num_threads_);
  }

  virtual ~SynchronousClient() { EndThreads(); }

 protected:
  void WaitToIssue(int thread_idx) {
    std::chrono::time_point<std::chrono::high_resolution_clock> next_time;
    if (NextIssueTime(thread_idx, &next_time)) {
      std::this_thread::sleep_until(next_time);
    }
  }

  size_t num_threads_;
  std::vector<SimpleResponse> responses_;
};

class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient {
 public:
  SynchronousUnaryClient(const ClientConfig& config):
    SynchronousClient(config) {StartThreads(num_threads_);}
  ~SynchronousUnaryClient() {}

  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
    WaitToIssue(thread_idx);
    auto* stub = channels_[thread_idx % channels_.size()].get_stub();
    double start = Timer::Now();
    grpc::ClientContext context;
    grpc::Status s =
        stub->UnaryCall(&context, request_, &responses_[thread_idx]);
    histogram->Add((Timer::Now() - start) * 1e9);
    return s.IsOk();
  }
};

class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient {
 public:
  SynchronousStreamingClient(const ClientConfig& config):
    SynchronousClient(config) {
    for (size_t thread_idx=0;thread_idx<num_threads_;thread_idx++){
      auto* stub = channels_[thread_idx % channels_.size()].get_stub();
      stream_ = stub->StreamingCall(&context_);
    }
    StartThreads(num_threads_);
  }
  ~SynchronousStreamingClient() {
    EndThreads();
    if (stream_) {
      SimpleResponse response;
      stream_->WritesDone();
      EXPECT_TRUE(stream_->Finish().IsOk());
    }
  }

  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
    WaitToIssue(thread_idx);
    double start = Timer::Now();
    if (stream_->Write(request_) && stream_->Read(&responses_[thread_idx])) {
      histogram->Add((Timer::Now() - start) * 1e9);
      return true;
    }
    return false;
  }
  private:
    grpc::ClientContext context_;
    std::unique_ptr<grpc::ClientReaderWriter<SimpleRequest,
                                             SimpleResponse>> stream_;
};

std::unique_ptr<Client>
CreateSynchronousUnaryClient(const ClientConfig& config) {
  return std::unique_ptr<Client>(new SynchronousUnaryClient(config));
}
std::unique_ptr<Client>
CreateSynchronousStreamingClient(const ClientConfig& config) {
  return std::unique_ptr<Client>(new SynchronousStreamingClient(config));
}

}  // namespace testing
}  // namespace grpc
<commit_msg>Move end_threads to subclass since some subclass-specific fields will still be alive at this time<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <cassert>
#include <chrono>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <sstream>

#include <sys/signal.h>

#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/histogram.h>
#include <grpc/support/log.h>
#include <grpc/support/host_port.h>
#include <gflags/gflags.h>
#include <grpc++/client_context.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include <gtest/gtest.h>
#include "test/cpp/util/create_test_channel.h"
#include "test/cpp/qps/client.h"
#include "test/cpp/qps/qpstest.grpc.pb.h"
#include "test/cpp/qps/histogram.h"
#include "test/cpp/qps/interarrival.h"
#include "test/cpp/qps/timer.h"

namespace grpc {
namespace testing {

class SynchronousClient : public Client {
 public:
  SynchronousClient(const ClientConfig& config) : Client(config) {
    num_threads_ =
      config.outstanding_rpcs_per_channel() * config.client_channels();
    responses_.resize(num_threads_);
    SetupLoadTest(config, num_threads_);
  }

  virtual ~SynchronousClient() {};

 protected:
  void WaitToIssue(int thread_idx) {
    std::chrono::time_point<std::chrono::high_resolution_clock> next_time;
    if (NextIssueTime(thread_idx, &next_time)) {
      std::this_thread::sleep_until(next_time);
    }
  }

  size_t num_threads_;
  std::vector<SimpleResponse> responses_;
};

class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient {
 public:
  SynchronousUnaryClient(const ClientConfig& config):
    SynchronousClient(config) {StartThreads(num_threads_);}
  ~SynchronousUnaryClient() {EndThreads();}
  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
    WaitToIssue(thread_idx);
    auto* stub = channels_[thread_idx % channels_.size()].get_stub();
    double start = Timer::Now();
    grpc::ClientContext context;
    grpc::Status s =
        stub->UnaryCall(&context, request_, &responses_[thread_idx]);
    histogram->Add((Timer::Now() - start) * 1e9);
    return s.IsOk();
  }
};

class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient {
 public:
  SynchronousStreamingClient(const ClientConfig& config):
    SynchronousClient(config) {
    for (size_t thread_idx=0;thread_idx<num_threads_;thread_idx++){
      auto* stub = channels_[thread_idx % channels_.size()].get_stub();
      stream_ = stub->StreamingCall(&context_);
    }
    StartThreads(num_threads_);
  }
  ~SynchronousStreamingClient() {
    EndThreads();
    if (stream_) {
      SimpleResponse response;
      stream_->WritesDone();
      EXPECT_TRUE(stream_->Finish().IsOk());
    }
  }

  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
    WaitToIssue(thread_idx);
    double start = Timer::Now();
    if (stream_->Write(request_) && stream_->Read(&responses_[thread_idx])) {
      histogram->Add((Timer::Now() - start) * 1e9);
      return true;
    }
    return false;
  }
  private:
    grpc::ClientContext context_;
    std::unique_ptr<grpc::ClientReaderWriter<SimpleRequest,
                                             SimpleResponse>> stream_;
};

std::unique_ptr<Client>
CreateSynchronousUnaryClient(const ClientConfig& config) {
  return std::unique_ptr<Client>(new SynchronousUnaryClient(config));
}
std::unique_ptr<Client>
CreateSynchronousStreamingClient(const ClientConfig& config) {
  return std::unique_ptr<Client>(new SynchronousStreamingClient(config));
}

}  // namespace testing
}  // namespace grpc
<|endoftext|>


<commit_before>
#include "config.h"

#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>

#define GROBOT_SIM

#include "grobot.h"

grobot::grobot()
{
    dx_est = 0.0f;
    dy_est = 0.0f;
}

grobot::~grobot()
{
}

void grobot::estop()
{
}

void grobot::setWheels(float Vl, float Vr)
{
}

void grobot::setvPath(float Wv, float Wr)
{
}

void grobot::pbMove(float mdisplacement)
{

}

void grobot::pbPivot(float pangle)
{
}

void grobot::dgoto(float Dx, float Dy, float Rf)
{
    printf("goto %f, %f, %f\n", Dx, Dy, Rf);

    this->dx_est = Dx;
    this->dy_est = Dy;
    this->gotocomplete = 1;
}

void grobot::resetPosition()
{
}

void grobot::updatePosition()
{
}

float grobot::getArclen()
{
    return 0.0f;
}

void grobot::getDisplacement(float &dxtemp, float &dytemp)
{
    dxtemp = this->dx_est;
    dytemp = this->dy_est;
}

int grobot::getGstatus()
{
    return 0;
}

int grobot::getGOTOstatus()
{
    int retval = this->gotocomplete;

    this->gotocomplete = 0;
    return retval;
}

void grobot::sleepy()
{
    struct timeval tv = { 0, 100 };

    select(0, NULL, NULL, NULL, &tv);
}

void grobot::setCBexec(int id)
{
}

void grobot::setCBstatus(int id, int status, cb_type_t cbt)
{
}

void grobot::createNULLbehavior()
{
}

void grobot::createPRIMbehavior(cb_type_t cbt)
{
}

void grobot::set_gotocomplete()
{
}
<commit_msg>Implement resetPosition<commit_after>
#include "config.h"

#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>

#define GROBOT_SIM

#include "grobot.h"

grobot::grobot()
{
    dx_est = 0.0f;
    dy_est = 0.0f;
}

grobot::~grobot()
{
}

void grobot::estop()
{
}

void grobot::setWheels(float Vl, float Vr)
{
}

void grobot::setvPath(float Wv, float Wr)
{
}

void grobot::pbMove(float mdisplacement)
{

}

void grobot::pbPivot(float pangle)
{
}

void grobot::dgoto(float Dx, float Dy, float Rf)
{
    printf("goto %f, %f, %f\n", Dx, Dy, Rf);

    this->dx_est = Dx;
    this->dy_est = Dy;
    this->gotocomplete = 1;
}

void grobot::resetPosition()
{
    this->dx_est = 0;
    this->dy_est = 0;
}

void grobot::updatePosition()
{
}

float grobot::getArclen()
{
    return 0.0f;
}

void grobot::getDisplacement(float &dxtemp, float &dytemp)
{
    dxtemp = this->dx_est;
    dytemp = this->dy_est;
}

int grobot::getGstatus()
{
    return 0;
}

int grobot::getGOTOstatus()
{
    int retval = this->gotocomplete;

    this->gotocomplete = 0;
    return retval;
}

void grobot::sleepy()
{
    struct timeval tv = { 0, 100 };

    select(0, NULL, NULL, NULL, &tv);
}

void grobot::setCBexec(int id)
{
}

void grobot::setCBstatus(int id, int status, cb_type_t cbt)
{
}

void grobot::createNULLbehavior()
{
}

void grobot::createPRIMbehavior(cb_type_t cbt)
{
}

void grobot::set_gotocomplete()
{
}
<|endoftext|>


<commit_before>#include "PackIDMgr.h"
#include "PackNode.h"
#include "typedef.h"

#include <ee/std_functor.h>
#include <ee/FileHelper.h>
#include <ee/Exception.h>
#include <ee/SymbolType.h>

#include <sprite2/SymType.h>
#include <simp/NodeFactory.h>
#include <gum/FilepathHelper.h>
#include <gum/SymbolFile.h>

#include <json/json.h>

#include <algorithm>
#include <fstream>

namespace esprpacker
{

SINGLETON_DEFINITION(PackIDMgr)

PackIDMgr::PackIDMgr()
	: m_curr_pkg(NULL)
	, m_curr_pkg_id(-1)
{
}

PackIDMgr::~PackIDMgr()
{
	for_each(m_pkgs.begin(), m_pkgs.end(), ee::DeletePointerFunctor<Package>());
}

void PackIDMgr::Init(const std::string& filepath, const std::string& platform)
{
	std::string fix = gum::FilepathHelper::Format(filepath);
	m_dir = ee::FileHelper::GetFileDir(fix);
	m_platform = platform;

	if (!ee::FileHelper::IsFileExist(filepath)) {
		return;
	}

	Json::Value val;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();

	m_pkgs.reserve(val.size());
	for (int i = 0, n = val.size(); i < n; ++i)
	{
		const Json::Value& src = val[i];

		Package* pkg = new Package;

		pkg->name = src["name"].asString();

		pkg->path = src["path"].asString();
		pkg->path = ee::FileHelper::GetAbsolutePath(m_dir, pkg->path);
		pkg->path = ee::FileHelper::FormatFilepath(pkg->path);

		pkg->id = src["pkg_id"].asInt();

		pkg->img_cut = false;
		if (src.isMember("img_cut")) {
			pkg->img_cut = true;
			pkg->cut_img = src["img_cut"]["img"].asString();
			pkg->cut_json = src["img_cut"]["json"].asString();
			pkg->cut_ori = src["img_cut"]["ori"].asString();
		}

		std::string name = pkg->name;
		std::string::size_type pos = pkg->name.find('/');
		if (pos != std::string::npos) {
			name = name.substr(pos + 1);
		}
		std::string spr_id_file = GetSprIDFile(name);
		if (ee::FileHelper::IsFileExist(spr_id_file)) {
			InitSprsID(spr_id_file, pkg);
		}

		m_pkgs.push_back(pkg);
	}
}

void PackIDMgr::AddCurrPath(const std::string& path)
{
	if (m_curr_pkg_id != -1) {
		return;
	}

	std::string fix = gum::FilepathHelper::Format(path);
	m_curr_paths.push_back(fix);

	if (m_curr_pkg) {
		return;
	}

	for (int i = 0, n = m_pkgs.size(); i < n; ++i) {
		if (m_pkgs[i]->path.find(fix) != std::string::npos) {
			m_curr_pkg = m_pkgs[i];
			break;
		}
	}
}

void PackIDMgr::QueryID(const std::string& filepath, int& pkg_id, int& node_id) const
{
	static int NEXT_NODE_ID = 0;
	if (m_curr_pkg_id != -1)
	{
		pkg_id = m_curr_pkg_id;
		node_id = NEXT_NODE_ID++;
		return;
	}
	else if (IsCurrPkg(filepath))
	{
		assert(m_curr_pkg);
		pkg_id = m_curr_pkg->id;
		node_id = NEXT_NODE_ID++;
		return;
	}

	Package* pkg = NULL;
	for (int i = 0, n = m_pkgs.size(); i < n; ++i) {
		if (filepath.find(m_pkgs[i]->path) != std::string::npos) {
			pkg = m_pkgs[i];
			break;
		}
	}

	if (!pkg) {
		throw ee::Exception("query pkg id fail: %s", filepath.c_str());
	}

	pkg_id = pkg->id;

	std::map<std::string, uint32_t>::iterator itr = pkg->sprs.find(filepath);
	if (itr == pkg->sprs.end()) {
		throw ee::Exception("query spr id fail: %s", filepath.c_str());
	}
	node_id = simp::NodeID::GetNodeID(itr->second);
}

bool PackIDMgr::IsCurrPkg(const std::string& filepath) const
{
	if (m_curr_pkg_id != -1) {
		return true;
	}
	if (filepath.empty() || filepath == ee::SYM_GROUP_TAG || filepath == SPRITE_FILEPATH) {
		return true;
	}
	if (gum::SymbolFile::Instance()->Type(filepath) == s2::SYM_TEXTBOX) {
		return true;
	}
	for (int i = 0, n = m_curr_paths.size(); i < n; ++i) {
		if (filepath.find(m_curr_paths[i]) != std::string::npos) {
			return true;
		}
	}
	return false;
}

bool PackIDMgr::IsCurrPkg(const PackNode* node) const
{
	int curr_pkg_id = (m_curr_pkg_id != -1 ? m_curr_pkg_id : m_curr_pkg->id);
	return curr_pkg_id == node->GetPkgID();
}

std::string PackIDMgr::GetSprIDFile(const std::string& pkg_name) const
{
	return m_dir + "\\spr" + "\\" + m_platform + "\\" + pkg_name + ".json";
}

void PackIDMgr::GetCurrImgCutPath(std::string& img, std::string& json, std::string& ori) const
{
	if (!m_curr_pkg) {
		return;
	}

	img = m_curr_pkg->cut_img;
	json = m_curr_pkg->cut_json;
	ori = m_curr_pkg->cut_ori;
}

void PackIDMgr::InitSprsID(const std::string& filepath, Package* pkg) const
{
	Json::Value val;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();

	for (int i = 0, n = val.size(); i < n; ++i)
	{
		const Json::Value& spr_val = val[i];
		std::string filepath = spr_val["file"].asString();

		filepath = gum::FilepathHelper::Absolute(pkg->path, filepath);
		if (!gum::FilepathHelper::Exists(filepath)) {
			continue;
		}
		filepath = gum::FilepathHelper::Format(filepath);
		uint32_t id = spr_val["id"].asUInt();

		if (pkg->sprs.find(filepath) != pkg->sprs.end()) {
			throw ee::Exception("PackIDMgr::InitSprsID: dup filepath %s", filepath.c_str());
		}

		pkg->sprs.insert(std::make_pair(filepath, id));
	}
}

}<commit_msg>[FIXED] pack with default sym<commit_after>#include "PackIDMgr.h"
#include "PackNode.h"
#include "typedef.h"

#include <ee/std_functor.h>
#include <ee/FileHelper.h>
#include <ee/Exception.h>
#include <ee/SymbolType.h>
#include <ee/ImageData.h>
#include <ee/Symbol.h>

#include <sprite2/SymType.h>
#include <simp/NodeFactory.h>
#include <gum/FilepathHelper.h>
#include <gum/SymbolFile.h>

#include <json/json.h>

#include <algorithm>
#include <fstream>

namespace esprpacker
{

SINGLETON_DEFINITION(PackIDMgr)

PackIDMgr::PackIDMgr()
	: m_curr_pkg(NULL)
	, m_curr_pkg_id(-1)
{
}

PackIDMgr::~PackIDMgr()
{
	for_each(m_pkgs.begin(), m_pkgs.end(), ee::DeletePointerFunctor<Package>());
}

void PackIDMgr::Init(const std::string& filepath, const std::string& platform)
{
	std::string fix = gum::FilepathHelper::Format(filepath);
	m_dir = ee::FileHelper::GetFileDir(fix);
	m_platform = platform;

	if (!ee::FileHelper::IsFileExist(filepath)) {
		return;
	}

	Json::Value val;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();

	m_pkgs.reserve(val.size());
	for (int i = 0, n = val.size(); i < n; ++i)
	{
		const Json::Value& src = val[i];

		Package* pkg = new Package;

		pkg->name = src["name"].asString();

		pkg->path = src["path"].asString();
		pkg->path = ee::FileHelper::GetAbsolutePath(m_dir, pkg->path);
		pkg->path = ee::FileHelper::FormatFilepath(pkg->path);

		pkg->id = src["pkg_id"].asInt();

		pkg->img_cut = false;
		if (src.isMember("img_cut")) {
			pkg->img_cut = true;
			pkg->cut_img = src["img_cut"]["img"].asString();
			pkg->cut_json = src["img_cut"]["json"].asString();
			pkg->cut_ori = src["img_cut"]["ori"].asString();
		}

		std::string name = pkg->name;
		std::string::size_type pos = pkg->name.find('/');
		if (pos != std::string::npos) {
			name = name.substr(pos + 1);
		}
		std::string spr_id_file = GetSprIDFile(name);
		if (ee::FileHelper::IsFileExist(spr_id_file)) {
			InitSprsID(spr_id_file, pkg);
		}

		m_pkgs.push_back(pkg);
	}
}

void PackIDMgr::AddCurrPath(const std::string& path)
{
	if (m_curr_pkg_id != -1) {
		return;
	}

	std::string fix = gum::FilepathHelper::Format(path);
	m_curr_paths.push_back(fix);

	if (m_curr_pkg) {
		return;
	}

	for (int i = 0, n = m_pkgs.size(); i < n; ++i) {
		if (m_pkgs[i]->path.find(fix) != std::string::npos) {
			m_curr_pkg = m_pkgs[i];
			break;
		}
	}
}

void PackIDMgr::QueryID(const std::string& filepath, int& pkg_id, int& node_id) const
{
	static int NEXT_NODE_ID = 0;
	if (m_curr_pkg_id != -1)
	{
		pkg_id = m_curr_pkg_id;
		node_id = NEXT_NODE_ID++;
		return;
	}
	else if (IsCurrPkg(filepath))
	{
		assert(m_curr_pkg);
		pkg_id = m_curr_pkg->id;
		node_id = NEXT_NODE_ID++;
		return;
	}

	Package* pkg = NULL;
	for (int i = 0, n = m_pkgs.size(); i < n; ++i) {
		if (filepath.find(m_pkgs[i]->path) != std::string::npos) {
			pkg = m_pkgs[i];
			break;
		}
	}

	if (!pkg)
	{
		const std::string default_sym = ee::ImageDataMgr::Instance()->GetDefaultSym();
		if (default_sym.empty()) {
			throw ee::Exception("query spr id fail: %s", filepath.c_str());
		}
		return QueryID(default_sym, pkg_id, node_id);
	}

	pkg_id = pkg->id;

	std::map<std::string, uint32_t>::iterator itr = pkg->sprs.find(filepath);
	if (itr == pkg->sprs.end()) {
		const std::string default_sym = ee::ImageDataMgr::Instance()->GetDefaultSym();
		if (default_sym.empty()) {
			throw ee::Exception("query spr id fail: %s", filepath.c_str());
		}
		return QueryID(default_sym, pkg_id, node_id);
	}
	node_id = simp::NodeID::GetNodeID(itr->second);
}

bool PackIDMgr::IsCurrPkg(const std::string& filepath) const
{
	if (m_curr_pkg_id != -1) {
		return true;
	}
	if (filepath.empty() || filepath == ee::SYM_GROUP_TAG || filepath == SPRITE_FILEPATH) {
		return true;
	}
	if (gum::SymbolFile::Instance()->Type(filepath) == s2::SYM_TEXTBOX) {
		return true;
	}
	for (int i = 0, n = m_curr_paths.size(); i < n; ++i) {
		if (filepath.find(m_curr_paths[i]) != std::string::npos) {
			return true;
		}
	}
	return false;
}

bool PackIDMgr::IsCurrPkg(const PackNode* node) const
{
	int curr_pkg_id = (m_curr_pkg_id != -1 ? m_curr_pkg_id : m_curr_pkg->id);
	return curr_pkg_id == node->GetPkgID();
}

std::string PackIDMgr::GetSprIDFile(const std::string& pkg_name) const
{
	return m_dir + "\\spr" + "\\" + m_platform + "\\" + pkg_name + ".json";
}

void PackIDMgr::GetCurrImgCutPath(std::string& img, std::string& json, std::string& ori) const
{
	if (!m_curr_pkg) {
		return;
	}

	img = m_curr_pkg->cut_img;
	json = m_curr_pkg->cut_json;
	ori = m_curr_pkg->cut_ori;
}

void PackIDMgr::InitSprsID(const std::string& filepath, Package* pkg) const
{
	Json::Value val;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();

	for (int i = 0, n = val.size(); i < n; ++i)
	{
		const Json::Value& spr_val = val[i];
		std::string filepath = spr_val["file"].asString();

		filepath = gum::FilepathHelper::Absolute(pkg->path, filepath);
		if (!gum::FilepathHelper::Exists(filepath)) {
			continue;
		}
		filepath = gum::FilepathHelper::Format(filepath);
		uint32_t id = spr_val["id"].asUInt();

		if (pkg->sprs.find(filepath) != pkg->sprs.end()) {
			throw ee::Exception("PackIDMgr::InitSprsID: dup filepath %s", filepath.c_str());
		}

		pkg->sprs.insert(std::make_pair(filepath, id));
	}
}

}<|endoftext|>


<commit_before>// Copyright (c) 2009 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 "native_client/src/include/portability.h"

#if NACL_OSX
#include <crt_externs.h>
#endif

#ifdef _WIN64  /* TODO(gregoryd): remove this when win64 issues are fixed */
#define NACL_NO_INLINE
#endif

EXTERN_C_BEGIN
#include "native_client/src/shared/platform/nacl_sync.h"
#include "native_client/src/shared/platform/nacl_sync_checked.h"
#include "native_client/src/trusted/service_runtime/nacl_globals.h"
#include "native_client/src/trusted/service_runtime/expiration.h"
#include "native_client/src/trusted/service_runtime/nacl_app.h"
#include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
#include "native_client/src/trusted/service_runtime/sel_ldr.h"
#include "native_client/src/trusted/platform_qualify/nacl_os_qualify.h"
EXTERN_C_END

int verbosity = 0;

#ifdef __GNUC__

/*
 * GDB's canonical overlay managment routine.
 * We need its symbol in the symbol table so don't inline it.
 * Note: _ovly_debug_event has to be an unmangled 'C' style symbol.
 * TODO(dje): add some explanation for the non-GDB person.
 */
EXTERN_C_BEGIN
static void __attribute__ ((noinline)) _ovly_debug_event (void) {
  /*
   * The asm volatile is here as instructed by the GCC docs.
   * It's not enough to declare a function noinline.
   * GCC will still look inside the function to see if it's worth calling.
   */
  asm volatile ("");
}
EXTERN_C_END

#endif

static void StopForDebuggerInit(const struct NaClApp *state) {
  /* Put xlate_base in a place where gdb can find it.  */
  nacl_global_xlate_base = state->mem_start;

#ifdef __GNUC__
  _ovly_debug_event();
#endif
}

int SelMain(const int desc, const NaClHandle handle) {
  char *av[1];
  int ac = 1;

  char                          **envp;
  struct NaClApp                state;
  char                          *nacl_file = 0;
  int                           main_thread_only = 1;
  int                           export_addr_to = -2;

  struct NaClApp                *nap;

  NaClErrorCode                 errcode;

  int                           ret_code = 1;
#if NACL_OSX
  // Mac dynamic libraries cannot access the environ variable directly.
  envp = *_NSGetEnviron();
#else
  extern char                   **environ;
  envp = environ;
#endif

  NaClAllModulesInit();

  /* used to be -P */
  NaClSrpcFileDescriptor = desc;
  /* used to be -X */
  export_addr_to = desc;

  /* to be passed to NaClMain, eventually... */
  av[0] = const_cast<char*>("NaClMain");

  if (!NaClAppCtor(&state)) {
    fprintf(stderr, "Error while constructing app state\n");
    goto done_file_dtor;
  }

  state.restrict_to_main_thread = main_thread_only;

  nap = &state;
  errcode = LOAD_OK;

  /* import IMC handle - used to be "-i" */
  NaClAddImcHandle(nap, handle, desc);

  /*
   * in order to report load error to the browser plugin through the
   * secure command channel, we do not immediate jump to cleanup code
   * on error.  rather, we continue processing (assuming earlier
   * errors do not make it inappropriate) until the secure command
   * channel is set up, and then bail out.
   */

  /*
   * Ensure this operating system platform is supported.
   */
  if (!NaClOsIsSupported()) {
    errcode = LOAD_UNSUPPORTED_OS_PLATFORM;
    nap->module_load_status = errcode;
    fprintf(stderr, "Error while loading \"%s\": %s\n",
            nacl_file,
            NaClErrorString(errcode));
  }

  /* Give debuggers a well known point at which xlate_base is known.  */
  StopForDebuggerInit(&state);

  /*
   * If export_addr_to is set to a non-negative integer, we create a
   * bound socket and socket address pair and bind the former to
   * descriptor 3 and the latter to descriptor 4.  The socket address
   * is written out to the export_addr_to descriptor.
   *
   * The service runtime also accepts a connection on the bound socket
   * and spawns a secure command channel thread to service it.
   *
   * If export_addr_to is -1, we only create the bound socket and
   * socket address pair, and we do not export to an IMC socket.  This
   * use case is typically only used in testing, where we only "dump"
   * the socket address to stdout or similar channel.
   */
  if (-2 < export_addr_to) {
    NaClCreateServiceSocket(nap);
    if (0 <= export_addr_to) {
      NaClSendServiceAddressTo(nap, export_addr_to);
      /*
       * NB: spawns a thread that uses the command channel.  we do
       * this after NaClAppLoadFile so that NaClApp object is more
       * fully populated.  Hereafter any changes to nap should be done
       * while holding locks.
       */
      NaClSecureCommandChannel(nap);
    }
  }

  NaClXMutexLock(&nap->mu);
  nap->module_load_status = LOAD_OK;
  NaClXCondVarBroadcast(&nap->cv);
  NaClXMutexUnlock(&nap->mu);

  if (NULL != nap->secure_channel) {
    /*
     * wait for start_module RPC call on secure channel thread.
     */
    NaClWaitForModuleStartStatusCall(nap);
  }

  /*
   * error reporting done; can quit now if there was an error earlier.
   */
  if (LOAD_OK != errcode) {
    goto done;
  }

  /*
   * only nap->ehdrs.e_entry is usable, no symbol table is
   * available.
   */
  if (!NaClCreateMainThread(nap,
                            ac,
                            av,
                            envp)) {
    fprintf(stderr, "creating main thread failed\n");
    goto done;
  }

  ret_code = NaClWaitForMainThreadToExit(nap);

  /*
   * exit_group or equiv kills any still running threads while module
   * addr space is still valid.  otherwise we'd have to kill threads
   * before we clean up the address space.
   */
  return ret_code;

 done:
  fflush(stdout);

  NaClAppDtor(&state);

 done_file_dtor:
  fflush(stdout);

  NaClAllModulesFini();

  return ret_code;
}

<commit_msg>Remove possible nullptr deref from an unused (with non-null values) variable.<commit_after>// Copyright (c) 2009 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 "native_client/src/include/portability.h"

#if NACL_OSX
#include <crt_externs.h>
#endif

#ifdef _WIN64  /* TODO(gregoryd): remove this when win64 issues are fixed */
#define NACL_NO_INLINE
#endif

EXTERN_C_BEGIN
#include "native_client/src/shared/platform/nacl_sync.h"
#include "native_client/src/shared/platform/nacl_sync_checked.h"
#include "native_client/src/trusted/service_runtime/nacl_globals.h"
#include "native_client/src/trusted/service_runtime/expiration.h"
#include "native_client/src/trusted/service_runtime/nacl_app.h"
#include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
#include "native_client/src/trusted/service_runtime/sel_ldr.h"
#include "native_client/src/trusted/platform_qualify/nacl_os_qualify.h"
EXTERN_C_END

int verbosity = 0;

#ifdef __GNUC__

/*
 * GDB's canonical overlay managment routine.
 * We need its symbol in the symbol table so don't inline it.
 * Note: _ovly_debug_event has to be an unmangled 'C' style symbol.
 * TODO(dje): add some explanation for the non-GDB person.
 */
EXTERN_C_BEGIN
static void __attribute__ ((noinline)) _ovly_debug_event (void) {
  /*
   * The asm volatile is here as instructed by the GCC docs.
   * It's not enough to declare a function noinline.
   * GCC will still look inside the function to see if it's worth calling.
   */
  asm volatile ("");
}
EXTERN_C_END

#endif

static void StopForDebuggerInit(const struct NaClApp *state) {
  /* Put xlate_base in a place where gdb can find it.  */
  nacl_global_xlate_base = state->mem_start;

#ifdef __GNUC__
  _ovly_debug_event();
#endif
}

int SelMain(const int desc, const NaClHandle handle) {
  char *av[1];
  int ac = 1;

  char                          **envp;
  struct NaClApp                state;
  int                           main_thread_only = 1;
  int                           export_addr_to = -2;

  struct NaClApp                *nap;

  NaClErrorCode                 errcode;

  int                           ret_code = 1;
#if NACL_OSX
  // Mac dynamic libraries cannot access the environ variable directly.
  envp = *_NSGetEnviron();
#else
  extern char                   **environ;
  envp = environ;
#endif

  NaClAllModulesInit();

  /* used to be -P */
  NaClSrpcFileDescriptor = desc;
  /* used to be -X */
  export_addr_to = desc;

  /* to be passed to NaClMain, eventually... */
  av[0] = const_cast<char*>("NaClMain");

  if (!NaClAppCtor(&state)) {
    fprintf(stderr, "Error while constructing app state\n");
    goto done_file_dtor;
  }

  state.restrict_to_main_thread = main_thread_only;

  nap = &state;
  errcode = LOAD_OK;

  /* import IMC handle - used to be "-i" */
  NaClAddImcHandle(nap, handle, desc);

  /*
   * in order to report load error to the browser plugin through the
   * secure command channel, we do not immediate jump to cleanup code
   * on error.  rather, we continue processing (assuming earlier
   * errors do not make it inappropriate) until the secure command
   * channel is set up, and then bail out.
   */

  /*
   * Ensure this operating system platform is supported.
   */
  if (!NaClOsIsSupported()) {
    errcode = LOAD_UNSUPPORTED_OS_PLATFORM;
    nap->module_load_status = errcode;
    fprintf(stderr, "Error while loading in SelMain: %s\n",
            NaClErrorString(errcode));
  }

  /* Give debuggers a well known point at which xlate_base is known.  */
  StopForDebuggerInit(&state);

  /*
   * If export_addr_to is set to a non-negative integer, we create a
   * bound socket and socket address pair and bind the former to
   * descriptor 3 and the latter to descriptor 4.  The socket address
   * is written out to the export_addr_to descriptor.
   *
   * The service runtime also accepts a connection on the bound socket
   * and spawns a secure command channel thread to service it.
   *
   * If export_addr_to is -1, we only create the bound socket and
   * socket address pair, and we do not export to an IMC socket.  This
   * use case is typically only used in testing, where we only "dump"
   * the socket address to stdout or similar channel.
   */
  if (-2 < export_addr_to) {
    NaClCreateServiceSocket(nap);
    if (0 <= export_addr_to) {
      NaClSendServiceAddressTo(nap, export_addr_to);
      /*
       * NB: spawns a thread that uses the command channel.  we do
       * this after NaClAppLoadFile so that NaClApp object is more
       * fully populated.  Hereafter any changes to nap should be done
       * while holding locks.
       */
      NaClSecureCommandChannel(nap);
    }
  }

  NaClXMutexLock(&nap->mu);
  nap->module_load_status = LOAD_OK;
  NaClXCondVarBroadcast(&nap->cv);
  NaClXMutexUnlock(&nap->mu);

  if (NULL != nap->secure_channel) {
    /*
     * wait for start_module RPC call on secure channel thread.
     */
    NaClWaitForModuleStartStatusCall(nap);
  }

  /*
   * error reporting done; can quit now if there was an error earlier.
   */
  if (LOAD_OK != errcode) {
    goto done;
  }

  /*
   * only nap->ehdrs.e_entry is usable, no symbol table is
   * available.
   */
  if (!NaClCreateMainThread(nap,
                            ac,
                            av,
                            envp)) {
    fprintf(stderr, "creating main thread failed\n");
    goto done;
  }

  ret_code = NaClWaitForMainThreadToExit(nap);

  /*
   * exit_group or equiv kills any still running threads while module
   * addr space is still valid.  otherwise we'd have to kill threads
   * before we clean up the address space.
   */
  return ret_code;

 done:
  fflush(stdout);

  NaClAppDtor(&state);

 done_file_dtor:
  fflush(stdout);

  NaClAllModulesFini();

  return ret_code;
}

<|endoftext|>