<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2019 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/cpu/backend/x64/x64_code_cache.h"

#include <cstdlib>
#include <cstring>

#if ENABLE_VTUNE
#include "third_party/vtune/include/jitprofiling.h"
#pragma comment(lib, "../third_party/vtune/lib64/jitprofiling.lib")
#endif

#include "xenia/base/assert.h"
#include "xenia/base/clock.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/memory.h"
#include "xenia/cpu/function.h"
#include "xenia/cpu/module.h"

namespace xe {
namespace cpu {
namespace backend {
namespace x64 {

X64CodeCache::X64CodeCache() = default;

X64CodeCache::~X64CodeCache() {
  if (indirection_table_base_) {
    xe::memory::DeallocFixed(indirection_table_base_, 0,
                             xe::memory::DeallocationType::kRelease);
  }

  // Unmap all views and close mapping.
  if (mapping_) {
    xe::memory::UnmapFileView(mapping_, generated_code_base_,
                              kGeneratedCodeSize);
    xe::memory::CloseFileMappingHandle(mapping_);
    mapping_ = nullptr;
  }
}

bool X64CodeCache::Initialize() {
  indirection_table_base_ = reinterpret_cast<uint8_t*>(xe::memory::AllocFixed(
      reinterpret_cast<void*>(kIndirectionTableBase), kIndirectionTableSize,
      xe::memory::AllocationType::kReserve,
      xe::memory::PageAccess::kReadWrite));
  if (!indirection_table_base_) {
    XELOGE("Unable to allocate code cache indirection table");
    XELOGE(
        "This is likely because the %.8X-%.8X range is in use by some other "
        "system DLL",
        kIndirectionTableBase, kIndirectionTableBase + kIndirectionTableSize);
  }

  // Create mmap file. This allows us to share the code cache with the debugger.
  file_name_ = std::wstring(L"Local\\xenia_code_cache_") +
               std::to_wstring(Clock::QueryHostTickCount());
  mapping_ = xe::memory::CreateFileMappingHandle(
      file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite,
      false);
  if (!mapping_) {
    XELOGE("Unable to create code cache mmap");
    return false;
  }

  // Map generated code region into the file. Pages are committed as required.
  generated_code_base_ = reinterpret_cast<uint8_t*>(xe::memory::MapFileView(
      mapping_, reinterpret_cast<void*>(kGeneratedCodeBase), kGeneratedCodeSize,
      xe::memory::PageAccess::kExecuteReadWrite, 0));
  if (!generated_code_base_) {
    XELOGE("Unable to allocate code cache generated code storage");
    XELOGE(
        "This is likely because the %.8X-%.8X range is in use by some other "
        "system DLL",
        kGeneratedCodeBase, kGeneratedCodeBase + kGeneratedCodeSize);
    return false;
  }

  // Preallocate the function map to a large, reasonable size.
  generated_code_map_.reserve(kMaximumFunctionCount);

  return true;
}

void X64CodeCache::set_indirection_default(uint32_t default_value) {
  indirection_default_value_ = default_value;
}

void X64CodeCache::AddIndirection(uint32_t guest_address,
                                  uint32_t host_address) {
  if (!indirection_table_base_) {
    return;
  }

  uint32_t* indirection_slot = reinterpret_cast<uint32_t*>(
      indirection_table_base_ + (guest_address - kIndirectionTableBase));
  *indirection_slot = host_address;
}

void X64CodeCache::CommitExecutableRange(uint32_t guest_low,
                                         uint32_t guest_high) {
  if (!indirection_table_base_) {
    return;
  }

  // Commit the memory.
  xe::memory::AllocFixed(
      indirection_table_base_ + (guest_low - kIndirectionTableBase),
      guest_high - guest_low, xe::memory::AllocationType::kCommit,
      xe::memory::PageAccess::kExecuteReadWrite);

  // Fill memory with the default value.
  uint32_t* p = reinterpret_cast<uint32_t*>(indirection_table_base_);
  for (uint32_t address = guest_low; address < guest_high; ++address) {
    p[(address - kIndirectionTableBase) / 4] = indirection_default_value_;
  }
}

void* X64CodeCache::PlaceHostCode(uint32_t guest_address, void* machine_code,
                                  const EmitFunctionInfo& func_info) {
  // Same for now. We may use different pools or whatnot later on, like when
  // we only want to place guest code in a serialized cache on disk.
  return PlaceGuestCode(guest_address, machine_code, func_info, nullptr);
}

void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
                                   const EmitFunctionInfo& func_info,
                                   GuestFunction* function_info) {
  // Hold a lock while we bump the pointers up. This is important as the
  // unwind table requires entries AND code to be sorted in order.
  size_t low_mark;
  size_t high_mark;
  size_t code_offset;
  uint8_t* code_address;
  UnwindReservation unwind_reservation;
  {
    auto global_lock = global_critical_region_.Acquire();

    low_mark = generated_code_offset_;

    // Reserve code.
    // Always move the code to land on 16b alignment.
    code_offset = generated_code_offset_;
    code_address = generated_code_base_ + code_offset;
    generated_code_offset_ += xe::round_up(func_info.code_size.total, 16);

    // Reserve unwind info.
    // We go on the high size of the unwind info as we don't know how big we
    // need it, and a few extra bytes of padding isn't the worst thing.
    unwind_reservation =
        RequestUnwindReservation(generated_code_base_ + generated_code_offset_);
    generated_code_offset_ += xe::round_up(unwind_reservation.data_size, 16);

    high_mark = generated_code_offset_;

    // Store in map. It is maintained in sorted order of host PC dependent on
    // us also being append-only.
    generated_code_map_.emplace_back(
        (uint64_t(code_address - generated_code_base_) << 32) |
            generated_code_offset_,
        function_info);

    // TODO(DrChat): The following code doesn't really need to be under the
    // global lock except for PlaceCode (but it depends on the previous code
    // already being ran)

    // If we are going above the high water mark of committed memory, commit
    // some more. It's ok if multiple threads do this, as redundant commits
    // aren't harmful.
    size_t old_commit_mark, new_commit_mark;
    do {
      old_commit_mark = generated_code_commit_mark_;
      if (high_mark <= old_commit_mark) break;

      new_commit_mark = old_commit_mark + 16 * 1024 * 1024;
      xe::memory::AllocFixed(generated_code_base_, new_commit_mark,
                             xe::memory::AllocationType::kCommit,
                             xe::memory::PageAccess::kExecuteReadWrite);
    } while (generated_code_commit_mark_.compare_exchange_weak(
        old_commit_mark, new_commit_mark));

    // Copy code.
    std::memcpy(code_address, machine_code, func_info.code_size.total);

    // Fill unused slots with 0xCC
    std::memset(code_address + func_info.code_size.total, 0xCC,
                generated_code_offset_ - code_offset);

    // Notify subclasses of placed code.
    PlaceCode(guest_address, machine_code, func_info, code_address,
              unwind_reservation);
  }

#if ENABLE_VTUNE
  if (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON) {
    std::string method_name;
    if (function_info && function_info->name().size() != 0) {
      method_name = function_info->name();
    } else {
      method_name = xe::format_string("sub_%.8X", guest_address);
    }

    iJIT_Method_Load_V2 method = {0};
    method.method_id = iJIT_GetNewMethodID();
    method.method_load_address = code_address;
    method.method_size = uint32_t(code_size);
    method.method_name = const_cast<char*>(method_name.data());
    method.module_name = function_info
                             ? (char*)function_info->module()->name().c_str()
                             : nullptr;
    iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
  }
#endif

  // Now that everything is ready, fix up the indirection table.
  // Note that we do support code that doesn't have an indirection fixup, so
  // ignore those when we see them.
  if (guest_address && indirection_table_base_) {
    uint32_t* indirection_slot = reinterpret_cast<uint32_t*>(
        indirection_table_base_ + (guest_address - kIndirectionTableBase));
    *indirection_slot = uint32_t(reinterpret_cast<uint64_t>(code_address));
  }

  return code_address;
}

uint32_t X64CodeCache::PlaceData(const void* data, size_t length) {
  // Hold a lock while we bump the pointers up.
  size_t high_mark;
  uint8_t* data_address = nullptr;
  {
    auto global_lock = global_critical_region_.Acquire();

    // Reserve code.
    // Always move the code to land on 16b alignment.
    data_address = generated_code_base_ + generated_code_offset_;
    generated_code_offset_ += xe::round_up(length, 16);

    high_mark = generated_code_offset_;
  }

  // If we are going above the high water mark of committed memory, commit some
  // more. It's ok if multiple threads do this, as redundant commits aren't
  // harmful.
  size_t old_commit_mark, new_commit_mark;
  do {
    old_commit_mark = generated_code_commit_mark_;
    if (high_mark <= old_commit_mark) break;

    new_commit_mark = old_commit_mark + 16 * 1024 * 1024;
    xe::memory::AllocFixed(generated_code_base_, new_commit_mark,
                           xe::memory::AllocationType::kCommit,
                           xe::memory::PageAccess::kExecuteReadWrite);
  } while (generated_code_commit_mark_.compare_exchange_weak(old_commit_mark,
                                                             new_commit_mark));

  // Copy code.
  std::memcpy(data_address, data, length);

  return uint32_t(uintptr_t(data_address));
}

GuestFunction* X64CodeCache::LookupFunction(uint64_t host_pc) {
  uint32_t key = uint32_t(host_pc - kGeneratedCodeBase);
  void* fn_entry = std::bsearch(
      &key, generated_code_map_.data(), generated_code_map_.size() + 1,
      sizeof(std::pair<uint32_t, Function*>),
      [](const void* key_ptr, const void* element_ptr) {
        auto key = *reinterpret_cast<const uint32_t*>(key_ptr);
        auto element =
            reinterpret_cast<const std::pair<uint64_t, GuestFunction*>*>(
                element_ptr);
        if (key < (element->first >> 32)) {
          return -1;
        } else if (key > uint32_t(element->first)) {
          return 1;
        } else {
          return 0;
        }
      });
  if (fn_entry) {
    return reinterpret_cast<const std::pair<uint64_t, GuestFunction*>*>(
               fn_entry)
        ->second;
  } else {
    return nullptr;
  }
}

}  // namespace x64
}  // namespace backend
}  // namespace cpu
}  // namespace xe
<commit_msg>[x64] Further simplification / fix buffer overrun in code cache.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2019 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/cpu/backend/x64/x64_code_cache.h"

#include <cstdlib>
#include <cstring>

#if ENABLE_VTUNE
#include "third_party/vtune/include/jitprofiling.h"
#pragma comment(lib, "../third_party/vtune/lib64/jitprofiling.lib")
#endif

#include "xenia/base/assert.h"
#include "xenia/base/clock.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/memory.h"
#include "xenia/cpu/function.h"
#include "xenia/cpu/module.h"

namespace xe {
namespace cpu {
namespace backend {
namespace x64 {

X64CodeCache::X64CodeCache() = default;

X64CodeCache::~X64CodeCache() {
  if (indirection_table_base_) {
    xe::memory::DeallocFixed(indirection_table_base_, 0,
                             xe::memory::DeallocationType::kRelease);
  }

  // Unmap all views and close mapping.
  if (mapping_) {
    xe::memory::UnmapFileView(mapping_, generated_code_base_,
                              kGeneratedCodeSize);
    xe::memory::CloseFileMappingHandle(mapping_);
    mapping_ = nullptr;
  }
}

bool X64CodeCache::Initialize() {
  indirection_table_base_ = reinterpret_cast<uint8_t*>(xe::memory::AllocFixed(
      reinterpret_cast<void*>(kIndirectionTableBase), kIndirectionTableSize,
      xe::memory::AllocationType::kReserve,
      xe::memory::PageAccess::kReadWrite));
  if (!indirection_table_base_) {
    XELOGE("Unable to allocate code cache indirection table");
    XELOGE(
        "This is likely because the %.8X-%.8X range is in use by some other "
        "system DLL",
        kIndirectionTableBase, kIndirectionTableBase + kIndirectionTableSize);
  }

  // Create mmap file. This allows us to share the code cache with the debugger.
  file_name_ = std::wstring(L"Local\\xenia_code_cache_") +
               std::to_wstring(Clock::QueryHostTickCount());
  mapping_ = xe::memory::CreateFileMappingHandle(
      file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite,
      false);
  if (!mapping_) {
    XELOGE("Unable to create code cache mmap");
    return false;
  }

  // Map generated code region into the file. Pages are committed as required.
  generated_code_base_ = reinterpret_cast<uint8_t*>(xe::memory::MapFileView(
      mapping_, reinterpret_cast<void*>(kGeneratedCodeBase), kGeneratedCodeSize,
      xe::memory::PageAccess::kExecuteReadWrite, 0));
  if (!generated_code_base_) {
    XELOGE("Unable to allocate code cache generated code storage");
    XELOGE(
        "This is likely because the %.8X-%.8X range is in use by some other "
        "system DLL",
        kGeneratedCodeBase, kGeneratedCodeBase + kGeneratedCodeSize);
    return false;
  }

  // Preallocate the function map to a large, reasonable size.
  generated_code_map_.reserve(kMaximumFunctionCount);

  return true;
}

void X64CodeCache::set_indirection_default(uint32_t default_value) {
  indirection_default_value_ = default_value;
}

void X64CodeCache::AddIndirection(uint32_t guest_address,
                                  uint32_t host_address) {
  if (!indirection_table_base_) {
    return;
  }

  uint32_t* indirection_slot = reinterpret_cast<uint32_t*>(
      indirection_table_base_ + (guest_address - kIndirectionTableBase));
  *indirection_slot = host_address;
}

void X64CodeCache::CommitExecutableRange(uint32_t guest_low,
                                         uint32_t guest_high) {
  if (!indirection_table_base_) {
    return;
  }

  // Commit the memory.
  xe::memory::AllocFixed(
      indirection_table_base_ + (guest_low - kIndirectionTableBase),
      guest_high - guest_low, xe::memory::AllocationType::kCommit,
      xe::memory::PageAccess::kExecuteReadWrite);

  // Fill memory with the default value.
  uint32_t* p = reinterpret_cast<uint32_t*>(indirection_table_base_);
  for (uint32_t address = guest_low; address < guest_high; ++address) {
    p[(address - kIndirectionTableBase) / 4] = indirection_default_value_;
  }
}

void* X64CodeCache::PlaceHostCode(uint32_t guest_address, void* machine_code,
                                  const EmitFunctionInfo& func_info) {
  // Same for now. We may use different pools or whatnot later on, like when
  // we only want to place guest code in a serialized cache on disk.
  return PlaceGuestCode(guest_address, machine_code, func_info, nullptr);
}

void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
                                   const EmitFunctionInfo& func_info,
                                   GuestFunction* function_info) {
  // Hold a lock while we bump the pointers up. This is important as the
  // unwind table requires entries AND code to be sorted in order.
  size_t low_mark;
  size_t high_mark;
  uint8_t* code_address;
  UnwindReservation unwind_reservation;
  {
    auto global_lock = global_critical_region_.Acquire();

    low_mark = generated_code_offset_;

    // Reserve code.
    // Always move the code to land on 16b alignment.
    code_address = generated_code_base_ + generated_code_offset_;
    generated_code_offset_ += xe::round_up(func_info.code_size.total, 16);

    auto tail_address = generated_code_base_ + generated_code_offset_;

    // Reserve unwind info.
    // We go on the high size of the unwind info as we don't know how big we
    // need it, and a few extra bytes of padding isn't the worst thing.
    unwind_reservation =
        RequestUnwindReservation(generated_code_base_ + generated_code_offset_);
    generated_code_offset_ += xe::round_up(unwind_reservation.data_size, 16);

    auto end_address = generated_code_base_ + generated_code_offset_;

    high_mark = generated_code_offset_;

    // Store in map. It is maintained in sorted order of host PC dependent on
    // us also being append-only.
    generated_code_map_.emplace_back(
        (uint64_t(code_address - generated_code_base_) << 32) |
            generated_code_offset_,
        function_info);

    // TODO(DrChat): The following code doesn't really need to be under the
    // global lock except for PlaceCode (but it depends on the previous code
    // already being ran)

    // If we are going above the high water mark of committed memory, commit
    // some more. It's ok if multiple threads do this, as redundant commits
    // aren't harmful.
    size_t old_commit_mark, new_commit_mark;
    do {
      old_commit_mark = generated_code_commit_mark_;
      if (high_mark <= old_commit_mark) break;

      new_commit_mark = old_commit_mark + 16 * 1024 * 1024;
      xe::memory::AllocFixed(generated_code_base_, new_commit_mark,
                             xe::memory::AllocationType::kCommit,
                             xe::memory::PageAccess::kExecuteReadWrite);
    } while (generated_code_commit_mark_.compare_exchange_weak(
        old_commit_mark, new_commit_mark));

    // Copy code.
    std::memcpy(code_address, machine_code, func_info.code_size.total);

    // Fill unused slots with 0xCC
    std::memset(tail_address, 0xCC,
                static_cast<size_t>(end_address - tail_address));

    // Notify subclasses of placed code.
    PlaceCode(guest_address, machine_code, func_info, code_address,
              unwind_reservation);
  }

#if ENABLE_VTUNE
  if (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON) {
    std::string method_name;
    if (function_info && function_info->name().size() != 0) {
      method_name = function_info->name();
    } else {
      method_name = xe::format_string("sub_%.8X", guest_address);
    }

    iJIT_Method_Load_V2 method = {0};
    method.method_id = iJIT_GetNewMethodID();
    method.method_load_address = code_address;
    method.method_size = uint32_t(code_size);
    method.method_name = const_cast<char*>(method_name.data());
    method.module_name = function_info
                             ? (char*)function_info->module()->name().c_str()
                             : nullptr;
    iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
  }
#endif

  // Now that everything is ready, fix up the indirection table.
  // Note that we do support code that doesn't have an indirection fixup, so
  // ignore those when we see them.
  if (guest_address && indirection_table_base_) {
    uint32_t* indirection_slot = reinterpret_cast<uint32_t*>(
        indirection_table_base_ + (guest_address - kIndirectionTableBase));
    *indirection_slot = uint32_t(reinterpret_cast<uint64_t>(code_address));
  }

  return code_address;
}

uint32_t X64CodeCache::PlaceData(const void* data, size_t length) {
  // Hold a lock while we bump the pointers up.
  size_t high_mark;
  uint8_t* data_address = nullptr;
  {
    auto global_lock = global_critical_region_.Acquire();

    // Reserve code.
    // Always move the code to land on 16b alignment.
    data_address = generated_code_base_ + generated_code_offset_;
    generated_code_offset_ += xe::round_up(length, 16);

    high_mark = generated_code_offset_;
  }

  // If we are going above the high water mark of committed memory, commit some
  // more. It's ok if multiple threads do this, as redundant commits aren't
  // harmful.
  size_t old_commit_mark, new_commit_mark;
  do {
    old_commit_mark = generated_code_commit_mark_;
    if (high_mark <= old_commit_mark) break;

    new_commit_mark = old_commit_mark + 16 * 1024 * 1024;
    xe::memory::AllocFixed(generated_code_base_, new_commit_mark,
                           xe::memory::AllocationType::kCommit,
                           xe::memory::PageAccess::kExecuteReadWrite);
  } while (generated_code_commit_mark_.compare_exchange_weak(old_commit_mark,
                                                             new_commit_mark));

  // Copy code.
  std::memcpy(data_address, data, length);

  return uint32_t(uintptr_t(data_address));
}

GuestFunction* X64CodeCache::LookupFunction(uint64_t host_pc) {
  uint32_t key = uint32_t(host_pc - kGeneratedCodeBase);
  void* fn_entry = std::bsearch(
      &key, generated_code_map_.data(), generated_code_map_.size() + 1,
      sizeof(std::pair<uint32_t, Function*>),
      [](const void* key_ptr, const void* element_ptr) {
        auto key = *reinterpret_cast<const uint32_t*>(key_ptr);
        auto element =
            reinterpret_cast<const std::pair<uint64_t, GuestFunction*>*>(
                element_ptr);
        if (key < (element->first >> 32)) {
          return -1;
        } else if (key > uint32_t(element->first)) {
          return 1;
        } else {
          return 0;
        }
      });
  if (fn_entry) {
    return reinterpret_cast<const std::pair<uint64_t, GuestFunction*>*>(
               fn_entry)
        ->second;
  } else {
    return nullptr;
  }
}

}  // namespace x64
}  // namespace backend
}  // namespace cpu
}  // namespace xe
<|endoftext|>


<commit_before>// coding: utf-8
/* Copyright (c) 2014, Roboterclub Aachen e.V.
 * All Rights Reserved.
 *
 * The file is part of the xpcc library and is released under the 3-clause BSD
 * license. See the file `LICENSE` for the full license governing this code.
 */
// ----------------------------------------------------------------------------

#ifndef XPCC_COROUTINE_HPP
#define XPCC_COROUTINE_HPP

#include "macros.hpp"
#include <xpcc/utils/arithmetic_traits.hpp>

namespace xpcc
{

namespace co
{

/// @cond
/// State of a coroutine.
enum State
{
	// reasons to stop
	Stop = 0,			///< Coroutine finished
	NestingError = 1,	///< Nested Coroutine has run out of nesting levels

	// reasons to wait
	WrongContext = 2,	///< Coroutine already running in a different context
	WrongState = 3,		///< Another coroutine of the same class is already running in this context

	// reasons to keep running
	Running = 4,		///< Coroutine is running
};
/// @endcond

/// All Coroutines return an encapsulated result type.
template < typename T >
struct Result
{
	/// Return only the `state`. The `result` will be initialized by it's default constructor.
	Result(uint8_t state) : state(state) {}
	/// Return `state` and valid `result`.
	Result(uint8_t state, T result) : state(state), result(result) {}
	/// The `co::State`.
	uint8_t state;
	/// Custom return value.
	T result;
};
/// @cond
/// void is not an object type
template <>
struct Result<void>
{
	/// Return only the `state`. There is no result.
	Result(uint8_t state) : state(state) {}
	/// Constructor with dummy result needed by the `CO_CALL_BLOCKING` macro.
	Result(uint8_t state, uint8_t /*dummy_result*/) : state(state) {}
	// This anonymous union reduces the size to only 1 byte, instead of two
	// `CO_CALL_BLOCKING` will still return something, but it will be either 0 or 1 (`Stop` or `NestingError`).
	union
	{
		/// The `co::State`.
		uint8_t state;
		/// Dummy result needed by the `CO_CALL_BLOCKING` macro.
		uint8_t result;
	};
};
/// @endcond

/**
 * This is the base class which must be inherited from for using
 * coroutines in your class.
 *
 * You are responsible to choosing the right nesting depth!
 * This class will guard itself against calling another coroutine at too
 * deep a nesting level and inform you gently of this by returning
 * `xpcc::co::NestingError` from your called `coroutine(ctx)`.
 * It is then up to you to recognise this in your program design
 * and increase the nesting depth or rethink your code.
 *
 * Be aware that only one coroutine of the same object can run at the
 * same time. Even if you call another coroutine, it will simply not
 * run until the conflicting coroutine finished.
 *
 * Each coroutine requires a context pointer, which is used to ensure the
 * coroutine only executes in the context that it was originally started from.
 * If you call a coroutine in a different context, it will return
 * `xpcc::co::WrongContext`.
 * Similarly, if you call a different coroutine of the same class in
 * the same context, while another coroutine is running, it will return
 * `xpcc::co::WrongState`.
 * Using the `CO_CALL(coroutine(ctx))` macro, you can wait for these
 * coroutines to become available and then run them, so you usually do
 * not need to worry about those cases.
 *
 * You may exit and return a value by using `CO_RETURN(value)` or
 * return the result of another coroutine using `CO_RETURN_CALL(coroutine(ctx))`.
 * This return value is wrapped in a `xpcc::co::Result<Type>` struct
 * and transparently returned by the `CO_CALL` macro so it can be used
 * to influence your program flow.
 * If the coroutine reaches `CO_END()` it will exit automatically,
 * with the result of `0` cast to the return type.
 * Should you wish to return a value at the end, you may use
 * `CO_END_RETURN(value)`.
 * You may also return the result of another coroutine using
 * `CO_END_RETURN_CALL(coroutine(ctx))`.
 *
 * @ingroup	coroutine
 * @author	Niklas Hauser
 * @tparam	Depth	maximum nesting depth: the maximum number of
 * 					coroutines that are called within coroutines (should be <128).
 */
template< uint8_t Depth >
class NestedCoroutine
{
	/// Used to store a coroutines's position (what Dunkels calls a
	/// "local continuation").
	typedef uint8_t CoState;
protected:
	/// Construct a new class with nested coroutines
	NestedCoroutine()
	:	coLevel(0), coContext(0)
	{
		for (CoState &level : coStateArray)
		{
			level = CoStopped;
		}
	}

public:
	/// Force all coroutines to stop running at the current nesting level
	inline void
	stopCoroutine()
	{
		uint_fast8_t level = coLevel;
		while (level < Depth + 1)
		{
			coStateArray[level++] = CoStopped;
		}
		if (coLevel == 0)
			coContext = 0;
	}

	/// @return	`true` if a coroutine is running at the current nesting level, else `false`
	bool inline
	isCoroutineRunning() const
	{
		return !isStoppedCo();
	}

	/// @return the nesting depth in the current coroutine, or -1 if called outside any coroutine
	int8_t inline
	getCoroutineDepth() const
	{
		return static_cast<int8_t>(coLevel) - 1;
	}

#ifdef __DOXYGEN__
	/// @cond
	/**
	 * Run the coroutine.
	 *
	 * You need to implement this method in you subclass yourself.
	 *
	 * @return	>`NestingError` if still running, <=`NestingError` if it has finished.
	 */
	xpcc::co::Result< ReturnType >
	coroutine(void *ctx, ...);
	/// @endcond
#endif

protected:
	/// @cond

	/// increases nesting level, call this in the switch statement!
	/// @return current state before increasing nesting level
	CoState inline
	pushCo()
	{
		return coStateArray[coLevel++];
	}

	/// always call this before returning from the run function!
	/// decreases nesting level
	void inline
	popCo()
	{
		coLevel--;
	}

	// invalidates the parent nesting level
	// @warning	be aware in which nesting level you call this! (before popCo()!)
	void inline
	stopCo()
	{
		coStateArray[coLevel-1] = CoStopped;
		if (coLevel == 1)
			coContext = 0;
	}

	/// sets the state of the parent nesting level
	/// @warning	be aware in which nesting level you call this! (before popCo()!)
	void inline
	setCo(CoState state)
	{
		coStateArray[coLevel-1] = state;
	}

	/// @return `true` if the nesting depth allows for another level.
	/// @warning	be aware in which nesting level you call this! (before pushCo()!)
	bool inline
	nestingOkCo() const
	{
		return (coLevel < Depth + 1);
	}

	/// @return	`true` if `stopCo()` has been called before
	bool inline
	isStoppedCo() const
	{
		return (coStateArray[coLevel] == CoStopped);
	}

	/// @return `true` if the coroutine is called in the same context, or the context is not set
	///			`false` if the coroutine is claimed by another context
	bool inline
	beginCo(void *ctx)
	{
		// only one comparison, if this coroutine is called in the same context
		if (ctx == coContext)
			return true;

		// two comparisons + assignment, if this coroutine is called for the first time
		if (coContext == 0)
		{
			coContext = ctx;
			return true;
		}

		return false;
	}

public:
	static constexpr CoState CoStopped = static_cast<CoState>(0);
	/// @endcond
private:
	uint8_t coLevel;
	CoState coStateArray[Depth+1];
	void *coContext;
};

// ----------------------------------------------------------------------------
// we won't document the specialisation again
/// @cond
template <>
class NestedCoroutine<0>
{
	typedef uint8_t CoState;
protected:
	NestedCoroutine() :
		coState(CoStopped), coLevel(-1), coContext(0)
	{
	}

public:
	void inline
	stopCoroutine()
	{
		this->stopCo();
	}

	bool inline
	isCoroutineRunning() const
	{
		return !isStoppedCo();
	}

	int8_t inline
	getCoroutineDepth() const
	{
		return coLevel;
	}

protected:
	CoState inline
	pushCo()
	{
		coLevel = 0;
		return coState;
	}

	void inline
	popCo()
	{
		coLevel = -1;
	}

	void inline
	stopCo()
	{
		coState = CoStopped;
		coContext = 0;
	}

	bool inline
	nestingOkCo() const
	{
		return (coLevel != 0);
	}

	void inline
	setCo(CoState state)
	{
		coState = state;
	}

	bool inline
	isStoppedCo() const
	{
		return (coState == CoStopped);
	}

	bool inline
	beginCo(void *ctx)
	{
		if (ctx == coContext)
			return true;

		if (coContext == 0)
		{
			coContext = ctx;
			return true;
		}

		return false;
	}

public:
	static constexpr CoState CoStopped = static_cast<CoState>(0);
private:
	CoState coState;
	int8_t coLevel;
	void *coContext;
};
/// @endcond

typedef NestedCoroutine<0> Coroutine;

} // namespace co

} // namespace xpcc

#endif // XPCC_COROUTINE_HPP
<commit_msg>Coroutine: Add ability to disable nesting level depth checking.<commit_after>// coding: utf-8
/* Copyright (c) 2014, Roboterclub Aachen e.V.
 * All Rights Reserved.
 *
 * The file is part of the xpcc library and is released under the 3-clause BSD
 * license. See the file `LICENSE` for the full license governing this code.
 */
// ----------------------------------------------------------------------------

#ifndef XPCC_COROUTINE_HPP
#define XPCC_COROUTINE_HPP

#include "macros.hpp"
#include <xpcc/utils/arithmetic_traits.hpp>

#ifdef __DOXYGEN__

/**
 * Nested Coroutines protect against memory corruption by checking if the nesting level
 * is within the allocated nesting level depth.
 * If the allocated nesting level is exceeded, the coroutine does not execute, but returns
 * the `xpcc::co::NestingError` state value.
 * However, the `PT_CALL()` or `CO_CALL()` macros are not constructed to handle this error and
 * will interpret this error as a normal coroutine stop and therefore immediately continue program
 * execution.
 *
 * Since the required nesting depth of a nested coroutine can be known before runtime
 * by looking at the source code and counting the nesting levels, this check acts only as a
 * protection against executing random code, when entering too many levels.
 * So instead of the entire program crashing, the coroutine simply does not execute at all,
 * which can make it easier to track down the problem too few allocated nesting levels.
 *
 * You as a programmer are responible for allocating the correct amount of nesting levels!
 * However, if you are sure that you have counted the levels correctly and your code is
 * not breaking, you may remove this check from all coroutines in your `project.cfg`:
 *
 * [defines]
 * XPCC_COROUTINE_CHECK_NESTING_DEPTH = false
 *
 * @see	NestedCoroutine
 * @ingroup	coroutine
 */
#define XPCC_COROUTINE_CHECK_NESTING_DEPTH	true

#else
// by default we check all nesting level depths
#	ifndef	XPCC_COROUTINE_CHECK_NESTING_DEPTH
#		define XPCC_COROUTINE_CHECK_NESTING_DEPTH	true
#	endif
#endif

namespace xpcc
{

namespace co
{

/// @cond
/// State of a coroutine.
enum State
{
	// reasons to stop
	Stop = 0,			///< Coroutine finished
	NestingError = 1,	///< Nested Coroutine has run out of nesting levels

	// reasons to wait
	WrongContext = 2,	///< Coroutine already running in a different context
	WrongState = 3,		///< Another coroutine of the same class is already running in this context

	// reasons to keep running
	Running = 4,		///< Coroutine is running
};
/// @endcond

/// All Coroutines return an encapsulated result type.
template < typename T >
struct Result
{
	/// Return only the `state`. The `result` will be initialized by it's default constructor.
	Result(uint8_t state) : state(state) {}
	/// Return `state` and valid `result`.
	Result(uint8_t state, T result) : state(state), result(result) {}
	/// The `co::State`.
	uint8_t state;
	/// Custom return value.
	T result;
};
/// @cond
/// void is not an object type
template <>
struct Result<void>
{
	/// Return only the `state`. There is no result.
	Result(uint8_t state) : state(state) {}
	/// Constructor with dummy result needed by the `CO_CALL_BLOCKING` macro.
	Result(uint8_t state, uint8_t /*dummy_result*/) : state(state) {}
	// This anonymous union reduces the size to only 1 byte, instead of two
	// `CO_CALL_BLOCKING` will still return something, but it will be either 0 or 1 (`Stop` or `NestingError`).
	union
	{
		/// The `co::State`.
		uint8_t state;
		/// Dummy result needed by the `CO_CALL_BLOCKING` macro.
		uint8_t result;
	};
};
/// @endcond

/**
 * This is the base class which must be inherited from for using
 * coroutines in your class.
 *
 * You are responsible to choosing the right nesting depth!
 * This class will guard itself against calling another coroutine at too
 * deep a nesting level and inform you gently of this by returning
 * `xpcc::co::NestingError` from your called `coroutine(ctx)`.
 * It is then up to you to recognise this in your program design
 * and increase the nesting depth or rethink your code.
 *
 * Be aware that only one coroutine of the same object can run at the
 * same time. Even if you call another coroutine, it will simply not
 * run until the conflicting coroutine finished.
 *
 * Each coroutine requires a context pointer, which is used to ensure the
 * coroutine only executes in the context that it was originally started from.
 * If you call a coroutine in a different context, it will return
 * `xpcc::co::WrongContext`.
 * Similarly, if you call a different coroutine of the same class in
 * the same context, while another coroutine is running, it will return
 * `xpcc::co::WrongState`.
 * Using the `CO_CALL(coroutine(ctx))` macro, you can wait for these
 * coroutines to become available and then run them, so you usually do
 * not need to worry about those cases.
 *
 * You may exit and return a value by using `CO_RETURN(value)` or
 * return the result of another coroutine using `CO_RETURN_CALL(coroutine(ctx))`.
 * This return value is wrapped in a `xpcc::co::Result<Type>` struct
 * and transparently returned by the `CO_CALL` macro so it can be used
 * to influence your program flow.
 * If the coroutine reaches `CO_END()` it will exit automatically,
 * with the result of `0` cast to the return type.
 * Should you wish to return a value at the end, you may use
 * `CO_END_RETURN(value)`.
 * You may also return the result of another coroutine using
 * `CO_END_RETURN_CALL(coroutine(ctx))`.
 *
 * @ingroup	coroutine
 * @author	Niklas Hauser
 * @tparam	Depth	maximum nesting depth: the maximum number of
 * 					coroutines that are called within coroutines (should be <128).
 */
template< uint8_t Depth >
class NestedCoroutine
{
	/// Used to store a coroutines's position (what Dunkels calls a
	/// "local continuation").
	typedef uint8_t CoState;
protected:
	/// Construct a new class with nested coroutines
	NestedCoroutine()
	:	coLevel(0), coContext(0)
	{
		for (CoState &level : coStateArray)
		{
			level = CoStopped;
		}
	}

public:
	/// Force all coroutines to stop running at the current nesting level
	inline void
	stopCoroutine()
	{
		uint_fast8_t level = coLevel;
		while (level < Depth + 1)
		{
			coStateArray[level++] = CoStopped;
		}
		if (coLevel == 0)
			coContext = 0;
	}

	/// @return	`true` if a coroutine is running at the current nesting level, else `false`
	bool inline
	isCoroutineRunning() const
	{
		return !isStoppedCo();
	}

	/// @return the nesting depth in the current coroutine, or -1 if called outside any coroutine
	int8_t inline
	getCoroutineDepth() const
	{
		return static_cast<int8_t>(coLevel) - 1;
	}

#ifdef __DOXYGEN__
	/// @cond
	/**
	 * Run the coroutine.
	 *
	 * You need to implement this method in you subclass yourself.
	 *
	 * @return	>`NestingError` if still running, <=`NestingError` if it has finished.
	 */
	xpcc::co::Result< ReturnType >
	coroutine(void *ctx, ...);
	/// @endcond
#endif

protected:
	/// @cond

	/// increases nesting level, call this in the switch statement!
	/// @return current state before increasing nesting level
	CoState inline
	pushCo()
	{
		return coStateArray[coLevel++];
	}

	/// always call this before returning from the run function!
	/// decreases nesting level
	void inline
	popCo()
	{
		coLevel--;
	}

	// invalidates the parent nesting level
	// @warning	be aware in which nesting level you call this! (before popCo()!)
	void inline
	stopCo()
	{
		coStateArray[coLevel-1] = CoStopped;
		if (coLevel == 1)
			coContext = 0;
	}

	/// sets the state of the parent nesting level
	/// @warning	be aware in which nesting level you call this! (before popCo()!)
	void inline
	setCo(CoState state)
	{
		coStateArray[coLevel-1] = state;
	}

	/// @return `true` if the nesting depth allows for another level.
	/// @warning	be aware in which nesting level you call this! (before pushCo()!)
	bool inline
	nestingOkCo() const
	{
#if XPCC_COROUTINE_CHECK_NESTING_DEPTH
		return (coLevel < Depth + 1);
#else
		return true;
#endif
	}

	/// @return	`true` if `stopCo()` has been called before
	bool inline
	isStoppedCo() const
	{
		return (coStateArray[coLevel] == CoStopped);
	}

	/// @return `true` if the coroutine is called in the same context, or the context is not set
	///			`false` if the coroutine is claimed by another context
	bool inline
	beginCo(void *ctx)
	{
		// only one comparison, if this coroutine is called in the same context
		if (ctx == coContext)
			return true;

		// two comparisons + assignment, if this coroutine is called for the first time
		if (coContext == 0)
		{
			coContext = ctx;
			return true;
		}

		return false;
	}

public:
	static constexpr CoState CoStopped = static_cast<CoState>(0);
	/// @endcond
private:
	uint8_t coLevel;
	CoState coStateArray[Depth+1];
	void *coContext;
};

// ----------------------------------------------------------------------------
// we won't document the specialisation again
/// @cond
template <>
class NestedCoroutine<0>
{
	typedef uint8_t CoState;
protected:
	NestedCoroutine() :
		coState(CoStopped), coLevel(-1), coContext(0)
	{
	}

public:
	void inline
	stopCoroutine()
	{
		this->stopCo();
	}

	bool inline
	isCoroutineRunning() const
	{
		return !isStoppedCo();
	}

	int8_t inline
	getCoroutineDepth() const
	{
		return coLevel;
	}

protected:
	CoState inline
	pushCo()
	{
		coLevel = 0;
		return coState;
	}

	void inline
	popCo()
	{
		coLevel = -1;
	}

	void inline
	stopCo()
	{
		coState = CoStopped;
		coContext = 0;
	}

	bool inline
	nestingOkCo() const
	{
#if XPCC_COROUTINE_CHECK_NESTING_DEPTH
		return (coLevel != 0);
#else
		return true;
#endif
	}

	void inline
	setCo(CoState state)
	{
		coState = state;
	}

	bool inline
	isStoppedCo() const
	{
		return (coState == CoStopped);
	}

	bool inline
	beginCo(void *ctx)
	{
		if (ctx == coContext)
			return true;

		if (coContext == 0)
		{
			coContext = ctx;
			return true;
		}

		return false;
	}

public:
	static constexpr CoState CoStopped = static_cast<CoState>(0);
private:
	CoState coState;
	int8_t coLevel;
	void *coContext;
};
/// @endcond

typedef NestedCoroutine<0> Coroutine;

} // namespace co

} // namespace xpcc

#endif // XPCC_COROUTINE_HPP
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: namingservice.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 17:31:45 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_stoc.hxx"

#include <hash_map>

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _UNO_DISPATCHER_H_
#include <uno/dispatcher.h>
#endif
#ifndef _UNO_MAPPING_HXX_
#include <uno/mapping.hxx>
#endif

#ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
#include <cppuhelper/queryinterface.hxx>
#endif
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif
#ifndef _CPPUHELPER_COMPONENT_HXX_
#include <cppuhelper/component.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif
#ifndef _CPPUHELPER_IMPLEMENTATIONENTRY_HXX_
#include <cppuhelper/implementationentry.hxx>
#endif

#include <com/sun/star/uno/XNamingService.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>

using namespace cppu;
using namespace rtl;
using namespace osl;
using namespace std;

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;

#define SERVICENAME "com.sun.star.uno.NamingService"
#define IMPLNAME    "com.sun.star.comp.stoc.NamingService"

namespace stoc_namingservice
{
static rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;

static Sequence< OUString > ns_getSupportedServiceNames()
{
    static Sequence < OUString > *pNames = 0;
    if( ! pNames )
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if( !pNames )
        {
            static Sequence< OUString > seqNames(1);
            seqNames.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM(SERVICENAME));
            pNames = &seqNames;
        }
    }
    return *pNames;
}

static OUString ns_getImplementationName()
{
    static OUString *pImplName = 0;
    if( ! pImplName )
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if( ! pImplName )
        {
            static OUString implName( RTL_CONSTASCII_USTRINGPARAM( IMPLNAME ) );
            pImplName = &implName;
        }
    }
    return *pImplName;
}

struct equalOWString_Impl
{
  sal_Bool operator()(const OUString & s1, const OUString & s2) const
        { return s1 == s2; }
};

struct hashOWString_Impl
{
    size_t operator()(const OUString & rName) const
        { return rName.hashCode(); }
};

typedef hash_map
<
    OUString,
    Reference<XInterface >,
    hashOWString_Impl,
    equalOWString_Impl
> HashMap_OWString_Interface;

//==================================================================================================
class NamingService_Impl
    : public WeakImplHelper2 < XServiceInfo, XNamingService >
{
    Mutex                               aMutex;
    HashMap_OWString_Interface          aMap;
public:
    NamingService_Impl();
    ~NamingService_Impl();

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName()
    throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName )
    throw(::com::sun::star::uno::RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
    throw(::com::sun::star::uno::RuntimeException);
    static Sequence< OUString > SAL_CALL getSupportedServiceNames_Static()
    {
        OUString aStr( OUString::createFromAscii( SERVICENAME ) );
        return Sequence< OUString >( &aStr, 1 );
    }

    virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getRegisteredObject( const ::rtl::OUString& Name ) throw(Exception, RuntimeException);
    virtual void SAL_CALL registerObject( const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Object ) throw(Exception, RuntimeException);
    virtual void SAL_CALL revokeObject( const ::rtl::OUString& Name ) throw(Exception, RuntimeException);
};

//==================================================================================================
static Reference<XInterface> SAL_CALL NamingService_Impl_create( const Reference<XComponentContext> & )
{
    return *new NamingService_Impl();
}

//==================================================================================================
NamingService_Impl::NamingService_Impl()
{
    g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}

//==================================================================================================
NamingService_Impl::~NamingService_Impl()
{
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XServiceInfo
OUString NamingService_Impl::getImplementationName()
    throw(::com::sun::star::uno::RuntimeException)
{
    return ns_getImplementationName();
}

// XServiceInfo
sal_Bool NamingService_Impl::supportsService( const OUString & rServiceName )
    throw(::com::sun::star::uno::RuntimeException)
{
    const Sequence< OUString > & rSNL = getSupportedServiceNames();
    const OUString * pArray = rSNL.getConstArray();
    for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
    {
        if (pArray[nPos] == rServiceName)
            return sal_True;
    }
    return sal_False;
}

// XServiceInfo
Sequence< OUString > NamingService_Impl::getSupportedServiceNames()
    throw(::com::sun::star::uno::RuntimeException)
{
    return ns_getSupportedServiceNames();
}

// XServiceInfo
Reference< XInterface > NamingService_Impl::getRegisteredObject( const OUString& Name ) throw(Exception, RuntimeException)
{
    Guard< Mutex > aGuard( aMutex );
    Reference< XInterface > xRet;
    HashMap_OWString_Interface::iterator aIt = aMap.find( Name );
    if( aIt != aMap.end() )
        xRet = (*aIt).second;
    return xRet;
}

// XServiceInfo
void NamingService_Impl::registerObject( const OUString& Name, const Reference< XInterface >& Object ) throw(Exception, RuntimeException)
{
    Guard< Mutex > aGuard( aMutex );
    aMap[ Name ] = Object;
}

// XServiceInfo
void NamingService_Impl::revokeObject( const OUString& Name ) throw(Exception, RuntimeException)
{
    Guard< Mutex > aGuard( aMutex );
    aMap.erase( Name );
}

}

using namespace stoc_namingservice;
static struct ImplementationEntry g_entries[] =
{
    {
        NamingService_Impl_create, ns_getImplementationName,
        ns_getSupportedServiceNames, createSingleComponentFactory,
        &g_moduleCount.modCnt , 0
    },
    { 0, 0, 0, 0, 0, 0 }
};

extern "C"
{
sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
{
    return g_moduleCount.canUnload( &g_moduleCount , pTime );
}

//==================================================================================================
void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}
//==================================================================================================
sal_Bool SAL_CALL component_writeInfo(
    void * pServiceManager, void * pRegistryKey )
{
    return component_writeInfoHelper( pServiceManager, pRegistryKey, g_entries );
}
//==================================================================================================
void * SAL_CALL component_getFactory(
    const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
    return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
}
}
<commit_msg>INTEGRATION: CWS changefileheader (1.8.56); FILE MERGED 2008/04/01 15:42:26 thb 1.8.56.2: #i85898# Stripping all external header guards 2008/03/31 07:26:10 rt 1.8.56.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: namingservice.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_stoc.hxx"

#include <hash_map>
#include <osl/mutex.hxx>
#include <osl/diagnose.h>
#include <uno/dispatcher.h>
#include <uno/mapping.hxx>
#include <cppuhelper/queryinterface.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/factory.hxx>
#include <cppuhelper/component.hxx>
#include <cppuhelper/implbase2.hxx>
#ifndef _CPPUHELPER_IMPLEMENTATIONENTRY_HXX_
#include <cppuhelper/implementationentry.hxx>
#endif

#include <com/sun/star/uno/XNamingService.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>

using namespace cppu;
using namespace rtl;
using namespace osl;
using namespace std;

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;

#define SERVICENAME "com.sun.star.uno.NamingService"
#define IMPLNAME    "com.sun.star.comp.stoc.NamingService"

namespace stoc_namingservice
{
static rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;

static Sequence< OUString > ns_getSupportedServiceNames()
{
    static Sequence < OUString > *pNames = 0;
    if( ! pNames )
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if( !pNames )
        {
            static Sequence< OUString > seqNames(1);
            seqNames.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM(SERVICENAME));
            pNames = &seqNames;
        }
    }
    return *pNames;
}

static OUString ns_getImplementationName()
{
    static OUString *pImplName = 0;
    if( ! pImplName )
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if( ! pImplName )
        {
            static OUString implName( RTL_CONSTASCII_USTRINGPARAM( IMPLNAME ) );
            pImplName = &implName;
        }
    }
    return *pImplName;
}

struct equalOWString_Impl
{
  sal_Bool operator()(const OUString & s1, const OUString & s2) const
        { return s1 == s2; }
};

struct hashOWString_Impl
{
    size_t operator()(const OUString & rName) const
        { return rName.hashCode(); }
};

typedef hash_map
<
    OUString,
    Reference<XInterface >,
    hashOWString_Impl,
    equalOWString_Impl
> HashMap_OWString_Interface;

//==================================================================================================
class NamingService_Impl
    : public WeakImplHelper2 < XServiceInfo, XNamingService >
{
    Mutex                               aMutex;
    HashMap_OWString_Interface          aMap;
public:
    NamingService_Impl();
    ~NamingService_Impl();

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName()
    throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName )
    throw(::com::sun::star::uno::RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
    throw(::com::sun::star::uno::RuntimeException);
    static Sequence< OUString > SAL_CALL getSupportedServiceNames_Static()
    {
        OUString aStr( OUString::createFromAscii( SERVICENAME ) );
        return Sequence< OUString >( &aStr, 1 );
    }

    virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getRegisteredObject( const ::rtl::OUString& Name ) throw(Exception, RuntimeException);
    virtual void SAL_CALL registerObject( const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Object ) throw(Exception, RuntimeException);
    virtual void SAL_CALL revokeObject( const ::rtl::OUString& Name ) throw(Exception, RuntimeException);
};

//==================================================================================================
static Reference<XInterface> SAL_CALL NamingService_Impl_create( const Reference<XComponentContext> & )
{
    return *new NamingService_Impl();
}

//==================================================================================================
NamingService_Impl::NamingService_Impl()
{
    g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}

//==================================================================================================
NamingService_Impl::~NamingService_Impl()
{
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XServiceInfo
OUString NamingService_Impl::getImplementationName()
    throw(::com::sun::star::uno::RuntimeException)
{
    return ns_getImplementationName();
}

// XServiceInfo
sal_Bool NamingService_Impl::supportsService( const OUString & rServiceName )
    throw(::com::sun::star::uno::RuntimeException)
{
    const Sequence< OUString > & rSNL = getSupportedServiceNames();
    const OUString * pArray = rSNL.getConstArray();
    for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
    {
        if (pArray[nPos] == rServiceName)
            return sal_True;
    }
    return sal_False;
}

// XServiceInfo
Sequence< OUString > NamingService_Impl::getSupportedServiceNames()
    throw(::com::sun::star::uno::RuntimeException)
{
    return ns_getSupportedServiceNames();
}

// XServiceInfo
Reference< XInterface > NamingService_Impl::getRegisteredObject( const OUString& Name ) throw(Exception, RuntimeException)
{
    Guard< Mutex > aGuard( aMutex );
    Reference< XInterface > xRet;
    HashMap_OWString_Interface::iterator aIt = aMap.find( Name );
    if( aIt != aMap.end() )
        xRet = (*aIt).second;
    return xRet;
}

// XServiceInfo
void NamingService_Impl::registerObject( const OUString& Name, const Reference< XInterface >& Object ) throw(Exception, RuntimeException)
{
    Guard< Mutex > aGuard( aMutex );
    aMap[ Name ] = Object;
}

// XServiceInfo
void NamingService_Impl::revokeObject( const OUString& Name ) throw(Exception, RuntimeException)
{
    Guard< Mutex > aGuard( aMutex );
    aMap.erase( Name );
}

}

using namespace stoc_namingservice;
static struct ImplementationEntry g_entries[] =
{
    {
        NamingService_Impl_create, ns_getImplementationName,
        ns_getSupportedServiceNames, createSingleComponentFactory,
        &g_moduleCount.modCnt , 0
    },
    { 0, 0, 0, 0, 0, 0 }
};

extern "C"
{
sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
{
    return g_moduleCount.canUnload( &g_moduleCount , pTime );
}

//==================================================================================================
void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}
//==================================================================================================
sal_Bool SAL_CALL component_writeInfo(
    void * pServiceManager, void * pRegistryKey )
{
    return component_writeInfoHelper( pServiceManager, pRegistryKey, g_entries );
}
//==================================================================================================
void * SAL_CALL component_getFactory(
    const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
    return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
}
}
<|endoftext|>


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

#include "chrome/browser/browser_main.h"
#include "chrome/browser/browser_main_win.h"

#include <windows.h>
#include <shellapi.h>

#include <algorithm>

#include "app/l10n_util.h"
#include "app/l10n_util_win.h"
#include "app/win_util.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/i18n/rtl.h"
#include "base/nss_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/views/uninstall_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/winsock_init.h"
#include "net/socket/ssl_client_socket_nss_factory.h"
#include "views/focus/accelerator_handler.h"
#include "views/window/window.h"

void DidEndMainMessageLoop() {
  OleUninitialize();
}

void RecordBreakpadStatusUMA(MetricsService* metrics) {
  DWORD len = ::GetEnvironmentVariableW(
      ASCIIToWide(env_vars::kNoOOBreakpad).c_str() , NULL, 0);
  metrics->RecordBreakpadRegistration((len == 0));
  metrics->RecordBreakpadHasDebugger(TRUE == ::IsDebuggerPresent());
}

void WarnAboutMinimumSystemRequirements() {
  if (base::win::GetVersion() < base::win::VERSION_XP) {
    // Display a warning message if the user is running chrome on Windows 2000.
    const std::wstring text =
        l10n_util::GetString(IDS_UNSUPPORTED_OS_PRE_WIN_XP);
    const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
    win_util::MessageBox(NULL, text, caption,
                         MB_OK | MB_ICONWARNING | MB_TOPMOST);
  }
}

int AskForUninstallConfirmation() {
  int ret = ResultCodes::NORMAL_EXIT;
  views::Window::CreateChromeWindow(NULL, gfx::Rect(),
                                    new UninstallView(ret))->Show();
  views::AcceleratorHandler accelerator_handler;
  MessageLoopForUI::current()->Run(&accelerator_handler);
  return ret;
}

void ShowCloseBrowserFirstMessageBox() {
  const std::wstring text = l10n_util::GetString(IDS_UNINSTALL_CLOSE_APP);
  const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
  const UINT flags = MB_OK | MB_ICONWARNING | MB_TOPMOST;
  win_util::MessageBox(NULL, text, caption, flags);
}

int DoUninstallTasks(bool chrome_still_running) {
  // We want to show a warning to user (and exit) if Chrome is already running
  // *before* we show the uninstall confirmation dialog box. But while the
  // uninstall confirmation dialog is up, user might start Chrome, so we
  // check once again after user acknowledges Uninstall dialog.
  if (chrome_still_running) {
    ShowCloseBrowserFirstMessageBox();
    return ResultCodes::UNINSTALL_CHROME_ALIVE;
  }
  int ret = AskForUninstallConfirmation();
  if (Upgrade::IsBrowserAlreadyRunning()) {
    ShowCloseBrowserFirstMessageBox();
    return ResultCodes::UNINSTALL_CHROME_ALIVE;
  }

  if (ret != ResultCodes::UNINSTALL_USER_CANCEL) {
    // The following actions are just best effort.
    VLOG(1) << "Executing uninstall actions";
    if (!FirstRun::RemoveSentinel())
      VLOG(1) << "Failed to delete sentinel file.";
    // We want to remove user level shortcuts and we only care about the ones
    // created by us and not by the installer so |alternate| is false.
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER,
                                                false))
      VLOG(1) << "Failed to delete desktop shortcut.";
    if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist,
                                                    ShellUtil::CURRENT_USER))
      VLOG(1) << "Failed to delete quick launch shortcut.";
  }
  return ret;
}

// Prepares the localized strings that are going to be displayed to
// the user if the browser process dies. These strings are stored in the
// environment block so they are accessible in the early stages of the
// chrome executable's lifetime.
void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
  // Clear this var so child processes don't show the dialog by default.
  scoped_ptr<base::Environment> env(base::Environment::Create());
  env->UnSetVar(env_vars::kShowRestart);

  // For non-interactive tests we don't restart on crash.
  if (env->HasVar(env_vars::kHeadless))
    return;

  // If the known command-line test options are used we don't create the
  // environment block which means we don't get the restart dialog.
  if (parsed_command_line.HasSwitch(switches::kBrowserCrashTest) ||
      parsed_command_line.HasSwitch(switches::kBrowserAssertTest) ||
      parsed_command_line.HasSwitch(switches::kNoErrorDialogs))
    return;

  // The encoding we use for the info is "title|context|direction" where
  // direction is either env_vars::kRtlLocale or env_vars::kLtrLocale depending
  // on the current locale.
  string16 dlg_strings(l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
  dlg_strings.push_back('|');
  string16 adjusted_string(
      l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_CONTENT));
  base::i18n::AdjustStringForLocaleDirection(&adjusted_string);
  dlg_strings.append(adjusted_string);
  dlg_strings.push_back('|');
  dlg_strings.append(ASCIIToUTF16(
      base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));

  env->SetVar(env_vars::kRestartInfo, UTF16ToUTF8(dlg_strings));
}

// This method handles the --hide-icons and --show-icons command line options
// for chrome that get triggered by Windows from registry entries
// HideIconsCommand & ShowIconsCommand. Chrome doesn't support hide icons
// functionality so we just ask the users if they want to uninstall Chrome.
int HandleIconsCommands(const CommandLine &parsed_command_line) {
  if (parsed_command_line.HasSwitch(switches::kHideIcons)) {
    std::wstring cp_applet;
    base::win::Version version = base::win::GetVersion();
    if (version >= base::win::VERSION_VISTA) {
      cp_applet.assign(L"Programs and Features");  // Windows Vista and later.
    } else if (version >= base::win::VERSION_XP) {
      cp_applet.assign(L"Add/Remove Programs");  // Windows XP.
    } else {
      return ResultCodes::UNSUPPORTED_PARAM;  // Not supported
    }

    const std::wstring msg = l10n_util::GetStringF(IDS_HIDE_ICONS_NOT_SUPPORTED,
                                                   cp_applet);
    const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
    const UINT flags = MB_OKCANCEL | MB_ICONWARNING | MB_TOPMOST;
    if (IDOK == win_util::MessageBox(NULL, msg, caption, flags))
      ShellExecute(NULL, NULL, L"appwiz.cpl", NULL, NULL, SW_SHOWNORMAL);
    return ResultCodes::NORMAL_EXIT;  // Exit as we are not launching browser.
  }
  // We don't hide icons so we shouldn't do anything special to show them
  return ResultCodes::UNSUPPORTED_PARAM;
}

// Check if there is any machine level Chrome installed on the current
// machine. If yes and the current Chrome process is user level, we do not
// allow the user level Chrome to run. So we notify the user and uninstall
// user level Chrome.
bool CheckMachineLevelInstall() {
  // TODO(tommi): Check if using the default distribution is always the right
  // thing to do.
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  scoped_ptr<installer::Version> version(InstallUtil::GetChromeVersion(dist,
                                                                       true));
  if (version.get()) {
    FilePath exe_path;
    PathService::Get(base::DIR_EXE, &exe_path);
    std::wstring exe = exe_path.value();
    FilePath user_exe_path(installer::GetChromeInstallPath(false, dist));
    if (FilePath::CompareEqualIgnoreCase(exe, user_exe_path.value())) {
      const std::wstring text =
          l10n_util::GetString(IDS_MACHINE_LEVEL_INSTALL_CONFLICT);
      const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
      const UINT flags = MB_OK | MB_ICONERROR | MB_TOPMOST;
      win_util::MessageBox(NULL, text, caption, flags);
      FilePath uninstall_path(InstallUtil::GetChromeUninstallCmd(false, dist));
      CommandLine uninstall_cmd(uninstall_path);
      if (!uninstall_cmd.GetProgram().value().empty()) {
        uninstall_cmd.AppendSwitch(installer_util::switches::kForceUninstall);
        uninstall_cmd.AppendSwitch(
            installer_util::switches::kDoNotRemoveSharedItems);
        base::LaunchApp(uninstall_cmd, false, false, NULL);
      }
      return true;
    }
  }
  return false;
}

// BrowserMainPartsWin ---------------------------------------------------------

class BrowserMainPartsWin : public BrowserMainParts {
 public:
  explicit BrowserMainPartsWin(const MainFunctionParams& parameters)
      : BrowserMainParts(parameters) {}

 protected:
  virtual void PreEarlyInitialization() {
    // Initialize Winsock.
    net::EnsureWinsockInit();
  }

  virtual void PreMainMessageLoopStart() {
    OleInitialize(NULL);

    // If we're running tests (ui_task is non-null), then the ResourceBundle
    // has already been initialized.
    if (!parameters().ui_task) {
      // Override the configured locale with the user's preferred UI language.
      l10n_util::OverrideLocaleWithUILanguageList();
    }
  }

 private:
  virtual void InitializeSSL() {
    // Use NSS for SSL by default.
    // Because of a build system issue (http://crbug.com/43461), the default
    // client socket factory uses SChannel (the system SSL library) for SSL by
    // default on Windows.

    // Disabling this temporarily to test out if NSS is causing heap corruption.
#if 0
    if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
      net::ClientSocketFactory::SetSSLClientSocketFactory(
          net::SSLClientSocketNSSFactory);
      // We want to be sure to init NSPR on the main thread.
      base::EnsureNSPRInit();
    }
#endif
  }
};

// static
BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
    const MainFunctionParams& parameters) {
  return new BrowserMainPartsWin(parameters);
}
<commit_msg>Revert 69196 - Revert 69190 - Revert 68827 - Use SChannel for Windows.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser_main.h"
#include "chrome/browser/browser_main_win.h"

#include <windows.h>
#include <shellapi.h>

#include <algorithm>

#include "app/l10n_util.h"
#include "app/l10n_util_win.h"
#include "app/win_util.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/i18n/rtl.h"
#include "base/nss_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/views/uninstall_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/winsock_init.h"
#include "net/socket/ssl_client_socket_nss_factory.h"
#include "views/focus/accelerator_handler.h"
#include "views/window/window.h"

void DidEndMainMessageLoop() {
  OleUninitialize();
}

void RecordBreakpadStatusUMA(MetricsService* metrics) {
  DWORD len = ::GetEnvironmentVariableW(
      ASCIIToWide(env_vars::kNoOOBreakpad).c_str() , NULL, 0);
  metrics->RecordBreakpadRegistration((len == 0));
  metrics->RecordBreakpadHasDebugger(TRUE == ::IsDebuggerPresent());
}

void WarnAboutMinimumSystemRequirements() {
  if (base::win::GetVersion() < base::win::VERSION_XP) {
    // Display a warning message if the user is running chrome on Windows 2000.
    const std::wstring text =
        l10n_util::GetString(IDS_UNSUPPORTED_OS_PRE_WIN_XP);
    const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
    win_util::MessageBox(NULL, text, caption,
                         MB_OK | MB_ICONWARNING | MB_TOPMOST);
  }
}

int AskForUninstallConfirmation() {
  int ret = ResultCodes::NORMAL_EXIT;
  views::Window::CreateChromeWindow(NULL, gfx::Rect(),
                                    new UninstallView(ret))->Show();
  views::AcceleratorHandler accelerator_handler;
  MessageLoopForUI::current()->Run(&accelerator_handler);
  return ret;
}

void ShowCloseBrowserFirstMessageBox() {
  const std::wstring text = l10n_util::GetString(IDS_UNINSTALL_CLOSE_APP);
  const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
  const UINT flags = MB_OK | MB_ICONWARNING | MB_TOPMOST;
  win_util::MessageBox(NULL, text, caption, flags);
}

int DoUninstallTasks(bool chrome_still_running) {
  // We want to show a warning to user (and exit) if Chrome is already running
  // *before* we show the uninstall confirmation dialog box. But while the
  // uninstall confirmation dialog is up, user might start Chrome, so we
  // check once again after user acknowledges Uninstall dialog.
  if (chrome_still_running) {
    ShowCloseBrowserFirstMessageBox();
    return ResultCodes::UNINSTALL_CHROME_ALIVE;
  }
  int ret = AskForUninstallConfirmation();
  if (Upgrade::IsBrowserAlreadyRunning()) {
    ShowCloseBrowserFirstMessageBox();
    return ResultCodes::UNINSTALL_CHROME_ALIVE;
  }

  if (ret != ResultCodes::UNINSTALL_USER_CANCEL) {
    // The following actions are just best effort.
    VLOG(1) << "Executing uninstall actions";
    if (!FirstRun::RemoveSentinel())
      VLOG(1) << "Failed to delete sentinel file.";
    // We want to remove user level shortcuts and we only care about the ones
    // created by us and not by the installer so |alternate| is false.
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER,
                                                false))
      VLOG(1) << "Failed to delete desktop shortcut.";
    if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist,
                                                    ShellUtil::CURRENT_USER))
      VLOG(1) << "Failed to delete quick launch shortcut.";
  }
  return ret;
}

// Prepares the localized strings that are going to be displayed to
// the user if the browser process dies. These strings are stored in the
// environment block so they are accessible in the early stages of the
// chrome executable's lifetime.
void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
  // Clear this var so child processes don't show the dialog by default.
  scoped_ptr<base::Environment> env(base::Environment::Create());
  env->UnSetVar(env_vars::kShowRestart);

  // For non-interactive tests we don't restart on crash.
  if (env->HasVar(env_vars::kHeadless))
    return;

  // If the known command-line test options are used we don't create the
  // environment block which means we don't get the restart dialog.
  if (parsed_command_line.HasSwitch(switches::kBrowserCrashTest) ||
      parsed_command_line.HasSwitch(switches::kBrowserAssertTest) ||
      parsed_command_line.HasSwitch(switches::kNoErrorDialogs))
    return;

  // The encoding we use for the info is "title|context|direction" where
  // direction is either env_vars::kRtlLocale or env_vars::kLtrLocale depending
  // on the current locale.
  string16 dlg_strings(l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
  dlg_strings.push_back('|');
  string16 adjusted_string(
      l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_CONTENT));
  base::i18n::AdjustStringForLocaleDirection(&adjusted_string);
  dlg_strings.append(adjusted_string);
  dlg_strings.push_back('|');
  dlg_strings.append(ASCIIToUTF16(
      base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));

  env->SetVar(env_vars::kRestartInfo, UTF16ToUTF8(dlg_strings));
}

// This method handles the --hide-icons and --show-icons command line options
// for chrome that get triggered by Windows from registry entries
// HideIconsCommand & ShowIconsCommand. Chrome doesn't support hide icons
// functionality so we just ask the users if they want to uninstall Chrome.
int HandleIconsCommands(const CommandLine &parsed_command_line) {
  if (parsed_command_line.HasSwitch(switches::kHideIcons)) {
    std::wstring cp_applet;
    base::win::Version version = base::win::GetVersion();
    if (version >= base::win::VERSION_VISTA) {
      cp_applet.assign(L"Programs and Features");  // Windows Vista and later.
    } else if (version >= base::win::VERSION_XP) {
      cp_applet.assign(L"Add/Remove Programs");  // Windows XP.
    } else {
      return ResultCodes::UNSUPPORTED_PARAM;  // Not supported
    }

    const std::wstring msg = l10n_util::GetStringF(IDS_HIDE_ICONS_NOT_SUPPORTED,
                                                   cp_applet);
    const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
    const UINT flags = MB_OKCANCEL | MB_ICONWARNING | MB_TOPMOST;
    if (IDOK == win_util::MessageBox(NULL, msg, caption, flags))
      ShellExecute(NULL, NULL, L"appwiz.cpl", NULL, NULL, SW_SHOWNORMAL);
    return ResultCodes::NORMAL_EXIT;  // Exit as we are not launching browser.
  }
  // We don't hide icons so we shouldn't do anything special to show them
  return ResultCodes::UNSUPPORTED_PARAM;
}

// Check if there is any machine level Chrome installed on the current
// machine. If yes and the current Chrome process is user level, we do not
// allow the user level Chrome to run. So we notify the user and uninstall
// user level Chrome.
bool CheckMachineLevelInstall() {
  // TODO(tommi): Check if using the default distribution is always the right
  // thing to do.
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  scoped_ptr<installer::Version> version(InstallUtil::GetChromeVersion(dist,
                                                                       true));
  if (version.get()) {
    FilePath exe_path;
    PathService::Get(base::DIR_EXE, &exe_path);
    std::wstring exe = exe_path.value();
    FilePath user_exe_path(installer::GetChromeInstallPath(false, dist));
    if (FilePath::CompareEqualIgnoreCase(exe, user_exe_path.value())) {
      const std::wstring text =
          l10n_util::GetString(IDS_MACHINE_LEVEL_INSTALL_CONFLICT);
      const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
      const UINT flags = MB_OK | MB_ICONERROR | MB_TOPMOST;
      win_util::MessageBox(NULL, text, caption, flags);
      FilePath uninstall_path(InstallUtil::GetChromeUninstallCmd(false, dist));
      CommandLine uninstall_cmd(uninstall_path);
      if (!uninstall_cmd.GetProgram().value().empty()) {
        uninstall_cmd.AppendSwitch(installer_util::switches::kForceUninstall);
        uninstall_cmd.AppendSwitch(
            installer_util::switches::kDoNotRemoveSharedItems);
        base::LaunchApp(uninstall_cmd, false, false, NULL);
      }
      return true;
    }
  }
  return false;
}

// BrowserMainPartsWin ---------------------------------------------------------

class BrowserMainPartsWin : public BrowserMainParts {
 public:
  explicit BrowserMainPartsWin(const MainFunctionParams& parameters)
      : BrowserMainParts(parameters) {}

 protected:
  virtual void PreEarlyInitialization() {
    // Initialize Winsock.
    net::EnsureWinsockInit();
  }

  virtual void PreMainMessageLoopStart() {
    OleInitialize(NULL);

    // If we're running tests (ui_task is non-null), then the ResourceBundle
    // has already been initialized.
    if (!parameters().ui_task) {
      // Override the configured locale with the user's preferred UI language.
      l10n_util::OverrideLocaleWithUILanguageList();
    }
  }

 private:
  virtual void InitializeSSL() {
    // Use NSS for SSL by default.
    // Because of a build system issue (http://crbug.com/43461), the default
    // client socket factory uses SChannel (the system SSL library) for SSL by
    // default on Windows.
    if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
      net::ClientSocketFactory::SetSSLClientSocketFactory(
          net::SSLClientSocketNSSFactory);
      // We want to be sure to init NSPR on the main thread.
      base::EnsureNSPRInit();
    }
  }
};

// static
BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
    const MainFunctionParams& parameters) {
  return new BrowserMainPartsWin(parameters);
}
<|endoftext|>


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

#include "chrome/browser/browser_shutdown.h"

#include "app/resource_bundle.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/first_run.h"
#include "chrome/browser/jankometer.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "net/dns_global.h"

#if defined(OS_WIN)
#include "chrome/browser/rlz/rlz.h"
#endif

using base::Time;
using base::TimeDelta;

namespace browser_shutdown {

Time shutdown_started_;
ShutdownType shutdown_type_ = NOT_VALID;
int shutdown_num_processes_;
int shutdown_num_processes_slow_;

bool delete_resources_on_shutdown = true;

const char* const kShutdownMsFile = "chrome_shutdown_ms.txt";

void RegisterPrefs(PrefService* local_state) {
  local_state->RegisterIntegerPref(prefs::kShutdownType, NOT_VALID);
  local_state->RegisterIntegerPref(prefs::kShutdownNumProcesses, 0);
  local_state->RegisterIntegerPref(prefs::kShutdownNumProcessesSlow, 0);
}

ShutdownType GetShutdownType() {
  return shutdown_type_;
}

void OnShutdownStarting(ShutdownType type) {
  if (shutdown_type_ != NOT_VALID)
    return;

  shutdown_type_ = type;
  // For now, we're only counting the number of renderer processes
  // since we can't safely count the number of plugin processes from this
  // thread, and we'd really like to avoid anything which might add further
  // delays to shutdown time.
  shutdown_started_ = Time::Now();

  // Call FastShutdown on all of the RenderProcessHosts.  This will be
  // a no-op in some cases, so we still need to go through the normal
  // shutdown path for the ones that didn't exit here.
  shutdown_num_processes_ = 0;
  shutdown_num_processes_slow_ = 0;
  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    ++shutdown_num_processes_;
    if (!i.GetCurrentValue()->FastShutdownIfPossible()) {
      shutdown_num_processes_slow_++;
    }

    hosts.Advance();
  }
}

#if defined(OS_WIN)
FilePath GetShutdownMsPath() {
  FilePath shutdown_ms_file;
  PathService::Get(base::DIR_TEMP, &shutdown_ms_file);
  return shutdown_ms_file.AppendASCII(kShutdownMsFile);
}
#endif

void Shutdown() {
  // Unload plugins. This needs to happen on the IO thread.
  if (g_browser_process->io_thread()) {
    g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
        NewRunnableFunction(&ChromePluginLib::UnloadAllPlugins));
  }

  // WARNING: During logoff/shutdown (WM_ENDSESSION) we may not have enough
  // time to get here. If you have something that *must* happen on end session,
  // consider putting it in BrowserProcessImpl::EndSession.
  DCHECK(g_browser_process);

  // Notifies we are going away.
  g_browser_process->shutdown_event()->Signal();

  PrefService* prefs = g_browser_process->local_state();

  chrome_browser_net::SaveHostNamesForNextStartup(prefs);
  // TODO(jar): Trimming should be done more regularly, such as every 48 hours
  // of physical time, or perhaps after 48 hours of running (excluding time
  // between sessions possibly).
  // For now, we'll just trim at shutdown.
  chrome_browser_net::TrimSubresourceReferrers();
  chrome_browser_net::SaveSubresourceReferrers(prefs);

  MetricsService* metrics = g_browser_process->metrics_service();
  if (metrics) {
    metrics->RecordCleanShutdown();
    metrics->RecordCompletedSessionEnd();
  }

  if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
    // Record the shutdown info so that we can put it into a histogram at next
    // startup.
    prefs->SetInteger(prefs::kShutdownType, shutdown_type_);
    prefs->SetInteger(prefs::kShutdownNumProcesses, shutdown_num_processes_);
    prefs->SetInteger(prefs::kShutdownNumProcessesSlow,
                      shutdown_num_processes_slow_);
  }

  prefs->SavePersistentPrefs();

#if defined(OS_WIN)
  // Cleanup any statics created by RLZ. Must be done before NotificationService
  // is destroyed.
  RLZTracker::CleanupRlz();
#endif

  // The jank'o'meter requires that the browser process has been destroyed
  // before calling UninstallJankometer().
  delete g_browser_process;
  g_browser_process = NULL;

  // Uninstall Jank-O-Meter here after the IO thread is no longer running.
  UninstallJankometer();

  if (delete_resources_on_shutdown)
    ResourceBundle::CleanupSharedInstance();

#if defined(OS_WIN)
  if (!Upgrade::IsBrowserAlreadyRunning()) {
    Upgrade::SwapNewChromeExeIfPresent();
  }

  if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
    // Measure total shutdown time as late in the process as possible
    // and then write it to a file to be read at startup.
    // We can't use prefs since all services are shutdown at this point.
    TimeDelta shutdown_delta = Time::Now() - shutdown_started_;
    std::string shutdown_ms = Int64ToString(shutdown_delta.InMilliseconds());
    int len = static_cast<int>(shutdown_ms.length()) + 1;
    FilePath shutdown_ms_file = GetShutdownMsPath();
    file_util::WriteFile(shutdown_ms_file, shutdown_ms.c_str(), len);
  }
#endif

  UnregisterURLRequestChromeJob();
}

#if defined(OS_WIN)
void ReadLastShutdownInfo() {
  FilePath shutdown_ms_file = GetShutdownMsPath();
  std::string shutdown_ms_str;
  int64 shutdown_ms = 0;
  if (file_util::ReadFileToString(shutdown_ms_file, &shutdown_ms_str))
    shutdown_ms = StringToInt64(shutdown_ms_str);
  file_util::Delete(shutdown_ms_file, false);

  PrefService* prefs = g_browser_process->local_state();
  ShutdownType type =
      static_cast<ShutdownType>(prefs->GetInteger(prefs::kShutdownType));
  int num_procs = prefs->GetInteger(prefs::kShutdownNumProcesses);
  int num_procs_slow = prefs->GetInteger(prefs::kShutdownNumProcessesSlow);
  // clear the prefs immediately so we don't pick them up on a future run
  prefs->SetInteger(prefs::kShutdownType, NOT_VALID);
  prefs->SetInteger(prefs::kShutdownNumProcesses, 0);
  prefs->SetInteger(prefs::kShutdownNumProcessesSlow, 0);

  if (type > NOT_VALID && shutdown_ms > 0 && num_procs > 0) {
    const char *time_fmt = "Shutdown.%s.time";
    const char *time_per_fmt = "Shutdown.%s.time_per_process";
    std::string time;
    std::string time_per;
    if (type == WINDOW_CLOSE) {
      time = StringPrintf(time_fmt, "window_close");
      time_per = StringPrintf(time_per_fmt, "window_close");
    } else if (type == BROWSER_EXIT) {
      time = StringPrintf(time_fmt, "browser_exit");
      time_per = StringPrintf(time_per_fmt, "browser_exit");
    } else if (type == END_SESSION) {
      time = StringPrintf(time_fmt, "end_session");
      time_per = StringPrintf(time_per_fmt, "end_session");
    } else {
      NOTREACHED();
    }
    if (time.length()) {
      // TODO(erikkay): change these to UMA histograms after a bit more testing.
      UMA_HISTOGRAM_TIMES(time.c_str(),
                          TimeDelta::FromMilliseconds(shutdown_ms));
      UMA_HISTOGRAM_TIMES(time_per.c_str(),
                          TimeDelta::FromMilliseconds(shutdown_ms / num_procs));
      UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.total", num_procs);
      UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.slow", num_procs_slow);
    }
  }
}
#endif

}  // namespace browser_shutdown
<commit_msg>Fix compile failure due to bad merge.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser_shutdown.h"

#include "app/resource_bundle.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/first_run.h"
#include "chrome/browser/jankometer.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "net/dns_global.h"

#if defined(OS_WIN)
#include "chrome/browser/rlz/rlz.h"
#endif

using base::Time;
using base::TimeDelta;

namespace browser_shutdown {

Time shutdown_started_;
ShutdownType shutdown_type_ = NOT_VALID;
int shutdown_num_processes_;
int shutdown_num_processes_slow_;

bool delete_resources_on_shutdown = true;

const char* const kShutdownMsFile = "chrome_shutdown_ms.txt";

void RegisterPrefs(PrefService* local_state) {
  local_state->RegisterIntegerPref(prefs::kShutdownType, NOT_VALID);
  local_state->RegisterIntegerPref(prefs::kShutdownNumProcesses, 0);
  local_state->RegisterIntegerPref(prefs::kShutdownNumProcessesSlow, 0);
}

ShutdownType GetShutdownType() {
  return shutdown_type_;
}

void OnShutdownStarting(ShutdownType type) {
  if (shutdown_type_ != NOT_VALID)
    return;

  shutdown_type_ = type;
  // For now, we're only counting the number of renderer processes
  // since we can't safely count the number of plugin processes from this
  // thread, and we'd really like to avoid anything which might add further
  // delays to shutdown time.
  shutdown_started_ = Time::Now();

  // Call FastShutdown on all of the RenderProcessHosts.  This will be
  // a no-op in some cases, so we still need to go through the normal
  // shutdown path for the ones that didn't exit here.
  shutdown_num_processes_ = 0;
  shutdown_num_processes_slow_ = 0;
  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    ++shutdown_num_processes_;
    if (!i.GetCurrentValue()->FastShutdownIfPossible())
      ++shutdown_num_processes_slow_;
  }
}

#if defined(OS_WIN)
FilePath GetShutdownMsPath() {
  FilePath shutdown_ms_file;
  PathService::Get(base::DIR_TEMP, &shutdown_ms_file);
  return shutdown_ms_file.AppendASCII(kShutdownMsFile);
}
#endif

void Shutdown() {
  // Unload plugins. This needs to happen on the IO thread.
  if (g_browser_process->io_thread()) {
    g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
        NewRunnableFunction(&ChromePluginLib::UnloadAllPlugins));
  }

  // WARNING: During logoff/shutdown (WM_ENDSESSION) we may not have enough
  // time to get here. If you have something that *must* happen on end session,
  // consider putting it in BrowserProcessImpl::EndSession.
  DCHECK(g_browser_process);

  // Notifies we are going away.
  g_browser_process->shutdown_event()->Signal();

  PrefService* prefs = g_browser_process->local_state();

  chrome_browser_net::SaveHostNamesForNextStartup(prefs);
  // TODO(jar): Trimming should be done more regularly, such as every 48 hours
  // of physical time, or perhaps after 48 hours of running (excluding time
  // between sessions possibly).
  // For now, we'll just trim at shutdown.
  chrome_browser_net::TrimSubresourceReferrers();
  chrome_browser_net::SaveSubresourceReferrers(prefs);

  MetricsService* metrics = g_browser_process->metrics_service();
  if (metrics) {
    metrics->RecordCleanShutdown();
    metrics->RecordCompletedSessionEnd();
  }

  if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
    // Record the shutdown info so that we can put it into a histogram at next
    // startup.
    prefs->SetInteger(prefs::kShutdownType, shutdown_type_);
    prefs->SetInteger(prefs::kShutdownNumProcesses, shutdown_num_processes_);
    prefs->SetInteger(prefs::kShutdownNumProcessesSlow,
                      shutdown_num_processes_slow_);
  }

  prefs->SavePersistentPrefs();

#if defined(OS_WIN)
  // Cleanup any statics created by RLZ. Must be done before NotificationService
  // is destroyed.
  RLZTracker::CleanupRlz();
#endif

  // The jank'o'meter requires that the browser process has been destroyed
  // before calling UninstallJankometer().
  delete g_browser_process;
  g_browser_process = NULL;

  // Uninstall Jank-O-Meter here after the IO thread is no longer running.
  UninstallJankometer();

  if (delete_resources_on_shutdown)
    ResourceBundle::CleanupSharedInstance();

#if defined(OS_WIN)
  if (!Upgrade::IsBrowserAlreadyRunning()) {
    Upgrade::SwapNewChromeExeIfPresent();
  }

  if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
    // Measure total shutdown time as late in the process as possible
    // and then write it to a file to be read at startup.
    // We can't use prefs since all services are shutdown at this point.
    TimeDelta shutdown_delta = Time::Now() - shutdown_started_;
    std::string shutdown_ms = Int64ToString(shutdown_delta.InMilliseconds());
    int len = static_cast<int>(shutdown_ms.length()) + 1;
    FilePath shutdown_ms_file = GetShutdownMsPath();
    file_util::WriteFile(shutdown_ms_file, shutdown_ms.c_str(), len);
  }
#endif

  UnregisterURLRequestChromeJob();
}

#if defined(OS_WIN)
void ReadLastShutdownInfo() {
  FilePath shutdown_ms_file = GetShutdownMsPath();
  std::string shutdown_ms_str;
  int64 shutdown_ms = 0;
  if (file_util::ReadFileToString(shutdown_ms_file, &shutdown_ms_str))
    shutdown_ms = StringToInt64(shutdown_ms_str);
  file_util::Delete(shutdown_ms_file, false);

  PrefService* prefs = g_browser_process->local_state();
  ShutdownType type =
      static_cast<ShutdownType>(prefs->GetInteger(prefs::kShutdownType));
  int num_procs = prefs->GetInteger(prefs::kShutdownNumProcesses);
  int num_procs_slow = prefs->GetInteger(prefs::kShutdownNumProcessesSlow);
  // clear the prefs immediately so we don't pick them up on a future run
  prefs->SetInteger(prefs::kShutdownType, NOT_VALID);
  prefs->SetInteger(prefs::kShutdownNumProcesses, 0);
  prefs->SetInteger(prefs::kShutdownNumProcessesSlow, 0);

  if (type > NOT_VALID && shutdown_ms > 0 && num_procs > 0) {
    const char *time_fmt = "Shutdown.%s.time";
    const char *time_per_fmt = "Shutdown.%s.time_per_process";
    std::string time;
    std::string time_per;
    if (type == WINDOW_CLOSE) {
      time = StringPrintf(time_fmt, "window_close");
      time_per = StringPrintf(time_per_fmt, "window_close");
    } else if (type == BROWSER_EXIT) {
      time = StringPrintf(time_fmt, "browser_exit");
      time_per = StringPrintf(time_per_fmt, "browser_exit");
    } else if (type == END_SESSION) {
      time = StringPrintf(time_fmt, "end_session");
      time_per = StringPrintf(time_per_fmt, "end_session");
    } else {
      NOTREACHED();
    }
    if (time.length()) {
      // TODO(erikkay): change these to UMA histograms after a bit more testing.
      UMA_HISTOGRAM_TIMES(time.c_str(),
                          TimeDelta::FromMilliseconds(shutdown_ms));
      UMA_HISTOGRAM_TIMES(time_per.c_str(),
                          TimeDelta::FromMilliseconds(shutdown_ms / num_procs));
      UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.total", num_procs);
      UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.slow", num_procs_slow);
    }
  }
}
#endif

}  // namespace browser_shutdown
<|endoftext|>


<commit_before><commit_msg>Fix windows build<commit_after><|endoftext|>


<commit_before><commit_msg>Linux: remove the use of UNIX_PATH_MAX for systems which don't have it.<commit_after><|endoftext|>