<commit_before>/* Copyright 2018 The TensorFlow 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 "tensorflow/compiler/xla/service/multi_output_fusion.h"

#include "absl/container/flat_hash_set.h"
#include "tensorflow/compiler/xla/debug_options_flags.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/hlo_reachability.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/platform/types.h"

namespace xla {

StatusOr<bool> MultiOutputFusion::Run(HloModule* module) {
  bool changed = false;

  for (auto* computation : module->MakeNonfusionComputations()) {
    computation_ = computation;
    candidates_.clear();
    candidates_index_.clear();
    all_fusion_candidates_.clear();
    RecomputeReachability();

    int64 index = 0;
    for (auto it : computation_->MakeInstructionPostOrder()) {
      candidates_.emplace_back(it);
      InsertOrDie(&candidates_index_, it, index++);
    }

    // Create the initial candidate list for each Node.
    for (auto& node : candidates_) {
      HloInstruction* instruction = node.hlo;
      int64 instruction_id = get_candidate_id(instruction);
      FusionCandidate& instr_node = candidates_[instruction_id];
      if (!IsFusible(instruction)) {
        continue;
      }
      all_fusion_candidates_.push_back(instruction);

      std::vector<HloInstruction*> candidates;
      absl::flat_hash_set<HloInstruction*> candidates_set;
      VLOG(10) << "Looking at instruction: " << instruction->name();
      for (auto operand : instruction->operands()) {
        // Filter out the non-interesting instructions -- they
        // will not generate the savings.
        if (!IsProfitableOperand(operand)) {
          VLOG(10) << "Operand not profitable: " << operand->name();
          continue;
        }
        VLOG(10) << "Operand profitable: " << operand->name();
        for (auto user : operand->users()) {
          VLOG(10) << "User: " << user->name();
          if (user == instruction || !IsFusible(user)) {
            VLOG(10) << "User is not fusible, or is the instruction itself: "
                     << user->name();
            continue;
          }
          int64 user_id = get_candidate_id(user);
          if (is_connected(instruction, user)) {
            VLOG(10) << "User is connected: " << user->name();
            continue;
          }
          if (instruction_id < user_id &&
              user->opcode() == HloOpcode::kFusion) {
            VLOG(10) << "User ID for user: " << user->name() << " is "
                     << user_id << " which is higher than " << instruction_id;
            continue;
          }
          if (!LegalToFuse(instruction, user)) {
            VLOG(10) << "User not legal to fuse: " << user->name();
            continue;
          }
          if (candidates_set.insert(user).second) {
            VLOG(10) << "User added to candidate list: " << user->name();
            candidates.push_back(user);
          }
        }
      }

      // Iterate over candidates rather than candidates_set to avoid
      // nondeterminism.
      for (auto candidate : candidates) {
        int64 profit = GetProfit(instruction, candidate);
        if (profit > 0) {
          FusionCandidate& candidate_node =
              candidates_[get_candidate_id(candidate)];
          instr_node.fusibles.emplace_back(candidate, profit);
          candidate_node.fusibles.emplace_back(instruction, profit);
          worklist_.emplace(instruction, candidate, profit);
        }
      }
    }
    if (Perform()) {
      changed = true;
    }
  }
  return changed;
}

HloInstruction* MultiOutputFusion::Fuse(HloInstruction* instr1,
                                        HloInstruction* instr2) {
  HloInstruction* remaining = instr1;
  HloInstruction* fused = instr2;
  // Make sure that if only one of the instructions is a fusion, or if only one
  // of the instructions is a multi-output fusion, it's what will be fused into.
  if (fused->opcode() == HloOpcode::kFusion) {
    std::swap(remaining, fused);
  }
  if (fused->IsMultiOutputFusion()) {
    std::swap(remaining, fused);
  }
  if (fused->opcode() == HloOpcode::kFusion) {
    remaining->MergeFusionInstructionIntoMultiOutput(fused);
  } else {
    remaining->FuseInstructionIntoMultiOutput(fused);
    CHECK_EQ(0, fused->user_count());
    TF_CHECK_OK(computation()->RemoveInstruction(fused));
  }
  return remaining;
}

bool MultiOutputFusion::IsProfitableOperand(HloInstruction* instr) {
  // kConstant instruction will not have memory reads, so it won't be a profit
  // source. Skip them.
  if (instr->opcode() == HloOpcode::kConstant &&
      ShapeUtil::IsEffectiveScalar(instr->shape())) {
    return false;
  }
  // We don't target to fuse producer/consumer instructions -- this should
  // be taken care of by the instruction_fusion pass. If instr has only
  // one user, it will not have sibling instructions. We won't consider it.
  if (instr->user_count() < 2) {
    return false;
  }
  return true;
}

void MultiOutputFusion::Update(HloInstruction* instr1, HloInstruction* instr2) {
  HloInstruction* fusion = instr1;
  HloInstruction* fused = instr2;
  if (is_fused(instr1)) {
    fusion = instr2;
    fused = instr1;
  }

  // Insert the newly created instruction (if any), to candidates_.
  for (auto use : fusion->users()) {
    if (candidates_index_.find(use) == candidates_index_.end()) {
      int64 index = candidates_.size();
      candidates_.emplace_back(use);
      InsertOrDie(&candidates_index_, use, index++);
    }
  }
  FusionCandidate& fusion_node = candidates_[get_candidate_id(fusion)];
  FusionCandidate& fused_node = candidates_[get_candidate_id(fused)];

  // Update the reachability graph.
  UpdateReachability(fusion, fused, all_fusion_candidates_,
                     [this](HloInstruction* instr) { return is_fused(instr); });

  // Update the fusible list for fusion. Variable new_fusibles keeps
  // track of the new or changed entries.
  std::vector<std::pair<HloInstruction*, int64>> new_fusibles;
  absl::flat_hash_set<HloInstruction*> in_list;
  auto it = fusion_node.fusibles.begin();
  while (it != fusion_node.fusibles.end()) {
    HloInstruction* instr = it->first;
    if (is_fused(instr) || is_connected(fusion, instr)) {
      it = fusion_node.fusibles.erase(it);
      continue;
    }
    in_list.insert(instr);
    int64 profit = GetProfit(instr, fusion);
    if (profit > it->second) {
      it->second = profit;
      new_fusibles.emplace_back(instr, profit);
    }
    ++it;
  }

  // Fused_node has been fused into fusion_node. Take the fusion candidates
  // (fusibles) from fused_nodes and add them to the fusion_node's. Filter
  // out those fusibles that no longer valid (or already in the list).
  for (const auto& it : fused_node.fusibles) {
    HloInstruction* instr = it.first;
    if (instr == fusion || is_fused(instr) || is_connected(fusion, instr)) {
      continue;
    }
    if (in_list.contains(instr)) {
      continue;
    }
    int64 profit = GetProfit(instr, fusion);
    fusion_node.fusibles.emplace_back(instr, profit);
    new_fusibles.emplace_back(instr, profit);
  }
  fused_node.fusibles.clear();

  // Update the worklist_.
  for (auto it : new_fusibles) {
    worklist_.emplace(fusion, it.first, it.second);
  }
}

bool MultiOutputFusion::LegalToFuse(HloInstruction* instr1,
                                    HloInstruction* instr2) {
  if (instr1 == instr2) {
    return false;
  }
  if (instr1->opcode() != HloOpcode::kFusion) {
    return false;
  }

  // Fusing nodes with 0 users makes no sense and the rest of the implementation
  // doesn't support it either.
  if (instr1->user_count() == 0 || instr2->user_count() == 0) {
    return false;
  }

  // Check if the users of multioutput fusion is not a get-tuple-element.
  // If this is the case, we bail out because the transformation assumes
  // the users are get-tuple-element.
  auto multioutput_user_is_not_gte = [](HloInstruction* instr) {
    if (!instr->IsMultiOutputFusion()) {
      return false;
    }
    for (auto user : instr->users()) {
      if (user->opcode() != HloOpcode::kGetTupleElement) {
        return true;
      }
    }
    return false;
  };
  if (multioutput_user_is_not_gte(instr1) ||
      multioutput_user_is_not_gte(instr2)) {
    return false;
  }
  if (is_connected(instr1, instr2)) {
    return false;
  }
  if (!ShapesCompatibleForFusion(instr1, instr2)) {
    return false;
  }
  return true;
}

void MultiOutputFusion::RecomputeReachability() {
  // Free the memory used for the reachability map before computing a new one.
  reachability_.reset();
  reachability_ = HloReachabilityMap::Build(computation_);
}

void MultiOutputFusion::UpdateReachability(
    HloInstruction* instr1, HloInstruction* instr2,
    absl::Span<HloInstruction* const> instrs_to_update,
    const std::function<bool(HloInstruction*)>& skip) {
  for (auto instr : instrs_to_update) {
    if (skip != nullptr && skip(instr)) {
      continue;
    }
    if (reachability_->IsReachable(instr2, instr) &&
        reachability_->IsReachable(instr1, instr)) {
      // If a candidate was already reachable by both, no update needed.
      continue;
    }
    if (reachability_->IsReachable(instr2, instr)) {
      reachability_->FastSetReachabilityToUnion({instr, instr1}, instr);
    }
    if (reachability_->IsReachable(instr1, instr)) {
      reachability_->FastSetReachabilityToUnion({instr, instr2}, instr);
    }
  }
}

bool MultiOutputFusion::Perform() {
  int changed = false;
  // Pick the top candidate from queue and try to merge.
  while (!worklist_.empty()) {
    ToBeFused candidate = worklist_.top();
    worklist_.pop();

    HloInstruction* instr1 = candidate.instr1;
    HloInstruction* instr2 = candidate.instr2;

    if (is_fused(instr1) || is_fused(instr2)) {
      continue;
    }

    VLOG(1) << "Considering candidate profit_score=" << candidate.score
            << "\n\t\tinstr1 = " << instr1->ToString()
            << "\n\t\tinstr2 = " << instr2->ToString();

    if (LegalToFuse(instr1, instr2)) {
      if (!ConsumeFuel(name(), [&] {
            return absl::StrFormat("Not fusing %s and %s.", instr1->ToString(),
                                   instr2->ToString());
          })) {
        break;
      }
      VLOG(1) << "Fuse!";
      VLOG(2) << "Before multi_output_fusion:";
      VLOG(2) << "instr1: " << instr1->ToString();
      VLOG(2) << "\n"
              << instr1->fused_instructions_computation()->ToString(
                     HloPrintOptions().set_indent_amount(1));
      VLOG(2) << "instr2: " << instr2->ToString();
      if (instr2->opcode() == HloOpcode::kFusion) {
        VLOG(2) << "\n"
                << instr2->fused_instructions_computation()->ToString(
                       HloPrintOptions().set_indent_amount(1));
      }
      Update(instr1, instr2);
      HloInstruction* ret = Fuse(instr1, instr2);
      set_is_fused(ret == instr1 ? instr2 : instr1);
      changed = true;
      VLOG(2) << "After fusion, \t this: " << ret->name() << "\n"
              << ret->fused_instructions_computation()->ToString(
                     HloPrintOptions().set_indent_amount(1));
    }
  }
  if (DoProducerConsumerMultiOutputFusion()) {
    changed = true;
  }
  return changed;
}

bool MultiOutputFusion::DoProducerConsumerMultiOutputFusion() { return false; }

}  // namespace xla
<commit_msg>[XLA] Reset the state of multioutput fusion after run since it may be inside an hlo pipeline.<commit_after>/* Copyright 2018 The TensorFlow 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 "tensorflow/compiler/xla/service/multi_output_fusion.h"

#include "absl/container/flat_hash_set.h"
#include "tensorflow/compiler/xla/debug_options_flags.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/hlo_reachability.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/platform/types.h"

namespace xla {

StatusOr<bool> MultiOutputFusion::Run(HloModule* module) {
  bool changed = false;

  for (auto* computation : module->MakeNonfusionComputations()) {
    computation_ = computation;
    candidates_.clear();
    candidates_index_.clear();
    all_fusion_candidates_.clear();
    RecomputeReachability();

    int64 index = 0;
    for (auto it : computation_->MakeInstructionPostOrder()) {
      candidates_.emplace_back(it);
      InsertOrDie(&candidates_index_, it, index++);
    }

    // Create the initial candidate list for each Node.
    for (auto& node : candidates_) {
      HloInstruction* instruction = node.hlo;
      int64 instruction_id = get_candidate_id(instruction);
      FusionCandidate& instr_node = candidates_[instruction_id];
      if (!IsFusible(instruction)) {
        continue;
      }
      all_fusion_candidates_.push_back(instruction);

      std::vector<HloInstruction*> candidates;
      absl::flat_hash_set<HloInstruction*> candidates_set;
      VLOG(10) << "Looking at instruction: " << instruction->name();
      for (auto operand : instruction->operands()) {
        // Filter out the non-interesting instructions -- they
        // will not generate the savings.
        if (!IsProfitableOperand(operand)) {
          VLOG(10) << "Operand not profitable: " << operand->name();
          continue;
        }
        VLOG(10) << "Operand profitable: " << operand->name();
        for (auto user : operand->users()) {
          VLOG(10) << "User: " << user->name();
          if (user == instruction || !IsFusible(user)) {
            VLOG(10) << "User is not fusible, or is the instruction itself: "
                     << user->name();
            continue;
          }
          int64 user_id = get_candidate_id(user);
          if (is_connected(instruction, user)) {
            VLOG(10) << "User is connected: " << user->name();
            continue;
          }
          if (instruction_id < user_id &&
              user->opcode() == HloOpcode::kFusion) {
            VLOG(10) << "User ID for user: " << user->name() << " is "
                     << user_id << " which is higher than " << instruction_id;
            continue;
          }
          if (!LegalToFuse(instruction, user)) {
            VLOG(10) << "User not legal to fuse: " << user->name();
            continue;
          }
          if (candidates_set.insert(user).second) {
            VLOG(10) << "User added to candidate list: " << user->name();
            candidates.push_back(user);
          }
        }
      }

      // Iterate over candidates rather than candidates_set to avoid
      // nondeterminism.
      for (auto candidate : candidates) {
        int64 profit = GetProfit(instruction, candidate);
        if (profit > 0) {
          FusionCandidate& candidate_node =
              candidates_[get_candidate_id(candidate)];
          instr_node.fusibles.emplace_back(candidate, profit);
          candidate_node.fusibles.emplace_back(instruction, profit);
          worklist_.emplace(instruction, candidate, profit);
        }
      }
    }
    if (Perform()) {
      changed = true;
    }
  }
  // Clean up state in case this pass is wrapped in an HloPassPipeline.
  candidates_.clear();
  candidates_index_.clear();
  all_fusion_candidates_.clear();
  reachability_.reset();
  return changed;
}

HloInstruction* MultiOutputFusion::Fuse(HloInstruction* instr1,
                                        HloInstruction* instr2) {
  HloInstruction* remaining = instr1;
  HloInstruction* fused = instr2;
  // Make sure that if only one of the instructions is a fusion, or if only one
  // of the instructions is a multi-output fusion, it's what will be fused into.
  if (fused->opcode() == HloOpcode::kFusion) {
    std::swap(remaining, fused);
  }
  if (fused->IsMultiOutputFusion()) {
    std::swap(remaining, fused);
  }
  if (fused->opcode() == HloOpcode::kFusion) {
    remaining->MergeFusionInstructionIntoMultiOutput(fused);
  } else {
    remaining->FuseInstructionIntoMultiOutput(fused);
    CHECK_EQ(0, fused->user_count());
    TF_CHECK_OK(computation()->RemoveInstruction(fused));
  }
  return remaining;
}

bool MultiOutputFusion::IsProfitableOperand(HloInstruction* instr) {
  // kConstant instruction will not have memory reads, so it won't be a profit
  // source. Skip them.
  if (instr->opcode() == HloOpcode::kConstant &&
      ShapeUtil::IsEffectiveScalar(instr->shape())) {
    return false;
  }
  // We don't target to fuse producer/consumer instructions -- this should
  // be taken care of by the instruction_fusion pass. If instr has only
  // one user, it will not have sibling instructions. We won't consider it.
  if (instr->user_count() < 2) {
    return false;
  }
  return true;
}

void MultiOutputFusion::Update(HloInstruction* instr1, HloInstruction* instr2) {
  HloInstruction* fusion = instr1;
  HloInstruction* fused = instr2;
  if (is_fused(instr1)) {
    fusion = instr2;
    fused = instr1;
  }

  // Insert the newly created instruction (if any), to candidates_.
  for (auto use : fusion->users()) {
    if (candidates_index_.find(use) == candidates_index_.end()) {
      int64 index = candidates_.size();
      candidates_.emplace_back(use);
      InsertOrDie(&candidates_index_, use, index++);
    }
  }
  FusionCandidate& fusion_node = candidates_[get_candidate_id(fusion)];
  FusionCandidate& fused_node = candidates_[get_candidate_id(fused)];

  // Update the reachability graph.
  UpdateReachability(fusion, fused, all_fusion_candidates_,
                     [this](HloInstruction* instr) { return is_fused(instr); });

  // Update the fusible list for fusion. Variable new_fusibles keeps
  // track of the new or changed entries.
  std::vector<std::pair<HloInstruction*, int64>> new_fusibles;
  absl::flat_hash_set<HloInstruction*> in_list;
  auto it = fusion_node.fusibles.begin();
  while (it != fusion_node.fusibles.end()) {
    HloInstruction* instr = it->first;
    if (is_fused(instr) || is_connected(fusion, instr)) {
      it = fusion_node.fusibles.erase(it);
      continue;
    }
    in_list.insert(instr);
    int64 profit = GetProfit(instr, fusion);
    if (profit > it->second) {
      it->second = profit;
      new_fusibles.emplace_back(instr, profit);
    }
    ++it;
  }

  // Fused_node has been fused into fusion_node. Take the fusion candidates
  // (fusibles) from fused_nodes and add them to the fusion_node's. Filter
  // out those fusibles that no longer valid (or already in the list).
  for (const auto& it : fused_node.fusibles) {
    HloInstruction* instr = it.first;
    if (instr == fusion || is_fused(instr) || is_connected(fusion, instr)) {
      continue;
    }
    if (in_list.contains(instr)) {
      continue;
    }
    int64 profit = GetProfit(instr, fusion);
    fusion_node.fusibles.emplace_back(instr, profit);
    new_fusibles.emplace_back(instr, profit);
  }
  fused_node.fusibles.clear();

  // Update the worklist_.
  for (auto it : new_fusibles) {
    worklist_.emplace(fusion, it.first, it.second);
  }
}

bool MultiOutputFusion::LegalToFuse(HloInstruction* instr1,
                                    HloInstruction* instr2) {
  if (instr1 == instr2) {
    return false;
  }
  if (instr1->opcode() != HloOpcode::kFusion) {
    return false;
  }

  // Fusing nodes with 0 users makes no sense and the rest of the implementation
  // doesn't support it either.
  if (instr1->user_count() == 0 || instr2->user_count() == 0) {
    return false;
  }

  // Check if the users of multioutput fusion is not a get-tuple-element.
  // If this is the case, we bail out because the transformation assumes
  // the users are get-tuple-element.
  auto multioutput_user_is_not_gte = [](HloInstruction* instr) {
    if (!instr->IsMultiOutputFusion()) {
      return false;
    }
    for (auto user : instr->users()) {
      if (user->opcode() != HloOpcode::kGetTupleElement) {
        return true;
      }
    }
    return false;
  };
  if (multioutput_user_is_not_gte(instr1) ||
      multioutput_user_is_not_gte(instr2)) {
    return false;
  }
  if (is_connected(instr1, instr2)) {
    return false;
  }
  if (!ShapesCompatibleForFusion(instr1, instr2)) {
    return false;
  }
  return true;
}

void MultiOutputFusion::RecomputeReachability() {
  // Free the memory used for the reachability map before computing a new one.
  reachability_.reset();
  reachability_ = HloReachabilityMap::Build(computation_);
}

void MultiOutputFusion::UpdateReachability(
    HloInstruction* instr1, HloInstruction* instr2,
    absl::Span<HloInstruction* const> instrs_to_update,
    const std::function<bool(HloInstruction*)>& skip) {
  for (auto instr : instrs_to_update) {
    if (skip != nullptr && skip(instr)) {
      continue;
    }
    if (reachability_->IsReachable(instr2, instr) &&
        reachability_->IsReachable(instr1, instr)) {
      // If a candidate was already reachable by both, no update needed.
      continue;
    }
    if (reachability_->IsReachable(instr2, instr)) {
      reachability_->FastSetReachabilityToUnion({instr, instr1}, instr);
    }
    if (reachability_->IsReachable(instr1, instr)) {
      reachability_->FastSetReachabilityToUnion({instr, instr2}, instr);
    }
  }
}

bool MultiOutputFusion::Perform() {
  int changed = false;
  // Pick the top candidate from queue and try to merge.
  while (!worklist_.empty()) {
    ToBeFused candidate = worklist_.top();
    worklist_.pop();

    HloInstruction* instr1 = candidate.instr1;
    HloInstruction* instr2 = candidate.instr2;

    if (is_fused(instr1) || is_fused(instr2)) {
      continue;
    }

    VLOG(1) << "Considering candidate profit_score=" << candidate.score
            << "\n\t\tinstr1 = " << instr1->ToString()
            << "\n\t\tinstr2 = " << instr2->ToString();

    if (LegalToFuse(instr1, instr2)) {
      if (!ConsumeFuel(name(), [&] {
            return absl::StrFormat("Not fusing %s and %s.", instr1->ToString(),
                                   instr2->ToString());
          })) {
        break;
      }
      VLOG(1) << "Fuse!";
      VLOG(2) << "Before multi_output_fusion:";
      VLOG(2) << "instr1: " << instr1->ToString();
      VLOG(2) << "\n"
              << instr1->fused_instructions_computation()->ToString(
                     HloPrintOptions().set_indent_amount(1));
      VLOG(2) << "instr2: " << instr2->ToString();
      if (instr2->opcode() == HloOpcode::kFusion) {
        VLOG(2) << "\n"
                << instr2->fused_instructions_computation()->ToString(
                       HloPrintOptions().set_indent_amount(1));
      }
      Update(instr1, instr2);
      HloInstruction* ret = Fuse(instr1, instr2);
      set_is_fused(ret == instr1 ? instr2 : instr1);
      changed = true;
      VLOG(2) << "After fusion, \t this: " << ret->name() << "\n"
              << ret->fused_instructions_computation()->ToString(
                     HloPrintOptions().set_indent_amount(1));
    }
  }
  if (DoProducerConsumerMultiOutputFusion()) {
    changed = true;
  }
  return changed;
}

bool MultiOutputFusion::DoProducerConsumerMultiOutputFusion() { return false; }

}  // namespace xla
<|endoftext|>


<commit_before>/*The following code simulates the Producer-Consumer problem using Standard Library threads. A producer thread produces a shared resource and then sleeps for a second.
The consumer thread consumes the resource and then sleeps for a second. How much of the resource is produced or consumed is dictated by a pseudo-random subroutine.*/
#include <iostream>
#include <thread>
#include <mutex>
#include <random>
#include <chrono>

std::mutex resourceMutex;
size_t resource = 5;

size_t toss(std::default_random_engine &seed)
{
	std::uniform_real_distribution<double> rnd(0.0, 1.0);
	double trial = rnd(seed);
	return (trial < 0.5) ? 5 : 10;
}

void produce()
{
	std::default_random_engine seed;
	while (resource > 0)
	{
		std::unique_lock<std::mutex> lock(resourceMutex);
		size_t units = toss(seed);
		resource += units;
		std::cout << "Produced " << units << " units." << std::endl;
		std::cout << "Total: " << resource << "\n\n" << std::endl;
		lock.unlock();

		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

void consume()
{
	std::default_random_engine seed;
	while (resource > 0)
	{
		std::unique_lock<std::mutex> lock(resourceMutex);
		size_t units = toss(seed);
		resource -= units;
		std::cout << "Consumed " << units << " units." << std::endl;
		std::cout << "Total: " << resource << "\n\n" << std::endl;
		lock.unlock();

		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

int main()
{
	std::thread producer(produce);
	std::thread consumer(consume);

	producer.join();
	consumer.join();
}<commit_msg>Fixed a potential data race using atomics<commit_after>/*The following code simulates the Producer-Consumer problem using Standard Library threads. A producer thread produces a shared resource and then sleeps for a second.
The consumer thread consumes the resource and then sleeps for a second. How much of the resource is produced or consumed is dictated by a pseudo-random subroutine.*/
#include <iostream>
#include <thread>
#include <mutex>
#include <random>
#include <chrono>
#include <atomic>

std::mutex resourceMutex;
std::atomic<int> resource(1);

size_t toss(std::default_random_engine &seed)
{
	std::uniform_real_distribution<double> rnd(0.0, 1.0);
	double trial = rnd(seed);
	return (trial < 0.5) ? 5 : 10;
}

void produce()
{
	std::default_random_engine seed;
	while (resource > 0)
	{
		std::unique_lock<std::mutex> lock(resourceMutex);
		size_t units = toss(seed);
		resource += units;
		std::cout << "Produced " << units << " units." << std::endl;
		std::cout << "Total: " << resource << "\n\n" << std::endl;
		lock.unlock();

		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

void consume()
{
	std::default_random_engine seed;
	while (resource > 0)
	{
		std::unique_lock<std::mutex> lock(resourceMutex);
		size_t units = toss(seed);
		resource -= units;
		std::cout << "Consumed " << units << " units." << std::endl;
		std::cout << "Total: " << resource << "\n\n" << std::endl;
		lock.unlock();

		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

int main()
{
	std::thread producer(produce);
	std::thread consumer(consume);

	producer.join();
	consumer.join();
}<|endoftext|>


<commit_before>#include "OpcodeBase.hpp"
#include <map>
#include <vector>

using namespace csound;

// Define ENABLE_MIXER_IDEBUG to enable i-rate debug messages.
//#define ENABLE_MIXER_IDEBUG

// Define ENABLE_MIXER_KDEBUG to enable -rate and a-rate debug messages.
//#define ENABLE_MIXER_KDEBUG

/**
 * The mixer busses are laid out:
 * busses[csound][bus][channel][frame].
 */
static std::map<CSOUND *, std::map<size_t,
       std::vector< std::vector<MYFLT> > > > *busses = 0;

/**
 * The mixer send matrix is laid out:
 * matrix[csound][send][bus].
 */
static std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > > *matrix = 0;

/**
 * Creates the buss if it does not already exist.
 */
static void createBuss(CSOUND *csound, size_t buss)
{
#ifdef ENABLE_MIXER_IDEBUG
    csound->Message(csound, "createBuss: csound %p buss %d...\n", csound, buss);
#endif
    if((*busses)[csound].find(buss) == (*busses)[csound].end()) {
        size_t channels = csound->GetNchnls(csound);
        size_t frames = csound->GetKsmps(csound);
        (*busses)[csound][buss].resize(channels);
        for(size_t channel = 0; channel < channels; channel++) {
            (*busses)[csound][buss][channel].resize(frames);
        }
#ifdef ENABLE_MIXER_IDEBUG
        csound->Message(csound, "createBuss: created buss.\n");
#endif
    } else {
#ifdef ENABLE_MIXER_IDEBUG
        csound->Message(csound, "createBuss: buss already exists.\n");
#endif
    }
}

/**
 * MixerSetLevel isend, ibuss, kgain
 *
 * Controls the gain of any signal route from a send to a bus
 */
struct MixerSetLevel : public OpcodeBase<MixerSetLevel> {
    // No outputs.
    // Inputs.
    MYFLT *isend;
    MYFLT *ibuss;
    MYFLT *kgain;
    // State.
    size_t send;
    size_t buss;
    int init(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSetLevel::init...\n");
#endif
        send = static_cast<size_t>(*isend);
        buss = static_cast<size_t>(*ibuss);
        createBuss(csound, buss);
        (*matrix)[csound][send][buss] = *kgain;
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSetLevel::init: csound %p send %d buss %d gain %f\n",
             csound, send, buss, (*matrix)[csound][send][buss]);
#endif
        return OK;
    }
    int kontrol(CSOUND *csound)
    {
        (*matrix)[csound][send][buss] = *kgain;
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerSetLevel::kontrol: csound %p send %d buss "
             "%d gain %f\n", csound, send, buss, (*matrix)[csound][send][buss]);
#endif
        return OK;
    }
};

/**
 * kgain MixerGetLevel isend, ibuss
 *
 * Returns the gain of any signal route from a send to a bus.
 */
struct MixerGetLevel : public OpcodeBase<MixerGetLevel> {
    //.
    MYFLT *kgain;
    // Inputs.
    MYFLT *isend;
    MYFLT *ibuss;
    // State.
    size_t send;
    size_t buss;
    int init(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerGetLevel::init...\n");
#endif
        send = static_cast<size_t>(*isend);
        buss = static_cast<size_t>(*ibuss);
        createBuss(csound, buss);
        return OK;
    }
    int noteoff(CSOUND *)
    {
        return OK;
    }
    int kontrol(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerGetLevel::kontrol...\n");
#endif
        *kgain = (*matrix)[csound][send][buss];
        return OK;
    }
};
/**
 * MixerSend asignal, isend, ibus, ichannel
 *
 * Routes a signal from a send to a channel of a mixer bus.
 * The gain of the send is controlled by the previously set mixer level.
 */
struct MixerSend : public OpcodeBase<MixerSend> {
    // No outputs.
    // Inputs.
    MYFLT *ainput;
    MYFLT *isend;
    MYFLT *ibuss;
    MYFLT *ichannel;
    // State.
    size_t send;
    size_t buss;
    size_t channel;
    size_t frames;
    MYFLT *busspointer;
    int init(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSend::init...\n");
#endif
        send = static_cast<size_t>(*isend);
        buss = static_cast<size_t>(*ibuss);
        createBuss(csound, buss);
        channel = static_cast<size_t>(*ichannel);
        frames = opds.insdshead->ksmps;
        busspointer = &(*busses)[csound][buss][channel].front();
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSend::init: instance %p send %d buss "
             "%d channel %d frames %d busspointer %p\n",
             csound, send, buss, channel, frames, busspointer);
#endif
        return OK;
    }
    int noteoff(CSOUND *)
    {
        return OK;
    }
    int audio(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerSend::audio...\n");
#endif
        MYFLT gain = (*matrix)[csound][send][buss];
        for(size_t i = 0; i < frames; i++) {
            busspointer[i] += (ainput[i] * gain);
        }
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerSend::audio: instance %d send %d buss "
             "%d gain %f busspointer %p\n", csound, send, buss, gain, busspointer);
#endif
        return OK;
    }
};

/**
 * asignal MixerReceive ibuss, ichannel
 *
 * Receives a signal from a channel of a bus.
 * Obviously, instruments receiving signals must be numbered higher
 * than instruments sending those signals.
 */
struct MixerReceive : public OpcodeBase<MixerReceive> {
    // Output.
    MYFLT *aoutput;
    // Inputs.
    MYFLT *ibuss;
    MYFLT *ichannel;
    // State.
    size_t buss;
    size_t channel;
    size_t frames;
    MYFLT *busspointer;
    int init(CSOUND *csound)
    {
        buss = static_cast<size_t>(*ibuss);
        channel = static_cast<size_t>(*ichannel);
        frames = opds.insdshead->ksmps;
        createBuss(csound, buss);
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerReceive::init...\n");
#endif
        busspointer = &(*busses)[csound][buss][channel].front();
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerReceive::init csound %p buss %d channel "
             "%d frames %d busspointer %p\n", csound, buss, channel,
             frames, busspointer);
#endif
        return OK;
    }
    int noteoff(CSOUND *)
    {
        return OK;
    }
    int audio(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerReceive::audio...\n");
#endif
        for(size_t i = 0; i < frames; i++) {
            aoutput[i] = busspointer[i];
        }
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerReceive::audio aoutput %p busspointer %p\n",
             aoutput, buss);
#endif
        return OK;
    }
};

/**
 * MixerClear
 *
 * Clears all busses. Must be invoked after last MixerReceive.
 * You should probably use a highest-numbered instrument
 * with an indefinite duration that invokes only this opcode.
 */
struct MixerClear : public OpcodeBase<MixerClear> {
    // No output.
    // No input.
    // No state.
    int audio(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerClear::audio...\n")
#endif
        for(std::map<size_t,
                std::vector< std::vector<MYFLT> > >::iterator
                busi = (*busses)[csound].begin();
            busi != (*busses)[csound].end(); ++busi) {
          for(std::vector< std::vector<MYFLT> >::iterator
                channeli = busi->second.begin();
              channeli != busi->second.end(); ++channeli) {
            for(std::vector<MYFLT>::iterator
                  framei = (*channeli).begin();
                framei != (*channeli).end(); ++framei) {
              *framei = 0;
            }
          }
        }
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerClear::audio\n")
#endif
        return OK;
    }
};

extern "C"
{

    static OENTRY localops[] = {
        {
            (char*)"MixerSetLevel",
            sizeof(MixerSetLevel),
            _CW,
            3,
            (char*)"",
            (char*)"iik",
            (SUBR)&MixerSetLevel::init_,
            (SUBR)&MixerSetLevel::kontrol_,
            0
        },
        {
            (char*)"MixerSetLevel_i",
            sizeof(MixerSetLevel),
            _CW,
            1,
            (char*)"",
            (char*)"iii",
            (SUBR)&MixerSetLevel::init_,
            0,
            0
        },
        {
            (char*)"MixerGetLevel",
            sizeof(MixerGetLevel),
            _CR,
            3,
            (char*)"k",
            (char*)"ii",
            (SUBR)&MixerGetLevel::init_,
            (SUBR)&MixerGetLevel::kontrol_,
            0
        },
        {
            (char*)"MixerSend",
            sizeof(MixerSend),
            _CR,
            5,
            (char*)"",
            (char*)"aiii",
            (SUBR)&MixerSend::init_,
            0,
            (SUBR)&MixerSend::audio_
        },
        {
            (char*)"MixerReceive",
            sizeof(MixerReceive),
            _CW,
            5,
            (char*)"a",
            (char*)"ii",
            (SUBR)&MixerReceive::init_,
            0,
            (SUBR)&MixerReceive::audio_
        },
        {
            (char*)"MixerClear",
            sizeof(MixerClear),
            0,
            4,
            (char*)"",
            (char*)"",
            0,
            0,
            (SUBR)&MixerClear::audio_
        },
        { NULL, 0, 0, 0, NULL, NULL, (SUBR) NULL, (SUBR) NULL, (SUBR) NULL }
    };

    PUBLIC int csoundModuleCreate_mixer(CSOUND *csound)
    {
        busses = new std::map<CSOUND *,
                              std::map<size_t, std::vector< std::vector<MYFLT> > >>;
        matrix = new std::map<CSOUND *,
                              std::map<size_t, std::map<size_t, MYFLT> > >;
        return OK;
    }

    PUBLIC int csoundModuleInit_mixer(CSOUND *csound)
    {
        OENTRY  *ep = (OENTRY*) &(localops[0]);
        int     err = 0;

        while (ep->opname != NULL) {
            err |= csound->AppendOpcode(csound,
                                        ep->opname, ep->dsblksiz, ep->flags,
                                        ep->thread, ep->outypes, ep->intypes,
                                        (int (*)(CSOUND *, void*)) ep->iopadr,
                                        (int (*)(CSOUND *, void*)) ep->kopadr,
                                        (int (*)(CSOUND *, void*)) ep->aopadr);
            ep++;
        }
        return err;
    }

    /*
     * The mixer busses are laid out:
     * busses[csound][bus][channel][frame].
     * std::map<CSOUND *, std::map<size_t,
     *          std::vector< std::vector<MYFLT> > > > *busses = 0;
     * The mixer send matrix is laid out:
     * matrix[csound][send][bus].
     * std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > > *matrix = 0;
     */
    PUBLIC int csoundModuleDestroy_mixer(CSOUND *csound)
    {
      if(busses) {
        for(std::map<size_t,
              std::vector< std::vector<MYFLT> > >::iterator
              busi = (*busses)[csound].begin();
            busi != (*busses)[csound].end(); ++busi) {
          for(std::vector< std::vector<MYFLT> >::iterator
                channeli = busi->second.begin();
              channeli != busi->second.end(); ++channeli) {
            channeli->resize(0);
          }
          busi->second.clear();
        }
        busses->clear();
        delete busses;
        busses = 0;
      }
      if(matrix) {
        // std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > >
        for(std::map<size_t, std::map<size_t, MYFLT> >::iterator
              matrixi = (*matrix)[csound].begin();
            matrixi != (*matrix)[csound].end(); ++matrixi) {
          matrixi->second.clear();
        }
        matrix->clear();
        delete matrix;
        matrix = 0;
      }
        return OK;
    }

#ifndef INIT_STATIC_MODULES
    PUBLIC int csoundModuleCreate(CSOUND *csound)
    {
        return csoundModuleCreate_mixer(csound);
    }

    PUBLIC int csoundModuleInit(CSOUND *csound)
    {
        return csoundModuleInit_mixer(csound);
    }

    PUBLIC int csoundModuleDestroy(CSOUND *csound)
    {
        return csoundModuleDestroy_mixer(csound);
    }
#endif
}   // END EXTERN C

<commit_msg>stupidity<commit_after>#include "OpcodeBase.hpp"
#include <map>
#include <vector>

using namespace csound;

// Define ENABLE_MIXER_IDEBUG to enable i-rate debug messages.
//#define ENABLE_MIXER_IDEBUG

// Define ENABLE_MIXER_KDEBUG to enable -rate and a-rate debug messages.
//#define ENABLE_MIXER_KDEBUG

/**
 * The mixer busses are laid out:
 * busses[csound][bus][channel][frame].
 */
static std::map<CSOUND *, std::map<size_t,
       std::vector< std::vector<MYFLT> > > > *busses = 0;

/**
 * The mixer send matrix is laid out:
 * matrix[csound][send][bus].
 */
static std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > > *matrix = 0;

/**
 * Creates the buss if it does not already exist.
 */
static void createBuss(CSOUND *csound, size_t buss)
{
#ifdef ENABLE_MIXER_IDEBUG
    csound->Message(csound, "createBuss: csound %p buss %d...\n", csound, buss);
#endif
    if((*busses)[csound].find(buss) == (*busses)[csound].end()) {
        size_t channels = csound->GetNchnls(csound);
        size_t frames = csound->GetKsmps(csound);
        (*busses)[csound][buss].resize(channels);
        for(size_t channel = 0; channel < channels; channel++) {
            (*busses)[csound][buss][channel].resize(frames);
        }
#ifdef ENABLE_MIXER_IDEBUG
        csound->Message(csound, "createBuss: created buss.\n");
#endif
    } else {
#ifdef ENABLE_MIXER_IDEBUG
        csound->Message(csound, "createBuss: buss already exists.\n");
#endif
    }
}

/**
 * MixerSetLevel isend, ibuss, kgain
 *
 * Controls the gain of any signal route from a send to a bus
 */
struct MixerSetLevel : public OpcodeBase<MixerSetLevel> {
    // No outputs.
    // Inputs.
    MYFLT *isend;
    MYFLT *ibuss;
    MYFLT *kgain;
    // State.
    size_t send;
    size_t buss;
    int init(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSetLevel::init...\n");
#endif
        send = static_cast<size_t>(*isend);
        buss = static_cast<size_t>(*ibuss);
        createBuss(csound, buss);
        (*matrix)[csound][send][buss] = *kgain;
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSetLevel::init: csound %p send %d buss %d gain %f\n",
             csound, send, buss, (*matrix)[csound][send][buss]);
#endif
        return OK;
    }
    int kontrol(CSOUND *csound)
    {
        (*matrix)[csound][send][buss] = *kgain;
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerSetLevel::kontrol: csound %p send %d buss "
             "%d gain %f\n", csound, send, buss, (*matrix)[csound][send][buss]);
#endif
        return OK;
    }
};

/**
 * kgain MixerGetLevel isend, ibuss
 *
 * Returns the gain of any signal route from a send to a bus.
 */
struct MixerGetLevel : public OpcodeBase<MixerGetLevel> {
    //.
    MYFLT *kgain;
    // Inputs.
    MYFLT *isend;
    MYFLT *ibuss;
    // State.
    size_t send;
    size_t buss;
    int init(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerGetLevel::init...\n");
#endif
        send = static_cast<size_t>(*isend);
        buss = static_cast<size_t>(*ibuss);
        createBuss(csound, buss);
        return OK;
    }
    int noteoff(CSOUND *)
    {
        return OK;
    }
    int kontrol(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerGetLevel::kontrol...\n");
#endif
        *kgain = (*matrix)[csound][send][buss];
        return OK;
    }
};
/**
 * MixerSend asignal, isend, ibus, ichannel
 *
 * Routes a signal from a send to a channel of a mixer bus.
 * The gain of the send is controlled by the previously set mixer level.
 */
struct MixerSend : public OpcodeBase<MixerSend> {
    // No outputs.
    // Inputs.
    MYFLT *ainput;
    MYFLT *isend;
    MYFLT *ibuss;
    MYFLT *ichannel;
    // State.
    size_t send;
    size_t buss;
    size_t channel;
    size_t frames;
    MYFLT *busspointer;
    int init(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSend::init...\n");
#endif
        send = static_cast<size_t>(*isend);
        buss = static_cast<size_t>(*ibuss);
        createBuss(csound, buss);
        channel = static_cast<size_t>(*ichannel);
        frames = opds.insdshead->ksmps;
        busspointer = &(*busses)[csound][buss][channel].front();
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerSend::init: instance %p send %d buss "
             "%d channel %d frames %d busspointer %p\n",
             csound, send, buss, channel, frames, busspointer);
#endif
        return OK;
    }
    int noteoff(CSOUND *)
    {
        return OK;
    }
    int audio(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerSend::audio...\n");
#endif
        MYFLT gain = (*matrix)[csound][send][buss];
        for(size_t i = 0; i < frames; i++) {
            busspointer[i] += (ainput[i] * gain);
        }
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerSend::audio: instance %d send %d buss "
             "%d gain %f busspointer %p\n", csound, send, buss, gain, busspointer);
#endif
        return OK;
    }
};

/**
 * asignal MixerReceive ibuss, ichannel
 *
 * Receives a signal from a channel of a bus.
 * Obviously, instruments receiving signals must be numbered higher
 * than instruments sending those signals.
 */
struct MixerReceive : public OpcodeBase<MixerReceive> {
    // Output.
    MYFLT *aoutput;
    // Inputs.
    MYFLT *ibuss;
    MYFLT *ichannel;
    // State.
    size_t buss;
    size_t channel;
    size_t frames;
    MYFLT *busspointer;
    int init(CSOUND *csound)
    {
        buss = static_cast<size_t>(*ibuss);
        channel = static_cast<size_t>(*ichannel);
        frames = opds.insdshead->ksmps;
        createBuss(csound, buss);
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerReceive::init...\n");
#endif
        busspointer = &(*busses)[csound][buss][channel].front();
#ifdef ENABLE_MIXER_IDEBUG
        warn(csound, "MixerReceive::init csound %p buss %d channel "
             "%d frames %d busspointer %p\n", csound, buss, channel,
             frames, busspointer);
#endif
        return OK;
    }
    int noteoff(CSOUND *)
    {
        return OK;
    }
    int audio(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerReceive::audio...\n");
#endif
        for(size_t i = 0; i < frames; i++) {
            aoutput[i] = busspointer[i];
        }
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerReceive::audio aoutput %p busspointer %p\n",
             aoutput, buss);
#endif
        return OK;
    }
};

/**
 * MixerClear
 *
 * Clears all busses. Must be invoked after last MixerReceive.
 * You should probably use a highest-numbered instrument
 * with an indefinite duration that invokes only this opcode.
 */
struct MixerClear : public OpcodeBase<MixerClear> {
    // No output.
    // No input.
    // No state.
    int audio(CSOUND *csound)
    {
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerClear::audio...\n")
#endif
        for(std::map<size_t,
                std::vector< std::vector<MYFLT> > >::iterator
                busi = (*busses)[csound].begin();
            busi != (*busses)[csound].end(); ++busi) {
          for(std::vector< std::vector<MYFLT> >::iterator
                channeli = busi->second.begin();
              channeli != busi->second.end(); ++channeli) {
            for(std::vector<MYFLT>::iterator
                  framei = (*channeli).begin();
                framei != (*channeli).end(); ++framei) {
              *framei = 0;
            }
          }
        }
#ifdef ENABLE_MIXER_KDEBUG
        warn(csound, "MixerClear::audio\n")
#endif
        return OK;
    }
};

extern "C"
{

    static OENTRY localops[] = {
        {
            (char*)"MixerSetLevel",
            sizeof(MixerSetLevel),
            _CW,
            3,
            (char*)"",
            (char*)"iik",
            (SUBR)&MixerSetLevel::init_,
            (SUBR)&MixerSetLevel::kontrol_,
            0
        },
        {
            (char*)"MixerSetLevel_i",
            sizeof(MixerSetLevel),
            _CW,
            1,
            (char*)"",
            (char*)"iii",
            (SUBR)&MixerSetLevel::init_,
            0,
            0
        },
        {
            (char*)"MixerGetLevel",
            sizeof(MixerGetLevel),
            _CR,
            3,
            (char*)"k",
            (char*)"ii",
            (SUBR)&MixerGetLevel::init_,
            (SUBR)&MixerGetLevel::kontrol_,
            0
        },
        {
            (char*)"MixerSend",
            sizeof(MixerSend),
            _CR,
            5,
            (char*)"",
            (char*)"aiii",
            (SUBR)&MixerSend::init_,
            0,
            (SUBR)&MixerSend::audio_
        },
        {
            (char*)"MixerReceive",
            sizeof(MixerReceive),
            _CW,
            5,
            (char*)"a",
            (char*)"ii",
            (SUBR)&MixerReceive::init_,
            0,
            (SUBR)&MixerReceive::audio_
        },
        {
            (char*)"MixerClear",
            sizeof(MixerClear),
            0,
            4,
            (char*)"",
            (char*)"",
            0,
            0,
            (SUBR)&MixerClear::audio_
        },
        { NULL, 0, 0, 0, NULL, NULL, (SUBR) NULL, (SUBR) NULL, (SUBR) NULL }
    };

    PUBLIC int csoundModuleCreate_mixer(CSOUND *csound)
    {
        busses = new std::map<CSOUND *,
                              std::map<size_t, std::vector< std::vector<MYFLT> > > >;
        matrix = new std::map<CSOUND *,
                              std::map<size_t, std::map<size_t, MYFLT> > >;
        return OK;
    }

    PUBLIC int csoundModuleInit_mixer(CSOUND *csound)
    {
        OENTRY  *ep = (OENTRY*) &(localops[0]);
        int     err = 0;

        while (ep->opname != NULL) {
            err |= csound->AppendOpcode(csound,
                                        ep->opname, ep->dsblksiz, ep->flags,
                                        ep->thread, ep->outypes, ep->intypes,
                                        (int (*)(CSOUND *, void*)) ep->iopadr,
                                        (int (*)(CSOUND *, void*)) ep->kopadr,
                                        (int (*)(CSOUND *, void*)) ep->aopadr);
            ep++;
        }
        return err;
    }

    /*
     * The mixer busses are laid out:
     * busses[csound][bus][channel][frame].
     * std::map<CSOUND *, std::map<size_t,
     *          std::vector< std::vector<MYFLT> > > > *busses = 0;
     * The mixer send matrix is laid out:
     * matrix[csound][send][bus].
     * std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > > *matrix = 0;
     */
    PUBLIC int csoundModuleDestroy_mixer(CSOUND *csound)
    {
      if(busses) {
        for(std::map<size_t,
              std::vector< std::vector<MYFLT> > >::iterator
              busi = (*busses)[csound].begin();
            busi != (*busses)[csound].end(); ++busi) {
          for(std::vector< std::vector<MYFLT> >::iterator
                channeli = busi->second.begin();
              channeli != busi->second.end(); ++channeli) {
            channeli->resize(0);
          }
          busi->second.clear();
        }
        busses->clear();
        delete busses;
        busses = 0;
      }
      if(matrix) {
        // std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > >
        for(std::map<size_t, std::map<size_t, MYFLT> >::iterator
              matrixi = (*matrix)[csound].begin();
            matrixi != (*matrix)[csound].end(); ++matrixi) {
          matrixi->second.clear();
        }
        matrix->clear();
        delete matrix;
        matrix = 0;
      }
        return OK;
    }

#ifndef INIT_STATIC_MODULES
    PUBLIC int csoundModuleCreate(CSOUND *csound)
    {
        return csoundModuleCreate_mixer(csound);
    }

    PUBLIC int csoundModuleInit(CSOUND *csound)
    {
        return csoundModuleInit_mixer(csound);
    }

    PUBLIC int csoundModuleDestroy(CSOUND *csound)
    {
        return csoundModuleDestroy_mixer(csound);
    }
#endif
}   // END EXTERN C

<|endoftext|>


<commit_before>// @(#)alimdc:$Name$:$Id$
// Author: Fons Rademakers  26/11/99

/**************************************************************************
 * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// AliRunDB                                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <TSystem.h>
#include <TFile.h>
#include <TString.h>
#include <TDatime.h>
#include <TSQLServer.h>
#include <TSQLResult.h>
#include <TGrid.h>

#include "AliStats.h"
#include "AliRawDB.h"

#include "AliRunDB.h"

ClassImp(AliRunDB)

//______________________________________________________________________________
AliRunDB::AliRunDB(const char* localFS, Bool_t rdbms,
		   const char* alienHost, const char* alienDir) :
  fRunDB(NULL),
  fRDBMS(rdbms),
  fAlienHost(alienHost),
  fAlienDir(alienDir)
{
   // Open run database, and get or create tree.

   if (!localFS) return;

   // Get hostname
   char hostname[64], filename[64];

   // check that fs exists (crude check fails if fs is a file)
   gSystem->MakeDirectory(localFS);

   // Put wide read-write permissions
   if(gSystem->Chmod(localFS,1023)) {
     Error("AliRunDB","can't set permissions for run DB directory");
     return;
   }

   strcpy(hostname, gSystem->HostName());

   char *s;
   if ((s = strchr(hostname, '.')))
      *s = 0;

   sprintf(filename, "%s/%s_rundb.root", localFS, hostname);

   if (!gSystem->AccessPathName(filename, kFileExists))
      fRunDB = new TFile(filename, "UPDATE");
   else
      fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", AliRawDB::kMDC));

   // Put wide read-write permissions
   if(gSystem->Chmod(filename,438)) {
     Error("AliRunDB","can't set permissions for run DB file");
     return;
   }
}

//______________________________________________________________________________
AliRunDB::AliRunDB(const AliRunDB& runDB): TObject(runDB)
{
// copy constructor

  Fatal("AliRunDB", "copy constructor not implemented");
}

//______________________________________________________________________________
AliRunDB& AliRunDB::operator = (const AliRunDB& /*runDB*/)
{
// assignment operator

  Fatal("operator =", "assignment operator not implemented");
  return *this;
}

//______________________________________________________________________________
void AliRunDB::Update(AliStats *stats)
{
  UpdateLocal(stats);
  UpdateRDBMS(stats);
  UpdateAliEn(stats);
}

//______________________________________________________________________________
void AliRunDB::UpdateLocal(AliStats *stats)
{
   // Add stats object to database.

   if (!stats || !fRunDB) return;

   TDirectory *ds = gDirectory;
   fRunDB->cd();

   char sname[64];
   char *s = (char*)strrchr(stats->GetFileName(), '/');
   if (s) {
      s++;
      strcpy(sname, s);
   } else
      strcpy(sname, stats->GetFileName());
   s = strchr(sname, '.');
   if (s) *s = 0;

   stats->Write(sname);

   ds->cd();
}

//______________________________________________________________________________
void AliRunDB::UpdateRDBMS(AliStats *stats)
{
   // Add stats object to central MySQL DB.

   if (!stats || !fRDBMS) return;

   char sql[4096];
   char bt[25], et[25];

   strcpy(bt, stats->GetBeginTime().AsSQLString());
   strcpy(et, stats->GetEndTime().AsSQLString());

   sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
           "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", AliRawDB::kMDC,
           stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
           stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
           stats->GetLastEvent(), stats->GetCompressionMode(),
           stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
           bt, et);

   // open connection to MySQL server on pcsalo
   TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");

   if (!db || db->IsZombie()) {
      Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
      printf("%s\n", sql);
      delete db;
      return;
   }

   TSQLResult *res = db->Query(sql);

   if (!res) {
      Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", AliRawDB::kMDC));
      printf("%s\n", sql);
   }

   delete res;
   delete db;
}

//______________________________________________________________________________
void AliRunDB::UpdateAliEn(AliStats *stats)
{
   // Record file in AliEn catalog.

   if (!stats || fAlienHost.IsNull()) return;

   TGrid *g = TGrid::Connect(fAlienHost, "");

   //Protection in case root is compiled without AliEn support
   if(!g) {
      Error("UpdateAliEn", "ROOT compiled without AliEn support");
      return;
   }

   TString lfn = fAlienDir;
   TDatime dt;

   // make a subdirectory for each day
   lfn += "/adc-";
   lfn += dt.GetDate();

   // check if directory exists, if not create it
#if ROOT_VERSION_CODE < ROOT_VERSION(5,0,0)
   Grid_ResultHandle_t res = 0;
   if (!(res = g->OpenDir(lfn))) {
      // directory does not exist, create it
      if (g->Mkdir(lfn) == -1) {
         Error("UpdateAliEn", "cannot create directory %s", lfn.Data());
         lfn = fAlienDir;
      }
   }
   if (res) g->CloseResult(res);
#else
   Error("UpdateAliEn", "needs to be ported to new TGrid");
#endif

   lfn += "/";
   lfn += gSystem->BaseName(stats->GetFileName());

#if ROOT_VERSION_CODE < ROOT_VERSION(5,0,0)
   Int_t result = g->AddFile(lfn, stats->GetFileName(),
			     (int)stats->GetFileSize());
   if (result == -1) {
      Error("UpdateAliEn", "error adding file to AliEn catalog");
      printf("AliEn: AddFile(%s, %s, %d)\n", lfn.Data(), stats->GetFileName(),
             (int)stats->GetFileSize());
   }
#else
   Error("UpdateAliEn", "needs to be ported to new TGrid");
#endif

   delete g;
}

//______________________________________________________________________________
void AliRunDB::Close()
{
   // Close run database.

   if (fRunDB) fRunDB->Close();
   delete fRunDB;
}

<commit_msg>Removing obsolete call to a SQL database<commit_after>// @(#)alimdc:$Name$:$Id$
// Author: Fons Rademakers  26/11/99

/**************************************************************************
 * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// AliRunDB                                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <TSystem.h>
#include <TFile.h>
#include <TString.h>
#include <TDatime.h>
#include <TSQLServer.h>
#include <TSQLResult.h>
#include <TGrid.h>

#include "AliStats.h"
#include "AliRawDB.h"

#include "AliRunDB.h"

ClassImp(AliRunDB)

//______________________________________________________________________________
AliRunDB::AliRunDB(const char* localFS, Bool_t rdbms,
		   const char* alienHost, const char* alienDir) :
  fRunDB(NULL),
  fRDBMS(rdbms),
  fAlienHost(alienHost),
  fAlienDir(alienDir)
{
   // Open run database, and get or create tree.

   if (!localFS) return;

   // Get hostname
   char hostname[64], filename[64];

   // check that fs exists (crude check fails if fs is a file)
   gSystem->MakeDirectory(localFS);

   // Put wide read-write permissions
   if(gSystem->Chmod(localFS,1023)) {
     Error("AliRunDB","can't set permissions for run DB directory");
     return;
   }

   strcpy(hostname, gSystem->HostName());

   char *s;
   if ((s = strchr(hostname, '.')))
      *s = 0;

   sprintf(filename, "%s/%s_rundb.root", localFS, hostname);

   if (!gSystem->AccessPathName(filename, kFileExists))
      fRunDB = new TFile(filename, "UPDATE");
   else
      fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", AliRawDB::kMDC));

   // Put wide read-write permissions
   if(gSystem->Chmod(filename,438)) {
     Error("AliRunDB","can't set permissions for run DB file");
     return;
   }
}

//______________________________________________________________________________
AliRunDB::AliRunDB(const AliRunDB& runDB): TObject(runDB)
{
// copy constructor

  Fatal("AliRunDB", "copy constructor not implemented");
}

//______________________________________________________________________________
AliRunDB& AliRunDB::operator = (const AliRunDB& /*runDB*/)
{
// assignment operator

  Fatal("operator =", "assignment operator not implemented");
  return *this;
}

//______________________________________________________________________________
void AliRunDB::Update(AliStats *stats)
{
  UpdateLocal(stats);
  UpdateRDBMS(stats);
  UpdateAliEn(stats);
}

//______________________________________________________________________________
void AliRunDB::UpdateLocal(AliStats *stats)
{
   // Add stats object to database.

   if (!stats || !fRunDB) return;

   TDirectory *ds = gDirectory;
   fRunDB->cd();

   char sname[64];
   char *s = (char*)strrchr(stats->GetFileName(), '/');
   if (s) {
      s++;
      strcpy(sname, s);
   } else
      strcpy(sname, stats->GetFileName());
   s = strchr(sname, '.');
   if (s) *s = 0;

   stats->Write(sname);

   ds->cd();
}

//______________________________________________________________________________
void AliRunDB::UpdateRDBMS(AliStats *stats)
{
   // Add stats object to central MySQL DB.

   if (!stats || !fRDBMS) return;

   char sql[4096];
   char bt[25], et[25];

   strcpy(bt, stats->GetBeginTime().AsSQLString());
   strcpy(et, stats->GetEndTime().AsSQLString());

   sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
           "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", AliRawDB::kMDC,
           stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
           stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
           stats->GetLastEvent(), stats->GetCompressionMode(),
           stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
           bt, et);

   // open connection to MySQL server on pcsalo
//    TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");

//    if (!db || db->IsZombie()) {
//       Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
//       printf("%s\n", sql);
//       delete db;
//       return;
//    }

//    TSQLResult *res = db->Query(sql);

//    if (!res) {
//       Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", AliRawDB::kMDC));
//       printf("%s\n", sql);
//    }

//    delete res;
//    delete db;
}

//______________________________________________________________________________
void AliRunDB::UpdateAliEn(AliStats *stats)
{
   // Record file in AliEn catalog.

   if (!stats || fAlienHost.IsNull()) return;

   TGrid *g = TGrid::Connect(fAlienHost, "");

   //Protection in case root is compiled without AliEn support
   if(!g) {
      Error("UpdateAliEn", "ROOT compiled without AliEn support");
      return;
   }

   TString lfn = fAlienDir;
   TDatime dt;

   // make a subdirectory for each day
   lfn += "/adc-";
   lfn += dt.GetDate();

   // check if directory exists, if not create it
#if ROOT_VERSION_CODE < ROOT_VERSION(5,0,0)
   Grid_ResultHandle_t res = 0;
   if (!(res = g->OpenDir(lfn))) {
      // directory does not exist, create it
      if (g->Mkdir(lfn) == -1) {
         Error("UpdateAliEn", "cannot create directory %s", lfn.Data());
         lfn = fAlienDir;
      }
   }
   if (res) g->CloseResult(res);
#else
   Error("UpdateAliEn", "needs to be ported to new TGrid");
#endif

   lfn += "/";
   lfn += gSystem->BaseName(stats->GetFileName());

#if ROOT_VERSION_CODE < ROOT_VERSION(5,0,0)
   Int_t result = g->AddFile(lfn, stats->GetFileName(),
			     (int)stats->GetFileSize());
   if (result == -1) {
      Error("UpdateAliEn", "error adding file to AliEn catalog");
      printf("AliEn: AddFile(%s, %s, %d)\n", lfn.Data(), stats->GetFileName(),
             (int)stats->GetFileSize());
   }
#else
   Error("UpdateAliEn", "needs to be ported to new TGrid");
#endif

   delete g;
}

//______________________________________________________________________________
void AliRunDB::Close()
{
   // Close run database.

   if (fRunDB) fRunDB->Close();
   delete fRunDB;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>

#include <Windows.h>
#include <ShlObj.h>

#include <conio.h> // _getch()

#include "Osiris.hpp"

#include "Modules/OsirisModules.hpp"

#include <Utils/Utils.hpp>

#include <Ausar\Ausar.hpp>

#include <winnt.h>
#include <winternl.h>

#include <vector>
#include <iterator>

Osiris::Osiris()
{
    wchar_t Buffer[MAX_PATH] = { 0 };
    SHGetSpecialFolderPathW(nullptr, Buffer, CSIDL_PROFILE, false);

    std::wstring UserFolder(Buffer);
    UserFolder += L"\\AppData\\Local\\Packages\\Microsoft.Halo5Forge_8wekyb3d8bbwe\\LocalState\\Log.txt";

    Util::Log::Instance()->SetFile(UserFolder);

    LOG << "Osiris" << "---- ";
    LOG << '[' << __DATE__ << " : " << __TIME__ << ']' << std::endl;
    LOG << "\t-Wunkolo (Wunkolo@gmail.com)\n";
    LOG << std::wstring(80, '-') << std::endl;

    LOG << std::hex << std::uppercase << std::setfill(L'0')
        << "Process Base: 0x" << Util::Process::Base() << std::endl;
    LOG << "Osiris Thread ID: 0x" << Util::Thread::GetCurrentThreadId() << std::endl;
    LOG << "Osiris Base: 0x" << Util::Process::GetModuleBase("Osiris.dll") << std::endl;

    const Ausar::ThreadTable *Table;

    Table = Util::Process::GetModuleBase()(0x58CA4B0).Point<Ausar::ThreadTable>();

    //for( size_t i = 0; i < 64; i++ )
    //{
    //    if( Table->Entries[i].Active == 0 )
    //    {
    //        continue;
    //    }
    //    LOG << "Thread Name: " << reinterpret_cast<const char*>(Table->Entries[i].ThreadName) << std::endl;
    //    LOG << "Thread ID: " << Table->Entries[i].ThreadID << std::endl;
    //}

    uint64_t ThreadID = Table->GetThreadIDByName("MAIN");

    LOG << "Main Thread ID: " << ThreadID << std::endl;

    typedef enum _THREADINFOCLASS {
        ThreadBasicInformation = 0,
    } THREADINFOCLASS;

    typedef LONG KPRIORITY;

    typedef struct _CLIENT_ID {
        HANDLE UniqueProcess;
        HANDLE UniqueThread;
    } CLIENT_ID;
    typedef CLIENT_ID *PCLIENT_ID;

    typedef struct _THREAD_BASIC_INFORMATION
    {
        NTSTATUS                ExitStatus;
        PVOID                   TebBaseAddress;
        CLIENT_ID               ClientId;
        KAFFINITY               AffinityMask;
        KPRIORITY               Priority;
        KPRIORITY               BasePriority;
    } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

    typedef NTSTATUS(WINAPI *InfoThreadProc)(HANDLE, LONG, PVOID, ULONG, PULONG);

    HANDLE ThreadHandle = OpenThread(
        THREAD_ALL_ACCESS,
        false,
        static_cast<DWORD>(ThreadID)
    );

    Util::Pointer TEB(nullptr);

    InfoThreadProc NtQueryInformationThread = (InfoThreadProc)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationThread");

    THREAD_BASIC_INFORMATION ThreadInfo = { 0 };

    NTSTATUS ntStatus = NtQueryInformationThread(
        ThreadHandle,
        ThreadBasicInformation,
        &ThreadInfo,
        sizeof(THREAD_BASIC_INFORMATION),
        nullptr
    );

    LOG << ResumeThread(ThreadHandle) << std::endl;

    CloseHandle(ThreadHandle);

    TEB = Util::Pointer(ThreadInfo.TebBaseAddress)[0x58][0];

    LOG << "Physics Constants: " << TEB[0x2D30] << std::endl;
    LOG << "DOF Globals: " << TEB[0x49B0] << std::endl;
    LOG << "DOF Data: " << TEB[0x1310] << std::endl;
    LOG << "Director globals: " << TEB[0x198] << std::endl;
    LOG << "Hue saturation control: " << TEB[0x2FF8] << std::endl;
    LOG << "Game engine globals: " << TEB[0x13A8] << std::endl;
    LOG << "Local Game engine globals: " << TEB[0x13B0] << std::endl;
    LOG << "Game engine render globals: " << TEB[0x13B8] << std::endl;
    LOG << "Game time globals: " << TEB[0x12A8] << std::endl;
    LOG << "Composer globals: " << TEB[0x1C8] << std::endl;
    LOG << "Fp weapons: " << TEB[0x1260] << std::endl;
    LOG << "Player Focus: " << TEB[0x1320] << std::endl;
    LOG << "Player Control Globals: " << TEB[0x1340] << std::endl;
    LOG << "Player Control Globals Deter.: " << TEB[0x1348] << std::endl;
    LOG << "Player Globals: " << TEB[0x1370] << std::endl;

    LOG << "AI Globals: " << TEB[0x2E40] << std::endl;
    LOG << "AI Player state Globals: " << TEB[0x2E18] << std::endl;

    LOG << "Interaction ripples: " << TEB[0x4960] << std::endl;

    LOG << "Rasterizer: " << TEB[0x49A0] << std::endl;
    LOG << "Render game globals: " << TEB[0x49A8] << std::endl;
    LOG << "fp orientations: " << TEB[0x4A10] << std::endl;

    LOG << "Objects: " << TEB[0x4B18] << std::endl;
    LOG << "Object name list: " << TEB[0x4B20] << std::endl;
    LOG << "Object placement globals: " << TEB[0x4B58] << std::endl;
    LOG << "Object globals: " << TEB[0x4C08] << std::endl;
    LOG << "orientations: " << TEB[0x110] << std::endl;

    // Push Commands
    //PushModule<Research>("research");
    //PushModule<Player>("player");
}

Osiris::~Osiris()
{
}

void Osiris::Tick(const std::chrono::high_resolution_clock::duration &DeltaTime)
{
    for( std::pair<std::string, std::shared_ptr<OsirisModule>> Command : Commands )
    {
        if( Command.second )
        {
            Command.second->Tick(DeltaTime);
        }
    }
}<commit_msg>Added more globals to draft, fixed tls name<commit_after>#include <iostream>
#include <iomanip>

#include <Windows.h>
#include <ShlObj.h>

#include <conio.h> // _getch()

#include "Osiris.hpp"

#include "Modules/OsirisModules.hpp"

#include <Utils/Utils.hpp>

#include <Ausar\Ausar.hpp>

#include <winnt.h>
#include <winternl.h>

#include <vector>
#include <iterator>

Osiris::Osiris()
{
    wchar_t Buffer[MAX_PATH] = { 0 };
    SHGetSpecialFolderPathW(nullptr, Buffer, CSIDL_PROFILE, false);

    std::wstring UserFolder(Buffer);
    UserFolder += L"\\AppData\\Local\\Packages\\Microsoft.Halo5Forge_8wekyb3d8bbwe\\LocalState\\Log.txt";

    Util::Log::Instance()->SetFile(UserFolder);

    LOG << "Osiris" << "---- ";
    LOG << '[' << __DATE__ << " : " << __TIME__ << ']' << std::endl;
    LOG << "\t-Wunkolo (Wunkolo@gmail.com)\n";
    LOG << std::wstring(80, '-') << std::endl;

    LOG << std::hex << std::uppercase << std::setfill(L'0')
        << "Process Base: 0x" << Util::Process::Base() << std::endl;
    LOG << "Osiris Thread ID: 0x" << Util::Thread::GetCurrentThreadId() << std::endl;
    LOG << "Osiris Base: 0x" << Util::Process::GetModuleBase("Osiris.dll") << std::endl;

    const Ausar::ThreadTable *Table;

    Table = Util::Process::GetModuleBase()(0x58CA4B0).Point<Ausar::ThreadTable>();

    //for( size_t i = 0; i < 64; i++ )
    //{
    //    if( Table->Entries[i].Active == 0 )
    //    {
    //        continue;
    //    }
    //    LOG << "Thread Name: " << reinterpret_cast<const char*>(Table->Entries[i].ThreadName) << std::endl;
    //    LOG << "Thread ID: " << Table->Entries[i].ThreadID << std::endl;
    //}

    uint64_t ThreadID = Table->GetThreadIDByName("MAIN");

    LOG << "Main Thread ID: " << ThreadID << std::endl;

    typedef enum _THREADINFOCLASS {
        ThreadBasicInformation = 0,
    } THREADINFOCLASS;

    typedef LONG KPRIORITY;

    typedef struct _CLIENT_ID {
        HANDLE UniqueProcess;
        HANDLE UniqueThread;
    } CLIENT_ID;
    typedef CLIENT_ID *PCLIENT_ID;

    typedef struct _THREAD_BASIC_INFORMATION
    {
        NTSTATUS                ExitStatus;
        PVOID                   TebBaseAddress;
        CLIENT_ID               ClientId;
        KAFFINITY               AffinityMask;
        KPRIORITY               Priority;
        KPRIORITY               BasePriority;
    } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

    typedef NTSTATUS(WINAPI *InfoThreadProc)(HANDLE, LONG, PVOID, ULONG, PULONG);

    HANDLE ThreadHandle = OpenThread(
        THREAD_ALL_ACCESS,
        false,
        static_cast<DWORD>(ThreadID)
    );

    Util::Pointer Tls(nullptr);

    InfoThreadProc NtQueryInformationThread = (InfoThreadProc)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationThread");

    THREAD_BASIC_INFORMATION ThreadInfo = { 0 };

    NTSTATUS ntStatus = NtQueryInformationThread(
        ThreadHandle,
        ThreadBasicInformation,
        &ThreadInfo,
        sizeof(THREAD_BASIC_INFORMATION),
        nullptr
    );

    LOG << ResumeThread(ThreadHandle) << std::endl;

    CloseHandle(ThreadHandle);

    Tls = Util::Pointer(ThreadInfo.TebBaseAddress)[0x58][0];

    LOG << "Physics Constants: " << Tls[0x2D30] << std::endl;
    LOG << "userGraphicsScalingOptions: " << Tls[0x3050] << std::endl;

    LOG << "random math: " << Tls[0x2C38] << std::endl;
    LOG << "incident globals: " << Tls[0x2C38] << std::endl;

    LOG << "DOF Globals: " << Tls[0x49B0] << std::endl;
    LOG << "DOF Data: " << Tls[0x1310] << std::endl;
    LOG << "Director globals: " << Tls[0x198] << std::endl;
    LOG << "Hue saturation control: " << Tls[0x2FF8] << std::endl;
    LOG << "Game engine globals: " << Tls[0x13A8] << std::endl;
    LOG << "Local Game engine globals: " << Tls[0x13B0] << std::endl;
    LOG << "Game engine render globals: " << Tls[0x13B8] << std::endl;
    LOG << "Game time globals: " << Tls[0x12A8] << std::endl;
    LOG << "Composer globals: " << Tls[0x1C8] << std::endl;
    LOG << "Fp weapons: " << Tls[0x1260] << std::endl;

    LOG << "Player Focus: " << Tls[0x1320] << std::endl;
    LOG << "Player Control Globals: " << Tls[0x1340] << std::endl;
    LOG << "Player Control Globals Deter.: " << Tls[0x1348] << std::endl;
    LOG << "Player Globals: " << Tls[0x1370] << std::endl;
    LOG << "Player Mapping Globals: " << Tls[0x1350] << std::endl;

    LOG << "AI Globals: " << Tls[0x2E40] << std::endl;
    LOG << "AI Player state Globals: " << Tls[0x2E18] << std::endl;

    LOG << "Interaction ripples: " << Tls[0x4960] << std::endl;

    LOG << "Rasterizer: " << Tls[0x49A0] << std::endl;
    LOG << "Render game globals: " << Tls[0x49A8] << std::endl;
    LOG << "Render texture globals: " << Tls[0x3058] << std::endl;
    LOG << "atmosphere override settings: " << Tls[0x4998] << std::endl;
    LOG << "fp orientations: " << Tls[0x4A10] << std::endl;

    LOG << "Objects: " << Tls[0x4B18] << std::endl;
    LOG << "Object name list: " << Tls[0x4B20] << std::endl;
    LOG << "Object placement globals: " << Tls[0x4B58] << std::endl;
    LOG << "Object globals: " << Tls[0x4C08] << std::endl;
    LOG << "orientations: " << Tls[0x110] << std::endl;

    // Push Commands
    //PushModule<Research>("research");
    //PushModule<Player>("player");
}

Osiris::~Osiris()
{
}

void Osiris::Tick(const std::chrono::high_resolution_clock::duration &DeltaTime)
{
    for( std::pair<std::string, std::shared_ptr<OsirisModule>> Command : Commands )
    {
        if( Command.second )
        {
            Command.second->Tick(DeltaTime);
        }
    }
}<|endoftext|>


<commit_before>/*
 *  MT_RobotFrameBase.cpp
 *
 *  Created by Daniel Swain on 1/4/10.
 *
 */

#include "MT_RobotFrameBase.h"

#include "MT/MT_Robot/robot/SteeredRobot.h"

MT_RobotFrameBase::MT_RobotFrameBase(wxFrame* parent,
                                     wxWindowID id,
                                     const wxString& title,
                                     const wxPoint& pos,
                                     const wxSize& size,
                                     long style)
  : MT_TrackerFrameBase(parent, id, title, pos, size, style),
    m_pJoyStickFrame(NULL),
    m_bAutoIdentify(false),
    m_bRobotsIdentified(false),
    m_pRobotControlFrame(NULL),
    m_Robots(),
    m_pTrackedObjects(NULL)
{
}

MT_RobotFrameBase::~MT_RobotFrameBase()
{

}

void MT_RobotFrameBase::handleCommandLineArguments(int argc, wxChar** argv)
{
    MT_TrackerFrameBase::handleCommandLineArguments(argc, argv);
}

void MT_RobotFrameBase::handleOpenWithFile(const wxString& filename)
{
    MT_TrackerFrameBase::handleOpenWithFile(filename);
}

bool MT_RobotFrameBase::doKeyboardCallback(wxKeyEvent& event)
{
    bool tresult = MT_TrackerFrameBase::doKeyboardCallback(event);
    return tresult && MT_DO_BASE_KEY;
}

bool MT_RobotFrameBase::doMouseCallback(wxMouseEvent& event, double viewport_x, double viewport_y)
{
    bool tresult = MT_TrackerFrameBase::doMouseCallback(event, viewport_x, viewport_y);
    return tresult && MT_DO_BASE_MOUSE;
}

void MT_RobotFrameBase::onMenuRobotsConnect(wxCommandEvent& event)
{
    MT_RobotConnectDialog* dlg = new MT_RobotConnectDialog(&m_Robots, NULL, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::onMenuRobotsJoystick(wxCommandEvent& event)
{
    m_pJoyStickFrame->Show(true);
    registerDialogForXML(m_pJoyStickFrame);
    m_pJoyStickFrame->EnableEvents();
}

void MT_RobotFrameBase::onMenuRobotsCommand(wxCommandEvent& event)
{
    MT_RobotCommandDialog* dlg = new MT_RobotCommandDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::readUserXML()
{
    MT_TrackerFrameBase::readUserXML();

    MT_ReadRobotXML(&m_Robots, &m_XMLSettingsFile, false);

}

void MT_RobotFrameBase::writeUserXML()
{
    MT_WriteRobotXML(&m_Robots,
                  &m_XMLSettingsFile,
                  false);
    MT_TrackerFrameBase::writeUserXML();
}

void MT_RobotFrameBase::initUserData()
{
    MT_RobotFrameBase::initRobotFrameData();
    MT_TrackerFrameBase::initUserData();
}

void MT_RobotFrameBase::initRobotFrameData()
{
    m_pJoyStickFrame = new MT_JoyStickFrame(this, &m_Robots);
}

void MT_RobotFrameBase::createUserMenus(wxMenuBar* menubar)
{
    wxMenu* robot_menu = new wxMenu;
    makeRobotMenu(robot_menu);
    menubar->Append(robot_menu, wxT("Robots"));

    /* adds tracker menu */
    MT_TrackerFrameBase::createUserMenus(menubar);
}

void MT_RobotFrameBase::makeRobotMenu(wxMenu* robot_menu)
{
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_CONNECT, wxT("&Connections..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_CONNECT,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsConnect));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_JOYSTICK, wxT("&Joystick Control..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_JOYSTICK,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsJoystick));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_COMMAND, wxT("&Send Command..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_COMMAND,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsCommand));
}

MT_ControlFrameBase* MT_RobotFrameBase::createControlDialog()
{
    m_pRobotControlFrame = new MT_RobotControlFrameBase(this);
    m_pTrackerControlFrame = (MT_TrackerControlFrameBase *) m_pRobotControlFrame;
    return (MT_ControlFrameBase*) m_pRobotControlFrame;
}

void MT_RobotFrameBase::doUserTimedEvents()
{

}

void MT_RobotFrameBase::doUserStep()
{
    /* do tracking first, then control */
    MT_TrackerFrameBase::doUserStep();

    if(m_bAutoIdentify)
    {
        doAutoIdentify();
    }

    updateRobotStatesFromTracker();

    doControl();
}

void MT_RobotFrameBase::updateRobotStatesFromTracker()
{
    int ti;
    for(unsigned int i = 0; i < MT_MAX_NROBOTS; i++)
    {
        ti = m_Robots.TrackingIndex[i];
        if(ti != MT_NOT_TRACKED)
        {
            m_Robots.UpdateState(i,
                                 m_pTrackedObjects->getX(ti),
                                 m_pTrackedObjects->getY(ti),
                                 m_pTrackedObjects->getOrientation(ti));
        }
    }
}

void MT_RobotFrameBase::doControl()
{
    doUserControl();
}

bool MT_RobotFrameBase::startTracking()
{
    bool now_tracking = MT_TrackerFrameBase::startTracking();

    if(now_tracking && m_pTracker)
    {
        /* grab the tracked objects from the tracker */
        m_pTrackedObjects = m_pTracker->getTrackedObjects();
    }

    return now_tracking;
}

bool MT_RobotFrameBase::toggleAutoIdentify()
{

    // it only makes sense to do any of this if the tracker is up and running
    if(getIsTracking())
    {

        // toggle the value of the auto id flag
        if(m_bAutoIdentify)
        {
            m_bAutoIdentify = false;
            // stop the auto-id process
            doAutoIdentify(false);
        }
        else
        {
            m_bAutoIdentify = true;
            m_bRobotsIdentified = false;
        }

    }

    return m_bAutoIdentify;

}

void MT_RobotFrameBase::doAutoIdentify(bool DoAutoID)
{

    /* we'll want to know if this has changed */
    static int RobotToID = MT_NONE_AVAILABLE;

    /* if we're flagged to stop, then stop whichever robot may be moving for autoID */
    if(!DoAutoID)
    {
        if(RobotToID != MT_NONE_AVAILABLE)
        {
            m_Robots.GetRobot(RobotToID)->SafeStop();
        }
        RobotToID = MT_NONE_AVAILABLE;
        return;
    }

    /* first, make sure there's a robot to identify */
    int newRobotToID = m_Robots.GetNextUntracked();

    if(newRobotToID == MT_NONE_AVAILABLE)
    {
        /* none available! */
        RobotToID = MT_NONE_AVAILABLE;
        m_bRobotsIdentified = true;
        m_bAutoIdentify = false;
        /* change the label on the control frame  */
        m_pRobotControlFrame->onAutoIDToggle(false);
        return;
    }

    /* if the robots have been previously identified, reset the IDs */
    if(m_bRobotsIdentified)
    {
        m_Robots.ClearTrackingIDs();
    }

    /* OK, now we've got a robot to identify
       if it's new, we want to start it moving slowly */
    if(newRobotToID != RobotToID)
    {
        /* remember which robot for next time */
        RobotToID = newRobotToID;
        /* start it moving */
        m_Robots.GetRobot(RobotToID)->AutoIDResponse();
    }

    /* loop through tracked objects (until match is found) */
    for(unsigned int i = 0; i < m_pTrackedObjects->getNumObjects(); i++)
    {
        /* if this TO has been in 5 or more frames and not attached to a robot
           and is moving */
        if( (m_pTrackedObjects->getNumConsecutiveFrames(i) > 5) &&
            (m_pTrackedObjects->getRobotIndex(i) == MT_NO_ROBOT) &&
            (m_pTrackedObjects->getIsMoving(i)) )
        {
            /* stop the robot */
            m_Robots.GetRobot(RobotToID)->SafeStop();
            /* attach the current robot */
            m_pTrackedObjects->setRobotIndex(i, RobotToID);
            /* assign the TO ID to the robot */
            m_Robots.TrackingIndex[RobotToID] = i;
        }
    }

}

void MT_RobotFrameBase::doUserQuit()
{
    MT_TrackerFrameBase::doUserQuit();
}

void MT_RobotFrameBase::doUserGLDrawing()
{
    MT_TrackerFrameBase::doUserGLDrawing();
}

MT_RobotBase* MT_RobotFrameBase::getNewRobot(const char* config, const char* name)
{
    MT_RobotBase* thebot = new MT_SteeredRobot(config, name);
    ReadDataGroupFromXML(m_XMLSettingsFile, thebot->GetParameters());
    return thebot;
}

MT_RobotControlFrameBase::MT_RobotControlFrameBase(MT_RobotFrameBase* parent,
                                                   const int Buttons,
                                                   const wxPoint& pos,
                                                   const wxSize& size)
  : MT_TrackerControlFrameBase(parent, Buttons, pos, size)
{
    m_pParentRobotFrame = parent;
}

void MT_RobotControlFrameBase::doMasterInitialization()
{
    MT_TrackerControlFrameBase::doMasterInitialization();
}

unsigned int MT_RobotControlFrameBase::createButtons(wxBoxSizer* pSizer, wxPanel* pPanel)
{
    unsigned int nbuttons = MT_TrackerControlFrameBase::createButtons(pSizer, pPanel);

    if(getButtons() & MT_RCF_AUTOID)
    {
        m_pButtonAutoIdentify = new wxButton(pPanel,
                                             MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                                             wxT("AutoID Robots"));
        pSizer->Add(m_pButtonAutoIdentify, 0, wxALL | wxCENTER, 10);
        m_pButtonAutoIdentify->Disable();
        Connect(MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                wxEVT_COMMAND_BUTTON_CLICKED,
                wxCommandEventHandler(
                    MT_RobotControlFrameBase::onButtonAutoIdentifyPressed));
        nbuttons++;
    }
    return nbuttons;
}

void MT_RobotControlFrameBase::onButtonAutoIdentifyPressed(wxCommandEvent& WXUNUSED(event))
{
    onAutoIDToggle(m_pParentRobotFrame->toggleAutoIdentify());
}

void MT_RobotControlFrameBase::onAutoIDToggle(bool AutoID)
{

    if(AutoID == false)
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Reset Auto Identify"));
    }
    else
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Stop Auto Identify"));
    }

}

void MT_RobotControlFrameBase::onTrackingToggle(bool tracking)
{

    MT_TrackerControlFrameBase::onTrackingToggle(tracking);

    if(m_pButtonAutoIdentify)
    {
        if(tracking)
        {
            m_pButtonAutoIdentify->Enable();
        }
        else
        {
            m_pButtonAutoIdentify->Disable();
        }
    }

}

void MT_RobotControlFrameBase::enableButtons()
{
    if(m_pButtonAutoIdentify)
    {
        m_pButtonAutoIdentify->Enable();
    }
    MT_TrackerControlFrameBase::enableButtons();
}
<commit_msg>Fixed initialization of MT_RobotFrameBase<commit_after>/*
 *  MT_RobotFrameBase.cpp
 *
 *  Created by Daniel Swain on 1/4/10.
 *
 */

#include "MT_RobotFrameBase.h"

#include "MT/MT_Robot/robot/SteeredRobot.h"

MT_RobotFrameBase::MT_RobotFrameBase(wxFrame* parent,
                                     wxWindowID id,
                                     const wxString& title,
                                     const wxPoint& pos,
                                     const wxSize& size,
                                     long style)
  : MT_TrackerFrameBase(parent, id, title, pos, size, style),
    m_pJoyStickFrame(NULL),
    m_bAutoIdentify(false),
    m_bRobotsIdentified(false),
    m_pRobotControlFrame(NULL),
    m_Robots(),
    m_pTrackedObjects(NULL)
{
}

MT_RobotFrameBase::~MT_RobotFrameBase()
{

}

void MT_RobotFrameBase::handleCommandLineArguments(int argc, wxChar** argv)
{
    MT_TrackerFrameBase::handleCommandLineArguments(argc, argv);
}

void MT_RobotFrameBase::handleOpenWithFile(const wxString& filename)
{
    MT_TrackerFrameBase::handleOpenWithFile(filename);
}

bool MT_RobotFrameBase::doKeyboardCallback(wxKeyEvent& event)
{
    bool tresult = MT_TrackerFrameBase::doKeyboardCallback(event);
    return tresult && MT_DO_BASE_KEY;
}

bool MT_RobotFrameBase::doMouseCallback(wxMouseEvent& event, double viewport_x, double viewport_y)
{
    bool tresult = MT_TrackerFrameBase::doMouseCallback(event, viewport_x, viewport_y);
    return tresult && MT_DO_BASE_MOUSE;
}

void MT_RobotFrameBase::onMenuRobotsConnect(wxCommandEvent& event)
{
    MT_RobotConnectDialog* dlg = new MT_RobotConnectDialog(&m_Robots, NULL, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::onMenuRobotsJoystick(wxCommandEvent& event)
{
    m_pJoyStickFrame->Show(true);
    registerDialogForXML(m_pJoyStickFrame);
    m_pJoyStickFrame->EnableEvents();
}

void MT_RobotFrameBase::onMenuRobotsCommand(wxCommandEvent& event)
{
    MT_RobotCommandDialog* dlg = new MT_RobotCommandDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::readUserXML()
{
    MT_TrackerFrameBase::readUserXML();

    MT_ReadRobotXML(&m_Robots, &m_XMLSettingsFile, false);

}

void MT_RobotFrameBase::writeUserXML()
{
    MT_WriteRobotXML(&m_Robots,
                  &m_XMLSettingsFile,
                  false);
    MT_TrackerFrameBase::writeUserXML();
}

void MT_RobotFrameBase::initUserData()
{
    MT_RobotFrameBase::initRobotFrameData();
    MT_TrackerFrameBase::initUserData();
}

void MT_RobotFrameBase::initRobotFrameData()
{
    m_pJoyStickFrame = new MT_JoyStickFrame(this, &m_Robots);
}

void MT_RobotFrameBase::createUserMenus(wxMenuBar* menubar)
{
    wxMenu* robot_menu = new wxMenu;
    makeRobotMenu(robot_menu);
    menubar->Append(robot_menu, wxT("Robots"));

    /* adds tracker menu */
    MT_TrackerFrameBase::createUserMenus(menubar);
}

void MT_RobotFrameBase::makeRobotMenu(wxMenu* robot_menu)
{
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_CONNECT, wxT("&Connections..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_CONNECT,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsConnect));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_JOYSTICK, wxT("&Joystick Control..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_JOYSTICK,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsJoystick));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_COMMAND, wxT("&Send Command..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_COMMAND,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsCommand));
}

MT_ControlFrameBase* MT_RobotFrameBase::createControlDialog()
{
    m_pRobotControlFrame = new MT_RobotControlFrameBase(this);
    m_pTrackerControlFrame = (MT_TrackerControlFrameBase *) m_pRobotControlFrame;
    return (MT_ControlFrameBase*) m_pRobotControlFrame;
}

void MT_RobotFrameBase::doUserTimedEvents()
{

}

void MT_RobotFrameBase::doUserStep()
{
    /* do tracking first, then control */
    MT_TrackerFrameBase::doUserStep();

    if(m_bAutoIdentify)
    {
        doAutoIdentify();
    }

    updateRobotStatesFromTracker();

    doControl();
}

void MT_RobotFrameBase::updateRobotStatesFromTracker()
{
    int ti;
    for(unsigned int i = 0; i < MT_MAX_NROBOTS; i++)
    {
        ti = m_Robots.TrackingIndex[i];
        if(ti != MT_NOT_TRACKED)
        {
            m_Robots.UpdateState(i,
                                 m_pTrackedObjects->getX(ti),
                                 m_pTrackedObjects->getY(ti),
                                 m_pTrackedObjects->getOrientation(ti));
        }
    }
}

void MT_RobotFrameBase::doControl()
{
    doUserControl();
}

bool MT_RobotFrameBase::startTracking()
{
    bool now_tracking = MT_TrackerFrameBase::startTracking();

    if(now_tracking && m_pTracker)
    {
        /* grab the tracked objects from the tracker */
        m_pTrackedObjects = m_pTracker->getTrackedObjects();
    }

    return now_tracking;
}

bool MT_RobotFrameBase::toggleAutoIdentify()
{

    // it only makes sense to do any of this if the tracker is up and running
    if(getIsTracking())
    {

        // toggle the value of the auto id flag
        if(m_bAutoIdentify)
        {
            m_bAutoIdentify = false;
            // stop the auto-id process
            doAutoIdentify(false);
        }
        else
        {
            m_bAutoIdentify = true;
            m_bRobotsIdentified = false;
        }

    }

    return m_bAutoIdentify;

}

void MT_RobotFrameBase::doAutoIdentify(bool DoAutoID)
{

    /* we'll want to know if this has changed */
    static int RobotToID = MT_NONE_AVAILABLE;

    /* if we're flagged to stop, then stop whichever robot may be moving for autoID */
    if(!DoAutoID)
    {
        if(RobotToID != MT_NONE_AVAILABLE)
        {
            m_Robots.GetRobot(RobotToID)->SafeStop();
        }
        RobotToID = MT_NONE_AVAILABLE;
        return;
    }

    /* first, make sure there's a robot to identify */
    int newRobotToID = m_Robots.GetNextUntracked();

    if(newRobotToID == MT_NONE_AVAILABLE)
    {
        /* none available! */
        RobotToID = MT_NONE_AVAILABLE;
        m_bRobotsIdentified = true;
        m_bAutoIdentify = false;
        /* change the label on the control frame  */
        m_pRobotControlFrame->onAutoIDToggle(false);
        return;
    }

    /* if the robots have been previously identified, reset the IDs */
    if(m_bRobotsIdentified)
    {
        m_Robots.ClearTrackingIDs();
    }

    /* OK, now we've got a robot to identify
       if it's new, we want to start it moving slowly */
    if(newRobotToID != RobotToID)
    {
        /* remember which robot for next time */
        RobotToID = newRobotToID;
        /* start it moving */
        m_Robots.GetRobot(RobotToID)->AutoIDResponse();
    }

    /* loop through tracked objects (until match is found) */
    for(unsigned int i = 0; i < m_pTrackedObjects->getNumObjects(); i++)
    {
        /* if this TO has been in 5 or more frames and not attached to a robot
           and is moving */
        if( (m_pTrackedObjects->getNumConsecutiveFrames(i) > 5) &&
            (m_pTrackedObjects->getRobotIndex(i) == MT_NO_ROBOT) &&
            (m_pTrackedObjects->getIsMoving(i)) )
        {
            /* stop the robot */
            m_Robots.GetRobot(RobotToID)->SafeStop();
            /* attach the current robot */
            m_pTrackedObjects->setRobotIndex(i, RobotToID);
            /* assign the TO ID to the robot */
            m_Robots.TrackingIndex[RobotToID] = i;
        }
    }

}

void MT_RobotFrameBase::doUserQuit()
{
    MT_TrackerFrameBase::doUserQuit();
}

void MT_RobotFrameBase::doUserGLDrawing()
{
    MT_TrackerFrameBase::doUserGLDrawing();
}

MT_RobotBase* MT_RobotFrameBase::getNewRobot(const char* config, const char* name)
{
    MT_RobotBase* thebot = new MT_SteeredRobot(config, name);
    ReadDataGroupFromXML(m_XMLSettingsFile, thebot->GetParameters());
    return thebot;
}

MT_RobotControlFrameBase::MT_RobotControlFrameBase(MT_RobotFrameBase* parent,
                                                   const int Buttons,
                                                   const wxPoint& pos,
                                                   const wxSize& size)
  : MT_TrackerControlFrameBase(parent, Buttons, pos, size),
  m_pButtonAutoIdentify(NULL)
{
    m_pParentRobotFrame = parent;
}

void MT_RobotControlFrameBase::doMasterInitialization()
{
    MT_TrackerControlFrameBase::doMasterInitialization();
}

unsigned int MT_RobotControlFrameBase::createButtons(wxBoxSizer* pSizer, wxPanel* pPanel)
{
    unsigned int nbuttons = MT_TrackerControlFrameBase::createButtons(pSizer, pPanel);

    if(getButtons() & MT_RCF_AUTOID)
    {
        m_pButtonAutoIdentify = new wxButton(pPanel,
                                             MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                                             wxT("AutoID Robots"));
        pSizer->Add(m_pButtonAutoIdentify, 0, wxALL | wxCENTER, 10);
        m_pButtonAutoIdentify->Disable();
        Connect(MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                wxEVT_COMMAND_BUTTON_CLICKED,
                wxCommandEventHandler(
                    MT_RobotControlFrameBase::onButtonAutoIdentifyPressed));
        nbuttons++;
    }
    return nbuttons;
}

void MT_RobotControlFrameBase::onButtonAutoIdentifyPressed(wxCommandEvent& WXUNUSED(event))
{
    onAutoIDToggle(m_pParentRobotFrame->toggleAutoIdentify());
}

void MT_RobotControlFrameBase::onAutoIDToggle(bool AutoID)
{

    if(AutoID == false)
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Reset Auto Identify"));
    }
    else
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Stop Auto Identify"));
    }

}

void MT_RobotControlFrameBase::onTrackingToggle(bool tracking)
{

    MT_TrackerControlFrameBase::onTrackingToggle(tracking);

    if(m_pButtonAutoIdentify)
    {
        if(tracking)
        {
            m_pButtonAutoIdentify->Enable();
        }
        else
        {
            m_pButtonAutoIdentify->Disable();
        }
    }

}

void MT_RobotControlFrameBase::enableButtons()
{
    if(m_pButtonAutoIdentify)
    {
        m_pButtonAutoIdentify->Enable();
    }
    MT_TrackerControlFrameBase::enableButtons();
}
<|endoftext|>