<commit_before>// Copyright (c) 2012 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/service/service_process.h"

#include <algorithm>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/i18n/rtl.h"
#include "base/memory/singleton.h"
#include "base/path_service.h"
#include "base/prefs/json_pref_store.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/service_process_util.h"
#include "chrome/service/cloud_print/cloud_print_proxy.h"
#include "chrome/service/net/service_url_request_context.h"
#include "chrome/service/service_ipc_server.h"
#include "chrome/service/service_process_prefs.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/network_change_notifier.h"
#include "net/url_request/url_fetcher.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"

#if defined(OS_LINUX) || defined(OS_OPENBSD)
#include <glib-object.h>
#endif

#if defined(TOOLKIT_GTK)
#include <gtk/gtk.h>
#include "ui/gfx/gtk_util.h"
#endif

ServiceProcess* g_service_process = NULL;

namespace {

// Delay in seconds after the last service is disabled before we attempt
// a shutdown.
const int kShutdownDelaySeconds = 60;

// Delay in hours between launching a browser process to check the
// policy for us.
const int64 kPolicyCheckDelayHours = 8;

const char kDefaultServiceProcessLocale[] = "en-US";

class ServiceIOThread : public base::Thread {
 public:
  explicit ServiceIOThread(const char* name);
  virtual ~ServiceIOThread();

 protected:
  virtual void CleanUp() OVERRIDE;

 private:
  DISALLOW_COPY_AND_ASSIGN(ServiceIOThread);
};

ServiceIOThread::ServiceIOThread(const char* name) : base::Thread(name) {}
ServiceIOThread::~ServiceIOThread() {
  Stop();
}

void ServiceIOThread::CleanUp() {
  net::URLFetcher::CancelAll();
}

// Prepares the localized strings that are going to be displayed to
// the user if the service 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) {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  // Clear this var so child processes don't show the dialog by default.
  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::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.
  base::string16 dlg_strings(
      l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
  dlg_strings.push_back('|');
  base::string16 adjusted_string(l10n_util::GetStringFUTF16(
      IDS_SERVICE_CRASH_RECOVERY_CONTENT,
      l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT)));
  base::i18n::AdjustStringForLocaleDirection(&adjusted_string);
  dlg_strings.append(adjusted_string);
  dlg_strings.push_back('|');
  dlg_strings.append(base::ASCIIToUTF16(
      base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));

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

}  // namespace

ServiceProcess::ServiceProcess()
  : shutdown_event_(true, false),
    main_message_loop_(NULL),
    enabled_services_(0),
    update_available_(false) {
  DCHECK(!g_service_process);
  g_service_process = this;
}

bool ServiceProcess::Initialize(base::MessageLoopForUI* message_loop,
                                const CommandLine& command_line,
                                ServiceProcessState* state) {
#if defined(TOOLKIT_GTK)
  // TODO(jamiewalch): Calling GtkInitFromCommandLine here causes the process
  // to abort if run headless. The correct fix for this is to refactor the
  // service process to be more modular, a task that is currently underway.
  // However, since this problem is blocking cloud print, the following quick
  // hack will have to do. Note that the situation with this hack in place is
  // no worse than it was when we weren't initializing GTK at all.
  int argc = 1;
  scoped_ptr<char*[]> argv(new char*[2]);
  argv[0] = strdup(command_line.argv()[0].c_str());
  argv[1] = NULL;
  char **argv_pointer = argv.get();
  gtk_init_check(&argc, &argv_pointer);
  free(argv[0]);
#elif defined(OS_LINUX) || defined(OS_OPENBSD)
  // g_type_init has been deprecated since version 2.35.
#if !GLIB_CHECK_VERSION(2, 35, 0)
  // GLib type system initialization is needed for gconf.
  g_type_init();
#endif
#endif // defined(OS_LINUX) || defined(OS_OPENBSD)
  main_message_loop_ = message_loop;
  service_process_state_.reset(state);
  network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
  base::Thread::Options options;
  options.message_loop_type = base::MessageLoop::TYPE_IO;
  io_thread_.reset(new ServiceIOThread("ServiceProcess_IO"));
  file_thread_.reset(new base::Thread("ServiceProcess_File"));
  if (!io_thread_->StartWithOptions(options) ||
      !file_thread_->StartWithOptions(options)) {
    NOTREACHED();
    Teardown();
    return false;
  }
  blocking_pool_ = new base::SequencedWorkerPool(3, "ServiceBlocking");

  request_context_getter_ = new ServiceURLRequestContextGetter();

  base::FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  base::FilePath pref_path =
      user_data_dir.Append(chrome::kServiceStateFileName);
  service_prefs_.reset(new ServiceProcessPrefs(
      pref_path,
      JsonPrefStore::GetTaskRunnerForFile(pref_path, blocking_pool_.get())
          .get()));
  service_prefs_->ReadPrefs();

  // This switch it required to run connector with test gaia.
  if (command_line.HasSwitch(switches::kIgnoreUrlFetcherCertRequests))
    net::URLFetcher::SetIgnoreCertificateRequests(true);

  // Check if a locale override has been specified on the command-line.
  std::string locale = command_line.GetSwitchValueASCII(switches::kLang);
  if (!locale.empty()) {
    service_prefs_->SetString(prefs::kApplicationLocale, locale);
    service_prefs_->WritePrefs();
  } else {
    // If no command-line value was specified, read the last used locale from
    // the prefs.
    locale =
        service_prefs_->GetString(prefs::kApplicationLocale, std::string());
    // If no locale was specified anywhere, use the default one.
    if (locale.empty())
      locale = kDefaultServiceProcessLocale;
  }
  ResourceBundle::InitSharedInstanceWithLocale(locale, NULL);

  PrepareRestartOnCrashEnviroment(command_line);

  // Enable Cloud Print if needed. First check the command-line.
  // Then check if the cloud print proxy was previously enabled.
  if (command_line.HasSwitch(switches::kEnableCloudPrintProxy) ||
      service_prefs_->GetBoolean(prefs::kCloudPrintProxyEnabled, false)) {
    GetCloudPrintProxy()->EnableForUser();
  }

  VLOG(1) << "Starting Service Process IPC Server";
  ipc_server_.reset(new ServiceIPCServer(
      service_process_state_->GetServiceProcessChannel()));
  ipc_server_->Init();

  // After the IPC server has started we signal that the service process is
  // ready.
  if (!service_process_state_->SignalReady(
          io_thread_->message_loop_proxy().get(),
          base::Bind(&ServiceProcess::Terminate, base::Unretained(this)))) {
    return false;
  }

  // See if we need to stay running.
  ScheduleShutdownCheck();

  // Occasionally check to see if we need to launch the browser to get the
  // policy state information.
  CloudPrintPolicyCheckIfNeeded();
  return true;
}

bool ServiceProcess::Teardown() {
  service_prefs_.reset();
  cloud_print_proxy_.reset();

  ipc_server_.reset();
  // Signal this event before shutting down the service process. That way all
  // background threads can cleanup.
  shutdown_event_.Signal();
  io_thread_.reset();
  file_thread_.reset();

  if (blocking_pool_.get()) {
    // The goal is to make it impossible for chrome to 'infinite loop' during
    // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks
    // queued during shutdown get run. There's nothing particularly scientific
    // about the number chosen.
    const int kMaxNewShutdownBlockingTasks = 1000;
    blocking_pool_->Shutdown(kMaxNewShutdownBlockingTasks);
    blocking_pool_ = NULL;
  }

  // The NetworkChangeNotifier must be destroyed after all other threads that
  // might use it have been shut down.
  network_change_notifier_.reset();

  service_process_state_->SignalStopped();
  return true;
}

// This method is called when a shutdown command is received from IPC channel
// or there was an error in the IPC channel.
void ServiceProcess::Shutdown() {
#if defined(OS_MACOSX)
  // On MacOS X the service must be removed from the launchd job list.
  // http://www.chromium.org/developers/design-documents/service-processes
  // The best way to do that is to go through the ForceServiceProcessShutdown
  // path. If it succeeds Terminate() will be called from the handler registered
  // via service_process_state_->SignalReady().
  // On failure call Terminate() directly to force the process to actually
  // terminate.
  if (!ForceServiceProcessShutdown("", 0)) {
    Terminate();
  }
#else
  Terminate();
#endif
}

void ServiceProcess::Terminate() {
  main_message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
}

bool ServiceProcess::HandleClientDisconnect() {
  // If there are no enabled services or if there is an update available
  // we want to shutdown right away. Else we want to keep listening for
  // new connections.
  if (!enabled_services_ || update_available()) {
    Shutdown();
    return false;
  }
  return true;
}

cloud_print::CloudPrintProxy* ServiceProcess::GetCloudPrintProxy() {
  if (!cloud_print_proxy_.get()) {
    cloud_print_proxy_.reset(new cloud_print::CloudPrintProxy());
    cloud_print_proxy_->Initialize(service_prefs_.get(), this);
  }
  return cloud_print_proxy_.get();
}

void ServiceProcess::OnCloudPrintProxyEnabled(bool persist_state) {
  if (persist_state) {
    // Save the preference that we have enabled the cloud print proxy.
    service_prefs_->SetBoolean(prefs::kCloudPrintProxyEnabled, true);
    service_prefs_->WritePrefs();
  }
  OnServiceEnabled();
}

void ServiceProcess::OnCloudPrintProxyDisabled(bool persist_state) {
  if (persist_state) {
    // Save the preference that we have disabled the cloud print proxy.
    service_prefs_->SetBoolean(prefs::kCloudPrintProxyEnabled, false);
    service_prefs_->WritePrefs();
  }
  OnServiceDisabled();
}

ServiceURLRequestContextGetter*
ServiceProcess::GetServiceURLRequestContextGetter() {
  DCHECK(request_context_getter_.get());
  return request_context_getter_.get();
}

void ServiceProcess::OnServiceEnabled() {
  enabled_services_++;
  if ((1 == enabled_services_) &&
      !CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kNoServiceAutorun)) {
    if (!service_process_state_->AddToAutoRun()) {
      // TODO(scottbyer/sanjeevr/dmaclach): Handle error condition
      LOG(ERROR) << "Unable to AddToAutoRun";
    }
  }
}

void ServiceProcess::OnServiceDisabled() {
  DCHECK_NE(enabled_services_, 0);
  enabled_services_--;
  if (0 == enabled_services_) {
    if (!service_process_state_->RemoveFromAutoRun()) {
      // TODO(scottbyer/sanjeevr/dmaclach): Handle error condition
      LOG(ERROR) << "Unable to RemoveFromAutoRun";
    }
    // We will wait for some time to respond to IPCs before shutting down.
    ScheduleShutdownCheck();
  }
}

void ServiceProcess::ScheduleShutdownCheck() {
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&ServiceProcess::ShutdownIfNeeded, base::Unretained(this)),
      base::TimeDelta::FromSeconds(kShutdownDelaySeconds));
}

void ServiceProcess::ShutdownIfNeeded() {
  if (0 == enabled_services_) {
    if (ipc_server_->is_client_connected()) {
      // If there is a client connected, we need to try again later.
      // Note that there is still a timing window here because a client may
      // decide to connect at this point.
      // TODO(sanjeevr): Fix this timing window.
      ScheduleShutdownCheck();
    } else {
      Shutdown();
    }
  }
}

void ServiceProcess::ScheduleCloudPrintPolicyCheck() {
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&ServiceProcess::CloudPrintPolicyCheckIfNeeded,
                 base::Unretained(this)),
      base::TimeDelta::FromHours(kPolicyCheckDelayHours));
}

void ServiceProcess::CloudPrintPolicyCheckIfNeeded() {
  if (enabled_services_ && !ipc_server_->is_client_connected()) {
    GetCloudPrintProxy()->CheckCloudPrintProxyPolicy();
  }
  ScheduleCloudPrintPolicyCheck();
}

ServiceProcess::~ServiceProcess() {
  Teardown();
  g_service_process = NULL;
}
<commit_msg>Use USE_GLIB flag instead of OS_XXXX for choosing whether to initialize glib.<commit_after>// Copyright (c) 2012 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/service/service_process.h"

#include <algorithm>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/i18n/rtl.h"
#include "base/memory/singleton.h"
#include "base/path_service.h"
#include "base/prefs/json_pref_store.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/service_process_util.h"
#include "chrome/service/cloud_print/cloud_print_proxy.h"
#include "chrome/service/net/service_url_request_context.h"
#include "chrome/service/service_ipc_server.h"
#include "chrome/service/service_process_prefs.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/network_change_notifier.h"
#include "net/url_request/url_fetcher.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"

#if defined(USE_GLIB)
#include <glib-object.h>
#endif

#if defined(TOOLKIT_GTK)
#include <gtk/gtk.h>
#include "ui/gfx/gtk_util.h"
#endif

ServiceProcess* g_service_process = NULL;

namespace {

// Delay in seconds after the last service is disabled before we attempt
// a shutdown.
const int kShutdownDelaySeconds = 60;

// Delay in hours between launching a browser process to check the
// policy for us.
const int64 kPolicyCheckDelayHours = 8;

const char kDefaultServiceProcessLocale[] = "en-US";

class ServiceIOThread : public base::Thread {
 public:
  explicit ServiceIOThread(const char* name);
  virtual ~ServiceIOThread();

 protected:
  virtual void CleanUp() OVERRIDE;

 private:
  DISALLOW_COPY_AND_ASSIGN(ServiceIOThread);
};

ServiceIOThread::ServiceIOThread(const char* name) : base::Thread(name) {}
ServiceIOThread::~ServiceIOThread() {
  Stop();
}

void ServiceIOThread::CleanUp() {
  net::URLFetcher::CancelAll();
}

// Prepares the localized strings that are going to be displayed to
// the user if the service 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) {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  // Clear this var so child processes don't show the dialog by default.
  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::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.
  base::string16 dlg_strings(
      l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
  dlg_strings.push_back('|');
  base::string16 adjusted_string(l10n_util::GetStringFUTF16(
      IDS_SERVICE_CRASH_RECOVERY_CONTENT,
      l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT)));
  base::i18n::AdjustStringForLocaleDirection(&adjusted_string);
  dlg_strings.append(adjusted_string);
  dlg_strings.push_back('|');
  dlg_strings.append(base::ASCIIToUTF16(
      base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));

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

}  // namespace

ServiceProcess::ServiceProcess()
  : shutdown_event_(true, false),
    main_message_loop_(NULL),
    enabled_services_(0),
    update_available_(false) {
  DCHECK(!g_service_process);
  g_service_process = this;
}

bool ServiceProcess::Initialize(base::MessageLoopForUI* message_loop,
                                const CommandLine& command_line,
                                ServiceProcessState* state) {
#if defined(TOOLKIT_GTK)
  // TODO(jamiewalch): Calling GtkInitFromCommandLine here causes the process
  // to abort if run headless. The correct fix for this is to refactor the
  // service process to be more modular, a task that is currently underway.
  // However, since this problem is blocking cloud print, the following quick
  // hack will have to do. Note that the situation with this hack in place is
  // no worse than it was when we weren't initializing GTK at all.
  int argc = 1;
  scoped_ptr<char*[]> argv(new char*[2]);
  argv[0] = strdup(command_line.argv()[0].c_str());
  argv[1] = NULL;
  char **argv_pointer = argv.get();
  gtk_init_check(&argc, &argv_pointer);
  free(argv[0]);
#elif defined(USE_GLIB)
  // g_type_init has been deprecated since version 2.35.
#if !GLIB_CHECK_VERSION(2, 35, 0)
  // GLib type system initialization is needed for gconf.
  g_type_init();
#endif
#endif // defined(OS_LINUX) || defined(OS_OPENBSD)
  main_message_loop_ = message_loop;
  service_process_state_.reset(state);
  network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
  base::Thread::Options options;
  options.message_loop_type = base::MessageLoop::TYPE_IO;
  io_thread_.reset(new ServiceIOThread("ServiceProcess_IO"));
  file_thread_.reset(new base::Thread("ServiceProcess_File"));
  if (!io_thread_->StartWithOptions(options) ||
      !file_thread_->StartWithOptions(options)) {
    NOTREACHED();
    Teardown();
    return false;
  }
  blocking_pool_ = new base::SequencedWorkerPool(3, "ServiceBlocking");

  request_context_getter_ = new ServiceURLRequestContextGetter();

  base::FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  base::FilePath pref_path =
      user_data_dir.Append(chrome::kServiceStateFileName);
  service_prefs_.reset(new ServiceProcessPrefs(
      pref_path,
      JsonPrefStore::GetTaskRunnerForFile(pref_path, blocking_pool_.get())
          .get()));
  service_prefs_->ReadPrefs();

  // This switch it required to run connector with test gaia.
  if (command_line.HasSwitch(switches::kIgnoreUrlFetcherCertRequests))
    net::URLFetcher::SetIgnoreCertificateRequests(true);

  // Check if a locale override has been specified on the command-line.
  std::string locale = command_line.GetSwitchValueASCII(switches::kLang);
  if (!locale.empty()) {
    service_prefs_->SetString(prefs::kApplicationLocale, locale);
    service_prefs_->WritePrefs();
  } else {
    // If no command-line value was specified, read the last used locale from
    // the prefs.
    locale =
        service_prefs_->GetString(prefs::kApplicationLocale, std::string());
    // If no locale was specified anywhere, use the default one.
    if (locale.empty())
      locale = kDefaultServiceProcessLocale;
  }
  ResourceBundle::InitSharedInstanceWithLocale(locale, NULL);

  PrepareRestartOnCrashEnviroment(command_line);

  // Enable Cloud Print if needed. First check the command-line.
  // Then check if the cloud print proxy was previously enabled.
  if (command_line.HasSwitch(switches::kEnableCloudPrintProxy) ||
      service_prefs_->GetBoolean(prefs::kCloudPrintProxyEnabled, false)) {
    GetCloudPrintProxy()->EnableForUser();
  }

  VLOG(1) << "Starting Service Process IPC Server";
  ipc_server_.reset(new ServiceIPCServer(
      service_process_state_->GetServiceProcessChannel()));
  ipc_server_->Init();

  // After the IPC server has started we signal that the service process is
  // ready.
  if (!service_process_state_->SignalReady(
          io_thread_->message_loop_proxy().get(),
          base::Bind(&ServiceProcess::Terminate, base::Unretained(this)))) {
    return false;
  }

  // See if we need to stay running.
  ScheduleShutdownCheck();

  // Occasionally check to see if we need to launch the browser to get the
  // policy state information.
  CloudPrintPolicyCheckIfNeeded();
  return true;
}

bool ServiceProcess::Teardown() {
  service_prefs_.reset();
  cloud_print_proxy_.reset();

  ipc_server_.reset();
  // Signal this event before shutting down the service process. That way all
  // background threads can cleanup.
  shutdown_event_.Signal();
  io_thread_.reset();
  file_thread_.reset();

  if (blocking_pool_.get()) {
    // The goal is to make it impossible for chrome to 'infinite loop' during
    // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks
    // queued during shutdown get run. There's nothing particularly scientific
    // about the number chosen.
    const int kMaxNewShutdownBlockingTasks = 1000;
    blocking_pool_->Shutdown(kMaxNewShutdownBlockingTasks);
    blocking_pool_ = NULL;
  }

  // The NetworkChangeNotifier must be destroyed after all other threads that
  // might use it have been shut down.
  network_change_notifier_.reset();

  service_process_state_->SignalStopped();
  return true;
}

// This method is called when a shutdown command is received from IPC channel
// or there was an error in the IPC channel.
void ServiceProcess::Shutdown() {
#if defined(OS_MACOSX)
  // On MacOS X the service must be removed from the launchd job list.
  // http://www.chromium.org/developers/design-documents/service-processes
  // The best way to do that is to go through the ForceServiceProcessShutdown
  // path. If it succeeds Terminate() will be called from the handler registered
  // via service_process_state_->SignalReady().
  // On failure call Terminate() directly to force the process to actually
  // terminate.
  if (!ForceServiceProcessShutdown("", 0)) {
    Terminate();
  }
#else
  Terminate();
#endif
}

void ServiceProcess::Terminate() {
  main_message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
}

bool ServiceProcess::HandleClientDisconnect() {
  // If there are no enabled services or if there is an update available
  // we want to shutdown right away. Else we want to keep listening for
  // new connections.
  if (!enabled_services_ || update_available()) {
    Shutdown();
    return false;
  }
  return true;
}

cloud_print::CloudPrintProxy* ServiceProcess::GetCloudPrintProxy() {
  if (!cloud_print_proxy_.get()) {
    cloud_print_proxy_.reset(new cloud_print::CloudPrintProxy());
    cloud_print_proxy_->Initialize(service_prefs_.get(), this);
  }
  return cloud_print_proxy_.get();
}

void ServiceProcess::OnCloudPrintProxyEnabled(bool persist_state) {
  if (persist_state) {
    // Save the preference that we have enabled the cloud print proxy.
    service_prefs_->SetBoolean(prefs::kCloudPrintProxyEnabled, true);
    service_prefs_->WritePrefs();
  }
  OnServiceEnabled();
}

void ServiceProcess::OnCloudPrintProxyDisabled(bool persist_state) {
  if (persist_state) {
    // Save the preference that we have disabled the cloud print proxy.
    service_prefs_->SetBoolean(prefs::kCloudPrintProxyEnabled, false);
    service_prefs_->WritePrefs();
  }
  OnServiceDisabled();
}

ServiceURLRequestContextGetter*
ServiceProcess::GetServiceURLRequestContextGetter() {
  DCHECK(request_context_getter_.get());
  return request_context_getter_.get();
}

void ServiceProcess::OnServiceEnabled() {
  enabled_services_++;
  if ((1 == enabled_services_) &&
      !CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kNoServiceAutorun)) {
    if (!service_process_state_->AddToAutoRun()) {
      // TODO(scottbyer/sanjeevr/dmaclach): Handle error condition
      LOG(ERROR) << "Unable to AddToAutoRun";
    }
  }
}

void ServiceProcess::OnServiceDisabled() {
  DCHECK_NE(enabled_services_, 0);
  enabled_services_--;
  if (0 == enabled_services_) {
    if (!service_process_state_->RemoveFromAutoRun()) {
      // TODO(scottbyer/sanjeevr/dmaclach): Handle error condition
      LOG(ERROR) << "Unable to RemoveFromAutoRun";
    }
    // We will wait for some time to respond to IPCs before shutting down.
    ScheduleShutdownCheck();
  }
}

void ServiceProcess::ScheduleShutdownCheck() {
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&ServiceProcess::ShutdownIfNeeded, base::Unretained(this)),
      base::TimeDelta::FromSeconds(kShutdownDelaySeconds));
}

void ServiceProcess::ShutdownIfNeeded() {
  if (0 == enabled_services_) {
    if (ipc_server_->is_client_connected()) {
      // If there is a client connected, we need to try again later.
      // Note that there is still a timing window here because a client may
      // decide to connect at this point.
      // TODO(sanjeevr): Fix this timing window.
      ScheduleShutdownCheck();
    } else {
      Shutdown();
    }
  }
}

void ServiceProcess::ScheduleCloudPrintPolicyCheck() {
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&ServiceProcess::CloudPrintPolicyCheckIfNeeded,
                 base::Unretained(this)),
      base::TimeDelta::FromHours(kPolicyCheckDelayHours));
}

void ServiceProcess::CloudPrintPolicyCheckIfNeeded() {
  if (enabled_services_ && !ipc_server_->is_client_connected()) {
    GetCloudPrintProxy()->CheckCloudPrintProxyPolicy();
  }
  ScheduleCloudPrintPolicyCheck();
}

ServiceProcess::~ServiceProcess() {
  Teardown();
  g_service_process = NULL;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Resource.h>

#include "Magnum/AbstractShaderProgram.h"
#include "Magnum/Buffer.h"
#include "Magnum/Framebuffer.h"
#include "Magnum/Mesh.h"
#include "Magnum/PrimitiveQuery.h"
#include "Magnum/Renderbuffer.h"
#include "Magnum/RenderbufferFormat.h"
#include "Magnum/Shader.h"
#include "Magnum/TransformFeedback.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/Test/AbstractOpenGLTester.h"

namespace Magnum { namespace Test {

struct PrimitiveQueryGLTest: AbstractOpenGLTester {
    explicit PrimitiveQueryGLTest();

    void constructNoCreate();
    void wrap();

    #ifndef MAGNUM_TARGET_GLES
    void primitivesGenerated();
    void primitivesGeneratedIndexed();
    #endif
    void transformFeedbackPrimitivesWritten();
    #ifndef MAGNUM_TARGET_GLES
    void transformFeedbackOverflow();
    #endif
};

PrimitiveQueryGLTest::PrimitiveQueryGLTest() {
    addTests({&PrimitiveQueryGLTest::constructNoCreate,
              &PrimitiveQueryGLTest::wrap,

              #ifndef MAGNUM_TARGET_GLES
              &PrimitiveQueryGLTest::primitivesGenerated,
              &PrimitiveQueryGLTest::primitivesGeneratedIndexed,
              #endif
              &PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten,
              #ifndef MAGNUM_TARGET_GLES
              &PrimitiveQueryGLTest::transformFeedbackOverflow
              #endif
              });
}

void PrimitiveQueryGLTest::constructNoCreate() {
    {
        PrimitiveQuery query{NoCreate};

        MAGNUM_VERIFY_NO_ERROR();
        CORRADE_COMPARE(query.id(), 0);
    }

    MAGNUM_VERIFY_NO_ERROR();
}

void PrimitiveQueryGLTest::wrap() {
    #ifndef MAGNUM_TARGET_GLES
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback2>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available."));
    #endif

    GLuint id;
    glGenQueries(1, &id);

    /* Releasing won't delete anything */
    {
        auto query = PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten, ObjectFlag::DeleteOnDestruction);
        CORRADE_COMPARE(query.release(), id);
    }

    /* ...so we can wrap it again */
    PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten);
    glDeleteQueries(1, &id);
}

#ifndef MAGNUM_TARGET_GLES
void PrimitiveQueryGLTest::primitivesGenerated() {
    if(!Context::current().isExtensionSupported<Extensions::GL::EXT::transform_feedback>())
        CORRADE_SKIP(Extensions::GL::EXT::transform_feedback::string() + std::string(" is not available."));

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        typedef Attribute<0, Vector2> Position;

        explicit MyShader() {
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL210
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "#if __VERSION__ >= 130\n"
                "#define attribute in\n"
                "#endif\n"
                "attribute vec4 position;\n"
                "void main() {\n"
                "    gl_Position = position;\n"
                "}\n").compile());

            attachShader(vert);
            bindAttributeLocation(Position::Location, "position");
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer vertices;
    vertices.setData({nullptr, 9*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9)
        .addVertexBuffer(vertices, 0, MyShader::Position());

    MAGNUM_VERIFY_NO_ERROR();

    PrimitiveQuery q{PrimitiveQuery::Target::PrimitivesGenerated};
    q.begin();

    Renderer::enable(Renderer::Feature::RasterizerDiscard);
    mesh.draw(shader);

    q.end();
    const bool availableBefore = q.resultAvailable();
    const UnsignedInt count = q.result<UnsignedInt>();
    const bool availableAfter = q.resultAvailable();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_VERIFY(!availableBefore);
    CORRADE_VERIFY(availableAfter);
    CORRADE_COMPARE(count, 3);
}

void PrimitiveQueryGLTest::primitivesGeneratedIndexed() {
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback3>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback3::string() + std::string(" is not available."));

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        typedef Attribute<0, Vector2> Position;

        explicit MyShader() {
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL210
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "#if __VERSION__ >= 130\n"
                "#define attribute in\n"
                "#endif\n"
                "attribute vec4 position;\n"
                "void main() {\n"
                "    gl_Position = position;\n"
                "}\n").compile());

            attachShader(vert);
            bindAttributeLocation(Position::Location, "position");
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer vertices;
    vertices.setData({nullptr, 9*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9)
        .addVertexBuffer(vertices, 0, MyShader::Position());

    MAGNUM_VERIFY_NO_ERROR();

    PrimitiveQuery q{PrimitiveQuery::Target::PrimitivesGenerated};
    q.begin(0);

    Renderer::enable(Renderer::Feature::RasterizerDiscard);
    mesh.draw(shader);

    q.end();
    const UnsignedInt count = q.result<UnsignedInt>();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_COMPARE(count, 3);
}
#endif

void PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten() {
    #ifndef MAGNUM_TARGET_GLES
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback2>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available."));
    #endif

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        explicit MyShader() {
            #ifndef MAGNUM_TARGET_GLES
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL300
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);
            #else
            Shader vert(Version::GLES300, Shader::Type::Vertex);
            Shader frag(Version::GLES300, Shader::Type::Fragment);
            #endif

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "out mediump vec2 outputData;\n"
                "void main() {\n"
                "    outputData = vec2(1.0, -1.0);\n"
                /* Mesa drivers complain that vertex shader doesn't write to
                   gl_Position otherwise */
                "    gl_Position = vec4(1.0);\n"
                "}\n").compile());
            #ifndef MAGNUM_TARGET_GLES
            attachShader(vert);
            #else
            /* ES for some reason needs both vertex and fragment shader */
            CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile());
            attachShaders({vert, frag});
            #endif

            setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes);
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer output;
    output.setData({nullptr, 18*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9);

    MAGNUM_VERIFY_NO_ERROR();

    TransformFeedback feedback;
    feedback.attachBuffer(0, output);

    PrimitiveQuery q{PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten};
    q.begin();

    Renderer::enable(Renderer::Feature::RasterizerDiscard);

    mesh.draw(shader); /* Draw once without XFB (shouldn't be counted) */
    feedback.begin(shader, TransformFeedback::PrimitiveMode::Triangles);
    mesh.draw(shader);
    feedback.end();

    q.end();
    const UnsignedInt count = q.result<UnsignedInt>();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_COMPARE(count, 3); /* Three triangles (9 vertices) */
}

#ifndef MAGNUM_TARGET_GLES
void PrimitiveQueryGLTest::transformFeedbackOverflow() {
    #ifndef MAGNUM_TARGET_GLES
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback_overflow_query>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback_overflow_query::string() + std::string(" is not available."));
    #endif

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        explicit MyShader() {
            #ifndef MAGNUM_TARGET_GLES
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL300
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);
            #else
            Shader vert(Version::GLES300, Shader::Type::Vertex);
            Shader frag(Version::GLES300, Shader::Type::Fragment);
            #endif

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "out mediump vec2 outputData;\n"
                "void main() {\n"
                "    outputData = vec2(1.0, -1.0);\n"
                /* Mesa drivers complain that vertex shader doesn't write to
                   gl_Position otherwise */
                "    gl_Position = vec4(1.0);\n"
                "}\n").compile());
            #ifndef MAGNUM_TARGET_GLES
            attachShader(vert);
            #else
            /* ES for some reason needs both vertex and fragment shader */
            CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile());
            attachShaders({vert, frag});
            #endif

            setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes);
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer output;
    output.setData({nullptr, 18*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9);

    MAGNUM_VERIFY_NO_ERROR();

    TransformFeedback feedback;
    /* Deliberately one vertex smaller to not fit two of them */
    feedback.attachBuffer(0, output, 0, 17*sizeof(Vector2));

    Renderer::enable(Renderer::Feature::RasterizerDiscard);

    feedback.begin(shader, TransformFeedback::PrimitiveMode::Triangles);
    PrimitiveQuery q1{PrimitiveQuery::Target::TransformFeedbackOverflow},
        q2{PrimitiveQuery::Target::TransformFeedbackOverflow};
    q1.begin();
    mesh.draw(shader);
    q1.end();
    q2.begin();
    mesh.draw(shader);
    q2.end();
    feedback.end();

    const bool overflown1 = q1.result<bool>();
    const bool overflown2 = q2.result<bool>();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_VERIFY(!overflown1);
    CORRADE_VERIFY(overflown2); /* Got space for only 17 vertices instead of 2*9 */
}
#endif

}}

MAGNUM_GL_TEST_MAIN(Magnum::Test::PrimitiveQueryGLTest)
<commit_msg>Test: don't have unnecessarily large buffer size for XFB.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Resource.h>

#include "Magnum/AbstractShaderProgram.h"
#include "Magnum/Buffer.h"
#include "Magnum/Framebuffer.h"
#include "Magnum/Mesh.h"
#include "Magnum/PrimitiveQuery.h"
#include "Magnum/Renderbuffer.h"
#include "Magnum/RenderbufferFormat.h"
#include "Magnum/Shader.h"
#include "Magnum/TransformFeedback.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/Test/AbstractOpenGLTester.h"

namespace Magnum { namespace Test {

struct PrimitiveQueryGLTest: AbstractOpenGLTester {
    explicit PrimitiveQueryGLTest();

    void constructNoCreate();
    void wrap();

    #ifndef MAGNUM_TARGET_GLES
    void primitivesGenerated();
    void primitivesGeneratedIndexed();
    #endif
    void transformFeedbackPrimitivesWritten();
    #ifndef MAGNUM_TARGET_GLES
    void transformFeedbackOverflow();
    #endif
};

PrimitiveQueryGLTest::PrimitiveQueryGLTest() {
    addTests({&PrimitiveQueryGLTest::constructNoCreate,
              &PrimitiveQueryGLTest::wrap,

              #ifndef MAGNUM_TARGET_GLES
              &PrimitiveQueryGLTest::primitivesGenerated,
              &PrimitiveQueryGLTest::primitivesGeneratedIndexed,
              #endif
              &PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten,
              #ifndef MAGNUM_TARGET_GLES
              &PrimitiveQueryGLTest::transformFeedbackOverflow
              #endif
              });
}

void PrimitiveQueryGLTest::constructNoCreate() {
    {
        PrimitiveQuery query{NoCreate};

        MAGNUM_VERIFY_NO_ERROR();
        CORRADE_COMPARE(query.id(), 0);
    }

    MAGNUM_VERIFY_NO_ERROR();
}

void PrimitiveQueryGLTest::wrap() {
    #ifndef MAGNUM_TARGET_GLES
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback2>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available."));
    #endif

    GLuint id;
    glGenQueries(1, &id);

    /* Releasing won't delete anything */
    {
        auto query = PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten, ObjectFlag::DeleteOnDestruction);
        CORRADE_COMPARE(query.release(), id);
    }

    /* ...so we can wrap it again */
    PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten);
    glDeleteQueries(1, &id);
}

#ifndef MAGNUM_TARGET_GLES
void PrimitiveQueryGLTest::primitivesGenerated() {
    if(!Context::current().isExtensionSupported<Extensions::GL::EXT::transform_feedback>())
        CORRADE_SKIP(Extensions::GL::EXT::transform_feedback::string() + std::string(" is not available."));

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        typedef Attribute<0, Vector2> Position;

        explicit MyShader() {
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL210
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "#if __VERSION__ >= 130\n"
                "#define attribute in\n"
                "#endif\n"
                "attribute vec4 position;\n"
                "void main() {\n"
                "    gl_Position = position;\n"
                "}\n").compile());

            attachShader(vert);
            bindAttributeLocation(Position::Location, "position");
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer vertices;
    vertices.setData({nullptr, 9*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9)
        .addVertexBuffer(vertices, 0, MyShader::Position());

    MAGNUM_VERIFY_NO_ERROR();

    PrimitiveQuery q{PrimitiveQuery::Target::PrimitivesGenerated};
    q.begin();

    Renderer::enable(Renderer::Feature::RasterizerDiscard);
    mesh.draw(shader);

    q.end();
    const bool availableBefore = q.resultAvailable();
    const UnsignedInt count = q.result<UnsignedInt>();
    const bool availableAfter = q.resultAvailable();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_VERIFY(!availableBefore);
    CORRADE_VERIFY(availableAfter);
    CORRADE_COMPARE(count, 3);
}

void PrimitiveQueryGLTest::primitivesGeneratedIndexed() {
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback3>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback3::string() + std::string(" is not available."));

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        typedef Attribute<0, Vector2> Position;

        explicit MyShader() {
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL210
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "#if __VERSION__ >= 130\n"
                "#define attribute in\n"
                "#endif\n"
                "attribute vec4 position;\n"
                "void main() {\n"
                "    gl_Position = position;\n"
                "}\n").compile());

            attachShader(vert);
            bindAttributeLocation(Position::Location, "position");
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer vertices;
    vertices.setData({nullptr, 9*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9)
        .addVertexBuffer(vertices, 0, MyShader::Position());

    MAGNUM_VERIFY_NO_ERROR();

    PrimitiveQuery q{PrimitiveQuery::Target::PrimitivesGenerated};
    q.begin(0);

    Renderer::enable(Renderer::Feature::RasterizerDiscard);
    mesh.draw(shader);

    q.end();
    const UnsignedInt count = q.result<UnsignedInt>();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_COMPARE(count, 3);
}
#endif

void PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten() {
    #ifndef MAGNUM_TARGET_GLES
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback2>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available."));
    #endif

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        explicit MyShader() {
            #ifndef MAGNUM_TARGET_GLES
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL300
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);
            #else
            Shader vert(Version::GLES300, Shader::Type::Vertex);
            Shader frag(Version::GLES300, Shader::Type::Fragment);
            #endif

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "out mediump vec2 outputData;\n"
                "void main() {\n"
                "    outputData = vec2(1.0, -1.0);\n"
                /* Mesa drivers complain that vertex shader doesn't write to
                   gl_Position otherwise */
                "    gl_Position = vec4(1.0);\n"
                "}\n").compile());
            #ifndef MAGNUM_TARGET_GLES
            attachShader(vert);
            #else
            /* ES for some reason needs both vertex and fragment shader */
            CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile());
            attachShaders({vert, frag});
            #endif

            setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes);
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer output;
    output.setData({nullptr, 9*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9);

    MAGNUM_VERIFY_NO_ERROR();

    TransformFeedback feedback;
    feedback.attachBuffer(0, output);

    PrimitiveQuery q{PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten};
    q.begin();

    Renderer::enable(Renderer::Feature::RasterizerDiscard);

    mesh.draw(shader); /* Draw once without XFB (shouldn't be counted) */
    feedback.begin(shader, TransformFeedback::PrimitiveMode::Triangles);
    mesh.draw(shader);
    feedback.end();

    q.end();
    const UnsignedInt count = q.result<UnsignedInt>();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_COMPARE(count, 3); /* Three triangles (9 vertices) */
}

#ifndef MAGNUM_TARGET_GLES
void PrimitiveQueryGLTest::transformFeedbackOverflow() {
    #ifndef MAGNUM_TARGET_GLES
    if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback_overflow_query>())
        CORRADE_SKIP(Extensions::GL::ARB::transform_feedback_overflow_query::string() + std::string(" is not available."));
    #endif

    /* Bind some FB to avoid errors on contexts w/o default FB */
    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32});
    Framebuffer fb{{{}, Vector2i{32}}};
    fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color)
      .bind();

    struct MyShader: AbstractShaderProgram {
        explicit MyShader() {
            #ifndef MAGNUM_TARGET_GLES
            Shader vert(
                #ifndef CORRADE_TARGET_APPLE
                Version::GL300
                #else
                Version::GL310
                #endif
                , Shader::Type::Vertex);
            #else
            Shader vert(Version::GLES300, Shader::Type::Vertex);
            Shader frag(Version::GLES300, Shader::Type::Fragment);
            #endif

            CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource(
                "out mediump vec2 outputData;\n"
                "void main() {\n"
                "    outputData = vec2(1.0, -1.0);\n"
                /* Mesa drivers complain that vertex shader doesn't write to
                   gl_Position otherwise */
                "    gl_Position = vec4(1.0);\n"
                "}\n").compile());
            #ifndef MAGNUM_TARGET_GLES
            attachShader(vert);
            #else
            /* ES for some reason needs both vertex and fragment shader */
            CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile());
            attachShaders({vert, frag});
            #endif

            setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes);
            CORRADE_INTERNAL_ASSERT_OUTPUT(link());
        }
    } shader;

    Buffer output;
    output.setData({nullptr, 18*sizeof(Vector2)}, BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(9);

    MAGNUM_VERIFY_NO_ERROR();

    TransformFeedback feedback;
    /* Deliberately one vertex smaller to not fit two of them */
    feedback.attachBuffer(0, output, 0, 17*sizeof(Vector2));

    Renderer::enable(Renderer::Feature::RasterizerDiscard);

    feedback.begin(shader, TransformFeedback::PrimitiveMode::Triangles);
    PrimitiveQuery q1{PrimitiveQuery::Target::TransformFeedbackOverflow},
        q2{PrimitiveQuery::Target::TransformFeedbackOverflow};
    q1.begin();
    mesh.draw(shader);
    q1.end();
    q2.begin();
    mesh.draw(shader);
    q2.end();
    feedback.end();

    const bool overflown1 = q1.result<bool>();
    const bool overflown2 = q2.result<bool>();

    MAGNUM_VERIFY_NO_ERROR();
    CORRADE_VERIFY(!overflown1);
    CORRADE_VERIFY(overflown2); /* Got space for only 17 vertices instead of 2*9 */
}
#endif

}}

MAGNUM_GL_TEST_MAIN(Magnum::Test::PrimitiveQueryGLTest)
<|endoftext|>


<commit_before>//===--- tools/extra/clang-tidy/ClangTidyMain.cpp - Clang tidy tool -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
///  \file This file implements a clang-tidy tool.
///
///  This tool uses the Clang Tooling infrastructure, see
///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
///  for details on setting it up with LLVM source tree.
///
//===----------------------------------------------------------------------===//

#include "../ClangTidy.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "llvm/Support/Process.h"

using namespace clang::ast_matchers;
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;

static cl::OptionCategory ClangTidyCategory("clang-tidy options");

static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp ClangTidyHelp(
    "Configuration files:\n"
    "  clang-tidy attempts to read configuration for each source file from a\n"
    "  .clang-tidy file located in the closest parent directory of the source\n"
    "  file. If any configuration options have a corresponding command-line\n"
    "  option, command-line option takes precedence. The effective\n"
    "  configuration can be inspected using -dump-config.\n\n");

const char DefaultChecks[] =
    "*,"                       // Enable all checks, except these:
    "-clang-analyzer-alpha*,"  // Too many false positives.
    "-llvm-include-order,"     // Not implemented yet.
    "-google-*,";              // Doesn't apply to LLVM.

static cl::opt<std::string>
Checks("checks", cl::desc("Comma-separated list of globs with optional '-'\n"
                          "prefix. Globs are processed in order of appearance\n"
                          "in the list. Globs without '-' prefix add checks\n"
                          "with matching names to the set, globs with the '-'\n"
                          "prefix remove checks with matching names from the\n"
                          "set of enabled checks.\n"
                          "This option's value is appended to the value read\n"
                          "from a .clang-tidy file, if any."),
       cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<std::string>
HeaderFilter("header-filter",
             cl::desc("Regular expression matching the names of the\n"
                      "headers to output diagnostics from. Diagnostics\n"
                      "from the main file of each translation unit are\n"
                      "always displayed.\n"
                      "Can be used together with -line-filter.\n"
                      "This option overrides the value read from a\n"
                      ".clang-tidy file."),
             cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<std::string>
LineFilter("line-filter",
           cl::desc("List of files with line ranges to filter the\n"
                    "warnings. Can be used together with\n"
                    "-header-filter. The format of the list is a JSON\n"
                    "array of objects:\n"
                    "  [\n"
                    "    {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n"
                    "    {\"name\":\"file2.h\"}\n"
                    "  ]"),
           cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<bool> Fix("fix", cl::desc("Fix detected errors if possible."),
                         cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<bool>
ListChecks("list-checks",
           cl::desc("List all enabled checks and exit. Use with\n"
                    "-checks='*' to list all available checks."),
           cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<bool>
DumpConfig("dump-config",
           cl::desc("Dumps configuration in the YAML format to stdout."),
           cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<bool> AnalyzeTemporaryDtors(
    "analyze-temporary-dtors",
    cl::desc("Enable temporary destructor-aware analysis in\n"
             "clang-analyzer- checks.\n"
             "This option overrides the value read from a\n"
             ".clang-tidy file."),
    cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<std::string> ExportFixes(
    "export-fixes",
    cl::desc("YAML file to store suggested fixes in. The\n"
             "stored fixes can be applied to the input source\n"
             "code with clang-apply-replacements."),
    cl::value_desc("filename"), cl::cat(ClangTidyCategory));

namespace clang {
namespace tidy {

static void printStats(const ClangTidyStats &Stats) {
  if (Stats.errorsIgnored()) {
    llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
    StringRef Separator = "";
    if (Stats.ErrorsIgnoredNonUserCode) {
      llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
      Separator = ", ";
    }
    if (Stats.ErrorsIgnoredLineFilter) {
      llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
                   << " due to line filter";
      Separator = ", ";
    }
    if (Stats.ErrorsIgnoredNOLINT) {
      llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
      Separator = ", ";
    }
    if (Stats.ErrorsIgnoredCheckFilter)
      llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter
                   << " with check filters";
    llvm::errs() << ").\n";
    if (Stats.ErrorsIgnoredNonUserCode)
      llvm::errs() << "Use -header-filter='.*' to display errors from all "
                      "non-system headers.\n";
  }
}

int clangTidyMain(int argc, const char **argv) {
  CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory);

  ClangTidyGlobalOptions GlobalOptions;
  if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
    llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
    llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
    return 1;
  }

  ClangTidyOptions DefaultOptions;
  DefaultOptions.Checks = DefaultChecks;
  DefaultOptions.HeaderFilterRegex = HeaderFilter;
  DefaultOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
  DefaultOptions.User = llvm::sys::Process::GetEnv("USER");
  // USERNAME is used on Windows.
  if (!DefaultOptions.User)
    DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME");

  ClangTidyOptions OverrideOptions;
  if (Checks.getNumOccurrences() > 0)
    OverrideOptions.Checks = Checks;
  if (HeaderFilter.getNumOccurrences() > 0)
    OverrideOptions.HeaderFilterRegex = HeaderFilter;
  if (AnalyzeTemporaryDtors.getNumOccurrences() > 0)
    OverrideOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;

  auto OptionsProvider = llvm::make_unique<FileOptionsProvider>(
      GlobalOptions, DefaultOptions, OverrideOptions);

  std::string FileName = OptionsParser.getSourcePathList().front();
  ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName);
  std::vector<std::string> EnabledChecks = getCheckNames(EffectiveOptions);

  // FIXME: Allow using --list-checks without positional arguments.
  if (ListChecks) {
    llvm::outs() << "Enabled checks:";
    for (auto CheckName : EnabledChecks)
      llvm::outs() << "\n    " << CheckName;
    llvm::outs() << "\n\n";
    return 0;
  }

  if (DumpConfig) {
    EffectiveOptions.CheckOptions = getCheckOptions(EffectiveOptions);
    llvm::outs() << configurationAsText(ClangTidyOptions::getDefaults()
                                            .mergeWith(EffectiveOptions))
                 << "\n";
    return 0;
  }

  if (EnabledChecks.empty()) {
    llvm::errs() << "Error: no checks enabled.\n";
    llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
    return 1;
  }

  std::vector<ClangTidyError> Errors;
  ClangTidyStats Stats =
      runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(),
                   OptionsParser.getSourcePathList(), &Errors);
  handleErrors(Errors, Fix);

  if (!ExportFixes.empty() && !Errors.empty()) {
    std::error_code EC;
    llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
    if (EC) {
      llvm::errs() << "Error opening output file: " << EC.message() << '\n';
      return 1;
    }
    exportReplacements(Errors, OS);
  }

  printStats(Stats);
  return 0;
}

// This anchor is used to force the linker to link the LLVMModule.
extern volatile int LLVMModuleAnchorSource;
static int LLVMModuleAnchorDestination = LLVMModuleAnchorSource;

// This anchor is used to force the linker to link the GoogleModule.
extern volatile int GoogleModuleAnchorSource;
static int GoogleModuleAnchorDestination = GoogleModuleAnchorSource;

// This anchor is used to force the linker to link the MiscModule.
extern volatile int MiscModuleAnchorSource;
static int MiscModuleAnchorDestination = MiscModuleAnchorSource;

} // namespace tidy
} // namespace clang

int main(int argc, const char **argv) {
  return clang::tidy::clangTidyMain(argc, argv);
}
<commit_msg>[clang-tidy] Add a -config={YAML} option.<commit_after>//===--- tools/extra/clang-tidy/ClangTidyMain.cpp - Clang tidy tool -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
///  \file This file implements a clang-tidy tool.
///
///  This tool uses the Clang Tooling infrastructure, see
///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
///  for details on setting it up with LLVM source tree.
///
//===----------------------------------------------------------------------===//

#include "../ClangTidy.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "llvm/Support/Process.h"

using namespace clang::ast_matchers;
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;

static cl::OptionCategory ClangTidyCategory("clang-tidy options");

static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp ClangTidyHelp(
    "Configuration files:\n"
    "  clang-tidy attempts to read configuration for each source file from a\n"
    "  .clang-tidy file located in the closest parent directory of the source\n"
    "  file. If any configuration options have a corresponding command-line\n"
    "  option, command-line option takes precedence. The effective\n"
    "  configuration can be inspected using -dump-config.\n\n");

const char DefaultChecks[] =
    "*,"                       // Enable all checks, except these:
    "-clang-analyzer-alpha*,"  // Too many false positives.
    "-llvm-include-order,"     // Not implemented yet.
    "-google-*,";              // Doesn't apply to LLVM.

static cl::opt<std::string>
Checks("checks", cl::desc("Comma-separated list of globs with optional '-'\n"
                          "prefix. Globs are processed in order of appearance\n"
                          "in the list. Globs without '-' prefix add checks\n"
                          "with matching names to the set, globs with the '-'\n"
                          "prefix remove checks with matching names from the\n"
                          "set of enabled checks.\n"
                          "This option's value is appended to the value read\n"
                          "from a .clang-tidy file, if any."),
       cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<std::string>
HeaderFilter("header-filter",
             cl::desc("Regular expression matching the names of the\n"
                      "headers to output diagnostics from. Diagnostics\n"
                      "from the main file of each translation unit are\n"
                      "always displayed.\n"
                      "Can be used together with -line-filter.\n"
                      "This option overrides the value read from a\n"
                      ".clang-tidy file."),
             cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<std::string>
LineFilter("line-filter",
           cl::desc("List of files with line ranges to filter the\n"
                    "warnings. Can be used together with\n"
                    "-header-filter. The format of the list is a JSON\n"
                    "array of objects:\n"
                    "  [\n"
                    "    {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n"
                    "    {\"name\":\"file2.h\"}\n"
                    "  ]"),
           cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<bool> Fix("fix", cl::desc("Fix detected errors if possible."),
                         cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<bool>
ListChecks("list-checks",
           cl::desc("List all enabled checks and exit. Use with\n"
                    "-checks='*' to list all available checks."),
           cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<std::string> Config(
    "config",
    cl::desc("Specifies a configuration in YAML/JSON format:\n"
             "  -config=\"{Checks: '*', CheckOptions: {key: x, value: y}}\"\n"
             "When the value is empty, clang-tidy will attempt to find\n"
             "a file named .clang-tidy for each sorce file in its parent\n"
             "directories."),
    cl::init(""), cl::cat(ClangTidyCategory));

static cl::opt<bool>
DumpConfig("dump-config",
           cl::desc("Dumps configuration in the YAML format to stdout."),
           cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<bool> AnalyzeTemporaryDtors(
    "analyze-temporary-dtors",
    cl::desc("Enable temporary destructor-aware analysis in\n"
             "clang-analyzer- checks.\n"
             "This option overrides the value read from a\n"
             ".clang-tidy file."),
    cl::init(false), cl::cat(ClangTidyCategory));

static cl::opt<std::string> ExportFixes(
    "export-fixes",
    cl::desc("YAML file to store suggested fixes in. The\n"
             "stored fixes can be applied to the input source\n"
             "code with clang-apply-replacements."),
    cl::value_desc("filename"), cl::cat(ClangTidyCategory));

namespace clang {
namespace tidy {

static void printStats(const ClangTidyStats &Stats) {
  if (Stats.errorsIgnored()) {
    llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
    StringRef Separator = "";
    if (Stats.ErrorsIgnoredNonUserCode) {
      llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
      Separator = ", ";
    }
    if (Stats.ErrorsIgnoredLineFilter) {
      llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
                   << " due to line filter";
      Separator = ", ";
    }
    if (Stats.ErrorsIgnoredNOLINT) {
      llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
      Separator = ", ";
    }
    if (Stats.ErrorsIgnoredCheckFilter)
      llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter
                   << " with check filters";
    llvm::errs() << ").\n";
    if (Stats.ErrorsIgnoredNonUserCode)
      llvm::errs() << "Use -header-filter='.*' to display errors from all "
                      "non-system headers.\n";
  }
}

std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider() {
  ClangTidyGlobalOptions GlobalOptions;
  if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
    llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
    llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
    return nullptr;
  }

  ClangTidyOptions DefaultOptions;
  DefaultOptions.Checks = DefaultChecks;
  DefaultOptions.HeaderFilterRegex = HeaderFilter;
  DefaultOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
  DefaultOptions.User = llvm::sys::Process::GetEnv("USER");
  // USERNAME is used on Windows.
  if (!DefaultOptions.User)
    DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME");

  ClangTidyOptions OverrideOptions;
  if (Checks.getNumOccurrences() > 0)
    OverrideOptions.Checks = Checks;
  if (HeaderFilter.getNumOccurrences() > 0)
    OverrideOptions.HeaderFilterRegex = HeaderFilter;
  if (AnalyzeTemporaryDtors.getNumOccurrences() > 0)
    OverrideOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;

  if (!Config.empty()) {
    if (llvm::ErrorOr<ClangTidyOptions> ParsedConfig =
            parseConfiguration(Config)) {
      return llvm::make_unique<DefaultOptionsProvider>(
          GlobalOptions, ClangTidyOptions::getDefaults()
                             .mergeWith(DefaultOptions)
                             .mergeWith(*ParsedConfig)
                             .mergeWith(OverrideOptions));
    } else {
      llvm::errs() << "Error: invalid configuration specified.\n"
                   << ParsedConfig.getError().message() << "\n";
      return nullptr;
    }
  }
  return llvm::make_unique<FileOptionsProvider>(GlobalOptions, DefaultOptions,
                                                OverrideOptions);
}

int clangTidyMain(int argc, const char **argv) {
  CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory);

  auto OptionsProvider = createOptionsProvider();
  if (!OptionsProvider)
    return 1;

  std::string FileName = OptionsParser.getSourcePathList().front();
  ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName);
  std::vector<std::string> EnabledChecks = getCheckNames(EffectiveOptions);

  // FIXME: Allow using --list-checks without positional arguments.
  if (ListChecks) {
    llvm::outs() << "Enabled checks:";
    for (auto CheckName : EnabledChecks)
      llvm::outs() << "\n    " << CheckName;
    llvm::outs() << "\n\n";
    return 0;
  }

  if (DumpConfig) {
    EffectiveOptions.CheckOptions = getCheckOptions(EffectiveOptions);
    llvm::outs() << configurationAsText(ClangTidyOptions::getDefaults()
                                            .mergeWith(EffectiveOptions))
                 << "\n";
    return 0;
  }

  if (EnabledChecks.empty()) {
    llvm::errs() << "Error: no checks enabled.\n";
    llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
    return 1;
  }

  std::vector<ClangTidyError> Errors;
  ClangTidyStats Stats =
      runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(),
                   OptionsParser.getSourcePathList(), &Errors);
  handleErrors(Errors, Fix);

  if (!ExportFixes.empty() && !Errors.empty()) {
    std::error_code EC;
    llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
    if (EC) {
      llvm::errs() << "Error opening output file: " << EC.message() << '\n';
      return 1;
    }
    exportReplacements(Errors, OS);
  }

  printStats(Stats);
  return 0;
}

// This anchor is used to force the linker to link the LLVMModule.
extern volatile int LLVMModuleAnchorSource;
static int LLVMModuleAnchorDestination = LLVMModuleAnchorSource;

// This anchor is used to force the linker to link the GoogleModule.
extern volatile int GoogleModuleAnchorSource;
static int GoogleModuleAnchorDestination = GoogleModuleAnchorSource;

// This anchor is used to force the linker to link the MiscModule.
extern volatile int MiscModuleAnchorSource;
static int MiscModuleAnchorDestination = MiscModuleAnchorSource;

} // namespace tidy
} // namespace clang

int main(int argc, const char **argv) {
  return clang::tidy::clangTidyMain(argc, argv);
}
<|endoftext|>


<commit_before>#include "onoff_gpio.h"

#include <QDebug>

OnOffMorse::OnOffMorse()
{
    int pin = 30;
    exportPin(pin);
    setDirection(pin, "out");

    QString path = QString("/sys/class/gpio%1/value").arg(pin);
    m_file.setFileName(path);
    if (!m_file.open(QIODevice::WriteOnly)) {
        qDebug() << "Failed to open pin value setter:" << m_file.errorString();
    }
}

OnOffMorse::~OnOffMorse()
{
}

void OnOffMorse::setOn(bool setOn)
{
    m_file.write(setOn ? "1" : "0");
}

void OnOffMorse::exportPin(int pin)
{
    QString path = QString("/sys/class/gip/export");
    QFile file(path);
    if (file.open(QIODevice::WriteOnly)) {
        file.write( QString::number(pin).toLatin1() );
    } else {
        qDebug() << "Failed to export pin:" << file.errorString();
    }
}

void OnOffMorse::setDirection(int pin, const QByteArray &direction)
{
    QString path = QString("/sys/class/gpio%1/value").arg(pin);
    QFile file(path);
    if (file.open(QIODevice::WriteOnly)) {
        file.write(direction);
    } else {
        qDebug() << "Failed to set value on pin:" << file.errorString();
    }
}
<commit_msg>Fixed typos<commit_after>#include "onoff_gpio.h"

#include <QDebug>

OnOffMorse::OnOffMorse()
{
    int pin = 30;
    exportPin(pin);
    setDirection(pin, "out");

    QString path = QString("/sys/class/gpio/gpio%1/value").arg(pin);
    m_file.setFileName(path);
    if (!m_file.open(QIODevice::WriteOnly)) {
        qDebug() << "Failed to open pin value setter:" << m_file.errorString();
    }
}

OnOffMorse::~OnOffMorse()
{
}

void OnOffMorse::setOn(bool setOn)
{
    m_file.write(setOn ? "1" : "0");
}

void OnOffMorse::exportPin(int pin)
{
    QString path = QString("/sys/class/gpio/export");
    QFile file(path);
    if (file.open(QIODevice::WriteOnly)) {
        file.write( QString::number(pin).toLatin1() );
    } else {
        qDebug() << "Failed to export pin:" << file.errorString();
    }
}

void OnOffMorse::setDirection(int pin, const QByteArray &direction)
{
    QString path = QString("/sys/class/gpio/gpio%1/direction").arg(pin);
    QFile file(path);
    if (file.open(QIODevice::WriteOnly)) {
        file.write(direction);
    } else {
        qDebug() << "Failed to set value on pin:" << file.errorString();
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "persistencehandlerproxy.h"
#include "documentretriever.h"
#include "documentdb.h"
#include <vespa/searchcore/proton/feedoperation/createbucketoperation.h>
#include <vespa/searchcore/proton/feedoperation/deletebucketoperation.h>
#include <vespa/searchcore/proton/feedoperation/joinbucketsoperation.h>
#include <vespa/searchcore/proton/feedoperation/putoperation.h>
#include <vespa/searchcore/proton/feedoperation/removeoperation.h>
#include <vespa/searchcore/proton/feedoperation/splitbucketoperation.h>
#include <vespa/searchcore/proton/feedoperation/updateoperation.h>
#include <vespa/persistence/spi/result.h>

using storage::spi::Bucket;
using storage::spi::Timestamp;

namespace proton {

PersistenceHandlerProxy::PersistenceHandlerProxy(const DocumentDB::SP &documentDB)
    : _documentDB(documentDB),
      _feedHandler(_documentDB->getFeedHandler()),
      _bucketHandler(_documentDB->getBucketHandler()),
      _clusterStateHandler(_documentDB->getClusterStateHandler())
{
    _documentDB->retain();
}

PersistenceHandlerProxy::~PersistenceHandlerProxy()
{
    _documentDB->release();
}

void
PersistenceHandlerProxy::initialize()
{
    _documentDB->waitForOnlineState();
}

void
PersistenceHandlerProxy::handlePut(FeedToken token,
                                   const Bucket &bucket,
                                   Timestamp timestamp,
                                   const document::Document::SP &doc)
{
    FeedOperation::UP op(new PutOperation(bucket.getBucketId().stripUnused(),
                                          timestamp, doc));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleUpdate(FeedToken token,
                                      const Bucket &bucket,
                                      Timestamp timestamp,
                                      const document::DocumentUpdate::SP &upd)
{
    FeedOperation::UP op(new UpdateOperation(bucket.getBucketId().
                                             stripUnused(),
                                             timestamp, upd));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleRemove(FeedToken token,
                                      const Bucket &bucket,
                                      Timestamp timestamp,
                                      const document::DocumentId &id)
{
    FeedOperation::UP op(new RemoveOperation(bucket.getBucketId().
                                             stripUnused(),
                                             timestamp, id));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleListBuckets(IBucketIdListResultHandler &resultHandler)
{
    _bucketHandler.handleListBuckets(resultHandler);
}

void
PersistenceHandlerProxy::handleSetClusterState(const storage::spi::ClusterState &calc,
                                               IGenericResultHandler &resultHandler)
{
    _clusterStateHandler.handleSetClusterState(calc, resultHandler);
}

void
PersistenceHandlerProxy::handleSetActiveState(
        const storage::spi::Bucket &bucket,
        storage::spi::BucketInfo::ActiveState newState,
        IGenericResultHandler &resultHandler)
{
    _bucketHandler.handleSetCurrentState(bucket.getBucketId().stripUnused(),
                                         newState, resultHandler);
}

void
PersistenceHandlerProxy::handleGetBucketInfo(const Bucket &bucket,
                                             IBucketInfoResultHandler &resultHandler)
{
    _bucketHandler.handleGetBucketInfo(bucket, resultHandler);
}

void
PersistenceHandlerProxy::handleCreateBucket(FeedToken token,
                                            const Bucket &bucket)
{
    FeedOperation::UP op(new CreateBucketOperation(bucket.getBucketId().
                                                   stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleDeleteBucket(FeedToken token,
                                            const Bucket &bucket)
{
    FeedOperation::UP op(new DeleteBucketOperation(bucket.getBucketId().
                                                   stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleGetModifiedBuckets(IBucketIdListResultHandler &resultHandler)
{
    _clusterStateHandler.handleGetModifiedBuckets(resultHandler);
}

void
PersistenceHandlerProxy::handleSplit(FeedToken token,
                                     const Bucket &source,
                                     const Bucket &target1,
                                     const Bucket &target2)
{
    FeedOperation::UP op(new SplitBucketOperation(source.getBucketId().
                                                  stripUnused(),
                                                  target1.getBucketId().
                                                  stripUnused(),
                                                  target2.getBucketId().
                                                  stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleJoin(FeedToken token,
                                    const Bucket &source1,
                                    const Bucket &source2,
                                    const Bucket &target)
{
    FeedOperation::UP op(new JoinBucketsOperation(source1.getBucketId().
                                                  stripUnused(),
                                                  source2.getBucketId().
                                                  stripUnused(),
                                                  target.getBucketId().
                                                  stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

IPersistenceHandler::RetrieversSP
PersistenceHandlerProxy::getDocumentRetrievers(storage::spi::ReadConsistency consistency)
{
    return _documentDB->getDocumentRetrievers(consistency);
}

BucketGuard::UP
PersistenceHandlerProxy::lockBucket(const storage::spi::Bucket &bucket)
{
    return _documentDB->lockBucket(bucket.getBucketId().stripUnused());
}

void
PersistenceHandlerProxy::handleListActiveBuckets(
        IBucketIdListResultHandler &resultHandler)
{
    _bucketHandler.handleListActiveBuckets(resultHandler);
}

void
PersistenceHandlerProxy::handlePopulateActiveBuckets(
        document::BucketId::List &buckets,
        IGenericResultHandler &resultHandler)
{
    _bucketHandler.handlePopulateActiveBuckets(buckets, resultHandler);
}

} // namespace proton
<commit_msg>Remove unused include.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "persistencehandlerproxy.h"
#include "documentretriever.h"
#include "documentdb.h"
#include <vespa/searchcore/proton/feedoperation/createbucketoperation.h>
#include <vespa/searchcore/proton/feedoperation/deletebucketoperation.h>
#include <vespa/searchcore/proton/feedoperation/joinbucketsoperation.h>
#include <vespa/searchcore/proton/feedoperation/putoperation.h>
#include <vespa/searchcore/proton/feedoperation/removeoperation.h>
#include <vespa/searchcore/proton/feedoperation/splitbucketoperation.h>
#include <vespa/searchcore/proton/feedoperation/updateoperation.h>

using storage::spi::Bucket;
using storage::spi::Timestamp;

namespace proton {

PersistenceHandlerProxy::PersistenceHandlerProxy(const DocumentDB::SP &documentDB)
    : _documentDB(documentDB),
      _feedHandler(_documentDB->getFeedHandler()),
      _bucketHandler(_documentDB->getBucketHandler()),
      _clusterStateHandler(_documentDB->getClusterStateHandler())
{
    _documentDB->retain();
}

PersistenceHandlerProxy::~PersistenceHandlerProxy()
{
    _documentDB->release();
}

void
PersistenceHandlerProxy::initialize()
{
    _documentDB->waitForOnlineState();
}

void
PersistenceHandlerProxy::handlePut(FeedToken token,
                                   const Bucket &bucket,
                                   Timestamp timestamp,
                                   const document::Document::SP &doc)
{
    FeedOperation::UP op(new PutOperation(bucket.getBucketId().stripUnused(),
                                          timestamp, doc));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleUpdate(FeedToken token,
                                      const Bucket &bucket,
                                      Timestamp timestamp,
                                      const document::DocumentUpdate::SP &upd)
{
    FeedOperation::UP op(new UpdateOperation(bucket.getBucketId().
                                             stripUnused(),
                                             timestamp, upd));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleRemove(FeedToken token,
                                      const Bucket &bucket,
                                      Timestamp timestamp,
                                      const document::DocumentId &id)
{
    FeedOperation::UP op(new RemoveOperation(bucket.getBucketId().
                                             stripUnused(),
                                             timestamp, id));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleListBuckets(IBucketIdListResultHandler &resultHandler)
{
    _bucketHandler.handleListBuckets(resultHandler);
}

void
PersistenceHandlerProxy::handleSetClusterState(const storage::spi::ClusterState &calc,
                                               IGenericResultHandler &resultHandler)
{
    _clusterStateHandler.handleSetClusterState(calc, resultHandler);
}

void
PersistenceHandlerProxy::handleSetActiveState(
        const storage::spi::Bucket &bucket,
        storage::spi::BucketInfo::ActiveState newState,
        IGenericResultHandler &resultHandler)
{
    _bucketHandler.handleSetCurrentState(bucket.getBucketId().stripUnused(),
                                         newState, resultHandler);
}

void
PersistenceHandlerProxy::handleGetBucketInfo(const Bucket &bucket,
                                             IBucketInfoResultHandler &resultHandler)
{
    _bucketHandler.handleGetBucketInfo(bucket, resultHandler);
}

void
PersistenceHandlerProxy::handleCreateBucket(FeedToken token,
                                            const Bucket &bucket)
{
    FeedOperation::UP op(new CreateBucketOperation(bucket.getBucketId().
                                                   stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleDeleteBucket(FeedToken token,
                                            const Bucket &bucket)
{
    FeedOperation::UP op(new DeleteBucketOperation(bucket.getBucketId().
                                                   stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleGetModifiedBuckets(IBucketIdListResultHandler &resultHandler)
{
    _clusterStateHandler.handleGetModifiedBuckets(resultHandler);
}

void
PersistenceHandlerProxy::handleSplit(FeedToken token,
                                     const Bucket &source,
                                     const Bucket &target1,
                                     const Bucket &target2)
{
    FeedOperation::UP op(new SplitBucketOperation(source.getBucketId().
                                                  stripUnused(),
                                                  target1.getBucketId().
                                                  stripUnused(),
                                                  target2.getBucketId().
                                                  stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

void
PersistenceHandlerProxy::handleJoin(FeedToken token,
                                    const Bucket &source1,
                                    const Bucket &source2,
                                    const Bucket &target)
{
    FeedOperation::UP op(new JoinBucketsOperation(source1.getBucketId().
                                                  stripUnused(),
                                                  source2.getBucketId().
                                                  stripUnused(),
                                                  target.getBucketId().
                                                  stripUnused()));
    _feedHandler.handleOperation(token, std::move(op));
}

IPersistenceHandler::RetrieversSP
PersistenceHandlerProxy::getDocumentRetrievers(storage::spi::ReadConsistency consistency)
{
    return _documentDB->getDocumentRetrievers(consistency);
}

BucketGuard::UP
PersistenceHandlerProxy::lockBucket(const storage::spi::Bucket &bucket)
{
    return _documentDB->lockBucket(bucket.getBucketId().stripUnused());
}

void
PersistenceHandlerProxy::handleListActiveBuckets(
        IBucketIdListResultHandler &resultHandler)
{
    _bucketHandler.handleListActiveBuckets(resultHandler);
}

void
PersistenceHandlerProxy::handlePopulateActiveBuckets(
        document::BucketId::List &buckets,
        IGenericResultHandler &resultHandler)
{
    _bucketHandler.handlePopulateActiveBuckets(buckets, resultHandler);
}

} // namespace proton
<|endoftext|>