<commit_before>#include "application_manager/hmi_state.h"
#include "utils/helpers.h"

namespace application_manager {

HmiState::HmiState(uint32_t app_id, const StateContext& state_context_,
                   StateID state_id):
  app_id_(app_id),
  state_id_(state_id),
  state_context_(state_context_),
  hmi_level_(mobile_apis::HMILevel::INVALID_ENUM),
  audio_streaming_state_(mobile_apis::AudioStreamingState::INVALID_ENUM),
  system_context_(mobile_apis::SystemContext::INVALID_ENUM) {
}

HmiState::HmiState(uint32_t app_id, const StateContext& state_context):
  app_id_(app_id),
  state_id_(STATE_ID_REGULAR),
  state_context_(state_context),
  hmi_level_(mobile_apis::HMILevel::INVALID_ENUM),
  audio_streaming_state_(mobile_apis::AudioStreamingState::INVALID_ENUM),
  system_context_(mobile_apis::SystemContext::INVALID_ENUM) {
}

void HmiState::set_parent(HmiStatePtr parent) {
  DCHECK_OR_RETURN_VOID(parent);
  parent_ = parent;
}

mobile_apis::AudioStreamingState::eType
VRHmiState::audio_streaming_state() const {
  using namespace mobile_apis;
  return AudioStreamingState::NOT_AUDIBLE;
}

VRHmiState::VRHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_VR_SESSION) {
}

TTSHmiState::TTSHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_TTS_SESSION) {
}

mobile_apis::AudioStreamingState::eType
TTSHmiState::audio_streaming_state() const {
  using namespace helpers;
  using namespace mobile_apis;

  AudioStreamingState::eType expected_state = AudioStreamingState::NOT_AUDIBLE;
  if (state_context_.is_attenuated_supported() &&
    AudioStreamingState::NOT_AUDIBLE != parent()->audio_streaming_state() &&
    Compare<HMILevel::eType, EQ, ONE> (hmi_level(), HMILevel::HMI_FULL,
                                       HMILevel::HMI_LIMITED)) {
    expected_state = AudioStreamingState::ATTENUATED;
  }
  return expected_state;
}

NaviStreamingHmiState::NaviStreamingHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_NAVI_STREAMING) {
}

mobile_apis::AudioStreamingState::eType
NaviStreamingHmiState::audio_streaming_state() const {
  using namespace helpers;
  using namespace mobile_apis;

  AudioStreamingState::eType expected_state = parent()->audio_streaming_state();
  if (Compare<HMILevel::eType, EQ, ONE> (hmi_level(), HMILevel::HMI_FULL) &&
      !state_context_.is_navi_app(app_id_) &&
      AudioStreamingState::AUDIBLE == expected_state) {
    if (state_context_.is_attenuated_supported()) {
      expected_state = AudioStreamingState::ATTENUATED;
    } else {
      expected_state = AudioStreamingState::NOT_AUDIBLE;
    }
  }
  return expected_state;
}

PhoneCallHmiState::PhoneCallHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_PHONE_CALL) {
}

mobile_apis::HMILevel::eType PhoneCallHmiState::hmi_level() const {
  using namespace mobile_apis;
   HMILevel::eType expected_level(HMILevel::HMI_BACKGROUND);
   if (parent()->hmi_level() == HMILevel::HMI_FULL
       && state_context_.is_navi_app(app_id_)) {
     expected_level = HMILevel::HMI_LIMITED;
   }
   return expected_level;
}

SafetyModeHmiState::SafetyModeHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_SAFETY_MODE) {
}

}
<commit_msg>Set ATTENUATED not only for FULL apps.<commit_after>#include "application_manager/hmi_state.h"
#include "utils/helpers.h"

namespace application_manager {

HmiState::HmiState(uint32_t app_id, const StateContext& state_context_,
                   StateID state_id):
  app_id_(app_id),
  state_id_(state_id),
  state_context_(state_context_),
  hmi_level_(mobile_apis::HMILevel::INVALID_ENUM),
  audio_streaming_state_(mobile_apis::AudioStreamingState::INVALID_ENUM),
  system_context_(mobile_apis::SystemContext::INVALID_ENUM) {
}

HmiState::HmiState(uint32_t app_id, const StateContext& state_context):
  app_id_(app_id),
  state_id_(STATE_ID_REGULAR),
  state_context_(state_context),
  hmi_level_(mobile_apis::HMILevel::INVALID_ENUM),
  audio_streaming_state_(mobile_apis::AudioStreamingState::INVALID_ENUM),
  system_context_(mobile_apis::SystemContext::INVALID_ENUM) {
}

void HmiState::set_parent(HmiStatePtr parent) {
  DCHECK_OR_RETURN_VOID(parent);
  parent_ = parent;
}

mobile_apis::AudioStreamingState::eType
VRHmiState::audio_streaming_state() const {
  using namespace mobile_apis;
  return AudioStreamingState::NOT_AUDIBLE;
}

VRHmiState::VRHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_VR_SESSION) {
}

TTSHmiState::TTSHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_TTS_SESSION) {
}

mobile_apis::AudioStreamingState::eType
TTSHmiState::audio_streaming_state() const {
  using namespace helpers;
  using namespace mobile_apis;

  AudioStreamingState::eType expected_state = AudioStreamingState::NOT_AUDIBLE;
  if (state_context_.is_attenuated_supported() &&
    AudioStreamingState::NOT_AUDIBLE != parent()->audio_streaming_state() &&
    Compare<HMILevel::eType, EQ, ONE> (hmi_level(), HMILevel::HMI_FULL,
                                       HMILevel::HMI_LIMITED)) {
    expected_state = AudioStreamingState::ATTENUATED;
  }
  return expected_state;
}

NaviStreamingHmiState::NaviStreamingHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_NAVI_STREAMING) {
}

mobile_apis::AudioStreamingState::eType
NaviStreamingHmiState::audio_streaming_state() const {
  using namespace helpers;
  using namespace mobile_apis;

  AudioStreamingState::eType expected_state = parent()->audio_streaming_state();
  if (!state_context_.is_navi_app(app_id_) &&
      AudioStreamingState::AUDIBLE == expected_state) {
    if (state_context_.is_attenuated_supported()) {
      expected_state = AudioStreamingState::ATTENUATED;
    } else {
      expected_state = AudioStreamingState::NOT_AUDIBLE;
    }
  }
  return expected_state;
}

PhoneCallHmiState::PhoneCallHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_PHONE_CALL) {
}

mobile_apis::HMILevel::eType PhoneCallHmiState::hmi_level() const {
  using namespace mobile_apis;
   HMILevel::eType expected_level(HMILevel::HMI_BACKGROUND);
   if (parent()->hmi_level() == HMILevel::HMI_FULL
       && state_context_.is_navi_app(app_id_)) {
     expected_level = HMILevel::HMI_LIMITED;
   }
   return expected_level;
}

SafetyModeHmiState::SafetyModeHmiState(uint32_t app_id, StateContext& state_context):
  HmiState(app_id, state_context, STATE_ID_SAFETY_MODE) {
}

}
<|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/child_process_launcher.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/result_codes.h"

#if defined(OS_WIN)
#include "chrome/common/sandbox_policy.h"
#elif defined(OS_LINUX)
#include "base/singleton.h"
#include "chrome/browser/crash_handler_host_linux.h"
#include "chrome/browser/zygote_host_linux.h"
#include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
#endif

#if defined(OS_MACOSX)
#include "chrome/browser/mach_broker_mac.h"
#endif

#if defined(OS_POSIX)
#include "base/global_descriptors_posix.h"
#endif

// Having the functionality of ChildProcessLauncher be in an internal
// ref counted object allows us to automatically terminate the process when the
// parent class destructs, while still holding on to state that we need.
class ChildProcessLauncher::Context
    : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
 public:
  Context()
      : starting_(true)
#if defined(OS_LINUX)
        , zygote_(false)
#endif
        {
  }

  void Launch(
#if defined(OS_WIN)
      const FilePath& exposed_dir,
#elif defined(OS_POSIX)
      bool use_zygote,
      const base::environment_vector& environ,
      int ipcfd,
#endif
      CommandLine* cmd_line,
      Client* client) {
    client_ = client;

    CHECK(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_));

    ChromeThread::PostTask(
        ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
        NewRunnableMethod(
            this,
            &Context::LaunchInternal,
#if defined(OS_WIN)
            exposed_dir,
#elif defined(POSIX)
            use_zygote,
            environ,
            ipcfd,
#endif
            cmd_line));
  }

  void ResetClient() {
    // No need for locking as this function gets called on the same thread that
    // client_ would be used.
    CHECK(ChromeThread::CurrentlyOn(client_thread_id_));
    client_ = NULL;
  }

 private:
  friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
  friend class ChildProcessLauncher;

  ~Context() {
    Terminate();
  }

  void LaunchInternal(
#if defined(OS_WIN)
      const FilePath& exposed_dir,
#elif defined(OS_POSIX)
      bool use_zygote,
      const base::environment_vector& env,
      int ipcfd,
#endif
      CommandLine* cmd_line) {
    scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
    base::ProcessHandle handle = base::kNullProcessHandle;
#if defined(OS_WIN)
    handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir);
#elif defined(OS_POSIX)

#if defined(OS_LINUX)
    if (use_zygote) {
      base::GlobalDescriptors::Mapping mapping;
      mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd));
      const int crash_signal_fd =
          Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket();
      if (crash_signal_fd >= 0) {
        mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
                                                   crash_signal_fd));
      }
      handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping);
    } else
    // Fall through to the normal posix case below when we're not zygoting.
#endif
    {
      base::file_handle_mapping_vector fds_to_map;
      fds_to_map.push_back(std::make_pair(
          ipcfd,
          kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));

#if defined(OS_LINUX)
      // On Linux, we need to add some extra file descriptors for crash handling
      // and the sandbox.
      bool is_renderer =
          cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
          switches::kRendererProcess;
      bool is_plugin =
          cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
          switches::kPluginProcess;

      if (is_renderer || is_plugin) {
        int crash_signal_fd;
        if (is_renderer) {
          crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()->
              GetDeathSignalSocket();
        } else {
          crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()->
              GetDeathSignalSocket();
        }
        if (crash_signal_fd >= 0) {
          fds_to_map.push_back(std::make_pair(
              crash_signal_fd,
              kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor));
        }
      }
      if (is_renderer) {
        const int sandbox_fd =
            Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
        fds_to_map.push_back(std::make_pair(
            sandbox_fd,
            kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
      }
#endif  // defined(OS_LINUX)

      // Actually launch the app.
      bool launched;
#if defined(OS_MACOSX)
      task_t child_task;
      launched = base::LaunchAppAndGetTask(
          cmd_line->argv(), env, fds_to_map, false, &child_task, &handle);
      if (launched && child_task != MACH_PORT_NULL) {
          MachBroker::instance()->RegisterPid(
              handle,
              MachBroker::MachInfo().SetTask(child_task));
      }
#else
      launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
                                 /* wait= */false, &handle);
#endif
      if (!launched)
        handle = base::kNullProcessHandle;
    }
#endif  // else defined(OS_POSIX)

    ChromeThread::PostTask(
        client_thread_id_, FROM_HERE,
        NewRunnableMethod(
            this,
            &ChildProcessLauncher::Context::NotifyProcessLaunched,
#if defined(OS_LINUX)
            use_zygote,
#endif
            handle));
  }

  void NotifyProcessLaunched(
#if defined(OS_LINUX)
      bool zygote,
#endif
      base::ProcessHandle handle) {
    starting_ = false;
    process_.set_handle(handle);
#if defined(OS_LINUX)
    zygote_ = zygote;
#endif
    if (client_) {
      client_->OnProcessLaunched();
    } else {
      Terminate();
    }
  }

  void DetermineDidProcessCrash() {
    DCHECK(ChromeThread::CurrentlyOn(client_thread_id_));
    base::ProcessHandle handle = process_.handle();
#if defined(OS_LINUX)
    if (zygote_) {
      ChromeThread::PostTask(
          ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
          NewRunnableMethod(this,
                            &Context::DetermineDidProcessCrashInternal,
                            handle));
    } else
#endif
    {
      DetermineDidProcessCrashInternal(handle);
    }
  }

  void DetermineDidProcessCrashInternal(base::ProcessHandle handle) {
    bool did_crash, child_exited;
#if defined(OS_LINUX)
    if (zygote_) {
      did_crash = Singleton<ZygoteHost>()->DidProcessCrash(handle,
                                                           &child_exited);
      ChromeThread::PostTask(
          client_thread_id_, FROM_HERE,
          NewRunnableMethod(this,
                            &Context::OnDidProcessCrashDetermined,
                            child_exited, did_crash));
    } else
#endif
    {
      did_crash = base::DidProcessCrash(&child_exited, handle);
      OnDidProcessCrashDetermined(child_exited, did_crash);
    }
  }

  void OnDidProcessCrashDetermined(bool child_exited, bool did_crash) {
    DCHECK(ChromeThread::CurrentlyOn(client_thread_id_));

    // POSIX: If the process crashed, then the kernel closed the socket for it
    // and so the child has already died by the time we get here. Since
    // DidProcessCrash called waitpid with WNOHANG, it'll reap the process.
    // However, if DidProcessCrash didn't reap the child, we'll need to in
    // Terminate via ProcessWatcher. So we can't close the handle here.
    if (child_exited)
      process_.Close();

    if (client_)
      client_->OnDidProcessCrashDetermined(did_crash);
    // The client may have deleted us in the callback. Do not add anything
    // after this point.
  }

  void Terminate() {
    DCHECK(ChromeThread::CurrentlyOn(client_thread_id_));
    if (!process_.handle())
      return;

    // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!  So
    // don't this on the UI/IO threads.
    ChromeThread::PostTask(
        ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
        NewRunnableFunction(
            &ChildProcessLauncher::Context::TerminateInternal,
#if defined(OS_LINUX)
            zygote_,
#endif
            process_.handle()));
    process_.set_handle(base::kNullProcessHandle);
  }

  static void TerminateInternal(
#if defined(OS_LINUX)
      bool zygote,
#endif
      base::ProcessHandle handle) {
    base::Process process(handle);
     // Client has gone away, so just kill the process.  Using exit code 0
    // means that UMA won't treat this as a crash.
    process.Terminate(ResultCodes::NORMAL_EXIT);
    // On POSIX, we must additionally reap the child.
#if defined(OS_POSIX)
#if defined(OS_LINUX)
    if (zygote) {
      // If the renderer was created via a zygote, we have to proxy the reaping
      // through the zygote process.
      Singleton<ZygoteHost>()->EnsureProcessTerminated(handle);
    } else
#endif  // OS_LINUX
    {
      ProcessWatcher::EnsureProcessTerminated(handle);
    }
#endif  // OS_POSIX
    process.Close();
  }

  Client* client_;
  ChromeThread::ID client_thread_id_;
  base::Process process_;
  bool starting_;

#if defined(OS_LINUX)
  bool zygote_;
#endif
};

ChildProcessLauncher::ChildProcessLauncher(
#if defined(OS_WIN)
    const FilePath& exposed_dir,
#elif defined(OS_POSIX)
    bool use_zygote,
    const base::environment_vector& environ,
    int ipcfd,
#endif
    CommandLine* cmd_line,
    Client* client) {
  context_ = new Context();
  context_->Launch(
#if defined(OS_WIN)
      exposed_dir,
#elif defined(OS_POSIX)
      use_zygote,
      environ,
      ipcfd,
#endif
      cmd_line,
      client);
}

ChildProcessLauncher::~ChildProcessLauncher() {
  context_->ResetClient();
}

bool ChildProcessLauncher::IsStarting() {
  return context_->starting_;
}

base::ProcessHandle ChildProcessLauncher::GetHandle() {
  DCHECK(!context_->starting_);
  return context_->process_.handle();
}

void ChildProcessLauncher::DetermineDidProcessCrash() {
  context_->DetermineDidProcessCrash();
}

void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
  DCHECK(!context_->starting_);
  context_->process_.SetProcessBackgrounded(background);
}
<commit_msg>Remove recently added DCHECK in 46384 which is causing some test crashes. BUG=none TEST=none TBR=estade<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/child_process_launcher.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/result_codes.h"

#if defined(OS_WIN)
#include "chrome/common/sandbox_policy.h"
#elif defined(OS_LINUX)
#include "base/singleton.h"
#include "chrome/browser/crash_handler_host_linux.h"
#include "chrome/browser/zygote_host_linux.h"
#include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
#endif

#if defined(OS_MACOSX)
#include "chrome/browser/mach_broker_mac.h"
#endif

#if defined(OS_POSIX)
#include "base/global_descriptors_posix.h"
#endif

// Having the functionality of ChildProcessLauncher be in an internal
// ref counted object allows us to automatically terminate the process when the
// parent class destructs, while still holding on to state that we need.
class ChildProcessLauncher::Context
    : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
 public:
  Context()
      : starting_(true)
#if defined(OS_LINUX)
        , zygote_(false)
#endif
        {
  }

  void Launch(
#if defined(OS_WIN)
      const FilePath& exposed_dir,
#elif defined(OS_POSIX)
      bool use_zygote,
      const base::environment_vector& environ,
      int ipcfd,
#endif
      CommandLine* cmd_line,
      Client* client) {
    client_ = client;

    CHECK(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_));

    ChromeThread::PostTask(
        ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
        NewRunnableMethod(
            this,
            &Context::LaunchInternal,
#if defined(OS_WIN)
            exposed_dir,
#elif defined(POSIX)
            use_zygote,
            environ,
            ipcfd,
#endif
            cmd_line));
  }

  void ResetClient() {
    // No need for locking as this function gets called on the same thread that
    // client_ would be used.
    CHECK(ChromeThread::CurrentlyOn(client_thread_id_));
    client_ = NULL;
  }

 private:
  friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
  friend class ChildProcessLauncher;

  ~Context() {
    Terminate();
  }

  void LaunchInternal(
#if defined(OS_WIN)
      const FilePath& exposed_dir,
#elif defined(OS_POSIX)
      bool use_zygote,
      const base::environment_vector& env,
      int ipcfd,
#endif
      CommandLine* cmd_line) {
    scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
    base::ProcessHandle handle = base::kNullProcessHandle;
#if defined(OS_WIN)
    handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir);
#elif defined(OS_POSIX)

#if defined(OS_LINUX)
    if (use_zygote) {
      base::GlobalDescriptors::Mapping mapping;
      mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd));
      const int crash_signal_fd =
          Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket();
      if (crash_signal_fd >= 0) {
        mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
                                                   crash_signal_fd));
      }
      handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping);
    } else
    // Fall through to the normal posix case below when we're not zygoting.
#endif
    {
      base::file_handle_mapping_vector fds_to_map;
      fds_to_map.push_back(std::make_pair(
          ipcfd,
          kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));

#if defined(OS_LINUX)
      // On Linux, we need to add some extra file descriptors for crash handling
      // and the sandbox.
      bool is_renderer =
          cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
          switches::kRendererProcess;
      bool is_plugin =
          cmd_line->GetSwitchValueASCII(switches::kProcessType) ==
          switches::kPluginProcess;

      if (is_renderer || is_plugin) {
        int crash_signal_fd;
        if (is_renderer) {
          crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()->
              GetDeathSignalSocket();
        } else {
          crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()->
              GetDeathSignalSocket();
        }
        if (crash_signal_fd >= 0) {
          fds_to_map.push_back(std::make_pair(
              crash_signal_fd,
              kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor));
        }
      }
      if (is_renderer) {
        const int sandbox_fd =
            Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
        fds_to_map.push_back(std::make_pair(
            sandbox_fd,
            kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
      }
#endif  // defined(OS_LINUX)

      // Actually launch the app.
      bool launched;
#if defined(OS_MACOSX)
      task_t child_task;
      launched = base::LaunchAppAndGetTask(
          cmd_line->argv(), env, fds_to_map, false, &child_task, &handle);
      if (launched && child_task != MACH_PORT_NULL) {
          MachBroker::instance()->RegisterPid(
              handle,
              MachBroker::MachInfo().SetTask(child_task));
      }
#else
      launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
                                 /* wait= */false, &handle);
#endif
      if (!launched)
        handle = base::kNullProcessHandle;
    }
#endif  // else defined(OS_POSIX)

    ChromeThread::PostTask(
        client_thread_id_, FROM_HERE,
        NewRunnableMethod(
            this,
            &ChildProcessLauncher::Context::NotifyProcessLaunched,
#if defined(OS_LINUX)
            use_zygote,
#endif
            handle));
  }

  void NotifyProcessLaunched(
#if defined(OS_LINUX)
      bool zygote,
#endif
      base::ProcessHandle handle) {
    starting_ = false;
    process_.set_handle(handle);
#if defined(OS_LINUX)
    zygote_ = zygote;
#endif
    if (client_) {
      client_->OnProcessLaunched();
    } else {
      Terminate();
    }
  }

  void DetermineDidProcessCrash() {
    DCHECK(ChromeThread::CurrentlyOn(client_thread_id_));
    base::ProcessHandle handle = process_.handle();
#if defined(OS_LINUX)
    if (zygote_) {
      ChromeThread::PostTask(
          ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
          NewRunnableMethod(this,
                            &Context::DetermineDidProcessCrashInternal,
                            handle));
    } else
#endif
    {
      DetermineDidProcessCrashInternal(handle);
    }
  }

  void DetermineDidProcessCrashInternal(base::ProcessHandle handle) {
    bool did_crash, child_exited;
#if defined(OS_LINUX)
    if (zygote_) {
      did_crash = Singleton<ZygoteHost>()->DidProcessCrash(handle,
                                                           &child_exited);
      ChromeThread::PostTask(
          client_thread_id_, FROM_HERE,
          NewRunnableMethod(this,
                            &Context::OnDidProcessCrashDetermined,
                            child_exited, did_crash));
    } else
#endif
    {
      did_crash = base::DidProcessCrash(&child_exited, handle);
      OnDidProcessCrashDetermined(child_exited, did_crash);
    }
  }

  void OnDidProcessCrashDetermined(bool child_exited, bool did_crash) {
    DCHECK(ChromeThread::CurrentlyOn(client_thread_id_));

    // POSIX: If the process crashed, then the kernel closed the socket for it
    // and so the child has already died by the time we get here. Since
    // DidProcessCrash called waitpid with WNOHANG, it'll reap the process.
    // However, if DidProcessCrash didn't reap the child, we'll need to in
    // Terminate via ProcessWatcher. So we can't close the handle here.
    if (child_exited)
      process_.Close();

    if (client_)
      client_->OnDidProcessCrashDetermined(did_crash);
    // The client may have deleted us in the callback. Do not add anything
    // after this point.
  }

  void Terminate() {
    if (!process_.handle())
      return;

    // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!  So
    // don't this on the UI/IO threads.
    ChromeThread::PostTask(
        ChromeThread::PROCESS_LAUNCHER, FROM_HERE,
        NewRunnableFunction(
            &ChildProcessLauncher::Context::TerminateInternal,
#if defined(OS_LINUX)
            zygote_,
#endif
            process_.handle()));
    process_.set_handle(base::kNullProcessHandle);
  }

  static void TerminateInternal(
#if defined(OS_LINUX)
      bool zygote,
#endif
      base::ProcessHandle handle) {
    base::Process process(handle);
     // Client has gone away, so just kill the process.  Using exit code 0
    // means that UMA won't treat this as a crash.
    process.Terminate(ResultCodes::NORMAL_EXIT);
    // On POSIX, we must additionally reap the child.
#if defined(OS_POSIX)
#if defined(OS_LINUX)
    if (zygote) {
      // If the renderer was created via a zygote, we have to proxy the reaping
      // through the zygote process.
      Singleton<ZygoteHost>()->EnsureProcessTerminated(handle);
    } else
#endif  // OS_LINUX
    {
      ProcessWatcher::EnsureProcessTerminated(handle);
    }
#endif  // OS_POSIX
    process.Close();
  }

  Client* client_;
  ChromeThread::ID client_thread_id_;
  base::Process process_;
  bool starting_;

#if defined(OS_LINUX)
  bool zygote_;
#endif
};

ChildProcessLauncher::ChildProcessLauncher(
#if defined(OS_WIN)
    const FilePath& exposed_dir,
#elif defined(OS_POSIX)
    bool use_zygote,
    const base::environment_vector& environ,
    int ipcfd,
#endif
    CommandLine* cmd_line,
    Client* client) {
  context_ = new Context();
  context_->Launch(
#if defined(OS_WIN)
      exposed_dir,
#elif defined(OS_POSIX)
      use_zygote,
      environ,
      ipcfd,
#endif
      cmd_line,
      client);
}

ChildProcessLauncher::~ChildProcessLauncher() {
  context_->ResetClient();
}

bool ChildProcessLauncher::IsStarting() {
  return context_->starting_;
}

base::ProcessHandle ChildProcessLauncher::GetHandle() {
  DCHECK(!context_->starting_);
  return context_->process_.handle();
}

void ChildProcessLauncher::DetermineDidProcessCrash() {
  context_->DetermineDidProcessCrash();
}

void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
  DCHECK(!context_->starting_);
  context_->process_.SetProcessBackgrounded(background);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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/debugger/debugger_window.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/json_writer.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/resources/debugger_resources.h"
#include "chrome/browser/debugger/debugger_shell.h"
#include "chrome/browser/debugger/debugger_view.h"
#include "chrome/browser/debugger/debugger_wrapper.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/render_view_host.h"
#include "chrome/browser/standard_layout.h"
#include "chrome/browser/tab_contents.h"
#include "chrome/browser/tab_contents_container_view.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/web_contents.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/views/grid_layout.h"
#include "chrome/views/native_scroll_bar.h"
#include "chrome/views/scroll_view.h"
#include "chrome/views/text_field.h"
#include "chrome/views/view.h"

DebuggerView::DebuggerView() : output_ready_(false) {
  web_container_ = new TabContentsContainerView();
  AddChildView(web_container_);
}

DebuggerView::~DebuggerView() {
}

void DebuggerView::GetPreferredSize(CSize* out) {
  out->cx = 700;
  out->cy = 400;
}

void DebuggerView::Layout() {
  web_container_->SetBounds(0, 0, GetWidth(), GetHeight());
}

void DebuggerView::DidChangeBounds(const CRect& previous,
                                   const CRect& current) {
  Layout();
}

void DebuggerView::ViewHierarchyChanged(bool is_add,
                                        ChromeViews::View* parent,
                                        ChromeViews::View* child) {
  if (is_add && child == this) {
    DCHECK(GetViewContainer());
    OnInit();
  }
}

void DebuggerView::Paint(ChromeCanvas* canvas) {
#ifndef NDEBUG
  SkPaint paint;
  canvas->FillRectInt(SK_ColorCYAN, bounds_.left, bounds_.top,
                      bounds_.Width(), bounds_.Height());
#endif
}

void DebuggerView::SetOutputViewReady() {
  output_ready_ = true;
  for (std::vector<std::wstring>::iterator i = pending_output_.begin();
       i != pending_output_.end(); ++i) {
    Output(*i);
  }
  pending_output_.clear();
}

void DebuggerView::Output(const std::string& out) {
  Output(UTF8ToWide(out));
}

void DebuggerView::Output(const std::wstring& out) {
  if (!output_ready_) {
    pending_output_.push_back(out);
    return;
  }
  Value* str_value = Value::CreateStringValue(out);
  std::string json;
  JSONWriter::Write(str_value, false, &json);
  const std::string js = StringPrintf("appendText(%s)", json.c_str());
  ExecuteJavascript(js);
}

void DebuggerView::OnInit() {
  // We can't create the WebContents until we've actually been put into a real
  // view hierarchy somewhere.
  Profile* profile = BrowserList::GetLastActive()->profile();
  TabContents* tc = TabContents::CreateWithType(TAB_CONTENTS_DEBUGGER,
      ::GetDesktopWindow(), profile, NULL);
  web_contents_ = tc->AsWebContents();
  web_contents_->SetupController(profile);
  web_contents_->set_delegate(this);
  web_container_->SetTabContents(web_contents_);
  web_contents_->render_view_host()->AllowDOMUIBindings();

  GURL contents("chrome-resource://debugger/");
  web_contents_->controller()->LoadURL(contents, PageTransition::START_PAGE);
}

void DebuggerView::OnShow() {
  web_contents_->Focus();
  if (output_ready_)
    ExecuteJavascript("focusOnCommandLine()");
}

void DebuggerView::OnClose() {
  web_container_->SetTabContents(NULL);
  web_contents_->CloseContents();
}

void DebuggerView::SetDebuggerBreak(bool is_broken) {
  const std::string js =
      StringPrintf("setDebuggerBreak(%s)", is_broken ? "true" : "false");
  ExecuteJavascript(js);
}

void DebuggerView::OpenURLFromTab(TabContents* source,
                               const GURL& url,
                               WindowOpenDisposition disposition,
                               PageTransition::Type transition) {
  BrowserList::GetLastActive()->OpenURL(url, disposition, transition);
}

void DebuggerView::ExecuteJavascript(const std::string& js) {
  const std::string url = StringPrintf("javascript:void(%s)", js.c_str());
  web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(L"",
      UTF8ToWide(url));
}

void DebuggerView::LoadingStateChanged(TabContents* source) {
  if (!source->is_loading())
    SetOutputViewReady();
}

<commit_msg>fix build bustage<commit_after>// Copyright (c) 2006-2008 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/debugger/debugger_window.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/json_writer.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/resources/debugger_resources.h"
#include "chrome/browser/debugger/debugger_shell.h"
#include "chrome/browser/debugger/debugger_view.h"
#include "chrome/browser/debugger/debugger_wrapper.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/render_view_host.h"
#include "chrome/browser/tab_contents.h"
#include "chrome/browser/tab_contents_container_view.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/standard_layout.h"
#include "chrome/browser/web_contents.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/views/grid_layout.h"
#include "chrome/views/native_scroll_bar.h"
#include "chrome/views/scroll_view.h"
#include "chrome/views/text_field.h"
#include "chrome/views/view.h"

DebuggerView::DebuggerView() : output_ready_(false) {
  web_container_ = new TabContentsContainerView();
  AddChildView(web_container_);
}

DebuggerView::~DebuggerView() {
}

void DebuggerView::GetPreferredSize(CSize* out) {
  out->cx = 700;
  out->cy = 400;
}

void DebuggerView::Layout() {
  web_container_->SetBounds(0, 0, GetWidth(), GetHeight());
}

void DebuggerView::DidChangeBounds(const CRect& previous,
                                   const CRect& current) {
  Layout();
}

void DebuggerView::ViewHierarchyChanged(bool is_add,
                                        ChromeViews::View* parent,
                                        ChromeViews::View* child) {
  if (is_add && child == this) {
    DCHECK(GetViewContainer());
    OnInit();
  }
}

void DebuggerView::Paint(ChromeCanvas* canvas) {
#ifndef NDEBUG
  SkPaint paint;
  canvas->FillRectInt(SK_ColorCYAN, bounds_.left, bounds_.top,
                      bounds_.Width(), bounds_.Height());
#endif
}

void DebuggerView::SetOutputViewReady() {
  output_ready_ = true;
  for (std::vector<std::wstring>::iterator i = pending_output_.begin();
       i != pending_output_.end(); ++i) {
    Output(*i);
  }
  pending_output_.clear();
}

void DebuggerView::Output(const std::string& out) {
  Output(UTF8ToWide(out));
}

void DebuggerView::Output(const std::wstring& out) {
  if (!output_ready_) {
    pending_output_.push_back(out);
    return;
  }
  Value* str_value = Value::CreateStringValue(out);
  std::string json;
  JSONWriter::Write(str_value, false, &json);
  const std::string js = StringPrintf("appendText(%s)", json.c_str());
  ExecuteJavascript(js);
}

void DebuggerView::OnInit() {
  // We can't create the WebContents until we've actually been put into a real
  // view hierarchy somewhere.
  Profile* profile = BrowserList::GetLastActive()->profile();
  TabContents* tc = TabContents::CreateWithType(TAB_CONTENTS_DEBUGGER,
      ::GetDesktopWindow(), profile, NULL);
  web_contents_ = tc->AsWebContents();
  web_contents_->SetupController(profile);
  web_contents_->set_delegate(this);
  web_container_->SetTabContents(web_contents_);
  web_contents_->render_view_host()->AllowDOMUIBindings();

  GURL contents("chrome-resource://debugger/");
  web_contents_->controller()->LoadURL(contents, PageTransition::START_PAGE);
}

void DebuggerView::OnShow() {
  web_contents_->Focus();
  if (output_ready_)
    ExecuteJavascript("focusOnCommandLine()");
}

void DebuggerView::OnClose() {
  web_container_->SetTabContents(NULL);
  web_contents_->CloseContents();
}

void DebuggerView::SetDebuggerBreak(bool is_broken) {
  const std::string js =
      StringPrintf("setDebuggerBreak(%s)", is_broken ? "true" : "false");
  ExecuteJavascript(js);
}

void DebuggerView::OpenURLFromTab(TabContents* source,
                               const GURL& url,
                               WindowOpenDisposition disposition,
                               PageTransition::Type transition) {
  BrowserList::GetLastActive()->OpenURL(url, disposition, transition);
}

void DebuggerView::ExecuteJavascript(const std::string& js) {
  const std::string url = StringPrintf("javascript:void(%s)", js.c_str());
  web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(L"",
      UTF8ToWide(url));
}

void DebuggerView::LoadingStateChanged(TabContents* source) {
  if (!source->is_loading())
    SetOutputViewReady();
}

<|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/dom_ui/fileicon_source.h"

#include "base/callback.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/time_format.h"
#include "gfx/codec/png_codec.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"

// The path used in internal URLs to file icon data.
static const char kFileIconPath[] = "fileicon";

FileIconSource::FileIconSource()
    : DataSource(kFileIconPath, MessageLoop::current()) {}

FileIconSource::~FileIconSource() {
  cancelable_consumer_.CancelAllRequests();
}

void FileIconSource::StartDataRequest(const std::string& path,
                                      bool is_off_the_record,
                                      int request_id) {
  IconManager* im = g_browser_process->icon_manager();

  std::string escaped_path = UnescapeURLComponent(path, UnescapeRule::SPACES);

#if defined(OS_WIN)
  // The path we receive has the wrong slashes and escaping for what we need;
  // this only appears to matter for getting icons from .exe files.
  std::replace(escaped_path.begin(), escaped_path.end(), '/', '\\');
  FilePath escaped_filepath(UTF8ToWide(escaped_path));
#elif defined(OS_POSIX)
  // The correct encoding on Linux may not actually be UTF8.
  FilePath escaped_filepath(escaped_path);
#endif
  SkBitmap* icon = im->LookupIcon(escaped_filepath, IconLoader::NORMAL);

  if (icon) {
    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes;
    gfx::PNGCodec::EncodeBGRASkBitmap(*icon, false, &icon_data->data);

    SendResponse(request_id, icon_data);
  } else {
    // Icon was not in cache, go fetch it slowly.
    IconManager::Handle h = im->LoadIcon(escaped_filepath,
        IconLoader::NORMAL,
        &cancelable_consumer_,
        NewCallback(this, &FileIconSource::OnFileIconDataAvailable));

    // Attach the ChromeURLDataManager request ID to the history request.
    cancelable_consumer_.SetClientData(im, h, request_id);
  }
}

void FileIconSource::OnFileIconDataAvailable(IconManager::Handle handle,
                                             SkBitmap* icon) {
  IconManager* im = g_browser_process->icon_manager();
  int request_id = cancelable_consumer_.GetClientData(im, handle);

  if (icon) {
    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes;
    gfx::PNGCodec::EncodeBGRASkBitmap(*icon, false, &icon_data->data);

    SendResponse(request_id, icon_data);
  } else {
    // TODO(glen): send a dummy icon.
    SendResponse(request_id, NULL);
  }
}
<commit_msg>Fix the build - forgot to check in a file.<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/dom_ui/fileicon_source.h"

#include "base/callback.h"
#include "base/ref_counted_memory.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/time_format.h"
#include "gfx/codec/png_codec.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"

// The path used in internal URLs to file icon data.
static const char kFileIconPath[] = "fileicon";

FileIconSource::FileIconSource()
    : DataSource(kFileIconPath, MessageLoop::current()) {}

FileIconSource::~FileIconSource() {
  cancelable_consumer_.CancelAllRequests();
}

void FileIconSource::StartDataRequest(const std::string& path,
                                      bool is_off_the_record,
                                      int request_id) {
  IconManager* im = g_browser_process->icon_manager();

  std::string escaped_path = UnescapeURLComponent(path, UnescapeRule::SPACES);

#if defined(OS_WIN)
  // The path we receive has the wrong slashes and escaping for what we need;
  // this only appears to matter for getting icons from .exe files.
  std::replace(escaped_path.begin(), escaped_path.end(), '/', '\\');
  FilePath escaped_filepath(UTF8ToWide(escaped_path));
#elif defined(OS_POSIX)
  // The correct encoding on Linux may not actually be UTF8.
  FilePath escaped_filepath(escaped_path);
#endif
  SkBitmap* icon = im->LookupIcon(escaped_filepath, IconLoader::NORMAL);

  if (icon) {
    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes;
    gfx::PNGCodec::EncodeBGRASkBitmap(*icon, false, &icon_data->data);

    SendResponse(request_id, icon_data);
  } else {
    // Icon was not in cache, go fetch it slowly.
    IconManager::Handle h = im->LoadIcon(escaped_filepath,
        IconLoader::NORMAL,
        &cancelable_consumer_,
        NewCallback(this, &FileIconSource::OnFileIconDataAvailable));

    // Attach the ChromeURLDataManager request ID to the history request.
    cancelable_consumer_.SetClientData(im, h, request_id);
  }
}

void FileIconSource::OnFileIconDataAvailable(IconManager::Handle handle,
                                             SkBitmap* icon) {
  IconManager* im = g_browser_process->icon_manager();
  int request_id = cancelable_consumer_.GetClientData(im, handle);

  if (icon) {
    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes;
    gfx::PNGCodec::EncodeBGRASkBitmap(*icon, false, &icon_data->data);

    SendResponse(request_id, icon_data);
  } else {
    // TODO(glen): send a dummy icon.
    SendResponse(request_id, NULL);
  }
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if defined(_MSC_VER)
#pragma warning ( disable: 4231 4251 4275 4786 )
#endif

#define __STDC_CONSTANT_MACROS
#include <log4cxx/net/socketappenderskeleton.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/bytearrayoutputstream.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::net;

SocketAppenderSkeleton::SocketAppenderSkeleton(int defaultPort, int reconnectionDelay1)
:  remoteHost(),
   address(),
   port(defaultPort),
   reconnectionDelay(reconnectionDelay1),
   locationInfo(false),
   thread() {
}

SocketAppenderSkeleton::SocketAppenderSkeleton(InetAddressPtr address1, int port1, int delay)
:
   remoteHost(),
   address(address1),
   port(port1),
   reconnectionDelay(delay),
   locationInfo(false),
   thread() {
    remoteHost = this->address->getHostName();
}

SocketAppenderSkeleton::SocketAppenderSkeleton(const LogString& host, int port1, int delay)
:   remoteHost(host),
    address(InetAddress::getByName(host)),
    port(port1),
    reconnectionDelay(delay),
    locationInfo(false),
    thread() {
}

SocketAppenderSkeleton::~SocketAppenderSkeleton()
{
        finalize();
}

void SocketAppenderSkeleton::activateOptions(Pool& p)
{
        AppenderSkeleton::activateOptions(p);
        connect(p);
}

void SocketAppenderSkeleton::close() {
    synchronized sync(mutex);
    if (closed) return;
    closed = true;
    cleanUp(pool);
    thread.interrupt();
    thread.join();
}

void SocketAppenderSkeleton::connect(Pool& p) {
    if (address == 0) {
        LogLog::error(LogString(LOG4CXX_STR("No remote host is set for Appender named \"")) +
             name + LOG4CXX_STR("\"."));
    } else {
        cleanUp(p);
        try {
            SocketPtr socket(new Socket(address, port));
            setSocket(socket, p);
        } catch(SocketException& e) {
                LogString msg = LOG4CXX_STR("Could not connect to remote log4cxx server at [")
                        +address->getHostName()+LOG4CXX_STR("].");
                if(reconnectionDelay > 0)
                {
                        msg += LOG4CXX_STR(" We will try again later. ");
                }
                fireConnector(); // fire the connector thread
                LogLog::error(msg, e);
        }
    }
}

void SocketAppenderSkeleton::setOption(const LogString& option, const LogString& value)
{
        if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("REMOTEHOST"), LOG4CXX_STR("remotehost")))
        {
                setRemoteHost(value);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PORT"), LOG4CXX_STR("port")))
        {
                setPort(OptionConverter::toInt(value, getDefaultPort()));
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo")))
        {
                setLocationInfo(OptionConverter::toBoolean(value, false));
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("RECONNECTIONDELAY"), LOG4CXX_STR("reconnectiondelay")))
        {
                setReconnectionDelay(OptionConverter::toInt(value, getDefaultDelay()));
        }
        else
        {
                AppenderSkeleton::setOption(option, value);
        }
}

void SocketAppenderSkeleton::fireConnector()
{
        synchronized sync(mutex);
        if (!thread.isActive()) {
                thread.run(monitor, this);
        }
}

void* LOG4CXX_THREAD_FUNC SocketAppenderSkeleton::monitor(apr_thread_t* /* thread */, void* data) {
        SocketAppenderSkeleton* socketAppender = (SocketAppenderSkeleton*) data;
        SocketPtr socket;
        bool isClosed = socketAppender->closed;
        while(!isClosed)
        {
                try
                {
                        Thread::sleep(socketAppender->reconnectionDelay);
                        if(!socketAppender->closed) {
                            LogLog::debug(LogString(LOG4CXX_STR("Attempting connection to "))
                                + socketAppender->address->getHostName());
                            socket = new Socket(socketAppender->address, socketAppender->port);
                            Pool p;
                            socketAppender->setSocket(socket, p);
                            LogLog::debug(LOG4CXX_STR("Connection established. Exiting connector thread."));
                        }
                        return NULL;
                }
                catch(ConnectException&)
                {
                        LogLog::debug(LOG4CXX_STR("Remote host ")
                                +socketAppender->address->getHostName()
                                +LOG4CXX_STR(" refused connection."));
                }
                catch(IOException& e)
                {
                        LogString exmsg;
                        log4cxx::helpers::Transcoder::decode(e.what(), exmsg);

                        LogLog::debug(((LogString) LOG4CXX_STR("Could not connect to "))
                                 + socketAppender->address->getHostName()
                                 + LOG4CXX_STR(". Exception is ")
                                 + exmsg);
                }
                isClosed = socketAppender->closed;
        }

        LogLog::debug(LOG4CXX_STR("Exiting Connector.run() method."));
        return NULL;
}
<commit_msg>LOGCXX-278: Threads for reconnecting sockets do not end cleanly when program exits<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if defined(_MSC_VER)
#pragma warning ( disable: 4231 4251 4275 4786 )
#endif

#define __STDC_CONSTANT_MACROS
#include <log4cxx/net/socketappenderskeleton.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/bytearrayoutputstream.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::net;

SocketAppenderSkeleton::SocketAppenderSkeleton(int defaultPort, int reconnectionDelay1)
:  remoteHost(),
   address(),
   port(defaultPort),
   reconnectionDelay(reconnectionDelay1),
   locationInfo(false),
   thread() {
}

SocketAppenderSkeleton::SocketAppenderSkeleton(InetAddressPtr address1, int port1, int delay)
:
   remoteHost(),
   address(address1),
   port(port1),
   reconnectionDelay(delay),
   locationInfo(false),
   thread() {
    remoteHost = this->address->getHostName();
}

SocketAppenderSkeleton::SocketAppenderSkeleton(const LogString& host, int port1, int delay)
:   remoteHost(host),
    address(InetAddress::getByName(host)),
    port(port1),
    reconnectionDelay(delay),
    locationInfo(false),
    thread() {
}

SocketAppenderSkeleton::~SocketAppenderSkeleton()
{
        finalize();
        try {
            thread.join();
        } catch(ThreadException& ex) {
            LogLog::error(LOG4CXX_STR("Error closing socket appender connection thread"), ex);
        }
}

void SocketAppenderSkeleton::activateOptions(Pool& p)
{
        AppenderSkeleton::activateOptions(p);
        connect(p);
}

void SocketAppenderSkeleton::close() {
    synchronized sync(mutex);
    if (closed) return;
    closed = true;
    cleanUp(pool);
    thread.interrupt();
}

void SocketAppenderSkeleton::connect(Pool& p) {
    if (address == 0) {
        LogLog::error(LogString(LOG4CXX_STR("No remote host is set for Appender named \"")) +
             name + LOG4CXX_STR("\"."));
    } else {
        cleanUp(p);
        try {
            SocketPtr socket(new Socket(address, port));
            setSocket(socket, p);
        } catch(SocketException& e) {
                LogString msg = LOG4CXX_STR("Could not connect to remote log4cxx server at [")
                        +address->getHostName()+LOG4CXX_STR("].");
                if(reconnectionDelay > 0)
                {
                        msg += LOG4CXX_STR(" We will try again later. ");
                }
                fireConnector(); // fire the connector thread
                LogLog::error(msg, e);
        }
    }
}

void SocketAppenderSkeleton::setOption(const LogString& option, const LogString& value)
{
        if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("REMOTEHOST"), LOG4CXX_STR("remotehost")))
        {
                setRemoteHost(value);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PORT"), LOG4CXX_STR("port")))
        {
                setPort(OptionConverter::toInt(value, getDefaultPort()));
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo")))
        {
                setLocationInfo(OptionConverter::toBoolean(value, false));
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("RECONNECTIONDELAY"), LOG4CXX_STR("reconnectiondelay")))
        {
                setReconnectionDelay(OptionConverter::toInt(value, getDefaultDelay()));
        }
        else
        {
                AppenderSkeleton::setOption(option, value);
        }
}

void SocketAppenderSkeleton::fireConnector()
{
        synchronized sync(mutex);
        if (!thread.isActive()) {
                thread.run(monitor, this);
        }
}

void* LOG4CXX_THREAD_FUNC SocketAppenderSkeleton::monitor(apr_thread_t* /* thread */, void* data) {
        SocketAppenderSkeleton* socketAppender = (SocketAppenderSkeleton*) data;
        SocketPtr socket;
        bool isClosed = socketAppender->closed;
        while(!isClosed)
        {
                try
                {
                        Thread::sleep(socketAppender->reconnectionDelay);
                        if(!socketAppender->closed) {
                            LogLog::debug(LogString(LOG4CXX_STR("Attempting connection to "))
                                + socketAppender->address->getHostName());
                            socket = new Socket(socketAppender->address, socketAppender->port);
                            Pool p;
                            socketAppender->setSocket(socket, p);
                            LogLog::debug(LOG4CXX_STR("Connection established. Exiting connector thread."));
                        }
                        return NULL;
                }
                catch(ConnectException&)
                {
                        LogLog::debug(LOG4CXX_STR("Remote host ")
                                +socketAppender->address->getHostName()
                                +LOG4CXX_STR(" refused connection."));
                }
                catch(IOException& e)
                {
                        LogString exmsg;
                        log4cxx::helpers::Transcoder::decode(e.what(), exmsg);

                        LogLog::debug(((LogString) LOG4CXX_STR("Could not connect to "))
                                 + socketAppender->address->getHostName()
                                 + LOG4CXX_STR(". Exception is ")
                                 + exmsg);
                }
                isClosed = socketAppender->closed;
        }

        LogLog::debug(LOG4CXX_STR("Exiting Connector.run() method."));
        return NULL;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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/dom_ui/fileicon_source.h"

#include "base/gfx/png_encoder.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"

// The path used in internal URLs to file icon data.
static const char kFileIconPath[] = "fileicon";

FileIconSource::FileIconSource()
    : DataSource(kFileIconPath, MessageLoop::current()) {}

FileIconSource::~FileIconSource() {
  cancelable_consumer_.CancelAllRequests();
}

void FileIconSource::StartDataRequest(const std::string& path,
                                      int request_id) {
  IconManager* im = g_browser_process->icon_manager();

  // Fast look up.
  SkBitmap* icon = im->LookupIcon(UTF8ToWide(path), IconLoader::NORMAL);

  if (icon) {
    std::vector<unsigned char> png_bytes;
    PNGEncoder::EncodeBGRASkBitmap(*icon, false, &png_bytes);

    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes(png_bytes);
    SendResponse(request_id, icon_data);
  } else {
    // Icon was not in cache, go fetch it slowly.
    IconManager::Handle h = im->LoadIcon(UTF8ToWide(path), IconLoader::NORMAL,
        &cancelable_consumer_,
        NewCallback(this, &FileIconSource::OnFileIconDataAvailable));

    // Attach the ChromeURLDataManager request ID to the history request.
    cancelable_consumer_.SetClientData(im, h, request_id);
  }
}

void FileIconSource::OnFileIconDataAvailable(IconManager::Handle handle,
                                             SkBitmap* icon) {
  IconManager* im = g_browser_process->icon_manager();
  int request_id = cancelable_consumer_.GetClientData(im, handle);

  if (icon) {
    std::vector<unsigned char> png_bytes;
    PNGEncoder::EncodeBGRASkBitmap(*icon, false, &png_bytes);

    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes(png_bytes);
    SendResponse(request_id, icon_data);
  } else {
    // TODO(glen): send a dummy icon.
    SendResponse(request_id, NULL);
  }
}<commit_msg>Show icons for exe files in download manager. Issue was that the paths were coming in with the wrong slash direction and escaping, which was OK for non-exes, but strangely bad for exes.<commit_after>// Copyright (c) 2006-2008 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/dom_ui/fileicon_source.h"

#include "base/gfx/png_encoder.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"

// The path used in internal URLs to file icon data.
static const char kFileIconPath[] = "fileicon";

FileIconSource::FileIconSource()
    : DataSource(kFileIconPath, MessageLoop::current()) {}

FileIconSource::~FileIconSource() {
  cancelable_consumer_.CancelAllRequests();
}

void FileIconSource::StartDataRequest(const std::string& path,
                                      int request_id) {
  IconManager* im = g_browser_process->icon_manager();

  // The path we receive has the wrong slashes and escaping for what we need;
  // this only appears to matter for getting icons from .exe files.
  std::string escaped_path = UnescapeURLComponent(path, UnescapeRule::SPACES);
  std::replace(escaped_path.begin(), escaped_path.end(), '/', '\\');

  // Fast look up.
  SkBitmap* icon = im->LookupIcon(UTF8ToWide(escaped_path), IconLoader::NORMAL);

  if (icon) {
    std::vector<unsigned char> png_bytes;
    PNGEncoder::EncodeBGRASkBitmap(*icon, false, &png_bytes);

    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes(png_bytes);
    SendResponse(request_id, icon_data);
  } else {
    // Icon was not in cache, go fetch it slowly.
    IconManager::Handle h = im->LoadIcon(UTF8ToWide(escaped_path),
        IconLoader::NORMAL,
        &cancelable_consumer_,
        NewCallback(this, &FileIconSource::OnFileIconDataAvailable));

    // Attach the ChromeURLDataManager request ID to the history request.
    cancelable_consumer_.SetClientData(im, h, request_id);
  }
}

void FileIconSource::OnFileIconDataAvailable(IconManager::Handle handle,
                                             SkBitmap* icon) {
  IconManager* im = g_browser_process->icon_manager();
  int request_id = cancelable_consumer_.GetClientData(im, handle);

  if (icon) {
    std::vector<unsigned char> png_bytes;
    PNGEncoder::EncodeBGRASkBitmap(*icon, false, &png_bytes);

    scoped_refptr<RefCountedBytes> icon_data = new RefCountedBytes(png_bytes);
    SendResponse(request_id, icon_data);
  } else {
    // TODO(glen): send a dummy icon.
    SendResponse(request_id, NULL);
  }
}<|endoftext|>


<commit_before>/* -*- c-basic-offset: 2 -*- */
/*
  Copyright(C) 2020  Sutou Kouhei <kou@clear-code.com>

  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <cstring>

#include "grn.h"
#include "grn_str.h"
#include "grn_token_column.h"
#include "grn_token_cursor.h"

#ifdef GRN_WITH_APACHE_ARROW
# include "grn_arrow.hpp"
# include <arrow/util/thread_pool.h>
# include <mutex>
#endif

namespace grn {
  namespace token_column {
    static uint32_t parallel_chunk_size = 1024;
    static uint32_t parallel_table_size_threshold = parallel_chunk_size * 10;

    class Builder
    {
    public:
      Builder(grn_ctx *ctx,
              grn_obj *column)
        : ctx_(ctx),
          column_(column),
          table_(grn_ctx_at(ctx, column->header.domain)),
          lexicon_(grn_ctx_at(ctx, DB_OBJ(column)->range)),
          source_(nullptr) {
        grn_id *source_ids = static_cast<grn_id *>(DB_OBJ(column)->source);
        source_ = grn_ctx_at(ctx, source_ids[0]);
      }

      ~Builder() {
        grn_obj_unref(ctx_, source_);
        grn_obj_unref(ctx_, lexicon_);
        grn_obj_unref(ctx_, table_);
      }

      void
      build() {
        grn_obj_set_visibility(ctx_, column_, false);
        if (use_parallel()) {
          build_parallel();
        } else {
          build_sequential();
        }
        grn_obj_set_visibility(ctx_, column_, true);
      }

    private:
      bool
      use_parallel() {
#ifdef GRN_WITH_APACHE_ARROW
        return grn_table_size(ctx_, table_) >= parallel_table_size_threshold;
#else
        return false;
#endif
      }

      void
      build_parallel() {
#ifdef GRN_WITH_APACHE_ARROW
        std::mutex mutex;
        auto pool = arrow::internal::GetCpuThreadPool();
        unsigned int token_flags = 0;
        grn_obj *db = grn_ctx_db(ctx_);
        uint32_t chunk_size = parallel_chunk_size;
        std::vector<grn_id> ids;
        auto build_chunk = [&](std::vector<grn_id> ids) {
          grn_ctx ctx;
          grn_ctx_init(&ctx, 0);
          grn_ctx_use(&ctx, db);
          grn_obj tokens;
          GRN_RECORD_INIT(&tokens, GRN_OBJ_VECTOR, DB_OBJ(lexicon_)->id);
          for (auto id : ids) {
            GRN_BULK_REWIND(&tokens);
            uint32_t value_size;
            auto value = grn_obj_get_value_(&ctx, source_, id, &value_size);
            if (value_size > 0) {
              auto token_cursor = grn_token_cursor_open(&ctx,
                                                        lexicon_,
                                                        value,
                                                        value_size,
                                                        GRN_TOKEN_ADD,
                                                        token_flags);
              if (token_cursor) {
                while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
                  grn_id token_id = grn_token_cursor_next(&ctx, token_cursor);
                  GRN_RECORD_PUT(&ctx, &tokens, token_id);
                }
                grn_token_cursor_close(&ctx, token_cursor);
              }
            }
            grn_obj_set_value(&ctx, column_, id, &tokens, GRN_OBJ_SET);
            if (ctx.rc != GRN_SUCCESS) {
              break;
            }
          }
          GRN_OBJ_FIN(&ctx, &tokens);
          if (ctx.rc != GRN_SUCCESS) {
            std::lock_guard<std::mutex> lock(mutex);
            if (ctx_->rc == GRN_SUCCESS) {
              ctx_->rc = ctx.rc;
              ctx_->errlvl = ctx.errlvl;
              ctx_->errfile = ctx.errfile;
              ctx_->errline = ctx.errline;
              ctx_->errfunc = ctx.errfunc;
              grn_strcpy(ctx_->errbuf, GRN_CTX_MSGSIZE, ctx.errbuf);
            }
          }
          grn_ctx_fin(&ctx);
          return arrow::Status::OK();
        };

        std::vector<arrow::Future<arrow::Status>> futures;
        GRN_TABLE_EACH_BEGIN(ctx_, table_, cursor, id) {
          ids.push_back(id);
          if (ids.size() == chunk_size) {
            auto future = pool->Submit(build_chunk, ids);
            if (!grnarrow::check(ctx_,
                                 future,
                                 "[token-column][build][parallel] "
                                 "failed to submit a job")) {
              break;
            }
            futures.push_back(*future);
            ids.clear();
          }
        } GRN_TABLE_EACH_END(ctx_, cursor);
        if (ctx_->rc == GRN_SUCCESS && !ids.empty()) {
          auto future = pool->Submit(build_chunk, ids);
          if (grnarrow::check(ctx_,
                              future,
                              "[token-column][build][parallel] "
                              "failed to submit a job")) {
            futures.push_back(*future);
          }
        }
        auto status = arrow::Status::OK();
        for (auto& future : futures) {
          status &= future.status();
        }
        grnarrow::check(ctx_,
                        status,
                        "[token-column][build][parallel] "
                        "failed to complete a job");
#endif
      }

      void
      build_sequential() {
        grn_obj tokens;
        GRN_RECORD_INIT(&tokens, GRN_OBJ_VECTOR, DB_OBJ(lexicon_)->id);
        unsigned int token_flags = 0;
        GRN_TABLE_EACH_BEGIN(ctx_, table_, cursor, id) {
          GRN_BULK_REWIND(&tokens);
          uint32_t value_size;
          const char *value = grn_obj_get_value_(ctx_, source_, id, &value_size);
          if (value_size > 0) {
            grn_token_cursor *token_cursor = grn_token_cursor_open(ctx_,
                                                                   lexicon_,
                                                                   value,
                                                                   value_size,
                                                                   GRN_TOKEN_ADD,
                                                                   token_flags);
            if (token_cursor) {
              while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
                grn_id token_id = grn_token_cursor_next(ctx_, token_cursor);
                GRN_RECORD_PUT(ctx_, &tokens, token_id);
              }
              grn_token_cursor_close(ctx_, token_cursor);
            }
          }
          grn_obj_set_value(ctx_, column_, id, &tokens, GRN_OBJ_SET);
          if (ctx_->rc != GRN_SUCCESS) {
            break;
          }
        } GRN_TABLE_EACH_END(ctx_, cursor);
        GRN_OBJ_FIN(ctx_, &tokens);
      }

      grn_ctx *ctx_;
      grn_obj *column_;
      grn_obj *table_;
      grn_obj *lexicon_;
      grn_obj *source_;
    };
  }
}

extern "C" {
  void
  grn_token_column_init_from_env(void)
  {
    {
      char grn_token_column_parallel_chunk_size_env[GRN_ENV_BUFFER_SIZE];
      grn_getenv("GRN_TOKEN_COLUMN_PARALLEL_CHUNK_SIZE",
                 grn_token_column_parallel_chunk_size_env,
                 GRN_ENV_BUFFER_SIZE);
      if (grn_token_column_parallel_chunk_size_env[0]) {
        size_t env_len = strlen(grn_token_column_parallel_chunk_size_env);
        uint32_t chunk_size =
          grn_atoui(grn_token_column_parallel_chunk_size_env,
                    grn_token_column_parallel_chunk_size_env + env_len,
                    NULL);
        if (chunk_size > 0) {
          grn::token_column::parallel_chunk_size = chunk_size;
        }
      }
    }

    {
      char grn_token_column_parallel_table_size_threshold_env[GRN_ENV_BUFFER_SIZE];
      grn_getenv("GRN_TOKEN_COLUMN_PARALLEL_TABLE_SIZE_THRESHOLD",
                 grn_token_column_parallel_table_size_threshold_env,
                 GRN_ENV_BUFFER_SIZE);
      if (grn_token_column_parallel_table_size_threshold_env[0]) {
        size_t env_len =
          strlen(grn_token_column_parallel_table_size_threshold_env);
        uint32_t threshold =
          grn_atoui(grn_token_column_parallel_table_size_threshold_env,
                    grn_token_column_parallel_table_size_threshold_env + env_len,
                    NULL);
        if (threshold > 0) {
          grn::token_column::parallel_table_size_threshold = threshold;
        }
      }
    }
  }

  void
  grn_token_column_update(grn_ctx *ctx,
                          grn_obj *column,
                          grn_id id,
                          int section,
                          grn_obj *old_value,
                          grn_obj *new_value)
  {
    grn_obj *lexicon = grn_ctx_at(ctx, DB_OBJ(column)->range);
    grn_obj tokens;
    GRN_RECORD_INIT(&tokens, GRN_OBJ_VECTOR, DB_OBJ(lexicon)->id);
    unsigned int token_flags = 0;
    grn_token_cursor *token_cursor =
      grn_token_cursor_open(ctx,
                            lexicon,
                            GRN_TEXT_VALUE(new_value),
                            GRN_TEXT_LEN(new_value),
                            GRN_TOKEN_ADD,
                            token_flags);
    if (token_cursor) {
      while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
        grn_id token_id = grn_token_cursor_next(ctx, token_cursor);
        GRN_RECORD_PUT(ctx, &tokens, token_id);
      }
      grn_token_cursor_close(ctx, token_cursor);
    }
    grn_obj_set_value(ctx, column, id, &tokens, GRN_OBJ_SET);
    GRN_OBJ_FIN(ctx, &tokens);
    grn_obj_unref(ctx, lexicon);
  }

  void
  grn_token_column_build(grn_ctx *ctx, grn_obj *column)
  {
    grn::token_column::Builder builder(ctx, column);
    builder.build();
  }
}
<commit_msg>token_column: reduce scope<commit_after>/* -*- c-basic-offset: 2 -*- */
/*
  Copyright(C) 2020  Sutou Kouhei <kou@clear-code.com>

  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <cstring>

#include "grn.h"
#include "grn_str.h"
#include "grn_token_column.h"
#include "grn_token_cursor.h"

#ifdef GRN_WITH_APACHE_ARROW
# include "grn_arrow.hpp"
# include <arrow/util/thread_pool.h>
# include <mutex>
#endif

namespace grn {
  namespace token_column {
    static uint32_t parallel_chunk_size = 1024;
    static uint32_t parallel_table_size_threshold = parallel_chunk_size * 10;

    class Builder
    {
    public:
      Builder(grn_ctx *ctx,
              grn_obj *column)
        : ctx_(ctx),
          column_(column),
          table_(grn_ctx_at(ctx, column->header.domain)),
          lexicon_(grn_ctx_at(ctx, DB_OBJ(column)->range)),
          source_(nullptr) {
        grn_id *source_ids = static_cast<grn_id *>(DB_OBJ(column)->source);
        source_ = grn_ctx_at(ctx, source_ids[0]);
      }

      ~Builder() {
        grn_obj_unref(ctx_, source_);
        grn_obj_unref(ctx_, lexicon_);
        grn_obj_unref(ctx_, table_);
      }

      void
      build() {
        grn_obj_set_visibility(ctx_, column_, false);
        if (use_parallel()) {
          build_parallel();
        } else {
          build_sequential();
        }
        grn_obj_set_visibility(ctx_, column_, true);
      }

    private:
      bool
      use_parallel() {
#ifdef GRN_WITH_APACHE_ARROW
        return grn_table_size(ctx_, table_) >= parallel_table_size_threshold;
#else
        return false;
#endif
      }

      void
      build_parallel() {
#ifdef GRN_WITH_APACHE_ARROW
        std::mutex mutex;
        auto pool = arrow::internal::GetCpuThreadPool();
        unsigned int token_flags = 0;
        grn_obj *db = grn_ctx_db(ctx_);
        uint32_t chunk_size = parallel_chunk_size;
        auto build_chunk = [&](std::vector<grn_id> ids) {
          grn_ctx ctx;
          grn_ctx_init(&ctx, 0);
          grn_ctx_use(&ctx, db);
          grn_obj tokens;
          GRN_RECORD_INIT(&tokens, GRN_OBJ_VECTOR, DB_OBJ(lexicon_)->id);
          for (auto id : ids) {
            GRN_BULK_REWIND(&tokens);
            uint32_t value_size;
            auto value = grn_obj_get_value_(&ctx, source_, id, &value_size);
            if (value_size > 0) {
              auto token_cursor = grn_token_cursor_open(&ctx,
                                                        lexicon_,
                                                        value,
                                                        value_size,
                                                        GRN_TOKEN_ADD,
                                                        token_flags);
              if (token_cursor) {
                while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
                  grn_id token_id = grn_token_cursor_next(&ctx, token_cursor);
                  GRN_RECORD_PUT(&ctx, &tokens, token_id);
                }
                grn_token_cursor_close(&ctx, token_cursor);
              }
            }
            grn_obj_set_value(&ctx, column_, id, &tokens, GRN_OBJ_SET);
            if (ctx.rc != GRN_SUCCESS) {
              break;
            }
          }
          GRN_OBJ_FIN(&ctx, &tokens);
          if (ctx.rc != GRN_SUCCESS) {
            std::lock_guard<std::mutex> lock(mutex);
            if (ctx_->rc == GRN_SUCCESS) {
              ctx_->rc = ctx.rc;
              ctx_->errlvl = ctx.errlvl;
              ctx_->errfile = ctx.errfile;
              ctx_->errline = ctx.errline;
              ctx_->errfunc = ctx.errfunc;
              grn_strcpy(ctx_->errbuf, GRN_CTX_MSGSIZE, ctx.errbuf);
            }
          }
          grn_ctx_fin(&ctx);
          return arrow::Status::OK();
        };

        std::vector<grn_id> ids;
        std::vector<arrow::Future<arrow::Status>> futures;
        GRN_TABLE_EACH_BEGIN(ctx_, table_, cursor, id) {
          ids.push_back(id);
          if (ids.size() == chunk_size) {
            auto future = pool->Submit(build_chunk, ids);
            if (!grnarrow::check(ctx_,
                                 future,
                                 "[token-column][build][parallel] "
                                 "failed to submit a job")) {
              break;
            }
            futures.push_back(*future);
            ids.clear();
          }
        } GRN_TABLE_EACH_END(ctx_, cursor);
        if (ctx_->rc == GRN_SUCCESS && !ids.empty()) {
          auto future = pool->Submit(build_chunk, ids);
          if (grnarrow::check(ctx_,
                              future,
                              "[token-column][build][parallel] "
                              "failed to submit a job")) {
            futures.push_back(*future);
          }
        }
        auto status = arrow::Status::OK();
        for (auto& future : futures) {
          status &= future.status();
        }
        grnarrow::check(ctx_,
                        status,
                        "[token-column][build][parallel] "
                        "failed to complete a job");
#endif
      }

      void
      build_sequential() {
        grn_obj tokens;
        GRN_RECORD_INIT(&tokens, GRN_OBJ_VECTOR, DB_OBJ(lexicon_)->id);
        unsigned int token_flags = 0;
        GRN_TABLE_EACH_BEGIN(ctx_, table_, cursor, id) {
          GRN_BULK_REWIND(&tokens);
          uint32_t value_size;
          const char *value = grn_obj_get_value_(ctx_, source_, id, &value_size);
          if (value_size > 0) {
            grn_token_cursor *token_cursor = grn_token_cursor_open(ctx_,
                                                                   lexicon_,
                                                                   value,
                                                                   value_size,
                                                                   GRN_TOKEN_ADD,
                                                                   token_flags);
            if (token_cursor) {
              while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
                grn_id token_id = grn_token_cursor_next(ctx_, token_cursor);
                GRN_RECORD_PUT(ctx_, &tokens, token_id);
              }
              grn_token_cursor_close(ctx_, token_cursor);
            }
          }
          grn_obj_set_value(ctx_, column_, id, &tokens, GRN_OBJ_SET);
          if (ctx_->rc != GRN_SUCCESS) {
            break;
          }
        } GRN_TABLE_EACH_END(ctx_, cursor);
        GRN_OBJ_FIN(ctx_, &tokens);
      }

      grn_ctx *ctx_;
      grn_obj *column_;
      grn_obj *table_;
      grn_obj *lexicon_;
      grn_obj *source_;
    };
  }
}

extern "C" {
  void
  grn_token_column_init_from_env(void)
  {
    {
      char grn_token_column_parallel_chunk_size_env[GRN_ENV_BUFFER_SIZE];
      grn_getenv("GRN_TOKEN_COLUMN_PARALLEL_CHUNK_SIZE",
                 grn_token_column_parallel_chunk_size_env,
                 GRN_ENV_BUFFER_SIZE);
      if (grn_token_column_parallel_chunk_size_env[0]) {
        size_t env_len = strlen(grn_token_column_parallel_chunk_size_env);
        uint32_t chunk_size =
          grn_atoui(grn_token_column_parallel_chunk_size_env,
                    grn_token_column_parallel_chunk_size_env + env_len,
                    NULL);
        if (chunk_size > 0) {
          grn::token_column::parallel_chunk_size = chunk_size;
        }
      }
    }

    {
      char grn_token_column_parallel_table_size_threshold_env[GRN_ENV_BUFFER_SIZE];
      grn_getenv("GRN_TOKEN_COLUMN_PARALLEL_TABLE_SIZE_THRESHOLD",
                 grn_token_column_parallel_table_size_threshold_env,
                 GRN_ENV_BUFFER_SIZE);
      if (grn_token_column_parallel_table_size_threshold_env[0]) {
        size_t env_len =
          strlen(grn_token_column_parallel_table_size_threshold_env);
        uint32_t threshold =
          grn_atoui(grn_token_column_parallel_table_size_threshold_env,
                    grn_token_column_parallel_table_size_threshold_env + env_len,
                    NULL);
        if (threshold > 0) {
          grn::token_column::parallel_table_size_threshold = threshold;
        }
      }
    }
  }

  void
  grn_token_column_update(grn_ctx *ctx,
                          grn_obj *column,
                          grn_id id,
                          int section,
                          grn_obj *old_value,
                          grn_obj *new_value)
  {
    grn_obj *lexicon = grn_ctx_at(ctx, DB_OBJ(column)->range);
    grn_obj tokens;
    GRN_RECORD_INIT(&tokens, GRN_OBJ_VECTOR, DB_OBJ(lexicon)->id);
    unsigned int token_flags = 0;
    grn_token_cursor *token_cursor =
      grn_token_cursor_open(ctx,
                            lexicon,
                            GRN_TEXT_VALUE(new_value),
                            GRN_TEXT_LEN(new_value),
                            GRN_TOKEN_ADD,
                            token_flags);
    if (token_cursor) {
      while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
        grn_id token_id = grn_token_cursor_next(ctx, token_cursor);
        GRN_RECORD_PUT(ctx, &tokens, token_id);
      }
      grn_token_cursor_close(ctx, token_cursor);
    }
    grn_obj_set_value(ctx, column, id, &tokens, GRN_OBJ_SET);
    GRN_OBJ_FIN(ctx, &tokens);
    grn_obj_unref(ctx, lexicon);
  }

  void
  grn_token_column_build(grn_ctx *ctx, grn_obj *column)
  {
    grn::token_column::Builder builder(ctx, column);
    builder.build();
  }
}
<|endoftext|>