<commit_before>// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "snapshot/fuchsia/process_reader_fuchsia.h"

#include <lib/zx/thread.h>
#include <link.h>
#include <zircon/syscalls.h>

#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "util/fuchsia/koid_utilities.h"

namespace crashpad {

namespace {

// Based on the thread's SP and the process's memory map, attempts to figure out
// the stack regions for the thread. Fuchsia's C ABI specifies
// https://fuchsia.googlesource.com/zircon/+/master/docs/safestack.md so the
// callstack and locals-that-have-their-address-taken are in two different
// stacks.
void GetStackRegions(
    const zx_thread_state_general_regs_t& regs,
    const MemoryMapFuchsia& memory_map,
    std::vector<CheckedRange<zx_vaddr_t, size_t>>* stack_regions) {
  stack_regions->clear();

  uint64_t sp;
#if defined(ARCH_CPU_X86_64)
  sp = regs.rsp;
#elif defined(ARCH_CPU_ARM64)
  sp = regs.sp;
#else
#error Port
#endif

  zx_info_maps_t range_with_sp;
  if (!memory_map.FindMappingForAddress(sp, &range_with_sp)) {
    LOG(ERROR) << "stack pointer not found in mapping";
    return;
  }

  if (range_with_sp.type != ZX_INFO_MAPS_TYPE_MAPPING) {
    LOG(ERROR) << "stack range has unexpected type, continuing anyway";
  }

  if (range_with_sp.u.mapping.mmu_flags & ZX_VM_PERM_EXECUTE) {
    LOG(ERROR)
        << "stack range is unexpectedly marked executable, continuing anyway";
  }

  // The stack covers [range_with_sp.base, range_with_sp.base +
  // range_with_sp.size). The stack pointer (sp) can be anywhere in that range.
  // It starts at the end of the range (range_with_sp.base + range_with_sp.size)
  // and goes downwards until range_with_sp.base. Capture the part of the stack
  // that is currently used: [sp, range_with_sp.base + range_with_sp.size).

  // Capture up to kExtraCaptureSize additional bytes of stack, but only if
  // present in the region that was already found.
  constexpr uint64_t kExtraCaptureSize = 128;
  const uint64_t start_address =
      std::max(sp >= kExtraCaptureSize ? sp - kExtraCaptureSize : sp,
               range_with_sp.base);
  const size_t region_size =
      range_with_sp.size - (start_address - range_with_sp.base);
  stack_regions->push_back(
      CheckedRange<zx_vaddr_t, size_t>(start_address, region_size));

  // TODO(scottmg): https://crashpad.chromium.org/bug/196, once the retrievable
  // registers include FS and similar for ARM, retrieve the region for the
  // unsafe part of the stack too.
}

}  // namespace

ProcessReaderFuchsia::Module::Module() = default;

ProcessReaderFuchsia::Module::~Module() = default;

ProcessReaderFuchsia::Thread::Thread() = default;

ProcessReaderFuchsia::Thread::~Thread() = default;

ProcessReaderFuchsia::ProcessReaderFuchsia() = default;

ProcessReaderFuchsia::~ProcessReaderFuchsia() = default;

bool ProcessReaderFuchsia::Initialize(const zx::process& process) {
  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);

  process_ = zx::unowned_process(process);

  process_memory_.reset(new ProcessMemoryFuchsia());
  process_memory_->Initialize(*process_);

  memory_map_.Initialize(*process_);

  INITIALIZATION_STATE_SET_VALID(initialized_);
  return true;
}

const std::vector<ProcessReaderFuchsia::Module>&
ProcessReaderFuchsia::Modules() {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);

  if (!initialized_modules_) {
    InitializeModules();
  }

  return modules_;
}

const std::vector<ProcessReaderFuchsia::Thread>&
ProcessReaderFuchsia::Threads() {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);

  if (!initialized_threads_) {
    InitializeThreads();
  }

  return threads_;
}

void ProcessReaderFuchsia::InitializeModules() {
  DCHECK(!initialized_modules_);
  DCHECK(modules_.empty());

  initialized_modules_ = true;

  // TODO(scottmg): <inspector/inspector.h> does some of this, but doesn't
  // expose any of the data that's necessary to fill out a Module after it
  // retrieves (some of) the data into internal structures. It may be worth
  // trying to refactor/upstream some of this into Fuchsia.

  // Starting from the ld.so's _dl_debug_addr, read the link_map structure and
  // walk the list to fill out modules_.

  uintptr_t debug_address;
  zx_status_t status = process_->get_property(
      ZX_PROP_PROCESS_DEBUG_ADDR, &debug_address, sizeof(debug_address));
  if (status != ZX_OK || debug_address == 0) {
    LOG(ERROR) << "zx_object_get_property ZX_PROP_PROCESS_DEBUG_ADDR";
    return;
  }

  constexpr auto k_r_debug_map_offset = offsetof(r_debug, r_map);
  uintptr_t map;
  if (!process_memory_->Read(
          debug_address + k_r_debug_map_offset, sizeof(map), &map)) {
    LOG(ERROR) << "read link_map";
    return;
  }

  int i = 0;
  constexpr int kMaxDso = 1000;  // Stop after an unreasonably large number.
  while (map != 0) {
    if (++i >= kMaxDso) {
      LOG(ERROR) << "possibly circular dso list, terminating";
      return;
    }

    constexpr auto k_link_map_addr_offset = offsetof(link_map, l_addr);
    zx_vaddr_t base;
    if (!process_memory_->Read(
            map + k_link_map_addr_offset, sizeof(base), &base)) {
      LOG(ERROR) << "Read base";
      // Could theoretically continue here, but realistically if any part of
      // link_map fails to read, things are looking bad, so just abort.
      break;
    }

    constexpr auto k_link_map_next_offset = offsetof(link_map, l_next);
    zx_vaddr_t next;
    if (!process_memory_->Read(
            map + k_link_map_next_offset, sizeof(next), &next)) {
      LOG(ERROR) << "Read next";
      break;
    }

    constexpr auto k_link_map_name_offset = offsetof(link_map, l_name);
    zx_vaddr_t name_address;
    if (!process_memory_->Read(map + k_link_map_name_offset,
                               sizeof(name_address),
                               &name_address)) {
      LOG(ERROR) << "Read name address";
      break;
    }

    std::string dsoname;
    if (!process_memory_->ReadCString(name_address, &dsoname)) {
      // In this case, it could be reasonable to continue on to the next module
      // as this data isn't strictly in the link_map.
      LOG(ERROR) << "ReadCString name";
    }

    // Debug symbols are indexed by module name x build-id on the crash server.
    // The module name in the indexed Breakpad files is set at build time. So
    // Crashpad needs to use the same module name at run time for symbol
    // resolution to work properly.
    //
    // TODO(fuchsia/DX-1234): once Crashpad switches to elf-search, the
    // following overwrites won't be necessary as only shared libraries will
    // have a soname at runtime, just like at build time.
    //
    // * For shared libraries, the soname is used as module name at build time,
    //   which is the dsoname here except for libzircon.so (because it is
    //   injected by the kernel, its load name is "<vDSO>" and Crashpad needs to
    //   replace it for symbol resolution to work properly).
    if (dsoname == "<vDSO>") {
      dsoname = "libzircon.so";
    }
    // * For executables and loadable modules, the dummy value "<_>" is used as
    //   module name at build time. This is because executable and loadable
    //   modules don't have a name on Fuchsia. So we need to use the same dummy
    //   value at build and run times.
    //   Most executables have an empty dsoname. Loadable modules (and some rare
    //   executables) have a non-empty dsoname starting with a specific prefix,
    //   which Crashpas can use to identify loadable modules and clear the
    //   dsoname for them.
    static constexpr const char kLoadableModuleLoadNamePrefix[] = "<VMO#";
    // Pre-C++ 20 std::basic_string::starts_with
    if (dsoname.compare(0,
                        strlen(kLoadableModuleLoadNamePrefix),
                        kLoadableModuleLoadNamePrefix) == 0) {
      dsoname = "";
    }

    Module module;
    if (dsoname.empty()) {
      // This value must be kept in sync with what is used at build time to
      // index symbols for executables and loadable modules.
      // See fuchsia/DX-1193 for more details.
      module.name = "<_>";
      module.type = ModuleSnapshot::kModuleTypeExecutable;
    } else {
      module.name = dsoname;
      // TODO(scottmg): Handle kModuleTypeDynamicLoader.
      module.type = ModuleSnapshot::kModuleTypeSharedLibrary;
    }

    std::unique_ptr<ElfImageReader> reader(new ElfImageReader());

    std::unique_ptr<ProcessMemoryRange> process_memory_range(
        new ProcessMemoryRange());
    // TODO(scottmg): Could this be limited range?
    process_memory_range->Initialize(process_memory_.get(), true);
    process_memory_ranges_.push_back(std::move(process_memory_range));

    reader->Initialize(*process_memory_ranges_.back(), base);
    module.reader = reader.get();
    module_readers_.push_back(std::move(reader));
    modules_.push_back(module);

    map = next;
  }
}

void ProcessReaderFuchsia::InitializeThreads() {
  DCHECK(!initialized_threads_);
  DCHECK(threads_.empty());

  initialized_threads_ = true;

  std::vector<zx_koid_t> thread_koids =
      GetChildKoids(*process_, ZX_INFO_PROCESS_THREADS);
  std::vector<zx::thread> thread_handles =
      GetHandlesForThreadKoids(*process_, thread_koids);
  DCHECK_EQ(thread_koids.size(), thread_handles.size());

  for (size_t i = 0; i < thread_handles.size(); ++i) {
    Thread thread;
    thread.id = thread_koids[i];

    if (thread_handles[i].is_valid()) {
      char name[ZX_MAX_NAME_LEN] = {0};
      zx_status_t status =
          thread_handles[i].get_property(ZX_PROP_NAME, &name, sizeof(name));
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status) << "zx_object_get_property ZX_PROP_NAME";
      } else {
        thread.name.assign(name);
      }

      zx_info_thread_t thread_info;
      status = thread_handles[i].get_info(
          ZX_INFO_THREAD, &thread_info, sizeof(thread_info), nullptr, nullptr);
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status) << "zx_object_get_info ZX_INFO_THREAD";
      } else {
        thread.state = thread_info.state;
      }

      zx_thread_state_general_regs_t general_regs;
      status = thread_handles[i].read_state(
          ZX_THREAD_STATE_GENERAL_REGS, &general_regs, sizeof(general_regs));
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status)
            << "zx_thread_read_state(ZX_THREAD_STATE_GENERAL_REGS)";
      } else {
        thread.general_registers = general_regs;

        GetStackRegions(general_regs, memory_map_, &thread.stack_regions);
      }

      zx_thread_state_vector_regs_t vector_regs;
      status = thread_handles[i].read_state(
          ZX_THREAD_STATE_VECTOR_REGS, &vector_regs, sizeof(vector_regs));
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status)
            << "zx_thread_read_state(ZX_THREAD_STATE_VECTOR_REGS)";
      } else {
        thread.vector_registers = vector_regs;
      }
    }

    threads_.push_back(thread);
  }
}

}  // namespace crashpad
<commit_msg>fuchsia: Check results of Initialize() subcalls in ProcessReaderFuchsia<commit_after>// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "snapshot/fuchsia/process_reader_fuchsia.h"

#include <lib/zx/thread.h>
#include <link.h>
#include <zircon/syscalls.h>

#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "util/fuchsia/koid_utilities.h"

namespace crashpad {

namespace {

// Based on the thread's SP and the process's memory map, attempts to figure out
// the stack regions for the thread. Fuchsia's C ABI specifies
// https://fuchsia.googlesource.com/zircon/+/master/docs/safestack.md so the
// callstack and locals-that-have-their-address-taken are in two different
// stacks.
void GetStackRegions(
    const zx_thread_state_general_regs_t& regs,
    const MemoryMapFuchsia& memory_map,
    std::vector<CheckedRange<zx_vaddr_t, size_t>>* stack_regions) {
  stack_regions->clear();

  uint64_t sp;
#if defined(ARCH_CPU_X86_64)
  sp = regs.rsp;
#elif defined(ARCH_CPU_ARM64)
  sp = regs.sp;
#else
#error Port
#endif

  zx_info_maps_t range_with_sp;
  if (!memory_map.FindMappingForAddress(sp, &range_with_sp)) {
    LOG(ERROR) << "stack pointer not found in mapping";
    return;
  }

  if (range_with_sp.type != ZX_INFO_MAPS_TYPE_MAPPING) {
    LOG(ERROR) << "stack range has unexpected type, continuing anyway";
  }

  if (range_with_sp.u.mapping.mmu_flags & ZX_VM_PERM_EXECUTE) {
    LOG(ERROR)
        << "stack range is unexpectedly marked executable, continuing anyway";
  }

  // The stack covers [range_with_sp.base, range_with_sp.base +
  // range_with_sp.size). The stack pointer (sp) can be anywhere in that range.
  // It starts at the end of the range (range_with_sp.base + range_with_sp.size)
  // and goes downwards until range_with_sp.base. Capture the part of the stack
  // that is currently used: [sp, range_with_sp.base + range_with_sp.size).

  // Capture up to kExtraCaptureSize additional bytes of stack, but only if
  // present in the region that was already found.
  constexpr uint64_t kExtraCaptureSize = 128;
  const uint64_t start_address =
      std::max(sp >= kExtraCaptureSize ? sp - kExtraCaptureSize : sp,
               range_with_sp.base);
  const size_t region_size =
      range_with_sp.size - (start_address - range_with_sp.base);
  stack_regions->push_back(
      CheckedRange<zx_vaddr_t, size_t>(start_address, region_size));

  // TODO(scottmg): https://crashpad.chromium.org/bug/196, once the retrievable
  // registers include FS and similar for ARM, retrieve the region for the
  // unsafe part of the stack too.
}

}  // namespace

ProcessReaderFuchsia::Module::Module() = default;

ProcessReaderFuchsia::Module::~Module() = default;

ProcessReaderFuchsia::Thread::Thread() = default;

ProcessReaderFuchsia::Thread::~Thread() = default;

ProcessReaderFuchsia::ProcessReaderFuchsia() = default;

ProcessReaderFuchsia::~ProcessReaderFuchsia() = default;

bool ProcessReaderFuchsia::Initialize(const zx::process& process) {
  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);

  process_ = zx::unowned_process(process);

  process_memory_.reset(new ProcessMemoryFuchsia());
  process_memory_->Initialize(*process_);

  if (!memory_map_.Initialize(*process_)) {
    return false;
  }

  INITIALIZATION_STATE_SET_VALID(initialized_);
  return true;
}

const std::vector<ProcessReaderFuchsia::Module>&
ProcessReaderFuchsia::Modules() {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);

  if (!initialized_modules_) {
    InitializeModules();
  }

  return modules_;
}

const std::vector<ProcessReaderFuchsia::Thread>&
ProcessReaderFuchsia::Threads() {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);

  if (!initialized_threads_) {
    InitializeThreads();
  }

  return threads_;
}

void ProcessReaderFuchsia::InitializeModules() {
  DCHECK(!initialized_modules_);
  DCHECK(modules_.empty());

  initialized_modules_ = true;

  // TODO(scottmg): <inspector/inspector.h> does some of this, but doesn't
  // expose any of the data that's necessary to fill out a Module after it
  // retrieves (some of) the data into internal structures. It may be worth
  // trying to refactor/upstream some of this into Fuchsia.

  // Starting from the ld.so's _dl_debug_addr, read the link_map structure and
  // walk the list to fill out modules_.

  uintptr_t debug_address;
  zx_status_t status = process_->get_property(
      ZX_PROP_PROCESS_DEBUG_ADDR, &debug_address, sizeof(debug_address));
  if (status != ZX_OK || debug_address == 0) {
    LOG(ERROR) << "zx_object_get_property ZX_PROP_PROCESS_DEBUG_ADDR";
    return;
  }

  constexpr auto k_r_debug_map_offset = offsetof(r_debug, r_map);
  uintptr_t map;
  if (!process_memory_->Read(
          debug_address + k_r_debug_map_offset, sizeof(map), &map)) {
    LOG(ERROR) << "read link_map";
    return;
  }

  int i = 0;
  constexpr int kMaxDso = 1000;  // Stop after an unreasonably large number.
  while (map != 0) {
    if (++i >= kMaxDso) {
      LOG(ERROR) << "possibly circular dso list, terminating";
      return;
    }

    constexpr auto k_link_map_addr_offset = offsetof(link_map, l_addr);
    zx_vaddr_t base;
    if (!process_memory_->Read(
            map + k_link_map_addr_offset, sizeof(base), &base)) {
      LOG(ERROR) << "Read base";
      // Could theoretically continue here, but realistically if any part of
      // link_map fails to read, things are looking bad, so just abort.
      break;
    }

    constexpr auto k_link_map_next_offset = offsetof(link_map, l_next);
    zx_vaddr_t next;
    if (!process_memory_->Read(
            map + k_link_map_next_offset, sizeof(next), &next)) {
      LOG(ERROR) << "Read next";
      break;
    }

    constexpr auto k_link_map_name_offset = offsetof(link_map, l_name);
    zx_vaddr_t name_address;
    if (!process_memory_->Read(map + k_link_map_name_offset,
                               sizeof(name_address),
                               &name_address)) {
      LOG(ERROR) << "Read name address";
      break;
    }

    std::string dsoname;
    if (!process_memory_->ReadCString(name_address, &dsoname)) {
      // In this case, it could be reasonable to continue on to the next module
      // as this data isn't strictly in the link_map.
      LOG(ERROR) << "ReadCString name";
    }

    // Debug symbols are indexed by module name x build-id on the crash server.
    // The module name in the indexed Breakpad files is set at build time. So
    // Crashpad needs to use the same module name at run time for symbol
    // resolution to work properly.
    //
    // TODO(fuchsia/DX-1234): once Crashpad switches to elf-search, the
    // following overwrites won't be necessary as only shared libraries will
    // have a soname at runtime, just like at build time.
    //
    // * For shared libraries, the soname is used as module name at build time,
    //   which is the dsoname here except for libzircon.so (because it is
    //   injected by the kernel, its load name is "<vDSO>" and Crashpad needs to
    //   replace it for symbol resolution to work properly).
    if (dsoname == "<vDSO>") {
      dsoname = "libzircon.so";
    }
    // * For executables and loadable modules, the dummy value "<_>" is used as
    //   module name at build time. This is because executable and loadable
    //   modules don't have a name on Fuchsia. So we need to use the same dummy
    //   value at build and run times.
    //   Most executables have an empty dsoname. Loadable modules (and some rare
    //   executables) have a non-empty dsoname starting with a specific prefix,
    //   which Crashpas can use to identify loadable modules and clear the
    //   dsoname for them.
    static constexpr const char kLoadableModuleLoadNamePrefix[] = "<VMO#";
    // Pre-C++ 20 std::basic_string::starts_with
    if (dsoname.compare(0,
                        strlen(kLoadableModuleLoadNamePrefix),
                        kLoadableModuleLoadNamePrefix) == 0) {
      dsoname = "";
    }

    Module module;
    if (dsoname.empty()) {
      // This value must be kept in sync with what is used at build time to
      // index symbols for executables and loadable modules.
      // See fuchsia/DX-1193 for more details.
      module.name = "<_>";
      module.type = ModuleSnapshot::kModuleTypeExecutable;
    } else {
      module.name = dsoname;
      // TODO(scottmg): Handle kModuleTypeDynamicLoader.
      module.type = ModuleSnapshot::kModuleTypeSharedLibrary;
    }

    std::unique_ptr<ElfImageReader> reader(new ElfImageReader());

    std::unique_ptr<ProcessMemoryRange> process_memory_range(
        new ProcessMemoryRange());
    // TODO(scottmg): Could this be limited range?
    if (process_memory_range->Initialize(process_memory_.get(), true)) {
      process_memory_ranges_.push_back(std::move(process_memory_range));

      if (reader->Initialize(*process_memory_ranges_.back(), base)) {
        module.reader = reader.get();
        module_readers_.push_back(std::move(reader));
        modules_.push_back(module);
      }
    }

    map = next;
  }
}

void ProcessReaderFuchsia::InitializeThreads() {
  DCHECK(!initialized_threads_);
  DCHECK(threads_.empty());

  initialized_threads_ = true;

  std::vector<zx_koid_t> thread_koids =
      GetChildKoids(*process_, ZX_INFO_PROCESS_THREADS);
  std::vector<zx::thread> thread_handles =
      GetHandlesForThreadKoids(*process_, thread_koids);
  DCHECK_EQ(thread_koids.size(), thread_handles.size());

  for (size_t i = 0; i < thread_handles.size(); ++i) {
    Thread thread;
    thread.id = thread_koids[i];

    if (thread_handles[i].is_valid()) {
      char name[ZX_MAX_NAME_LEN] = {0};
      zx_status_t status =
          thread_handles[i].get_property(ZX_PROP_NAME, &name, sizeof(name));
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status) << "zx_object_get_property ZX_PROP_NAME";
      } else {
        thread.name.assign(name);
      }

      zx_info_thread_t thread_info;
      status = thread_handles[i].get_info(
          ZX_INFO_THREAD, &thread_info, sizeof(thread_info), nullptr, nullptr);
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status) << "zx_object_get_info ZX_INFO_THREAD";
      } else {
        thread.state = thread_info.state;
      }

      zx_thread_state_general_regs_t general_regs;
      status = thread_handles[i].read_state(
          ZX_THREAD_STATE_GENERAL_REGS, &general_regs, sizeof(general_regs));
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status)
            << "zx_thread_read_state(ZX_THREAD_STATE_GENERAL_REGS)";
      } else {
        thread.general_registers = general_regs;

        GetStackRegions(general_regs, memory_map_, &thread.stack_regions);
      }

      zx_thread_state_vector_regs_t vector_regs;
      status = thread_handles[i].read_state(
          ZX_THREAD_STATE_VECTOR_REGS, &vector_regs, sizeof(vector_regs));
      if (status != ZX_OK) {
        ZX_LOG(WARNING, status)
            << "zx_thread_read_state(ZX_THREAD_STATE_VECTOR_REGS)";
      } else {
        thread.vector_registers = vector_regs;
      }
    }

    threads_.push_back(thread);
  }
}

}  // namespace crashpad
<|endoftext|>


<commit_before>/*=====================================================================

 QGroundControl Open Source Ground Control Station

 (c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

 This file is part of the QGROUNDCONTROL project

 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

 ======================================================================*/

/// @file
///     @author Don Gagne <don@thegagnes.com>

#include "PowerComponentController.h"
#include "QGCMAVLink.h"
#include "UASManager.h"
#include "QGCMessageBox.h"

#include <QVariant>
#include <QQmlProperty>

PowerComponentController::PowerComponentController(void)
{

}

PowerComponentController::~PowerComponentController()
{
    _stopCalibration();
}

void PowerComponentController::calibrateEsc(void)
{
    _warningMessages.clear();
    connect(_uas, &UASInterface::textMessageReceived, this, &PowerComponentController::_handleUASTextMessage);
    _uas->startCalibration(UASInterface::StartCalibrationEsc);
}

void PowerComponentController::_stopCalibration(void)
{
    disconnect(_uas, &UASInterface::textMessageReceived, this, &PowerComponentController::_handleUASTextMessage);
}

void PowerComponentController::_handleUASTextMessage(int uasId, int compId, int severity, QString text)
{
    Q_UNUSED(compId);
    Q_UNUSED(severity);

    UASInterface* uas = _autopilot->uas();
    Q_ASSERT(uas);
    if (uasId != uas->getUASID()) {
        return;
    }

    // All calibration messages start with [cal]
    QString calPrefix("[cal] ");
    if (!text.startsWith(calPrefix)) {
        return;
    }
    text = text.right(text.length() - calPrefix.length());

    // Make sure we can understand this firmware rev
    QString calStartPrefix("calibration started: ");
    if (text.startsWith(calStartPrefix)) {
        text = text.right(text.length() - calStartPrefix.length());

        // Split version number and cal type
        QStringList parts = text.split(" ");
        if (parts.count() != 2) {
            emit incorrectFirmwareRevReporting();
            return;
        }

        int firmwareRev = parts[0].toInt();
        if (firmwareRev < _neededFirmwareRev) {
            emit oldFirmware();
            return;
        }
        if (firmwareRev > _neededFirmwareRev) {
            emit newerFirmware();
            return;
        }
    }

    if (text == "Connect battery now") {
        emit connectBattery();
        return;
    }

    if (text == "Battery connected") {
        emit batteryConnected();
        return;
    }

    QString failedPrefix("calibration failed: ");
    if (text.startsWith(failedPrefix)) {
        QString failureText = text.right(text.length() - failedPrefix.length());
        if (failureText.startsWith("Disconnect battery")) {
            emit disconnectBattery();
            return;
        }

        _stopCalibration();
        emit calibrationFailed(text.right(text.length() - failedPrefix.length()));
        return;
    }

    QString calCompletePrefix("calibration done:");
    if (text.startsWith(calCompletePrefix)) {
        _stopCalibration();
        emit calibrationSuccess(_warningMessages);
        return;
    }

    QString warningPrefix("calibration warning: ");
    if (text.startsWith(warningPrefix)) {
        _warningMessages << text.right(text.length() - warningPrefix.length());
    }
}
<commit_msg>Remove broken rev checking<commit_after>/*=====================================================================

 QGroundControl Open Source Ground Control Station

 (c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

 This file is part of the QGROUNDCONTROL project

 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

 ======================================================================*/

/// @file
///     @author Don Gagne <don@thegagnes.com>

#include "PowerComponentController.h"
#include "QGCMAVLink.h"
#include "UASManager.h"
#include "QGCMessageBox.h"

#include <QVariant>
#include <QQmlProperty>

PowerComponentController::PowerComponentController(void)
{

}

PowerComponentController::~PowerComponentController()
{
    _stopCalibration();
}

void PowerComponentController::calibrateEsc(void)
{
    _warningMessages.clear();
    connect(_uas, &UASInterface::textMessageReceived, this, &PowerComponentController::_handleUASTextMessage);
    _uas->startCalibration(UASInterface::StartCalibrationEsc);
}

void PowerComponentController::_stopCalibration(void)
{
    disconnect(_uas, &UASInterface::textMessageReceived, this, &PowerComponentController::_handleUASTextMessage);
}

void PowerComponentController::_handleUASTextMessage(int uasId, int compId, int severity, QString text)
{
    Q_UNUSED(compId);
    Q_UNUSED(severity);

    UASInterface* uas = _autopilot->uas();
    Q_ASSERT(uas);
    if (uasId != uas->getUASID()) {
        return;
    }

    // All calibration messages start with [cal]
    QString calPrefix("[cal] ");
    if (!text.startsWith(calPrefix)) {
        return;
    }
    text = text.right(text.length() - calPrefix.length());

    // Make sure we can understand this firmware rev
    QString calStartPrefix("calibration started: ");
    if (text.startsWith(calStartPrefix)) {
        text = text.right(text.length() - calStartPrefix.length());

        // Split version number and cal type
        QStringList parts = text.split(" ");
        if (parts.count() != 2) {
            emit incorrectFirmwareRevReporting();
            return;
        }

#if 0
        // FIXME: Cal version check is not working. Needs to be able to cancel, calibration

        int firmwareRev = parts[0].toInt();
        if (firmwareRev < _neededFirmwareRev) {
            emit oldFirmware();
            return;
        }
        if (firmwareRev > _neededFirmwareRev) {
            emit newerFirmware();
            return;
        }
#endif
    }

    if (text == "Connect battery now") {
        emit connectBattery();
        return;
    }

    if (text == "Battery connected") {
        emit batteryConnected();
        return;
    }

    QString failedPrefix("calibration failed: ");
    if (text.startsWith(failedPrefix)) {
        QString failureText = text.right(text.length() - failedPrefix.length());
        if (failureText.startsWith("Disconnect battery")) {
            emit disconnectBattery();
            return;
        }

        _stopCalibration();
        emit calibrationFailed(text.right(text.length() - failedPrefix.length()));
        return;
    }

    QString calCompletePrefix("calibration done:");
    if (text.startsWith(calCompletePrefix)) {
        _stopCalibration();
        emit calibrationSuccess(_warningMessages);
        return;
    }

    QString warningPrefix("calibration warning: ");
    if (text.startsWith(warningPrefix)) {
        _warningMessages << text.right(text.length() - warningPrefix.length());
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <string.h>
#include <stdlib.h>
#include "official/vk_layer.h"

// RenderDoc Includes

#include "vk_common.h"
#include "vk_core.h"
#include "vk_resources.h"
#include "vk_hookset_defs.h"

#include "common/common.h"
#include "common/threading.h"
#include "serialise/string_utils.h"

#include "data/version.h"

#include "os/os_specific.h"

// this should be in the vulkan definition header
#ifdef WIN32
#undef VK_LAYER_EXPORT
#define VK_LAYER_EXPORT extern "C" __declspec(dllexport)
#endif

// in vk_<platform>.cpp
bool LayerRegistered();

struct RegisterCallback
{
	RegisterCallback()
	{
		// we assume the implicit layer is registered - the UI will prompt the user about installing it.
		Process::RegisterEnvironmentModification(Process::EnvironmentModification(Process::eEnvModification_Replace, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "1"));
	}
};

static RegisterCallback registercb;

// RenderDoc State

// RenderDoc Intercepts, these must all be entry points with a dispatchable object
// as the first parameter

#define HookDefine1(ret, function, t1, p1) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1) \
	{ return CoreDisp(p1)->function(p1); }
#define HookDefine2(ret, function, t1, p1, t2, p2) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2) \
	{ return CoreDisp(p1)->function(p1, p2); }
#define HookDefine3(ret, function, t1, p1, t2, p2, t3, p3) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3) \
	{ return CoreDisp(p1)->function(p1, p2, p3); }
#define HookDefine4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4); }
#define HookDefine5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5); }
#define HookDefine6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6); }
#define HookDefine7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7); }
#define HookDefine8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8); }
#define HookDefine9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9, p9) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
#define HookDefine10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
#define HookDefine11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10, t11 p11) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }

DefineHooks();

// need to implement vkCreateInstance and vkDestroyInstance specially,
// to create and destroy the core WrappedVulkan object

VkResult hooked_vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
{
	WrappedVulkan *core = new WrappedVulkan("");
	return core->vkCreateInstance(pCreateInfo, pAllocator, pInstance);
}

void hooked_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator)
{
	WrappedVulkan *core = CoreDisp(instance);
	core->vkDestroyInstance(instance, pAllocator);
	delete core;
}

// Layer Intercepts

static const VkLayerProperties physLayers[] = {
	{
		RENDERDOC_LAYER_NAME,
		VK_API_VERSION,
		VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
		"Debugging capture layer for RenderDoc",
	}
};

static const VkExtensionProperties physExts[] = {
	{
		DEBUG_MARKER_EXTENSION_NAME,
		VK_MAKE_VERSION(0, 1, 0),
	}
};

static const VkLayerProperties globalLayers[] = {
	{
		RENDERDOC_LAYER_NAME,
		VK_API_VERSION,
		VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
		"Debugging capture layer for RenderDoc",
	}
};

VkResult getProps(uint32_t *dstCount, void *dstProps, uint32_t srcCount, void *srcProps, size_t elemSize)
{
	if(dstCount == NULL)
		return VK_RESULT_MAX_ENUM;

	if(dstProps == NULL)
	{
		*dstCount = srcCount;
		return VK_SUCCESS;
	}

	memcpy(dstProps, srcProps, elemSize*RDCMIN(srcCount, *dstCount));
	if(*dstCount < srcCount)
		return VK_INCOMPLETE;

	*dstCount = srcCount;

	return VK_SUCCESS;
}

#if defined(WIN32) && !defined(WIN64)

// Win32 __stdcall will still mangle even with extern "C", set up aliases

#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties=_VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties@12")
#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties=_VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties@16")
#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr=_VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr@8")
#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr=_VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr@8")

#endif

extern "C" {

VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties(
	VkPhysicalDevice                            physicalDevice,
	uint32_t*                                   pPropertyCount,
	VkLayerProperties*                          pProperties)
{
	return getProps(pPropertyCount, pProperties, ARRAY_COUNT(physLayers), (void *)physLayers, sizeof(VkLayerProperties));
}

VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties(
	VkPhysicalDevice        physicalDevice,
	const char             *pLayerName,
	uint32_t               *pPropertyCount,
	VkExtensionProperties  *pProperties)
{
	// if pLayerName is NULL we're calling down through the layer chain to the ICD.
	// This is our chance to filter out any reported extensions that we don't support
	if(pLayerName == NULL)
		return ObjDisp(physicalDevice)->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), pLayerName, pPropertyCount, pProperties);

	return getProps(pPropertyCount, pProperties, ARRAY_COUNT(physExts), (void *)physExts, sizeof(VkExtensionProperties));
}

#undef HookInit
#define HookInit(function) if (!strcmp(pName, STRINGIZE(CONCAT(vk, function)))) return (PFN_vkVoidFunction) &CONCAT(hooked_vk, function);

#undef HookInitExtension
#define HookInitExtension(ext, function) \
	if (!strcmp(pName, STRINGIZE(CONCAT(vk, function)))) \
	{ \
		if(instDevInfo->ext) return (PFN_vkVoidFunction) &CONCAT(hooked_vk, function); \
		else RDCWARN("Requested function %s but extension %s is not enabled!", STRINGIZE(function), STRINGIZE(ext)); \
	}

// proc addr routines

VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr(VkDevice device, const char* pName)
{
	if(!strcmp("vkGetDeviceProcAddr", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr;
	if(!strcmp("vkCreateDevice", pName))
		return (PFN_vkVoidFunction) &hooked_vkCreateDevice;
	if(!strcmp("vkDestroyDevice", pName))
		return (PFN_vkVoidFunction) &hooked_vkDestroyDevice;

	HookInitVulkanDevice();

	if(device == VK_NULL_HANDLE)
		return NULL;

	InstanceDeviceInfo *instDevInfo = GetRecord(device)->instDevInfo;

	HookInitVulkanDeviceExts();

	if(GetDeviceDispatchTable(device)->GetDeviceProcAddr == NULL)
		return NULL;
	return GetDeviceDispatchTable(device)->GetDeviceProcAddr(Unwrap(device), pName);
}

VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr(VkInstance instance, const char* pName)
{
	if(!strcmp("vkGetInstanceProcAddr", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr;
	if(!strcmp("vkEnumerateDeviceLayerProperties", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties;
	if(!strcmp("vkEnumerateDeviceExtensionProperties", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties;

	HookInitVulkanInstance();

	if(instance == VK_NULL_HANDLE)
		return NULL;

	InstanceDeviceInfo *instDevInfo = GetRecord(instance)->instDevInfo;

	HookInitVulkanInstanceExts();

	// GetInstanceProcAddr must also unconditionally return all device functions

#undef HookInitExtension
#define HookInitExtension(ext, function) if (!strcmp(pName, STRINGIZE(CONCAT(vk, function)))) return (PFN_vkVoidFunction) &CONCAT(hooked_vk, function);

	HookInitVulkanDevice();

	HookInitVulkanDeviceExts();

	if(GetInstanceDispatchTable(instance)->GetInstanceProcAddr == NULL)
		return NULL;
	return GetInstanceDispatchTable(instance)->GetInstanceProcAddr(Unwrap(instance), pName);
}

}
<commit_msg>Set hooked_vkCreate/DestroyInstance to be VKAPI_CALL. Refs #230<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <string.h>
#include <stdlib.h>
#include "official/vk_layer.h"

// RenderDoc Includes

#include "vk_common.h"
#include "vk_core.h"
#include "vk_resources.h"
#include "vk_hookset_defs.h"

#include "common/common.h"
#include "common/threading.h"
#include "serialise/string_utils.h"

#include "data/version.h"

#include "os/os_specific.h"

// this should be in the vulkan definition header
#ifdef WIN32
#undef VK_LAYER_EXPORT
#define VK_LAYER_EXPORT extern "C" __declspec(dllexport)
#endif

// in vk_<platform>.cpp
bool LayerRegistered();

struct RegisterCallback
{
	RegisterCallback()
	{
		// we assume the implicit layer is registered - the UI will prompt the user about installing it.
		Process::RegisterEnvironmentModification(Process::EnvironmentModification(Process::eEnvModification_Replace, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "1"));
	}
};

static RegisterCallback registercb;

// RenderDoc State

// RenderDoc Intercepts, these must all be entry points with a dispatchable object
// as the first parameter

#define HookDefine1(ret, function, t1, p1) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1) \
	{ return CoreDisp(p1)->function(p1); }
#define HookDefine2(ret, function, t1, p1, t2, p2) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2) \
	{ return CoreDisp(p1)->function(p1, p2); }
#define HookDefine3(ret, function, t1, p1, t2, p2, t3, p3) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3) \
	{ return CoreDisp(p1)->function(p1, p2, p3); }
#define HookDefine4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4); }
#define HookDefine5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5); }
#define HookDefine6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6); }
#define HookDefine7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7); }
#define HookDefine8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8); }
#define HookDefine9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9, p9) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
#define HookDefine10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
#define HookDefine11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11) \
	ret VKAPI_CALL CONCAT(hooked_, function)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10, t11 p11) \
	{ return CoreDisp(p1)->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }

DefineHooks();

// need to implement vkCreateInstance and vkDestroyInstance specially,
// to create and destroy the core WrappedVulkan object

VkResult VKAPI_CALL hooked_vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
{
	WrappedVulkan *core = new WrappedVulkan("");
	return core->vkCreateInstance(pCreateInfo, pAllocator, pInstance);
}

void VKAPI_CALL hooked_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator)
{
	WrappedVulkan *core = CoreDisp(instance);
	core->vkDestroyInstance(instance, pAllocator);
	delete core;
}

// Layer Intercepts

static const VkLayerProperties physLayers[] = {
	{
		RENDERDOC_LAYER_NAME,
		VK_API_VERSION,
		VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
		"Debugging capture layer for RenderDoc",
	}
};

static const VkExtensionProperties physExts[] = {
	{
		DEBUG_MARKER_EXTENSION_NAME,
		VK_MAKE_VERSION(0, 1, 0),
	}
};

static const VkLayerProperties globalLayers[] = {
	{
		RENDERDOC_LAYER_NAME,
		VK_API_VERSION,
		VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
		"Debugging capture layer for RenderDoc",
	}
};

VkResult getProps(uint32_t *dstCount, void *dstProps, uint32_t srcCount, void *srcProps, size_t elemSize)
{
	if(dstCount == NULL)
		return VK_RESULT_MAX_ENUM;

	if(dstProps == NULL)
	{
		*dstCount = srcCount;
		return VK_SUCCESS;
	}

	memcpy(dstProps, srcProps, elemSize*RDCMIN(srcCount, *dstCount));
	if(*dstCount < srcCount)
		return VK_INCOMPLETE;

	*dstCount = srcCount;

	return VK_SUCCESS;
}

#if defined(WIN32) && !defined(WIN64)

// Win32 __stdcall will still mangle even with extern "C", set up aliases

#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties=_VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties@12")
#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties=_VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties@16")
#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr=_VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr@8")
#pragma comment(linker, "/EXPORT:VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr=_VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr@8")

#endif

extern "C" {

VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties(
	VkPhysicalDevice                            physicalDevice,
	uint32_t*                                   pPropertyCount,
	VkLayerProperties*                          pProperties)
{
	return getProps(pPropertyCount, pProperties, ARRAY_COUNT(physLayers), (void *)physLayers, sizeof(VkLayerProperties));
}

VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties(
	VkPhysicalDevice        physicalDevice,
	const char             *pLayerName,
	uint32_t               *pPropertyCount,
	VkExtensionProperties  *pProperties)
{
	// if pLayerName is NULL we're calling down through the layer chain to the ICD.
	// This is our chance to filter out any reported extensions that we don't support
	if(pLayerName == NULL)
		return ObjDisp(physicalDevice)->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), pLayerName, pPropertyCount, pProperties);

	return getProps(pPropertyCount, pProperties, ARRAY_COUNT(physExts), (void *)physExts, sizeof(VkExtensionProperties));
}

#undef HookInit
#define HookInit(function) if (!strcmp(pName, STRINGIZE(CONCAT(vk, function)))) return (PFN_vkVoidFunction) &CONCAT(hooked_vk, function);

#undef HookInitExtension
#define HookInitExtension(ext, function) \
	if (!strcmp(pName, STRINGIZE(CONCAT(vk, function)))) \
	{ \
		if(instDevInfo->ext) return (PFN_vkVoidFunction) &CONCAT(hooked_vk, function); \
		else RDCWARN("Requested function %s but extension %s is not enabled!", STRINGIZE(function), STRINGIZE(ext)); \
	}

// proc addr routines

VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr(VkDevice device, const char* pName)
{
	if(!strcmp("vkGetDeviceProcAddr", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureGetDeviceProcAddr;
	if(!strcmp("vkCreateDevice", pName))
		return (PFN_vkVoidFunction) &hooked_vkCreateDevice;
	if(!strcmp("vkDestroyDevice", pName))
		return (PFN_vkVoidFunction) &hooked_vkDestroyDevice;

	HookInitVulkanDevice();

	if(device == VK_NULL_HANDLE)
		return NULL;

	InstanceDeviceInfo *instDevInfo = GetRecord(device)->instDevInfo;

	HookInitVulkanDeviceExts();

	if(GetDeviceDispatchTable(device)->GetDeviceProcAddr == NULL)
		return NULL;
	return GetDeviceDispatchTable(device)->GetDeviceProcAddr(Unwrap(device), pName);
}

VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr(VkInstance instance, const char* pName)
{
	if(!strcmp("vkGetInstanceProcAddr", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureGetInstanceProcAddr;
	if(!strcmp("vkEnumerateDeviceLayerProperties", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLayerProperties;
	if(!strcmp("vkEnumerateDeviceExtensionProperties", pName))
		return (PFN_vkVoidFunction) &VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties;

	HookInitVulkanInstance();

	if(instance == VK_NULL_HANDLE)
		return NULL;

	InstanceDeviceInfo *instDevInfo = GetRecord(instance)->instDevInfo;

	HookInitVulkanInstanceExts();

	// GetInstanceProcAddr must also unconditionally return all device functions

#undef HookInitExtension
#define HookInitExtension(ext, function) if (!strcmp(pName, STRINGIZE(CONCAT(vk, function)))) return (PFN_vkVoidFunction) &CONCAT(hooked_vk, function);

	HookInitVulkanDevice();

	HookInitVulkanDeviceExts();

	if(GetInstanceDispatchTable(instance)->GetInstanceProcAddr == NULL)
		return NULL;
	return GetInstanceDispatchTable(instance)->GetInstanceProcAddr(Unwrap(instance), pName);
}

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "valgrindengine.h"
#include "valgrindsettings.h"
#include "valgrindplugin.h"

#include <coreplugin/icore.h>
#include <coreplugin/ioutputpane.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/runconfiguration.h>
#include <analyzerbase/analyzermanager.h>

#include <QApplication>
#include <QMainWindow>

#define VALGRIND_DEBUG_OUTPUT 0

using namespace Analyzer;
using namespace Core;
using namespace Utils;
using namespace ProjectExplorer;

namespace Valgrind {
namespace Internal {

ValgrindRunControl::ValgrindRunControl(const AnalyzerStartParameters &sp,
        ProjectExplorer::RunConfiguration *runConfiguration)
    : AnalyzerRunControl(sp, runConfiguration),
      m_settings(0),
      m_isStopping(false)
{
    if (runConfiguration)
        if (IRunConfigurationAspect *aspect = runConfiguration->extraAspect(ANALYZER_VALGRIND_SETTINGS))
            m_settings = qobject_cast<ValgrindBaseSettings *>(aspect->currentSettings());

    if (!m_settings)
        m_settings = ValgrindPlugin::globalSettings();

}

ValgrindRunControl::~ValgrindRunControl()
{
}

bool ValgrindRunControl::startEngine()
{
    emit starting(this);

    FutureProgress *fp = ProgressManager::addTimedTask(m_progress, progressTitle(), "valgrind", 100);
    fp->setKeepOnFinish(FutureProgress::HideOnFinish);
    connect(fp, SIGNAL(canceled()), this, SLOT(handleProgressCanceled()));
    connect(fp, SIGNAL(finished()), this, SLOT(handleProgressFinished()));
    m_progress.reportStarted();

    const AnalyzerStartParameters &sp = startParameters();
#if VALGRIND_DEBUG_OUTPUT
    emit outputReceived(tr("Valgrind options: %1").arg(toolArguments().join(QLatin1Char(' '))), DebugFormat);
    emit outputReceived(tr("Working directory: %1").arg(sp.workingDirectory), DebugFormat);
    emit outputReceived(tr("Command line arguments: %1").arg(sp.debuggeeArgs), DebugFormat);
#endif

    ValgrindRunner *run = runner();
    run->setWorkingDirectory(sp.workingDirectory);
    QString valgrindExe = m_settings->valgrindExecutable();
    run->setValgrindExecutable(valgrindExe);
    run->setValgrindArguments(genericToolArguments() + toolArguments());
    run->setDebuggeeExecutable(sp.debuggee);
    run->setDebuggeeArguments(sp.debuggeeArgs);
    run->setEnvironment(sp.environment);
    run->setConnectionParameters(sp.connParams);
    run->setStartMode(sp.startMode);
    run->setLocalRunMode(sp.localRunMode);

    connect(run, SIGNAL(processOutputReceived(QString,Utils::OutputFormat)),
            SLOT(receiveProcessOutput(QString,Utils::OutputFormat)));
    connect(run, SIGNAL(processErrorReceived(QString,QProcess::ProcessError)),
            SLOT(receiveProcessError(QString,QProcess::ProcessError)));
    connect(run, SIGNAL(finished()), SLOT(runnerFinished()));

    if (!run->start()) {
        m_progress.cancel();
        return false;
    }
    return true;
}

void ValgrindRunControl::stopEngine()
{
    m_isStopping = true;
    runner()->stop();
}

QString ValgrindRunControl::executable() const
{
    return startParameters().debuggee;
}

QStringList ValgrindRunControl::genericToolArguments() const
{
    QTC_ASSERT(m_settings, return QStringList());
    QString smcCheckValue;
    switch (m_settings->selfModifyingCodeDetection()) {
    case ValgrindBaseSettings::DetectSmcNo:
        smcCheckValue = QLatin1String("none");
        break;
    case ValgrindBaseSettings::DetectSmcEverywhere:
        smcCheckValue = QLatin1String("all");
        break;
    case ValgrindBaseSettings::DetectSmcEverywhereButFile:
        smcCheckValue = QLatin1String("all-non-file");
        break;
    case ValgrindBaseSettings::DetectSmcStackOnly:
    default:
        smcCheckValue = QLatin1String("stack");
        break;
    }
    return QStringList() << QLatin1String("--smc-check=") + smcCheckValue;
}

void ValgrindRunControl::handleProgressCanceled()
{
    AnalyzerManager::stopTool();
    m_progress.reportCanceled();
    m_progress.reportFinished();
}

void ValgrindRunControl::handleProgressFinished()
{
    QApplication::alert(ICore::mainWindow(), 3000);
}

void ValgrindRunControl::runnerFinished()
{
    appendMessage(tr("Analyzing finished.") + QLatin1Char('\n'), NormalMessageFormat);
    emit finished();

    m_progress.reportFinished();

    disconnect(runner(), SIGNAL(processOutputReceived(QString,Utils::OutputFormat)),
               this, SLOT(receiveProcessOutput(QString,Utils::OutputFormat)));
    disconnect(runner(), SIGNAL(finished()),
               this, SLOT(runnerFinished()));
}

void ValgrindRunControl::receiveProcessOutput(const QString &output, OutputFormat format)
{
    appendMessage(output, format);
}

void ValgrindRunControl::receiveProcessError(const QString &message, QProcess::ProcessError error)
{
    if (error == QProcess::FailedToStart) {
        const QString valgrind = m_settings->valgrindExecutable();
        if (!valgrind.isEmpty())
            appendMessage(tr("Error: \"%1\" could not be started: %2").arg(valgrind, message) + QLatin1Char('\n'), ErrorMessageFormat);
        else
            appendMessage(tr("Error: no Valgrind executable set.") + QLatin1Char('\n'), ErrorMessageFormat);
    } else if (m_isStopping && error == QProcess::Crashed) { // process gets killed on stop
        appendMessage(tr("Process terminated.") + QLatin1Char('\n'), ErrorMessageFormat);
    } else {
        appendMessage(QString::fromLatin1("** %1 **\n").arg(message), ErrorMessageFormat);
    }

    if (m_isStopping)
        return;

    QObject *obj = ExtensionSystem::PluginManager::getObjectByName(QLatin1String("AppOutputPane"));
    if (IOutputPane *pane = qobject_cast<IOutputPane *>(obj))
        pane->popup(IOutputPane::NoModeSwitch);
}

} // namespace Internal
} // namepsace Valgrind
<commit_msg>Valgrind: Remove redundant local variable<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "valgrindengine.h"
#include "valgrindsettings.h"
#include "valgrindplugin.h"

#include <coreplugin/icore.h>
#include <coreplugin/ioutputpane.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/runconfiguration.h>
#include <analyzerbase/analyzermanager.h>

#include <QApplication>
#include <QMainWindow>

#define VALGRIND_DEBUG_OUTPUT 0

using namespace Analyzer;
using namespace Core;
using namespace Utils;
using namespace ProjectExplorer;

namespace Valgrind {
namespace Internal {

ValgrindRunControl::ValgrindRunControl(const AnalyzerStartParameters &sp,
        ProjectExplorer::RunConfiguration *runConfiguration)
    : AnalyzerRunControl(sp, runConfiguration),
      m_settings(0),
      m_isStopping(false)
{
    if (runConfiguration)
        if (IRunConfigurationAspect *aspect = runConfiguration->extraAspect(ANALYZER_VALGRIND_SETTINGS))
            m_settings = qobject_cast<ValgrindBaseSettings *>(aspect->currentSettings());

    if (!m_settings)
        m_settings = ValgrindPlugin::globalSettings();

}

ValgrindRunControl::~ValgrindRunControl()
{
}

bool ValgrindRunControl::startEngine()
{
    emit starting(this);

    FutureProgress *fp = ProgressManager::addTimedTask(m_progress, progressTitle(), "valgrind", 100);
    fp->setKeepOnFinish(FutureProgress::HideOnFinish);
    connect(fp, SIGNAL(canceled()), this, SLOT(handleProgressCanceled()));
    connect(fp, SIGNAL(finished()), this, SLOT(handleProgressFinished()));
    m_progress.reportStarted();

    const AnalyzerStartParameters &sp = startParameters();
#if VALGRIND_DEBUG_OUTPUT
    emit outputReceived(tr("Valgrind options: %1").arg(toolArguments().join(QLatin1Char(' '))), DebugFormat);
    emit outputReceived(tr("Working directory: %1").arg(sp.workingDirectory), DebugFormat);
    emit outputReceived(tr("Command line arguments: %1").arg(sp.debuggeeArgs), DebugFormat);
#endif

    ValgrindRunner *run = runner();
    run->setWorkingDirectory(sp.workingDirectory);
    run->setValgrindExecutable(m_settings->valgrindExecutable());
    run->setValgrindArguments(genericToolArguments() + toolArguments());
    run->setDebuggeeExecutable(sp.debuggee);
    run->setDebuggeeArguments(sp.debuggeeArgs);
    run->setEnvironment(sp.environment);
    run->setConnectionParameters(sp.connParams);
    run->setStartMode(sp.startMode);
    run->setLocalRunMode(sp.localRunMode);

    connect(run, SIGNAL(processOutputReceived(QString,Utils::OutputFormat)),
            SLOT(receiveProcessOutput(QString,Utils::OutputFormat)));
    connect(run, SIGNAL(processErrorReceived(QString,QProcess::ProcessError)),
            SLOT(receiveProcessError(QString,QProcess::ProcessError)));
    connect(run, SIGNAL(finished()), SLOT(runnerFinished()));

    if (!run->start()) {
        m_progress.cancel();
        return false;
    }
    return true;
}

void ValgrindRunControl::stopEngine()
{
    m_isStopping = true;
    runner()->stop();
}

QString ValgrindRunControl::executable() const
{
    return startParameters().debuggee;
}

QStringList ValgrindRunControl::genericToolArguments() const
{
    QTC_ASSERT(m_settings, return QStringList());
    QString smcCheckValue;
    switch (m_settings->selfModifyingCodeDetection()) {
    case ValgrindBaseSettings::DetectSmcNo:
        smcCheckValue = QLatin1String("none");
        break;
    case ValgrindBaseSettings::DetectSmcEverywhere:
        smcCheckValue = QLatin1String("all");
        break;
    case ValgrindBaseSettings::DetectSmcEverywhereButFile:
        smcCheckValue = QLatin1String("all-non-file");
        break;
    case ValgrindBaseSettings::DetectSmcStackOnly:
    default:
        smcCheckValue = QLatin1String("stack");
        break;
    }
    return QStringList() << QLatin1String("--smc-check=") + smcCheckValue;
}

void ValgrindRunControl::handleProgressCanceled()
{
    AnalyzerManager::stopTool();
    m_progress.reportCanceled();
    m_progress.reportFinished();
}

void ValgrindRunControl::handleProgressFinished()
{
    QApplication::alert(ICore::mainWindow(), 3000);
}

void ValgrindRunControl::runnerFinished()
{
    appendMessage(tr("Analyzing finished.") + QLatin1Char('\n'), NormalMessageFormat);
    emit finished();

    m_progress.reportFinished();

    disconnect(runner(), SIGNAL(processOutputReceived(QString,Utils::OutputFormat)),
               this, SLOT(receiveProcessOutput(QString,Utils::OutputFormat)));
    disconnect(runner(), SIGNAL(finished()),
               this, SLOT(runnerFinished()));
}

void ValgrindRunControl::receiveProcessOutput(const QString &output, OutputFormat format)
{
    appendMessage(output, format);
}

void ValgrindRunControl::receiveProcessError(const QString &message, QProcess::ProcessError error)
{
    if (error == QProcess::FailedToStart) {
        const QString valgrind = m_settings->valgrindExecutable();
        if (!valgrind.isEmpty())
            appendMessage(tr("Error: \"%1\" could not be started: %2").arg(valgrind, message) + QLatin1Char('\n'), ErrorMessageFormat);
        else
            appendMessage(tr("Error: no Valgrind executable set.") + QLatin1Char('\n'), ErrorMessageFormat);
    } else if (m_isStopping && error == QProcess::Crashed) { // process gets killed on stop
        appendMessage(tr("Process terminated.") + QLatin1Char('\n'), ErrorMessageFormat);
    } else {
        appendMessage(QString::fromLatin1("** %1 **\n").arg(message), ErrorMessageFormat);
    }

    if (m_isStopping)
        return;

    QObject *obj = ExtensionSystem::PluginManager::getObjectByName(QLatin1String("AppOutputPane"));
    if (IOutputPane *pane = qobject_cast<IOutputPane *>(obj))
        pane->popup(IOutputPane::NoModeSwitch);
}

} // namespace Internal
} // namepsace Valgrind
<|endoftext|>


<commit_before>#include "MaeBlock.hpp"
#include "MaeParser.hpp"

using namespace std;

namespace schrodinger
{
namespace mae
{

static const double tolerance = 0.00001; // Tolerance to match string cutoff

// Wrap to-string to allow it to take strings and be a no-op
template <typename T>
static string local_to_string(T val)
{
    return to_string(val);
}

static string local_to_string(string val)
{
    if(val.length() == 0) return R"("")";
    // Create new string big enough to escape every character and add quotes
    int pos_in_old = 0;
    bool escaped_char = false;
    for(; pos_in_old<val.length(); ++pos_in_old) {
        const char& c = val[pos_in_old];
        if(c == '"' || c == '\\' || c == ' ') {
            escaped_char = true;
            break;
        }
    }
    if(!escaped_char) return val;

    int pos_in_new = 1;
    string new_string(val.length()*2 + 2, '\"');
    for(pos_in_old = 0; pos_in_old<val.length(); ++pos_in_old)
    {
        const char& c = val[pos_in_old];
        if(c == '"' || c == '\\') {
            new_string[pos_in_new++] = '\\';
        }
        new_string[pos_in_new++] = val[pos_in_old];
    }
    new_string.resize(pos_in_new+1);
    return new_string;
}

template <typename T>
static void output_property_names(ostream& out,
        const string& indentation, map<string, T> properties)
{
    for(const auto& p : properties) {
        out << indentation << p.first << "\n";
    }
}

template <typename T>
static void output_property_values(ostream& out,
        const string& indentation, map<string, T> properties)
{
    for(const auto& p : properties) {
        out << indentation << local_to_string(p.second) << "\n";
    }
}

Block::~Block()
{
    // TODO: check with valgrind whether some destructor is needed
}

void Block::write(ostream& out, unsigned int current_indentation) const
{

    string root_indentation = string(current_indentation, ' ');
    string indentation = string(current_indentation+2, ' ');

    out << root_indentation << getName() << " {\n";

    output_property_names(out, indentation, m_bmap);
    output_property_names(out, indentation, m_rmap);
    output_property_names(out, indentation, m_imap);
    output_property_names(out, indentation, m_smap);

    if(m_bmap.size() + m_rmap.size() + m_imap.size() + m_smap.size() > 0) {
        out << indentation + ":::\n";
    }

    output_property_values(out, indentation, m_bmap);
    output_property_values(out, indentation, m_rmap);
    output_property_values(out, indentation, m_imap);
    output_property_values(out, indentation, m_smap);

    if(hasIndexedBlockData()) {
        const auto block_names = m_indexed_block_map->getBlockNames();
        for(const auto& name : block_names) {
            const auto& indexed_block = m_indexed_block_map->getIndexedBlock(name);
            indexed_block->write(out, current_indentation+2);
        }
    }

    for(const auto& p : m_sub_block) {
        const auto& sub_block = p.second;
        sub_block->write(out, current_indentation+2);
    }

    out << root_indentation << "}\n\n";

    return;
}

string Block::toString() const
{
    ostringstream stream;
    write(stream);

    return stream.str();
}

shared_ptr<const IndexedBlock> Block::getIndexedBlock(const string& name)
{
    if(!hasIndexedBlockData()) {
        throw out_of_range("Indexed block not found: " + name);
    }
    return const_pointer_cast<const IndexedBlock>(m_indexed_block_map->getIndexedBlock(name));
}

bool real_map_equal(map<string, double> rmap1,
        map<string, double> rmap2)
{
    if(rmap1.size() != rmap2.size()) return false;
    for(const auto& p : rmap1) {
        if(rmap2.count(p.first) != 1) return false;
        if(abs(p.second - rmap2[p.first]) > tolerance) return false;
    }

    return true;
}

bool Block::operator==(const Block& rhs) const
{
    if(m_bmap != rhs.m_bmap) return false;
    if(!real_map_equal(m_rmap, rhs.m_rmap)) return false;
    if(m_imap != rhs.m_imap) return false;
    if(m_smap != rhs.m_smap) return false;
    if(m_sub_block != rhs.m_sub_block) return false;
    if(!(*m_indexed_block_map == *(rhs.m_indexed_block_map))) return false;
    return true;
}

bool IndexedBlockMapI::operator==(const IndexedBlockMapI& rhs)
{
    const auto& block_names = getBlockNames();
    for(const auto& name : block_names) {
        if(!rhs.hasIndexedBlock(name)) return false;
        const auto& block1 = rhs.getIndexedBlock(name);
        const auto& block2 = getIndexedBlock(name);
        if(*block1 != *block2) return false;
    }
    return true;
}

bool IndexedBlockMap::hasIndexedBlock(const string& name) const
{
    return m_indexed_block.find(name) != m_indexed_block.end();
}

shared_ptr<const IndexedBlock>
IndexedBlockMap::getIndexedBlock(const string& name) const
{
    map<string,shared_ptr<IndexedBlock>>::const_iterator block_iter =
        m_indexed_block.find(name);
    if (block_iter != m_indexed_block.end()) {
        return const_pointer_cast<const IndexedBlock>(block_iter->second);
    } else {
        throw out_of_range("Indexed block not found: " + name);
    }
}

bool BufferedIndexedBlockMap::hasIndexedBlock(const string& name) const
{
    if (m_indexed_buffer.find(name) != m_indexed_buffer.end()) {
        return true;
    } else if (m_indexed_block.find(name) != m_indexed_block.end()) {
        return true;
    } else {
        return false;
    }
}

shared_ptr<const IndexedBlock>
BufferedIndexedBlockMap::getIndexedBlock(const string& name) const
{
    map<string, shared_ptr<IndexedBlock>>::const_iterator itb =
        m_indexed_block.find(name);
    if (itb != m_indexed_block.end()) {
        return itb->second;
    }

    auto itbb = m_indexed_buffer.find(name);
    if (itbb == m_indexed_buffer.end()) {
        throw out_of_range("Indexed block not found: " + name);
    } else {
        shared_ptr<const IndexedBlock> ib(itbb->second->getIndexedBlock());
        return ib;
    }
}

template <>
EXPORT_MAEPARSER void IndexedBlock::setProperty<BoolProperty>(
    const string& name, shared_ptr<IndexedBoolProperty> value)
{
    set_indexed_property<IndexedBoolProperty>(m_bmap, name, value);
}

template <>
EXPORT_MAEPARSER void IndexedBlock::setProperty<double>(
    const string& name, shared_ptr<IndexedProperty<double>> value)
{
    set_indexed_property<IndexedProperty<double>>(m_rmap, name, value);
}

template <>
EXPORT_MAEPARSER void
IndexedBlock::setProperty<int>(const string& name,
                               shared_ptr<IndexedProperty<int>> value)
{
    set_indexed_property<IndexedProperty<int>>(m_imap, name, value);
}

template <>
EXPORT_MAEPARSER void IndexedBlock::setProperty<string>(
    const string& name,
    shared_ptr<IndexedProperty<string>> value)
{
    set_indexed_property<IndexedProperty<string>>(m_smap, name, value);
}

size_t IndexedBlock::size() const
{
    size_t count = 0;
    // Counts of these maps are 1:1 with properties in the map
    for(const auto& p : m_bmap) count = max(p.second->size(), count);
    for(const auto& p : m_imap) count = max(p.second->size(), count);
    for(const auto& p : m_rmap) count = max(p.second->size(), count);
    for(const auto& p : m_smap) count = max(p.second->size(), count);

    return count;
}

template <typename T>
static void output_indexed_property_values(ostream& out,
        const string& indentation, map<string, T> properties,
        unsigned int index)
{
    for(const auto& p : properties) {
        const auto& property = p.second;
        if(property->isDefined(index)) {
            out << " " << local_to_string(property->at(index));
        } else {
            out << " <>";
        }
    }
}

void IndexedBlock::write(ostream& out, unsigned int current_indentation) const
{
    string root_indentation = string(current_indentation, ' ');
    string indentation = string(current_indentation+2, ' ');
    const bool has_data = m_bmap.size() + m_rmap.size() + m_imap.size() + m_smap.size() > 0;

    out << root_indentation << getName() << "[" << to_string((int)size()) << "] {\n";

    if(has_data) {
        out << indentation + "# First column is Index #\n";
    }

    output_property_names(out, indentation, m_bmap);
    output_property_names(out, indentation, m_rmap);
    output_property_names(out, indentation, m_imap);
    output_property_names(out, indentation, m_smap);

    if(has_data) {
        out << indentation + ":::\n";
    }

    for(unsigned int i=0; i<size(); ++i) {
        out << indentation << i+1;
        output_indexed_property_values(out, indentation, m_bmap, i);
        output_indexed_property_values(out, indentation, m_rmap, i);
        output_indexed_property_values(out, indentation, m_imap, i);
        output_indexed_property_values(out, indentation, m_smap, i);
        out << endl;
    }

    if(has_data) {
        out << indentation + ":::\n";
    }

    out << root_indentation << "}\n";

    return;
}

string IndexedBlock::toString() const
{
    ostringstream stream;
    write(stream);

    return stream.str();
}

template <typename T>
bool IndexedProperty<T>::operator==(const IndexedProperty<T>& rhs) const
{
    if(m_is_null == nullptr || rhs.m_is_null == nullptr) {
        if((m_is_null == nullptr) != (rhs.m_is_null == nullptr)) return false;
    } else if(*m_is_null != *(rhs.m_is_null)) {
        return false;
    }
    if(m_data != rhs.m_data) return false;
    return true;
}

// For doubles we need to implement our own comparator for the vectors to
// take precision into account
template <>
bool IndexedProperty<double>::operator==(const IndexedProperty<double>& rhs) const
{
    if(m_is_null == nullptr || rhs.m_is_null == nullptr) {
        if((m_is_null == nullptr) != (rhs.m_is_null == nullptr)) return false;
    } else if(*m_is_null != *(rhs.m_is_null)) return false;

    for(int i=0; i<m_data.size(); ++i)
        if(abs(m_data[i] - rhs.m_data[i]) > tolerance) return false;

    return true;
}

template <typename T>
static bool maps_indexed_props_equal(const T& lmap, const T& rmap)
{
    for(const auto& p : lmap) {
        if(rmap.size() != lmap.size()) return false;
        auto diff = std::mismatch(lmap.begin(), lmap.end(), rmap.begin(),
                 [](decltype(*begin(lmap)) l, decltype(*begin(lmap)) r)
                 {return l.first == r.first && *(l.second) == *(r.second);});
        if (diff.first != lmap.end()) return false;
    }
    return true;
}

bool IndexedBlock::operator==(const IndexedBlock& rhs) const
{
    using namespace std;

    if(!maps_indexed_props_equal(m_bmap, rhs.m_bmap)) return false;
    if(!maps_indexed_props_equal(m_imap, rhs.m_imap)) return false;
    if(!maps_indexed_props_equal(m_rmap, rhs.m_rmap)) return false;
    if(!maps_indexed_props_equal(m_smap, rhs.m_smap)) return false;

    return true;
}

} // namespace mae
} // namespace schrodinger
<commit_msg>remove unnecessary using<commit_after>#include "MaeBlock.hpp"
#include "MaeParser.hpp"

using namespace std;

namespace schrodinger
{
namespace mae
{

static const double tolerance = 0.00001; // Tolerance to match string cutoff

// Wrap to-string to allow it to take strings and be a no-op
template <typename T>
static string local_to_string(T val)
{
    return to_string(val);
}

static string local_to_string(string val)
{
    if(val.length() == 0) return R"("")";
    // Create new string big enough to escape every character and add quotes
    int pos_in_old = 0;
    bool escaped_char = false;
    for(; pos_in_old<val.length(); ++pos_in_old) {
        const char& c = val[pos_in_old];
        if(c == '"' || c == '\\' || c == ' ') {
            escaped_char = true;
            break;
        }
    }
    if(!escaped_char) return val;

    int pos_in_new = 1;
    string new_string(val.length()*2 + 2, '\"');
    for(pos_in_old = 0; pos_in_old<val.length(); ++pos_in_old)
    {
        const char& c = val[pos_in_old];
        if(c == '"' || c == '\\') {
            new_string[pos_in_new++] = '\\';
        }
        new_string[pos_in_new++] = val[pos_in_old];
    }
    new_string.resize(pos_in_new+1);
    return new_string;
}

template <typename T>
static void output_property_names(ostream& out,
        const string& indentation, map<string, T> properties)
{
    for(const auto& p : properties) {
        out << indentation << p.first << "\n";
    }
}

template <typename T>
static void output_property_values(ostream& out,
        const string& indentation, map<string, T> properties)
{
    for(const auto& p : properties) {
        out << indentation << local_to_string(p.second) << "\n";
    }
}

Block::~Block()
{
    // TODO: check with valgrind whether some destructor is needed
}

void Block::write(ostream& out, unsigned int current_indentation) const
{

    string root_indentation = string(current_indentation, ' ');
    string indentation = string(current_indentation+2, ' ');

    out << root_indentation << getName() << " {\n";

    output_property_names(out, indentation, m_bmap);
    output_property_names(out, indentation, m_rmap);
    output_property_names(out, indentation, m_imap);
    output_property_names(out, indentation, m_smap);

    if(m_bmap.size() + m_rmap.size() + m_imap.size() + m_smap.size() > 0) {
        out << indentation + ":::\n";
    }

    output_property_values(out, indentation, m_bmap);
    output_property_values(out, indentation, m_rmap);
    output_property_values(out, indentation, m_imap);
    output_property_values(out, indentation, m_smap);

    if(hasIndexedBlockData()) {
        const auto block_names = m_indexed_block_map->getBlockNames();
        for(const auto& name : block_names) {
            const auto& indexed_block = m_indexed_block_map->getIndexedBlock(name);
            indexed_block->write(out, current_indentation+2);
        }
    }

    for(const auto& p : m_sub_block) {
        const auto& sub_block = p.second;
        sub_block->write(out, current_indentation+2);
    }

    out << root_indentation << "}\n\n";

    return;
}

string Block::toString() const
{
    ostringstream stream;
    write(stream);

    return stream.str();
}

shared_ptr<const IndexedBlock> Block::getIndexedBlock(const string& name)
{
    if(!hasIndexedBlockData()) {
        throw out_of_range("Indexed block not found: " + name);
    }
    return const_pointer_cast<const IndexedBlock>(m_indexed_block_map->getIndexedBlock(name));
}

bool real_map_equal(map<string, double> rmap1,
        map<string, double> rmap2)
{
    if(rmap1.size() != rmap2.size()) return false;
    for(const auto& p : rmap1) {
        if(rmap2.count(p.first) != 1) return false;
        if(abs(p.second - rmap2[p.first]) > tolerance) return false;
    }

    return true;
}

bool Block::operator==(const Block& rhs) const
{
    if(m_bmap != rhs.m_bmap) return false;
    if(!real_map_equal(m_rmap, rhs.m_rmap)) return false;
    if(m_imap != rhs.m_imap) return false;
    if(m_smap != rhs.m_smap) return false;
    if(m_sub_block != rhs.m_sub_block) return false;
    if(!(*m_indexed_block_map == *(rhs.m_indexed_block_map))) return false;
    return true;
}

bool IndexedBlockMapI::operator==(const IndexedBlockMapI& rhs)
{
    const auto& block_names = getBlockNames();
    for(const auto& name : block_names) {
        if(!rhs.hasIndexedBlock(name)) return false;
        const auto& block1 = rhs.getIndexedBlock(name);
        const auto& block2 = getIndexedBlock(name);
        if(*block1 != *block2) return false;
    }
    return true;
}

bool IndexedBlockMap::hasIndexedBlock(const string& name) const
{
    return m_indexed_block.find(name) != m_indexed_block.end();
}

shared_ptr<const IndexedBlock>
IndexedBlockMap::getIndexedBlock(const string& name) const
{
    map<string,shared_ptr<IndexedBlock>>::const_iterator block_iter =
        m_indexed_block.find(name);
    if (block_iter != m_indexed_block.end()) {
        return const_pointer_cast<const IndexedBlock>(block_iter->second);
    } else {
        throw out_of_range("Indexed block not found: " + name);
    }
}

bool BufferedIndexedBlockMap::hasIndexedBlock(const string& name) const
{
    if (m_indexed_buffer.find(name) != m_indexed_buffer.end()) {
        return true;
    } else if (m_indexed_block.find(name) != m_indexed_block.end()) {
        return true;
    } else {
        return false;
    }
}

shared_ptr<const IndexedBlock>
BufferedIndexedBlockMap::getIndexedBlock(const string& name) const
{
    map<string, shared_ptr<IndexedBlock>>::const_iterator itb =
        m_indexed_block.find(name);
    if (itb != m_indexed_block.end()) {
        return itb->second;
    }

    auto itbb = m_indexed_buffer.find(name);
    if (itbb == m_indexed_buffer.end()) {
        throw out_of_range("Indexed block not found: " + name);
    } else {
        shared_ptr<const IndexedBlock> ib(itbb->second->getIndexedBlock());
        return ib;
    }
}

template <>
EXPORT_MAEPARSER void IndexedBlock::setProperty<BoolProperty>(
    const string& name, shared_ptr<IndexedBoolProperty> value)
{
    set_indexed_property<IndexedBoolProperty>(m_bmap, name, value);
}

template <>
EXPORT_MAEPARSER void IndexedBlock::setProperty<double>(
    const string& name, shared_ptr<IndexedProperty<double>> value)
{
    set_indexed_property<IndexedProperty<double>>(m_rmap, name, value);
}

template <>
EXPORT_MAEPARSER void
IndexedBlock::setProperty<int>(const string& name,
                               shared_ptr<IndexedProperty<int>> value)
{
    set_indexed_property<IndexedProperty<int>>(m_imap, name, value);
}

template <>
EXPORT_MAEPARSER void IndexedBlock::setProperty<string>(
    const string& name,
    shared_ptr<IndexedProperty<string>> value)
{
    set_indexed_property<IndexedProperty<string>>(m_smap, name, value);
}

size_t IndexedBlock::size() const
{
    size_t count = 0;
    // Counts of these maps are 1:1 with properties in the map
    for(const auto& p : m_bmap) count = max(p.second->size(), count);
    for(const auto& p : m_imap) count = max(p.second->size(), count);
    for(const auto& p : m_rmap) count = max(p.second->size(), count);
    for(const auto& p : m_smap) count = max(p.second->size(), count);

    return count;
}

template <typename T>
static void output_indexed_property_values(ostream& out,
        const string& indentation, map<string, T> properties,
        unsigned int index)
{
    for(const auto& p : properties) {
        const auto& property = p.second;
        if(property->isDefined(index)) {
            out << " " << local_to_string(property->at(index));
        } else {
            out << " <>";
        }
    }
}

void IndexedBlock::write(ostream& out, unsigned int current_indentation) const
{
    string root_indentation = string(current_indentation, ' ');
    string indentation = string(current_indentation+2, ' ');
    const bool has_data = m_bmap.size() + m_rmap.size() + m_imap.size() + m_smap.size() > 0;

    out << root_indentation << getName() << "[" << to_string((int)size()) << "] {\n";

    if(has_data) {
        out << indentation + "# First column is Index #\n";
    }

    output_property_names(out, indentation, m_bmap);
    output_property_names(out, indentation, m_rmap);
    output_property_names(out, indentation, m_imap);
    output_property_names(out, indentation, m_smap);

    if(has_data) {
        out << indentation + ":::\n";
    }

    for(unsigned int i=0; i<size(); ++i) {
        out << indentation << i+1;
        output_indexed_property_values(out, indentation, m_bmap, i);
        output_indexed_property_values(out, indentation, m_rmap, i);
        output_indexed_property_values(out, indentation, m_imap, i);
        output_indexed_property_values(out, indentation, m_smap, i);
        out << endl;
    }

    if(has_data) {
        out << indentation + ":::\n";
    }

    out << root_indentation << "}\n";

    return;
}

string IndexedBlock::toString() const
{
    ostringstream stream;
    write(stream);

    return stream.str();
}

template <typename T>
bool IndexedProperty<T>::operator==(const IndexedProperty<T>& rhs) const
{
    if(m_is_null == nullptr || rhs.m_is_null == nullptr) {
        if((m_is_null == nullptr) != (rhs.m_is_null == nullptr)) return false;
    } else if(*m_is_null != *(rhs.m_is_null)) {
        return false;
    }
    if(m_data != rhs.m_data) return false;
    return true;
}

// For doubles we need to implement our own comparator for the vectors to
// take precision into account
template <>
bool IndexedProperty<double>::operator==(const IndexedProperty<double>& rhs) const
{
    if(m_is_null == nullptr || rhs.m_is_null == nullptr) {
        if((m_is_null == nullptr) != (rhs.m_is_null == nullptr)) return false;
    } else if(*m_is_null != *(rhs.m_is_null)) return false;

    for(int i=0; i<m_data.size(); ++i)
        if(abs(m_data[i] - rhs.m_data[i]) > tolerance) return false;

    return true;
}

template <typename T>
static bool maps_indexed_props_equal(const T& lmap, const T& rmap)
{
    for(const auto& p : lmap) {
        if(rmap.size() != lmap.size()) return false;
        auto diff = std::mismatch(lmap.begin(), lmap.end(), rmap.begin(),
                 [](decltype(*begin(lmap)) l, decltype(*begin(lmap)) r)
                 {return l.first == r.first && *(l.second) == *(r.second);});
        if (diff.first != lmap.end()) return false;
    }
    return true;
}

bool IndexedBlock::operator==(const IndexedBlock& rhs) const
{
    if(!maps_indexed_props_equal(m_bmap, rhs.m_bmap)) return false;
    if(!maps_indexed_props_equal(m_imap, rhs.m_imap)) return false;
    if(!maps_indexed_props_equal(m_rmap, rhs.m_rmap)) return false;
    if(!maps_indexed_props_equal(m_smap, rhs.m_smap)) return false;

    return true;
}

} // namespace mae
} // namespace schrodinger
<|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "okina.hpp"

#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

namespace mfem
{

#ifdef MFEM_USE_CUDA
void Device::GpuDeviceSetup(const int device)
{
   cudaGetDeviceCount(&ngpu);
   MFEM_ASSERT(ngpu>0, "No CUDA device found!");
   cuInit(0);
   dev = device;
   cuDeviceGet(&cuDevice,dev);
   cuCtxCreate(&cuContext, CU_CTX_SCHED_AUTO, cuDevice);
   cuStream = new CUstream;
   MFEM_ASSERT(cuStream, "CUDA stream could not be created!");
   cuStreamCreate(cuStream, CU_STREAM_DEFAULT);
}
#endif

void Device::CudaDeviceSetup(const int device)
{
#ifdef MFEM_USE_CUDA
   GpuDeviceSetup(device);
#else
   MFEM_ABORT("CUDA requested but MFEM was not built with MFEM_USE_CUDA=YES");
#endif
}

void Device::RajaDeviceSetup(const int device)
{
#if defined(MFEM_USE_CUDA) && defined(MFEM_USE_RAJA)
   GpuDeviceSetup(device);
#elif !defined(MFEM_USE_RAJA)
   MFEM_ABORT("RAJA requested but MFEM was not build with MFEM_USE_RAJA=YES");
#endif
}

void Device::OccaDeviceSetup(CUdevice cu_dev, CUcontext cu_ctx)
{
#ifdef MFEM_USE_OCCA
   if (cuda)
   {
      occaDevice = OccaWrapDevice(cu_dev, cu_ctx);
   }
   else if (omp)
   {
      occaDevice.setup("mode: 'OpenMP'");
   }
   else
   {
      occaDevice.setup("mode: 'Serial'");
   }
   const std::string mfem_dir = occa::io::dirname("../_config.hpp");
   occa::io::addLibraryPath("fem", mfem_dir + "fem");
   occa::loadKernels();
   occa::loadKernels("fem");
#else
   MFEM_ABORT("OCCA requested but MFEM was not built with MFEM_USE_OCCA=YES");
#endif
}

void Device::MFEMDeviceSetup(const int dev)
{
   MFEM_ASSERT(ngpu==-1, "Only one MFEMDeviceSetup allowed");
   ngpu = 0;

   // We initialize CUDA first so OccaDeviceSetup() can reuse the same
   // initialized cuDevice and cuContext objects
   if (cuda) { CudaDeviceSetup(dev); }
   if (raja) { RajaDeviceSetup(dev); }
   if (occa) { OccaDeviceSetup(cuDevice, cuContext); }

   if (cuda && ngpu==0)
   {
      MFEM_ABORT("CUDA requested but MFEM was not built with MFEM_USE_CUDA=YES");
   }
}

Device::~Device()
{
   if (raja || cuda) { delete cuStream; }
}

} // mfem
<commit_msg>Update general/device.cpp<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "okina.hpp"

#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

namespace mfem
{

#ifdef MFEM_USE_CUDA
void Device::GpuDeviceSetup(const int device)
{
   cudaGetDeviceCount(&ngpu);
   MFEM_ASSERT(ngpu>0, "No CUDA device found!");
   cuInit(0);
   dev = device;
   cuDeviceGet(&cuDevice,dev);
   cuCtxCreate(&cuContext, CU_CTX_SCHED_AUTO, cuDevice);
   cuStream = new CUstream;
   MFEM_ASSERT(cuStream, "CUDA stream could not be created!");
   cuStreamCreate(cuStream, CU_STREAM_DEFAULT);
}
#endif

void Device::CudaDeviceSetup(const int device)
{
#ifdef MFEM_USE_CUDA
   GpuDeviceSetup(device);
#else
   MFEM_ABORT("CUDA requested but MFEM was not built with MFEM_USE_CUDA=YES");
#endif
}

void Device::RajaDeviceSetup(const int device)
{
#if defined(MFEM_USE_CUDA) && defined(MFEM_USE_RAJA)
   GpuDeviceSetup(device);
#elif !defined(MFEM_USE_RAJA)
   MFEM_ABORT("RAJA requested but MFEM was not built with MFEM_USE_RAJA=YES");
#endif
}

void Device::OccaDeviceSetup(CUdevice cu_dev, CUcontext cu_ctx)
{
#ifdef MFEM_USE_OCCA
   if (cuda)
   {
      occaDevice = OccaWrapDevice(cu_dev, cu_ctx);
   }
   else if (omp)
   {
      occaDevice.setup("mode: 'OpenMP'");
   }
   else
   {
      occaDevice.setup("mode: 'Serial'");
   }
   const std::string mfem_dir = occa::io::dirname("../_config.hpp");
   occa::io::addLibraryPath("fem", mfem_dir + "fem");
   occa::loadKernels();
   occa::loadKernels("fem");
#else
   MFEM_ABORT("OCCA requested but MFEM was not built with MFEM_USE_OCCA=YES");
#endif
}

void Device::MFEMDeviceSetup(const int dev)
{
   MFEM_ASSERT(ngpu==-1, "Only one MFEMDeviceSetup allowed");
   ngpu = 0;

   // We initialize CUDA first so OccaDeviceSetup() can reuse the same
   // initialized cuDevice and cuContext objects
   if (cuda) { CudaDeviceSetup(dev); }
   if (raja) { RajaDeviceSetup(dev); }
   if (occa) { OccaDeviceSetup(cuDevice, cuContext); }

   if (cuda && ngpu==0)
   {
      MFEM_ABORT("CUDA requested but MFEM was not built with MFEM_USE_CUDA=YES");
   }
}

Device::~Device()
{
   if (raja || cuda) { delete cuStream; }
}

} // mfem
<|endoftext|>