<commit_before>// Copyright (c) 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/extensions/user_script_master.h"

#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_util.h"

// Helper function to parse greasesmonkey headers
static bool GetDeclarationValue(const StringPiece& line,
                                const StringPiece& prefix,
                                std::string* value) {
  if (!line.starts_with(prefix))
    return false;

  std::string temp(line.data() + prefix.length(),
                   line.length() - prefix.length());
  TrimWhitespace(temp, TRIM_ALL, value);
  return true;
}

UserScriptMaster::ScriptReloader::ScriptReloader(UserScriptMaster* master)
    : master_(master),
      master_message_loop_(MessageLoop::current()) {
}

// static
bool UserScriptMaster::ScriptReloader::ParseMetadataHeader(
      const StringPiece& script_text, UserScript* script) {
  // http://wiki.greasespot.net/Metadata_block
  StringPiece line;
  size_t line_start = 0;
  size_t line_end = 0;
  bool in_metadata = false;

  static const StringPiece kUserScriptBegin("// ==UserScript==");
  static const StringPiece kUserScriptEng("// ==/UserScript==");
  static const StringPiece kIncludeDeclaration("// @include ");
  static const StringPiece kMatchDeclaration("// @match ");
  static const StringPiece kRunAtDeclaration("// @run-at ");
  static const StringPiece kRunAtDocumentStartValue("document-start");
  static const StringPiece kRunAtDocumentEndValue("document-end");

  while (line_start < script_text.length()) {
    line_end = script_text.find('\n', line_start);

    // Handle the case where there is no trailing newline in the file.
    if (line_end == std::string::npos) {
      line_end = script_text.length() - 1;
    }

    line.set(script_text.data() + line_start, line_end - line_start);

    if (!in_metadata) {
      if (line.starts_with(kUserScriptBegin)) {
        in_metadata = true;
      }
    } else {
      if (line.starts_with(kUserScriptEng)) {
        break;
      }

      std::string value;
      if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
        // We escape some characters that MatchPattern() considers special.
        ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
        ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
        script->add_glob(value);
      } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
        URLPattern pattern;
        if (!pattern.Parse(value))
          return false;
        script->add_url_pattern(pattern);
      } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
        if (value == kRunAtDocumentStartValue)
          script->set_run_location(UserScript::DOCUMENT_START);
        else if (value != kRunAtDocumentEndValue)
          return false;
      }

      // TODO(aa): Handle more types of metadata.
    }

    line_start = line_end + 1;
  }

  // It is probably a mistake to declare both @include and @match rules.
  if (script->globs().size() > 0 && script->url_patterns().size() > 0)
    return false;

  // If no patterns were specified, default to @include *. This is what
  // Greasemonkey does.
  if (script->globs().size() == 0 && script->url_patterns().size() == 0)
    script->add_glob("*");

  return true;
}

void UserScriptMaster::ScriptReloader::StartScan(
    MessageLoop* work_loop, const FilePath& script_dir,
    const UserScriptList& lone_scripts) {
  // Add a reference to ourselves to keep ourselves alive while we're running.
  // Balanced by NotifyMaster().
  AddRef();
  work_loop->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &UserScriptMaster::ScriptReloader::RunScan,
                        script_dir, lone_scripts));
}

void UserScriptMaster::ScriptReloader::NotifyMaster(
    base::SharedMemory* memory) {
  if (!master_) {
    // The master went away, so these new scripts aren't useful anymore.
    delete memory;
  } else {
    master_->NewScriptsAvailable(memory);
  }

  // Drop our self-reference.
  // Balances StartScan().
  Release();
}

static void LoadScriptContent(UserScript::File* script_file) {
  std::string content;
  file_util::ReadFileToString(script_file->path(), &content);
  script_file->set_content(content);
  LOG(INFO) << "Loaded user script file: " << script_file->path().value();
}

void UserScriptMaster::ScriptReloader::LoadScriptsFromDirectory(
    const FilePath script_dir, UserScriptList* result) {
  // Clear the list. We will populate it with the scrips found in script_dir.
  result->clear();

  // Find all the scripts in |script_dir|.
  if (!script_dir.value().empty()) {
    // Create the "<Profile>/User Scripts" directory if it doesn't exist
    if (!file_util::DirectoryExists(script_dir))
      file_util::CreateDirectory(script_dir);

    file_util::FileEnumerator enumerator(script_dir, false,
                                         file_util::FileEnumerator::FILES,
                                         FILE_PATH_LITERAL("*.user.js"));
    for (FilePath file = enumerator.Next(); !file.value().empty();
         file = enumerator.Next()) {
      result->push_back(UserScript());
      UserScript& user_script = result->back();
      // Push single js file in this UserScript.
      GURL url(std::string(chrome::kUserScriptScheme) + ":/" +
          net::FilePathToFileURL(file).ExtractFileName());
      user_script.js_scripts().push_back(UserScript::File(file, url));
      UserScript::File& script_file = user_script.js_scripts().back();
      LoadScriptContent(&script_file);
      ParseMetadataHeader(script_file.GetContent(), &user_script);
    }
  }
}

static void LoadLoneScripts(UserScriptList* lone_scripts) {
  for (size_t i = 0; i < lone_scripts->size(); ++i) {
    UserScript& script = lone_scripts->at(i);
    for (size_t k = 0; k < script.js_scripts().size(); ++k) {
      UserScript::File& script_file = script.js_scripts()[k];
      if (script_file.GetContent().empty()) {
        LoadScriptContent(&script_file);
      }
    }
    for (size_t k = 0; k < script.css_scripts().size(); ++k) {
      UserScript::File& script_file = script.css_scripts()[k];
      if (script_file.GetContent().empty()) {
        LoadScriptContent(&script_file);
      }
    }
  }
}

// Pickle user scripts and return pointer to the shared memory.
static base::SharedMemory* Serialize(UserScriptList& scripts) {
  Pickle pickle;
  pickle.WriteSize(scripts.size());
  for (size_t i = 0; i < scripts.size(); i++) {
    UserScript& script = scripts[i];
    script.Pickle(&pickle);
    // Write scripts as 'data' so that we can read it out in the slave without
    // allocating a new string.
    for (size_t j = 0; j < script.js_scripts().size(); j++) {
      StringPiece contents = script.js_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
    for (size_t j = 0; j < script.css_scripts().size(); j++) {
      StringPiece contents = script.css_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
  }

  // Create the shared memory object.
  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());

  if (!shared_memory->Create(std::wstring(),  // anonymous
                             false,  // read-only
                             false,  // open existing
                             pickle.size())) {
    return NULL;
  }

  // Map into our process.
  if (!shared_memory->Map(pickle.size()))
    return NULL;

  // Copy the pickle to shared memory.
  memcpy(shared_memory->memory(), pickle.data(), pickle.size());

  return shared_memory.release();
}

// This method will be called from the file thread
void UserScriptMaster::ScriptReloader::RunScan(
    const FilePath script_dir, UserScriptList lone_script) {
  UserScriptList scripts;
  // Get list of user scripts.
  if (!script_dir.empty())
    LoadScriptsFromDirectory(script_dir, &scripts);

  LoadLoneScripts(&lone_script);

  // Merge with the explicit scripts
  scripts.reserve(scripts.size() + lone_script.size());
  scripts.insert(scripts.end(),
      lone_script.begin(), lone_script.end());

  // Scripts now contains list of up-to-date scripts. Load the content in the
  // shared memory and let the master know it's ready. We need to post the task
  // back even if no scripts ware found to balance the AddRef/Release calls
  master_message_loop_->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &ScriptReloader::NotifyMaster,
                        Serialize(scripts)));
}

UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
                                   const FilePath& script_dir)
    : user_script_dir_(script_dir),
      worker_loop_(worker_loop),
      extensions_service_ready_(false),
      pending_scan_(false) {
  if (!user_script_dir_.value().empty())
    AddWatchedPath(script_dir);

  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSIONS_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
}

UserScriptMaster::~UserScriptMaster() {
  if (script_reloader_)
    script_reloader_->DisownMaster();

// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  STLDeleteElements(&dir_watchers_);
#endif
}

void UserScriptMaster::AddWatchedPath(const FilePath& path) {
// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  DirectoryWatcher* watcher = new DirectoryWatcher();
  base::Thread* file_thread = g_browser_process->file_thread();
  watcher->Watch(path, this, file_thread ? file_thread->message_loop() : NULL,
                 true);
  dir_watchers_.push_back(watcher);
#endif
}

void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) {
  // Ensure handle is deleted or released.
  scoped_ptr<base::SharedMemory> handle_deleter(handle);

  if (pending_scan_) {
    // While we were scanning, there were further changes.  Don't bother
    // notifying about these scripts and instead just immediately rescan.
    pending_scan_ = false;
    StartScan();
  } else {
    // We're no longer scanning.
    script_reloader_ = NULL;
    // We've got scripts ready to go.
    shared_memory_.swap(handle_deleter);

    NotificationService::current()->Notify(
        NotificationType::USER_SCRIPTS_UPDATED,
        NotificationService::AllSources(),
        Details<base::SharedMemory>(handle));
  }
}

void UserScriptMaster::OnDirectoryChanged(const FilePath& path) {
  if (script_reloader_.get()) {
    // We're already scanning for scripts.  We note that we should rescan when
    // we get the chance.
    pending_scan_ = true;
    return;
  }

  StartScan();
}

void UserScriptMaster::Observe(NotificationType type,
                               const NotificationSource& source,
                               const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_READY:
      extensions_service_ready_ = true;
      StartScan();
      break;
    case NotificationType::EXTENSIONS_LOADED: {
      // TODO(aa): Fix race here. A page could need a content script on startup,
      // before the extension has loaded.  We need to freeze the renderer in
      // that case.
      // See: http://code.google.com/p/chromium/issues/detail?id=11547.

      // Add any content scripts inside the extension.
      ExtensionList* extensions = Details<ExtensionList>(details).ptr();
      for (ExtensionList::iterator extension_iterator = extensions->begin();
           extension_iterator != extensions->end(); ++extension_iterator) {
        Extension* extension = *extension_iterator;
        const UserScriptList& scripts = extension->content_scripts();
        for (UserScriptList::const_iterator iter = scripts.begin();
             iter != scripts.end(); ++iter) {
          lone_scripts_.push_back(*iter);
        }
      }
      if (!extensions_service_ready_)
        StartScan();
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      // Remove any content scripts.
      Extension* extension = Details<Extension>(details).ptr();
      UserScriptList new_lone_scripts;
      for (UserScriptList::iterator iter = lone_scripts_.begin();
           iter != lone_scripts_.end(); ++iter) {
        if (iter->extension_id() != extension->id()) {
          new_lone_scripts.push_back(*iter);
        }
      }
      lone_scripts_ = new_lone_scripts;
      StartScan();

      // TODO(aa): Do we want to do something smarter for the scripts that have
      // already been injected?

      break;
    }

    default:
      DCHECK(false);
  }
}

void UserScriptMaster::StartScan() {
  if (!script_reloader_)
    script_reloader_ = new ScriptReloader(this);

  script_reloader_->StartScan(worker_loop_, user_script_dir_, lone_scripts_);
}
<commit_msg>Fix bug where content scripts are not run if they are in extensions that are loaded after EXTENSIONS_READY.<commit_after>// Copyright (c) 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/extensions/user_script_master.h"

#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_util.h"

// Helper function to parse greasesmonkey headers
static bool GetDeclarationValue(const StringPiece& line,
                                const StringPiece& prefix,
                                std::string* value) {
  if (!line.starts_with(prefix))
    return false;

  std::string temp(line.data() + prefix.length(),
                   line.length() - prefix.length());
  TrimWhitespace(temp, TRIM_ALL, value);
  return true;
}

UserScriptMaster::ScriptReloader::ScriptReloader(UserScriptMaster* master)
    : master_(master),
      master_message_loop_(MessageLoop::current()) {
}

// static
bool UserScriptMaster::ScriptReloader::ParseMetadataHeader(
      const StringPiece& script_text, UserScript* script) {
  // http://wiki.greasespot.net/Metadata_block
  StringPiece line;
  size_t line_start = 0;
  size_t line_end = 0;
  bool in_metadata = false;

  static const StringPiece kUserScriptBegin("// ==UserScript==");
  static const StringPiece kUserScriptEng("// ==/UserScript==");
  static const StringPiece kIncludeDeclaration("// @include ");
  static const StringPiece kMatchDeclaration("// @match ");
  static const StringPiece kRunAtDeclaration("// @run-at ");
  static const StringPiece kRunAtDocumentStartValue("document-start");
  static const StringPiece kRunAtDocumentEndValue("document-end");

  while (line_start < script_text.length()) {
    line_end = script_text.find('\n', line_start);

    // Handle the case where there is no trailing newline in the file.
    if (line_end == std::string::npos) {
      line_end = script_text.length() - 1;
    }

    line.set(script_text.data() + line_start, line_end - line_start);

    if (!in_metadata) {
      if (line.starts_with(kUserScriptBegin)) {
        in_metadata = true;
      }
    } else {
      if (line.starts_with(kUserScriptEng)) {
        break;
      }

      std::string value;
      if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
        // We escape some characters that MatchPattern() considers special.
        ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
        ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
        script->add_glob(value);
      } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
        URLPattern pattern;
        if (!pattern.Parse(value))
          return false;
        script->add_url_pattern(pattern);
      } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
        if (value == kRunAtDocumentStartValue)
          script->set_run_location(UserScript::DOCUMENT_START);
        else if (value != kRunAtDocumentEndValue)
          return false;
      }

      // TODO(aa): Handle more types of metadata.
    }

    line_start = line_end + 1;
  }

  // It is probably a mistake to declare both @include and @match rules.
  if (script->globs().size() > 0 && script->url_patterns().size() > 0)
    return false;

  // If no patterns were specified, default to @include *. This is what
  // Greasemonkey does.
  if (script->globs().size() == 0 && script->url_patterns().size() == 0)
    script->add_glob("*");

  return true;
}

void UserScriptMaster::ScriptReloader::StartScan(
    MessageLoop* work_loop, const FilePath& script_dir,
    const UserScriptList& lone_scripts) {
  // Add a reference to ourselves to keep ourselves alive while we're running.
  // Balanced by NotifyMaster().
  AddRef();
  work_loop->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &UserScriptMaster::ScriptReloader::RunScan,
                        script_dir, lone_scripts));
}

void UserScriptMaster::ScriptReloader::NotifyMaster(
    base::SharedMemory* memory) {
  if (!master_) {
    // The master went away, so these new scripts aren't useful anymore.
    delete memory;
  } else {
    master_->NewScriptsAvailable(memory);
  }

  // Drop our self-reference.
  // Balances StartScan().
  Release();
}

static void LoadScriptContent(UserScript::File* script_file) {
  std::string content;
  file_util::ReadFileToString(script_file->path(), &content);
  script_file->set_content(content);
  LOG(INFO) << "Loaded user script file: " << script_file->path().value();
}

void UserScriptMaster::ScriptReloader::LoadScriptsFromDirectory(
    const FilePath script_dir, UserScriptList* result) {
  // Clear the list. We will populate it with the scrips found in script_dir.
  result->clear();

  // Find all the scripts in |script_dir|.
  if (!script_dir.value().empty()) {
    // Create the "<Profile>/User Scripts" directory if it doesn't exist
    if (!file_util::DirectoryExists(script_dir))
      file_util::CreateDirectory(script_dir);

    file_util::FileEnumerator enumerator(script_dir, false,
                                         file_util::FileEnumerator::FILES,
                                         FILE_PATH_LITERAL("*.user.js"));
    for (FilePath file = enumerator.Next(); !file.value().empty();
         file = enumerator.Next()) {
      result->push_back(UserScript());
      UserScript& user_script = result->back();
      // Push single js file in this UserScript.
      GURL url(std::string(chrome::kUserScriptScheme) + ":/" +
          net::FilePathToFileURL(file).ExtractFileName());
      user_script.js_scripts().push_back(UserScript::File(file, url));
      UserScript::File& script_file = user_script.js_scripts().back();
      LoadScriptContent(&script_file);
      ParseMetadataHeader(script_file.GetContent(), &user_script);
    }
  }
}

static void LoadLoneScripts(UserScriptList* lone_scripts) {
  for (size_t i = 0; i < lone_scripts->size(); ++i) {
    UserScript& script = lone_scripts->at(i);
    for (size_t k = 0; k < script.js_scripts().size(); ++k) {
      UserScript::File& script_file = script.js_scripts()[k];
      if (script_file.GetContent().empty()) {
        LoadScriptContent(&script_file);
      }
    }
    for (size_t k = 0; k < script.css_scripts().size(); ++k) {
      UserScript::File& script_file = script.css_scripts()[k];
      if (script_file.GetContent().empty()) {
        LoadScriptContent(&script_file);
      }
    }
  }
}

// Pickle user scripts and return pointer to the shared memory.
static base::SharedMemory* Serialize(UserScriptList& scripts) {
  Pickle pickle;
  pickle.WriteSize(scripts.size());
  for (size_t i = 0; i < scripts.size(); i++) {
    UserScript& script = scripts[i];
    script.Pickle(&pickle);
    // Write scripts as 'data' so that we can read it out in the slave without
    // allocating a new string.
    for (size_t j = 0; j < script.js_scripts().size(); j++) {
      StringPiece contents = script.js_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
    for (size_t j = 0; j < script.css_scripts().size(); j++) {
      StringPiece contents = script.css_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
  }

  // Create the shared memory object.
  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());

  if (!shared_memory->Create(std::wstring(),  // anonymous
                             false,  // read-only
                             false,  // open existing
                             pickle.size())) {
    return NULL;
  }

  // Map into our process.
  if (!shared_memory->Map(pickle.size()))
    return NULL;

  // Copy the pickle to shared memory.
  memcpy(shared_memory->memory(), pickle.data(), pickle.size());

  return shared_memory.release();
}

// This method will be called from the file thread
void UserScriptMaster::ScriptReloader::RunScan(
    const FilePath script_dir, UserScriptList lone_script) {
  UserScriptList scripts;
  // Get list of user scripts.
  if (!script_dir.empty())
    LoadScriptsFromDirectory(script_dir, &scripts);

  LoadLoneScripts(&lone_script);

  // Merge with the explicit scripts
  scripts.reserve(scripts.size() + lone_script.size());
  scripts.insert(scripts.end(),
      lone_script.begin(), lone_script.end());

  // Scripts now contains list of up-to-date scripts. Load the content in the
  // shared memory and let the master know it's ready. We need to post the task
  // back even if no scripts ware found to balance the AddRef/Release calls
  master_message_loop_->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &ScriptReloader::NotifyMaster,
                        Serialize(scripts)));
}

UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
                                   const FilePath& script_dir)
    : user_script_dir_(script_dir),
      worker_loop_(worker_loop),
      extensions_service_ready_(false),
      pending_scan_(false) {
  if (!user_script_dir_.value().empty())
    AddWatchedPath(script_dir);

  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSIONS_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
}

UserScriptMaster::~UserScriptMaster() {
  if (script_reloader_)
    script_reloader_->DisownMaster();

// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  STLDeleteElements(&dir_watchers_);
#endif
}

void UserScriptMaster::AddWatchedPath(const FilePath& path) {
// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  DirectoryWatcher* watcher = new DirectoryWatcher();
  base::Thread* file_thread = g_browser_process->file_thread();
  watcher->Watch(path, this, file_thread ? file_thread->message_loop() : NULL,
                 true);
  dir_watchers_.push_back(watcher);
#endif
}

void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) {
  // Ensure handle is deleted or released.
  scoped_ptr<base::SharedMemory> handle_deleter(handle);

  if (pending_scan_) {
    // While we were scanning, there were further changes.  Don't bother
    // notifying about these scripts and instead just immediately rescan.
    pending_scan_ = false;
    StartScan();
  } else {
    // We're no longer scanning.
    script_reloader_ = NULL;
    // We've got scripts ready to go.
    shared_memory_.swap(handle_deleter);

    NotificationService::current()->Notify(
        NotificationType::USER_SCRIPTS_UPDATED,
        NotificationService::AllSources(),
        Details<base::SharedMemory>(handle));
  }
}

void UserScriptMaster::OnDirectoryChanged(const FilePath& path) {
  if (script_reloader_.get()) {
    // We're already scanning for scripts.  We note that we should rescan when
    // we get the chance.
    pending_scan_ = true;
    return;
  }

  StartScan();
}

void UserScriptMaster::Observe(NotificationType type,
                               const NotificationSource& source,
                               const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_READY:
      extensions_service_ready_ = true;
      StartScan();
      break;
    case NotificationType::EXTENSIONS_LOADED: {
      // TODO(aa): Fix race here. A page could need a content script on startup,
      // before the extension has loaded.  We need to freeze the renderer in
      // that case.
      // See: http://code.google.com/p/chromium/issues/detail?id=11547.

      // Add any content scripts inside the extension.
      ExtensionList* extensions = Details<ExtensionList>(details).ptr();
      for (ExtensionList::iterator extension_iterator = extensions->begin();
           extension_iterator != extensions->end(); ++extension_iterator) {
        Extension* extension = *extension_iterator;
        const UserScriptList& scripts = extension->content_scripts();
        for (UserScriptList::const_iterator iter = scripts.begin();
             iter != scripts.end(); ++iter) {
          lone_scripts_.push_back(*iter);
        }
      }
      if (extensions_service_ready_)
        StartScan();
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      // Remove any content scripts.
      Extension* extension = Details<Extension>(details).ptr();
      UserScriptList new_lone_scripts;
      for (UserScriptList::iterator iter = lone_scripts_.begin();
           iter != lone_scripts_.end(); ++iter) {
        if (iter->extension_id() != extension->id()) {
          new_lone_scripts.push_back(*iter);
        }
      }
      lone_scripts_ = new_lone_scripts;
      StartScan();

      // TODO(aa): Do we want to do something smarter for the scripts that have
      // already been injected?

      break;
    }

    default:
      DCHECK(false);
  }
}

void UserScriptMaster::StartScan() {
  if (!script_reloader_)
    script_reloader_ = new ScriptReloader(this);

  script_reloader_->StartScan(worker_loop_, user_script_dir_, lone_scripts_);
}
<|endoftext|>


<commit_before>#include "primitives.h"

#include "glm/mat4x4.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "gl/shaderProgram.h"
#include "gl/vertexLayout.h"
#include "gl/renderState.h"
#include "platform.h"

#include "shaders/debugPrimitive_vs.h"
#include "shaders/debugPrimitive_fs.h"

namespace Tangram {

namespace Primitives {

static bool s_initialized;
static std::unique_ptr<ShaderProgram> s_shader;
static std::unique_ptr<VertexLayout> s_layout;
static glm::vec2 s_resolution;
static GLuint s_boundBuffer;

static UniformLocation s_uColor{"u_color"};
static UniformLocation s_uProj{"u_proj"};

void init() {

    // lazy init
    if (!s_initialized) {
        s_shader = std::unique_ptr<ShaderProgram>(new ShaderProgram());

        s_shader->setSourceStrings(SHADER_SOURCE(debugPrimitive_fs),
                                   SHADER_SOURCE(debugPrimitive_vs));

        s_layout = std::unique_ptr<VertexLayout>(new VertexLayout({
            {"a_position", 2, GL_FLOAT, false, 0},
        }));

        s_initialized = true;
        GL_CHECK(glLineWidth(1.5f));
    }
}

void saveState() {
    // save the current gl state
    GL_CHECK(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*) &s_boundBuffer));
    RenderState::depthTest(GL_FALSE);
    RenderState::vertexBuffer(0);
}

void popState() {
    // undo modification on the gl states
    RenderState::vertexBuffer(s_boundBuffer);
}

void drawLine(const glm::vec2& _origin, const glm::vec2& _destination) {

    init();

    glm::vec2 verts[2] = {
        glm::vec2(_origin.x, _origin.y),
        glm::vec2(_destination.x, _destination.y)
    };

    saveState();

    s_shader->use();

    // enable the layout for the line vertices
    s_layout->enable(*s_shader, 0, &verts);

    GL_CHECK(glDrawArrays(GL_LINES, 0, 2));
    popState();

}

void drawRect(const glm::vec2& _origin, const glm::vec2& _destination) {
    drawLine(_origin, {_destination.x, _origin.y});
    drawLine({_destination.x, _origin.y}, _destination);
    drawLine(_destination, {_origin.x, _destination.y});
    drawLine({_origin.x,_destination.y}, _origin);
}

void drawPoly(const glm::vec2* _polygon, size_t _n) {
    init();

    saveState();

    s_shader->use();

    // enable the layout for the _polygon vertices
    s_layout->enable(*s_shader, 0, (void*)_polygon);

    GL_CHECK(glDrawArrays(GL_LINE_LOOP, 0, _n));
    popState();
}

void setColor(unsigned int _color) {
    init();

    float r = (_color >> 16 & 0xff) / 255.0;
    float g = (_color >> 8  & 0xff) / 255.0;
    float b = (_color       & 0xff) / 255.0;

    s_shader->setUniformf(s_uColor, r, g, b);
}

void setResolution(float _width, float _height) {
    init();

    glm::mat4 proj = glm::ortho(0.f, _width, _height, 0.f, -1.f, 1.f);
    s_shader->setUniformMatrix4f(s_uProj, proj);
}

}

}
<commit_msg>primites: no need to rebind previous vertexbuffer<commit_after>#include "primitives.h"

#include "glm/mat4x4.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "gl/shaderProgram.h"
#include "gl/vertexLayout.h"
#include "gl/renderState.h"
#include "platform.h"

#include "shaders/debugPrimitive_vs.h"
#include "shaders/debugPrimitive_fs.h"

namespace Tangram {

namespace Primitives {

static bool s_initialized;
static std::unique_ptr<ShaderProgram> s_shader;
static std::unique_ptr<VertexLayout> s_layout;
static glm::vec2 s_resolution;

static UniformLocation s_uColor{"u_color"};
static UniformLocation s_uProj{"u_proj"};

void init() {

    // lazy init
    if (!s_initialized) {
        s_shader = std::unique_ptr<ShaderProgram>(new ShaderProgram());

        s_shader->setSourceStrings(SHADER_SOURCE(debugPrimitive_fs),
                                   SHADER_SOURCE(debugPrimitive_vs));

        s_layout = std::unique_ptr<VertexLayout>(new VertexLayout({
            {"a_position", 2, GL_FLOAT, false, 0},
        }));

        s_initialized = true;
        GL_CHECK(glLineWidth(1.5f));
    }
}

void drawLine(const glm::vec2& _origin, const glm::vec2& _destination) {

    init();

    glm::vec2 verts[2] = {
        glm::vec2(_origin.x, _origin.y),
        glm::vec2(_destination.x, _destination.y)
    };

    if (!s_shader->use()) { return; }

    RenderState::depthTest(GL_FALSE);
    RenderState::vertexBuffer(0);

    // enable the layout for the line vertices
    s_layout->enable(*s_shader, 0, &verts);

    GL_CHECK(glDrawArrays(GL_LINES, 0, 2));
}

void drawRect(const glm::vec2& _origin, const glm::vec2& _destination) {
    drawLine(_origin, {_destination.x, _origin.y});
    drawLine({_destination.x, _origin.y}, _destination);
    drawLine(_destination, {_origin.x, _destination.y});
    drawLine({_origin.x,_destination.y}, _origin);
}

void drawPoly(const glm::vec2* _polygon, size_t _n) {
    init();

    if (!s_shader->use()) { return; }

    RenderState::depthTest(GL_FALSE);
    RenderState::vertexBuffer(0);

    // enable the layout for the _polygon vertices
    s_layout->enable(*s_shader, 0, (void*)_polygon);

    GL_CHECK(glDrawArrays(GL_LINE_LOOP, 0, _n));
}

void setColor(unsigned int _color) {
    init();

    float r = (_color >> 16 & 0xff) / 255.0;
    float g = (_color >> 8  & 0xff) / 255.0;
    float b = (_color       & 0xff) / 255.0;

    s_shader->setUniformf(s_uColor, r, g, b);
}

void setResolution(float _width, float _height) {
    init();

    glm::mat4 proj = glm::ortho(0.f, _width, _height, 0.f, -1.f, 1.f);
    s_shader->setUniformMatrix4f(s_uProj, proj);
}

}

}
<|endoftext|>


<commit_before>// ADHD200Converter.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Option.h"
#include "LoaderFactory.h"
#include "IOfunctions.h"
#include "TCCutter.h"
#include "TC2Corr.h"
#include "Corr2Graph.h"

using namespace std;

multimap<Subject, corr_t> processTC2Corr(multimap<Subject, tc_t>& smtc, const Option& opt) {
	string cutm = opt.cutMethod;
	// TODO: use a delegate function to directly generate TCCutter
	int cutParm = cutm == "nGraph" ? opt.nGraph : opt.nScan;

	TC2Corr t2c(opt.corrMethod);
	multimap<Subject, corr_t> res;
	for(auto& p : smtc) {
		TCCutter cutter(p.second, cutm, cutParm);
		while(cutter.haveNext()) {
			tc_t t = cutter.getNext();
			res.emplace(p.first, t2c.getCorr(t));
		}
	}
	return res;
}

int main(int argc, char* argv[])
{
	Option opt;
	if(!opt.parseInput(argc, argv))
		return 1;

	cout << "Time Course Path: " << opt.tcPath << "\n"
		<< "Correlation Path: " << opt.corrPath << "\n"
		<< "Graph Path: " << opt.graphPath << "\n"
		<< "Dataset name: " << opt.dataset << "\n"
		<< "Cutting method: " << opt.getCutMethod() << "\n"
		<< "Cutting method parameter - nGraph: " << opt.nGraph << "\n"
		<< "Cutting method parameter - nScan: " << opt.nScan << "\n"
		<< "Correlation method: " << opt.corrMethod << "\n"
		<< "Correlation threshold: " << opt.conThrshd << "\n"
		<< endl;

	cout << "Loading input data:" << endl;
	multimap<Subject, corr_t> corr;
	try {
		auto p = opt.getInputFolder();
		if(p.first == Option::FileType::TC) {
			cout << "  Loading time course data:" << endl;
			multimap<Subject, tc_t> smtc = loadInputTC(opt.tcPath, opt.dataset, opt.nSubject);
			cout << "  Generating correlation:" << endl;
			corr = processTC2Corr(smtc, opt);
		} else if(p.first == Option::FileType::CORR) {
			cout << "  Loading correlation data:" << endl;
			corr = loadInputCorr(opt.corrPath, opt.nSubject);
		}
	} catch(exception& e) {
		cerr << e.what() << endl;
		return 2;
	}

	if(opt.isOutputFolder(Option::FileType::CORR)) {
		cout << "Outputting correlations:" << endl;
		for(auto p : corr) {
			string fn = opt.corrPath + genCorrFilename(p.first);
			ofstream fout(fn);
			if(!fout) {
				cerr << "  Cannot open output file: " << fn << endl;
				continue;
			}
			writeCorr(fout, p.second);
		}
	}

	if(opt.isOutputFolder(Option::FileType::GRAPH)) {
		cout << "Generate graphs:" << endl;
		Corr2Graph c2g(opt.conThrshd);
		for(auto p : corr) {
			string fn = opt.graphPath + genGraphFilename(p.first);
			ofstream fout(fn);
			if(!fout) {
				cerr << "  Cannot open output file: " << fn << endl;
				continue;
			}
			writeGraph(fout, c2g.getGraph(p.second));
		}

	}
    return 0;
}

<commit_msg>Add progress output.<commit_after>// ADHD200Converter.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Option.h"
#include "LoaderFactory.h"
#include "IOfunctions.h"
#include "TCCutter.h"
#include "TC2Corr.h"
#include "Corr2Graph.h"

using namespace std;

multimap<Subject, corr_t> processTC2Corr(multimap<Subject, tc_t>& smtc, const Option& opt) {
	string cutm = opt.cutMethod;
	// TODO: use a delegate function to directly generate TCCutter
	int cutParm = cutm == "nGraph" ? opt.nGraph : opt.nScan;

	TC2Corr t2c(opt.corrMethod);
	multimap<Subject, corr_t> res;
	for(auto& p : smtc) {
		TCCutter cutter(p.second, cutm, cutParm);
		while(cutter.haveNext()) {
			tc_t t = cutter.getNext();
			res.emplace(p.first, t2c.getCorr(t));
		}
	}
	return res;
}

int main(int argc, char* argv[])
{
	Option opt;
	if(!opt.parseInput(argc, argv))
		return 1;

	ios::sync_with_stdio(false);
	cout << "Time Course Path: " << opt.tcPath << "\n"
		<< "Correlation Path: " << opt.corrPath << "\n"
		<< "Graph Path: " << opt.graphPath << "\n"
		<< "  Input data: " << opt.getInputFolder().second << "\n"
		<< ios::boolalpha
		<< "  Output to correlation: " << opt.isOutputFolder(Option::FileType::CORR) << "\t"
		<< "  Output to graph: " << opt.isOutputFolder(Option::FileType::GRAPH) << "\n"
		<< "Dataset name: " << opt.dataset << "\n"
		<< "Cutting method: " << opt.getCutMethod() << "\n"
		<< "Cutting method parameter - nGraph: " << opt.nGraph << "\n"
		<< "Cutting method parameter - nScan: " << opt.nScan << "\n"
		<< "Correlation method: " << opt.corrMethod << "\n"
		<< "Correlation threshold: " << opt.conThrshd << "\n"
		<< endl;

	cout << "Loading input data:" << endl;
	multimap<Subject, corr_t> corr;
	try {
		auto p = opt.getInputFolder();
		if(p.first == Option::FileType::TC) {
			cout << "  Loading time course data:" << endl;
			multimap<Subject, tc_t> smtc = loadInputTC(opt.tcPath, opt.dataset, opt.nSubject);
			cout << " Loaded " << smtc.size() << endl;
			cout << "  Generating correlation:" << endl;
			corr = processTC2Corr(smtc, opt);
		} else if(p.first == Option::FileType::CORR) {
			cout << "  Loading correlation data:" << endl;
			corr = loadInputCorr(opt.corrPath, opt.nSubject);
		}
		cout << " Loaded " << corr.size() << endl;
	} catch(exception& e) {
		cerr << e.what() << endl;
		return 2;
	}

	if(opt.isOutputFolder(Option::FileType::CORR)) {
		cout << "Outputting correlations:" << endl;
		int cnt = 0;
		for(auto p : corr) {
			string fn = opt.corrPath + genCorrFilename(p.first);
			ofstream fout(fn);
			if(!fout) {
				cerr << "  Cannot open output file: " << fn << endl;
				continue;
			}
			writeCorr(fout, p.second);
			if(++cnt % 100 == 0)
				cout << "  Outputted " << cnt << endl;
		}
		cout << "  Outputted " << cnt << endl;
	}

	if(opt.isOutputFolder(Option::FileType::GRAPH)) {
		cout << "Generate graphs:" << endl;
		Corr2Graph c2g(opt.conThrshd);
		int cnt = 0;
		for(auto p : corr) {
			string fn = opt.graphPath + genGraphFilename(p.first);
			ofstream fout(fn);
			if(!fout) {
				cerr << "  Cannot open output file: " << fn << endl;
				continue;
			}
			writeGraph(fout, c2g.getGraph(p.second));
			if(++cnt % 100 == 0)
				cout << "  Outputted " << cnt << endl;
		}
		cout << "  Outputted " << cnt << endl;
	}

	cout << "Finished" << endl;
    return 0;
}

<|endoftext|>


<commit_before>//======= Genetic.cpp -  Guide to Exploration of Otimization's Set -*- C++ -*-==//
////
////              The LLVM Time Cost Analyser Infrastructure
////
////  This file is distributed under the MIT License. See LICENSE.txt for details.
////
////===----------------------------------------------------------------------===//
/////
///// \file
///// \brief This file implements a tool that, when given a llvm code and its
///// profiling information, returns the best otimization sequence from a genetic
///// algorithm.
/////
////===----------------------------------------------------------------------===//

#include "GEOS.h"

#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/IR/LLVMContext.h"

#include "GEOSCommandLineParser.h"
#include "OfflineLearning/CodeMetricBase.h"
#include "OfflineLearning/AccuracyBase.h"
#include "OfflineLearning/CorrectionBase.h"
#include "OfflineLearning/OptAccuracyBase.h"

#include <vector>
#include <limits>
#include <random>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include "papi.h"
#include <list>
#include <queue>

#include <cstdlib>
#include <ctime>

#define SIZE 100
#define TSIZE 5
#define NOPT 50
typedef struct Solution {
  PassSequence Sequence;
  double Cost;
  bool isCalculated;

  Solution(PassSequence P, double C = 0, bool isC = false) {
    Sequence = P;
    Cost = C;
    isCalculated = isC;
  }

  void setCost(double C) { Cost = C; isCalculated = true; }

  Solution &operator=(Solution rhs) {
    Sequence = rhs.Sequence;
    Cost = rhs.Cost;
    isCalculated = rhs.isCalculated;
    return *this;
  }
} Solution;

struct compareSolution {
  bool operator()(Solution *S1, Solution *S2) const{
    return (S1->Cost > S2->Cost);
  }
};

typedef std::vector<Solution> PopT;

void initializePopulation(PopT &Population) {
  for (int i = 0; i < SIZE; i++) {
    PassSequence Sequence;
    Sequence.randomize(NOPT, true);
    Population.push_back(Solution(Sequence));
  }
}

void evaluate(Solution &S,
    std::shared_ptr<ProfileModule> PModule, CostEstimatorOptions Opts) {
  if (S.isCalculated) return;
  auto PO = GEOS::applyPasses(PModule, S.Sequence);
  if (!PO) return;
  auto NewCost = GEOS::analyseCost(PO, Opts);
  S.setCost(NewCost);
}

Solution *evaluatePopulation(PopT &Population,
    std::shared_ptr<ProfileModule> PModule, CostEstimatorOptions Opts) {
  Solution *Best = &Population[0];
  for (auto &I : Population) {
    evaluate(I, PModule, Opts);
    if (I.Cost < Best->Cost && I.isCalculated)
      Best = &I;
  }
  return Best;
}

Solution *selectParent(PopT &Population) {
  std::priority_queue
    <Solution*, std::vector<Solution*>, compareSolution> Tournament;
  std::vector<bool> isInserted(Population.size(), false);

  while (Tournament.size() != TSIZE) {
    int RandomPos = rand() % Population.size();
    if (isInserted[RandomPos]) continue;
    Tournament.push(&Population[RandomPos]);
    isInserted[RandomPos] = true;
  }
  return Tournament.top();
}

Solution crossOver(Solution S1, Solution S2) {
  PassSequence Crossover = S1.Sequence * S2.Sequence;
  return Solution(Crossover);
}

void mutation(Solution &S, double MutationRate) {
  PassSequence MutatedSeq;
  int MaxOpt = static_cast<int>(OptimizationKind::tailcallelim);
  for (unsigned i = 0; i < S.Sequence.size()+1; i++) {
    double RandomNumber = (double)rand() / RAND_MAX;
    bool Mutate = (MutationRate >= RandomNumber);
    if (Mutate) {
      if (i == S.Sequence.size())
        MutatedSeq.add(static_cast<OptimizationKind>(rand() % MaxOpt));
    } else {
      MutatedSeq.add(S.Sequence[i]);
    }
  }
  S.Sequence = MutatedSeq;
}

void updatePopulation(Solution C, Solution *P1, Solution *P2, Solution *Best) {
  Solution *Child;
  if (P1->Cost < P2->Cost)
    Child = P2;
  else
    Child = P1;
  *Child = C;

  if (Child->Cost < Best->Cost && Child->isCalculated)
    Best = Child;
}

bool isFinished(time_t Start) {
  time_t total = time(0) - Start;
  printf("Time:%ld\n", total);
  return (total >= 300);
}

int main(int argc, char** argv) {
  srand(time(0));
  GEOS::init();

  LLVMContext &Context = getGlobalContext();
  SMDiagnostic Error;

  gcl::GEOSParseCommandLineOptions(argc, argv);
  Module *MyModule =
    parseIRFile(LLVMFilename.c_str(), Error, Context).release();

  std::shared_ptr<ProfileModule> PModule(new ProfileModule(MyModule));
  CostEstimatorOptions Opts = gcl::populatePModule(PModule);

  /*
     auto MetricBase = loadMetricsBase(MBasePath);
     auto AccuracyBase = loadAccuracyBase(ABasePath);
     auto NearestMetricName = getNearestMetric(PModule, MetricBase);
     double EstimatedAccuracy =
     getAccuracyFor(NearestMetricName, Opts, AccuracyBase);

     auto CorrectionBase =
     loadCorrectionBase(CBasePath+"/"+NearestMetricName+".estr");
     auto OptAccuracyBase =
     loadOptAccuracyBase(OABasePath+"/"+NearestMetricName+".ocor");
     */

  int PAPIEvents[1] = {PAPI_TOT_CYC};
  double RealInitCost =
    (GEOS::getPAPIProfile(PModule, ExecutionKind::JIT, PAPIEvents, 1))[0];
  auto InitCost = GEOS::analyseCost(PModule, Opts);

  double MutationRate = 0.01;
  int Cycles = 0;
  PopT Population;

  printf("Starting genetic...\n");

  initializePopulation(Population);
  Solution *Best = evaluatePopulation(Population, PModule, Opts);

  time_t Start = time(0);
  while (!isFinished(Start)) {
    Solution *FirstParent = selectParent(Population);
    Solution *SecondParent = selectParent(Population);
    Solution Child = crossOver(*FirstParent, *SecondParent);
    mutation(Child, MutationRate);
    evaluate(Child, PModule, Opts);
    updatePopulation(Child, FirstParent, SecondParent, Best);
    Cycles += 1;
    printf("Cycles: %d - ", Cycles);
  }

  auto PO = GEOS::applyPasses(PModule, Best->Sequence);
  double RealFinalCost =
    (GEOS::getPAPIProfile(PO, ExecutionKind::JIT, PAPIEvents, 1))[0];
  double FinalCost = GEOS::analyseCost(PO, Opts);

  double EstimatedSU = FinalCost/InitCost;
  double RealSU = RealFinalCost/RealInitCost;
  printf("\nEstimated Speedup: %f\nReal Speedup: %f\n\nCycles: %d\n", EstimatedSU,
      RealSU, Cycles);

  Best->Sequence.print();
  return 0;
}
<commit_msg>ask:Genetic.cpp finished<commit_after>//======= Genetic.cpp -  Guide to Exploration of Otimization's Set -*- C++ -*-==//
////
////              The LLVM Time Cost Analyser Infrastructure
////
////  This file is distributed under the MIT License. See LICENSE.txt for details.
////
////===----------------------------------------------------------------------===//
/////
///// \file
///// \brief This file implements a tool that, when given a llvm code and its
///// profiling information, returns the best otimization sequence from a genetic
///// algorithm.
/////
////===----------------------------------------------------------------------===//

#include "GEOS.h"

#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/IR/LLVMContext.h"

#include "GEOSCommandLineParser.h"
#include "OfflineLearning/CodeMetricBase.h"
#include "OfflineLearning/AccuracyBase.h"
#include "OfflineLearning/CorrectionBase.h"
#include "OfflineLearning/OptAccuracyBase.h"

#include <vector>
#include <limits>
#include <random>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include "papi.h"
#include <list>
#include <queue>
#include <float.h>

#include <cstdlib>
#include <ctime>

static cl::opt<std::string>
MBasePath("metrics", cl::desc("Base of metrics"),
    cl::value_desc(".txt"),
    cl::Required);
static cl::alias
MBaseAlias("m", cl::desc("Alias for -metrics"), cl::aliasopt(MBasePath));

static cl::opt<std::string>
ABasePath("accuracy", cl::desc("Base of Accuracy"),
    cl::value_desc(".txt"),
    cl::Required);
static cl::alias
ABaseAlias("a", cl::desc("Alias for -accuracy"), cl::aliasopt(ABasePath));

static cl::opt<std::string>
CBasePath("correction-folder", cl::desc("Folder with corrections"),
    cl::value_desc(".txt"),
    cl::Required);
static cl::alias
CBaseAlias("cf", cl::desc("Alias for -correction-folder"), cl::aliasopt(CBasePath));

static cl::opt<std::string>
OABasePath("opt-accuracy-folder", cl::desc("Folder with accuracy for each otimization"),
    cl::value_desc(".txt"),
    cl::Required);
static cl::alias
OABaseAlias("oaf", cl::desc("Alias for -opt-accuracy"), cl::aliasopt(OABasePath));

static cl::opt<unsigned> SIZE("pop-size", cl::desc("Size of population"));
static cl::alias SIZEAlias("s", cl::desc("Alias for -pop-size"),
    cl::aliasopt(SIZE));

static cl::opt<unsigned> BSIZE("opt-list-size", cl::desc("Max total time (in seconds)"));
static cl::alias BSIZEAlias("ols", cl::desc("Alias for time-max"),
    cl::aliasopt(BSIZE));

static cl::opt<unsigned> NOPT("length-solution", cl::desc("Max total time (in seconds)"));
static cl::alias NOPTAlias("len", cl::desc("Alias for time-max"),
    cl::aliasopt(NOPT));

static cl::opt<unsigned> TIME_MAX("time-max", cl::desc("Max total time (in seconds)"));
static cl::alias TIME_MAXAlias("tm", cl::desc("Alias for time-max"),
    cl::aliasopt(TIME_MAX));

static cl::opt<unsigned> CYCLE_MAX("cycle-max", cl::desc("Max number of cycles"));
static cl::alias CYCLE_MAXAlias("cm", cl::desc("Alias for cycle-max"),
    cl::aliasopt(CYCLE_MAX));

static cl::opt<double> MutationRate("mut-rate", cl::desc("Max total time (in seconds)"));
static cl::alias MutationRateAlias("pm", cl::desc("Alias for time-max"),
    cl::aliasopt(MutationRate));

static cl::opt<double> CrossoverRate("cross-rate", cl::desc("Max total time (in seconds)"));
static cl::alias CrossoverRateAlias("pc", cl::desc("Alias for time-max"),
    cl::aliasopt(CrossoverRate));

#define SIZE_STD 100
#define NOPT_STD 70
#define BSIZE_STD 5
#define TIME_MAX_STD 300
#define CYCLE_MAX_STD 50

#define CRATE_STD 0.8
#define MRATE_STD 0.01

double getRandomDouble() {
  return rand()/RAND_MAX;
}

// ------------------------------- Types
typedef struct Solution {
  PassSequence Sequence;
  double Cost;
  bool isCalculated;

  Solution() {}
  Solution(PassSequence P, double C = DBL_MAX, bool isC = false) {
    Sequence = P;
    Cost = C;
    isCalculated = isC;
  }

  void setCost(double C) { Cost = C; isCalculated = true; }

  Solution &operator=(Solution rhs) {
    Sequence = rhs.Sequence;
    Cost = rhs.Cost;
    isCalculated = rhs.isCalculated;
    return *this;
  }
} Solution;

class CompareSolution {
  double Accuracy;
  bool getJudgement() const {
    return (Accuracy >= getRandomDouble());
  }

  public:
    CompareSolution(const double A = 1.0) {
      Accuracy = (A + 1.0)/2;
    }

    bool operator()(Solution S1, Solution S2) const {
      return ((S1.Cost > S2.Cost) == getJudgement());
    }
};

typedef std::vector<Solution> PopT;
typedef std::priority_queue<Solution, PopT, CompareSolution> BestSeqT;

// ---------------------- Functions
void initializePopulation(PopT &Population) {
  for (unsigned i = 0; i < SIZE; i++) {
    PassSequence Sequence;
    Sequence.randomize(NOPT);
    Population.push_back(Solution(Sequence));
  }
}

bool evaluate(Solution &S,
    CorrectionBaseT CorrectionBase, OptAccuracyBaseT OptAccuracyBase,
    std::shared_ptr<ProfileModule> PModule, CostEstimatorOptions Opts) {
  if (S.isCalculated) return true;

  auto PO = GEOS::applyPasses(PModule, S.Sequence);
  if (!PO) return false;

  auto OptAccuracy = getPassSequenceAccuracy
    (S.Sequence, Opts, OptAccuracyBase);
  auto NewCost = GEOS::analyseCost(PO, Opts);
    getCorrectionFor(S.Sequence, Opts, CorrectionBase);
  NewCost *= OptAccuracy;
  S.setCost(NewCost);
  return true;
}

double evaluatePopulation(PopT &Population,
    CorrectionBaseT CorrectionBase, OptAccuracyBaseT OptAccuracyBase,
    BestSeqT &BestSequences, std::shared_ptr<ProfileModule> PModule,
    CostEstimatorOptions Opts, double EstimatedAccuracy) {
  double TotalCost = 0;
  int NotCalculated = 0;
  BestSeqT OrderedPop((CompareSolution(EstimatedAccuracy)));

  BestSequences = BestSeqT(CompareSolution(EstimatedAccuracy));
  for (auto &I : Population) {
    if (evaluate(I, CorrectionBase, OptAccuracyBase, PModule, Opts))
      TotalCost += I.Cost;
    else NotCalculated++;
    OrderedPop.push(I);
  }

  for (unsigned i = 0; i < BSIZE; i++) {
    BestSequences.push(OrderedPop.top());
    OrderedPop.pop();
  }
  return TotalCost/(Population.size() - NotCalculated);
}

PopT selection(PopT Population, double Mean) {
  PopT MatingPool;
  for (auto S : Population) {
    int Sample = (int)(S.Cost/Mean);
    double Prob = (S.Cost/Mean) - Sample;
    for (auto i = 0; i < Sample; i++)
      MatingPool.push_back(S);
    if (Prob >= getRandomDouble())
      MatingPool.push_back(S);
  }
  return MatingPool;
}

PopT crossover(PopT MatingPool) {
  PopT NewPopulation;
  int MSize = MatingPool.size();
  while (NewPopulation.size() <= SIZE) {
    int ParentI = rand() % MSize;
    int ParentJ = rand() % MSize;
    if (CrossoverRate >= getRandomDouble()) {
      PassSequence Crossover = MatingPool[ParentI].Sequence *
        MatingPool[ParentJ].Sequence;
      NewPopulation.push_back(Solution(Crossover));
    } else {
      NewPopulation.push_back(MatingPool[ParentI]);
      NewPopulation.push_back(MatingPool[ParentJ]);
    }
  }
  return NewPopulation;
}

void mutation(PopT &Population) {
  PassSequence MutatedSeq;
  int MaxOpt = static_cast<int>(OptimizationKind::tailcallelim);
  for (auto S : Population) {
    if (S.isCalculated) continue;
    for (unsigned i = 0; i < S.Sequence.size(); i++) {
      if (MutationRate >= getRandomDouble()) {
        MutatedSeq.add(static_cast<OptimizationKind>(rand() % MaxOpt));
      } else {
        MutatedSeq.add(S.Sequence[i]);
      }
    }
    S.Sequence = MutatedSeq;
  }
}

bool isFinished(time_t Start, int Cycles) {
  time_t total = time(0) - Start;
  printf("Time:%ld\n", total);
  if (CYCLE_MAX && TIME_MAX)
    return (total >= (int)TIME_MAX || Cycles >= (int)CYCLE_MAX);
  else if (TIME_MAX)
    return (total >= (int)TIME_MAX);
  else
    return (Cycles >= (int)CYCLE_MAX);
}

int main(int argc, char** argv) {
  srand(time(0));
  GEOS::init();

  LLVMContext &Context = getGlobalContext();
  SMDiagnostic Error;

  gcl::GEOSParseCommandLineOptions(argc, argv);
  Module *MyModule =
    parseIRFile(LLVMFilename.c_str(), Error, Context).release();

  if (!SIZE) SIZE = SIZE_STD;
  if (!BSIZE) BSIZE = BSIZE_STD;
  if (!NOPT) NOPT = NOPT_STD;
  if (!TIME_MAX && !CYCLE_MAX) TIME_MAX = TIME_MAX_STD;
  if (!MutationRate) MutationRate = MRATE_STD;
  if (!CrossoverRate) CrossoverRate = CRATE_STD;

  std::shared_ptr<ProfileModule> PModule(new ProfileModule(MyModule));
  CostEstimatorOptions Opts = gcl::populatePModule(PModule);

  auto MetricBase = loadMetricsBase(MBasePath);
  auto AccuracyBase = loadAccuracyBase(ABasePath);
  auto NearestMetricName = getNearestMetric(PModule, MetricBase);
  double EstimatedAccuracy =
    getAccuracyFor(NearestMetricName, Opts, AccuracyBase);

  auto CorrectionBase =
    loadCorrectionBase(CBasePath+"/"+NearestMetricName+".estr");
  auto OptAccuracyBase =
    loadOptAccuracyBase(OABasePath+"/"+NearestMetricName+".ocor");

  int PAPIEvents[1] = {PAPI_TOT_CYC};
  double RealInitCost =
    (GEOS::getPAPIProfile(PModule, ExecutionKind::JIT, PAPIEvents, 1))[0];
  auto InitCost = GEOS::analyseCost(PModule, Opts);

  int Cycles = 0;
  double FitnessMean;
  CompareSolution CompSolVar(EstimatedAccuracy);

  BestSeqT BestSequences((CompareSolution(EstimatedAccuracy)));
  BestSeqT GlobalBest((CompareSolution(EstimatedAccuracy)));
  PopT Population;

  printf("Starting genetic...\n");

  initializePopulation(Population);
  FitnessMean = evaluatePopulation(Population, CorrectionBase, OptAccuracyBase,
      BestSequences, PModule, Opts, EstimatedAccuracy);

  time_t Start = time(0);
  while (!isFinished(Start, Cycles)) {
    PopT MatingPool =
      selection(Population, FitnessMean);
    Population =
      crossover(MatingPool);
    mutation(Population);

    FitnessMean = evaluatePopulation(Population, CorrectionBase, OptAccuracyBase,
        BestSequences, PModule, Opts, EstimatedAccuracy);

    BestSeqT Aux((CompareSolution(EstimatedAccuracy)));
    for (unsigned i = 0; i < BSIZE; i++) {
      Aux.push(BestSequences.top());
      BestSequences.pop();
      if (GlobalBest.size()) {
        Aux.push(GlobalBest.top());
        GlobalBest.pop();
      }
    }
    GlobalBest = BestSeqT(CompareSolution(EstimatedAccuracy));
    for (unsigned i = 0; i < BSIZE; i++) {
      GlobalBest.push(Aux.top());
      Aux.pop();
    }

    Cycles += 1;
    printf("Cycles: %d - ", Cycles);
  }

  double BestRealSpeedUp = 0;
  double BestEstSpeedUp = 0;
  Solution BestSolution;
  while (BestSequences.size() != 0) {
    auto B = BestSequences.top();
    auto PO = GEOS::applyPasses(PModule, B.Sequence);
    double RealFinalCost =
      (GEOS::getPAPIProfile(PO, ExecutionKind::JIT, PAPIEvents, 1))[0];
    double FinalCost = GEOS::analyseCost(PO, Opts);

    if ((RealInitCost/RealFinalCost) > BestRealSpeedUp) {
      BestRealSpeedUp = RealInitCost/RealFinalCost;
      BestEstSpeedUp = InitCost/FinalCost;
      BestSolution = B;
    }

    BestSequences.pop();
  }

  while (GlobalBest.size() != 0) {
    auto B = GlobalBest.top();
    auto PO = GEOS::applyPasses(PModule, B.Sequence);
    double RealFinalCost =
      (GEOS::getPAPIProfile(PO, ExecutionKind::JIT, PAPIEvents, 1))[0];
    double FinalCost = GEOS::analyseCost(PO, Opts);

    if ((RealInitCost/RealFinalCost) > BestRealSpeedUp) {
      BestRealSpeedUp = RealInitCost/RealFinalCost;
      BestEstSpeedUp = InitCost/FinalCost;
      BestSolution = B;
    }

    GlobalBest.pop();
  }

  printf("\nEstimated Speedup: %f\nReal Speedup: %f\n\nCycles: %d\n", BestEstSpeedUp,
      BestRealSpeedUp, Cycles);

  BestSolution.Sequence.print();
  return 0;
}
<|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/renderer_host/backing_store.h"

#include <stdlib.h>
#include <utility>

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "chrome/common/transport_dib.h"
#include "chrome/common/x11_util.h"
#include "chrome/common/x11_util_internal.h"
#include "third_party/skia/include/core/SkBitmap.h"

// X Backing Stores:
//
// Unlike Windows, where the backing store is kept in heap memory, we keep our
// backing store in the X server, as a pixmap. Thus expose events just require
// instructing the X server to copy from the backing store to the window.
//
// The backing store is in the same format as the visual which our main window
// is using. Bitmaps from the renderer are uploaded to the X server, either via
// shared memory or over the wire, and XRENDER is used to convert them to the
// correct format for the backing store.

BackingStore::BackingStore(RenderWidgetHost* widget,
                           const gfx::Size& size,
                           void* visual,
                           int depth)
    : render_widget_host_(widget),
      size_(size),
      display_(x11_util::GetXDisplay()),
      use_shared_memory_(x11_util::QuerySharedMemorySupport(display_)),
      use_render_(x11_util::QueryRenderSupport(display_)),
      visual_depth_(depth),
      root_window_(x11_util::GetX11RootWindow()) {
  COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);

  pixmap_ = XCreatePixmap(display_, root_window_,
                          size.width(), size.height(), depth);

  if (use_render_) {
    picture_ = XRenderCreatePicture(
        display_, pixmap_,
        x11_util::GetRenderVisualFormat(display_,
                                        static_cast<Visual*>(visual)),
                                        0, NULL);
  } else {
    picture_ = 0;
    pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display_, depth);
  }

  pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
}

BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
    : render_widget_host_(widget),
      size_(size),
      display_(NULL),
      use_shared_memory_(false),
      use_render_(false),
      visual_depth_(-1),
      root_window_(0) {
}

BackingStore::~BackingStore() {
  // In unit tests, display_ may be NULL.
  if (!display_)
    return;

  XRenderFreePicture(display_, picture_);
  XFreePixmap(display_, pixmap_);
  XFreeGC(display_, static_cast<GC>(pixmap_gc_));
}

void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap,
                                           const gfx::Rect &bitmap_rect) {
  const int width = bitmap_rect.width();
  const int height = bitmap_rect.height();
  Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height,
                                visual_depth_);

  XImage image;
  memset(&image, 0, sizeof(image));

  image.width = width;
  image.height = height;
  image.format = ZPixmap;
  image.byte_order = LSBFirst;
  image.bitmap_unit = 8;
  image.bitmap_bit_order = LSBFirst;
  image.red_mask = 0xff;
  image.green_mask = 0xff00;
  image.blue_mask = 0xff0000;

  if (pixmap_bpp_ == 32) {
    // If the X server depth is already 32-bits, then our job is easy.
    image.depth = visual_depth_;
    image.bits_per_pixel = 32;
    image.bytes_per_line = width * 4;
    image.data = static_cast<char*>(bitmap->memory());

    XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);
  } else if (pixmap_bpp_ == 24) {
    // In this case we just need to strip the alpha channel out of each
    // pixel. This is the case which covers VNC servers since they don't
    // support Xrender but typically have 24-bit visuals.
    //
    // It's possible to use some fancy SSE tricks here, but since this is the
    // slow path anyway, we do it slowly.

    uint8_t* bitmap24 = static_cast<uint8_t*>(malloc(3 * width * height));
    if (!bitmap24)
      return;
    const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory());
    for (int y = 0; y < height; ++y) {
      for (int x = 0; x < width; ++x) {
        const uint32_t pixel = *(bitmap_in++);
        bitmap24[0] = (pixel >> 16) & 0xff;
        bitmap24[1] = (pixel >> 8) & 0xff;
        bitmap24[2] = pixel & 0xff;
        bitmap24 += 3;
      }
    }

    image.depth = visual_depth_;
    image.bits_per_pixel = 24;
    image.bytes_per_line = width * 3;
    image.data = reinterpret_cast<char*>(bitmap24);

    XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);

    free(bitmap24);
  } else if (pixmap_bpp_ == 16) {
    // Some folks have VNC setups which still use 16-bit visuals and VNC
    // doesn't include Xrender.

    uint16_t* bitmap16 = static_cast<uint16_t*>(malloc(2 * width * height));
    if (!bitmap16)
      return;
    uint16_t* const orig_bitmap16 = bitmap16;
    const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory());
    for (int y = 0; y < height; ++y) {
      for (int x = 0; x < width; ++x) {
        const uint32_t pixel = *(bitmap_in++);
        uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
                             ((pixel >> 5) & 0x07e0) |
                             ((pixel >> 3) & 0x001f);
        *(bitmap16++) = out_pixel;
      }
    }

    image.depth = visual_depth_;
    image.bits_per_pixel = 16;
    image.bytes_per_line = width * 2;
    image.data = reinterpret_cast<char*>(orig_bitmap16);

    image.red_mask = 0xf800;
    image.green_mask = 0x07e0;
    image.blue_mask = 0x001f;

    XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);
    free(orig_bitmap16);
  } else {
    CHECK(false) << "Sorry, we don't support your visual depth without "
                    "Xrender support (depth:" << visual_depth_
                 << " bpp:" << pixmap_bpp_ << ")";
  }

  XCopyArea(display_, pixmap /* source */, pixmap_ /* target */,
            static_cast<GC>(pixmap_gc_),
            0, 0 /* source x, y */, bitmap_rect.width(), bitmap_rect.height(),
            bitmap_rect.x(), bitmap_rect.y() /* dest x, y */);

  XFreePixmap(display_, pixmap);
}

void BackingStore::PaintRect(base::ProcessHandle process,
                             TransportDIB* bitmap,
                             const gfx::Rect& bitmap_rect) {
  if (!display_)
    return;

  if (bitmap_rect.IsEmpty())
    return;

  const int width = bitmap_rect.width();
  const int height = bitmap_rect.height();
  // Assume that somewhere along the line, someone will do width * height * 4
  // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 =
  // 2**29 and floor(sqrt(2**29)) = 23170.
  if (width > 23170 || height > 23170)
    return;

  if (!use_render_)
    return PaintRectWithoutXrender(bitmap, bitmap_rect);

  Picture picture;
  Pixmap pixmap;

  if (use_shared_memory_) {
    const XID shmseg = bitmap->MapToX(display_);

    XShmSegmentInfo shminfo;
    memset(&shminfo, 0, sizeof(shminfo));
    shminfo.shmseg = shmseg;

    // The NULL in the following is the |data| pointer: this is an artifact of
    // Xlib trying to be helpful, rather than just exposing the X protocol. It
    // assumes that we have the shared memory segment mapped into our memory,
    // which we don't, and it's trying to calculate an offset by taking the
    // difference between the |data| pointer and the address of the mapping in
    // |shminfo|. Since both are NULL, the offset will be calculated to be 0,
    // which is correct for us.
    pixmap = XShmCreatePixmap(display_, root_window_, NULL, &shminfo, width,
                              height, 32);
  } else {
    // No shared memory support, we have to copy the bitmap contents to the X
    // server. Xlib wraps the underlying PutImage call behind several layers of
    // functions which try to convert the image into the format which the X
    // server expects. The following values hopefully disable all conversions.
    XImage image;
    memset(&image, 0, sizeof(image));

    image.width = width;
    image.height = height;
    image.depth = 32;
    image.bits_per_pixel = 32;
    image.format = ZPixmap;
    image.byte_order = LSBFirst;
    image.bitmap_unit = 8;
    image.bitmap_bit_order = LSBFirst;
    image.bytes_per_line = width * 4;
    image.red_mask = 0xff;
    image.green_mask = 0xff00;
    image.blue_mask = 0xff0000;
    image.data = static_cast<char*>(bitmap->memory());

    pixmap = XCreatePixmap(display_, root_window_, width, height, 32);
    GC gc = XCreateGC(display_, pixmap, 0, NULL);
    XPutImage(display_, pixmap, gc, &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);
    XFreeGC(display_, gc);
  }

  picture = x11_util::CreatePictureFromSkiaPixmap(display_, pixmap);
  XRenderComposite(display_, PictOpSrc, picture /* source */, 0 /* mask */,
                   picture_ /* dest */, 0, 0 /* source x, y */,
                   0, 0 /* mask x, y */,
                   bitmap_rect.x(), bitmap_rect.y() /* target x, y */,
                   width, height);

  // In the case of shared memory, we wait for the composite to complete so that
  // we are sure that the X server has finished reading.
  if (use_shared_memory_)
    XSync(display_, False);

  XRenderFreePicture(display_, picture);
  XFreePixmap(display_, pixmap);
}

void BackingStore::ScrollRect(base::ProcessHandle process,
                              TransportDIB* bitmap,
                              const gfx::Rect& bitmap_rect,
                              int dx, int dy,
                              const gfx::Rect& clip_rect,
                              const gfx::Size& view_size) {
  if (!display_)
    return;

  // We only support scrolling in one direction at a time.
  DCHECK(dx == 0 || dy == 0);

  if (dy) {
    // Positive values of |dy| scroll up
    if (abs(dy) < clip_rect.height()) {
      XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
                clip_rect.x() /* source x */,
                std::max(clip_rect.y(), clip_rect.y() - dy),
                clip_rect.width(),
                clip_rect.height() - abs(dy),
                clip_rect.x() /* dest x */,
                std::max(clip_rect.y(), clip_rect.y() + dy) /* dest y */);
    }
  } else if (dx) {
    // Positive values of |dx| scroll right
    if (abs(dx) < clip_rect.width()) {
      XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
                std::max(clip_rect.x(), clip_rect.x() - dx),
                clip_rect.y() /* source y */,
                clip_rect.width() - abs(dx),
                clip_rect.height(),
                std::max(clip_rect.x(), clip_rect.x() + dx) /* dest x */,
                clip_rect.y() /* dest x */);
    }
  }

  PaintRect(process, bitmap, bitmap_rect);
}

void BackingStore::ShowRect(const gfx::Rect& rect, XID target) {
  XCopyArea(display_, pixmap_, target, static_cast<GC>(pixmap_gc_),
            rect.x(), rect.y(), rect.width(), rect.height(),
            rect.x(), rect.y());
}

SkBitmap* BackingStore::PaintRectToBitmap(const gfx::Rect& rect) {
  static const int kBytesPerPixel = 4;

  const int width = rect.width();
  const int height = rect.height();
  XImage* image = XGetImage(display_, pixmap_,
                            rect.x(), rect.y(),
                            width, height,
                            AllPlanes, ZPixmap);
  // TODO(jhawkins): Need to convert the image data if the image bits per pixel
  // is not 32.
  if (image->bits_per_pixel != 32)
    return NULL;

  SkBitmap* bitmap = new SkBitmap();
  bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
  bitmap->allocPixels();
  unsigned char* bitmap_data =
    reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0));
  memcpy(bitmap_data, image->data, width * height * kBytesPerPixel);

  XFree(image);
  return bitmap;
}
<commit_msg>Fix a leak when we bail out early because of the wrong bpp.<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/renderer_host/backing_store.h"

#include <stdlib.h>
#include <utility>

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "chrome/common/transport_dib.h"
#include "chrome/common/x11_util.h"
#include "chrome/common/x11_util_internal.h"
#include "third_party/skia/include/core/SkBitmap.h"

// X Backing Stores:
//
// Unlike Windows, where the backing store is kept in heap memory, we keep our
// backing store in the X server, as a pixmap. Thus expose events just require
// instructing the X server to copy from the backing store to the window.
//
// The backing store is in the same format as the visual which our main window
// is using. Bitmaps from the renderer are uploaded to the X server, either via
// shared memory or over the wire, and XRENDER is used to convert them to the
// correct format for the backing store.

BackingStore::BackingStore(RenderWidgetHost* widget,
                           const gfx::Size& size,
                           void* visual,
                           int depth)
    : render_widget_host_(widget),
      size_(size),
      display_(x11_util::GetXDisplay()),
      use_shared_memory_(x11_util::QuerySharedMemorySupport(display_)),
      use_render_(x11_util::QueryRenderSupport(display_)),
      visual_depth_(depth),
      root_window_(x11_util::GetX11RootWindow()) {
  COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);

  pixmap_ = XCreatePixmap(display_, root_window_,
                          size.width(), size.height(), depth);

  if (use_render_) {
    picture_ = XRenderCreatePicture(
        display_, pixmap_,
        x11_util::GetRenderVisualFormat(display_,
                                        static_cast<Visual*>(visual)),
                                        0, NULL);
  } else {
    picture_ = 0;
    pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display_, depth);
  }

  pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
}

BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
    : render_widget_host_(widget),
      size_(size),
      display_(NULL),
      use_shared_memory_(false),
      use_render_(false),
      visual_depth_(-1),
      root_window_(0) {
}

BackingStore::~BackingStore() {
  // In unit tests, display_ may be NULL.
  if (!display_)
    return;

  XRenderFreePicture(display_, picture_);
  XFreePixmap(display_, pixmap_);
  XFreeGC(display_, static_cast<GC>(pixmap_gc_));
}

void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap,
                                           const gfx::Rect &bitmap_rect) {
  const int width = bitmap_rect.width();
  const int height = bitmap_rect.height();
  Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height,
                                visual_depth_);

  XImage image;
  memset(&image, 0, sizeof(image));

  image.width = width;
  image.height = height;
  image.format = ZPixmap;
  image.byte_order = LSBFirst;
  image.bitmap_unit = 8;
  image.bitmap_bit_order = LSBFirst;
  image.red_mask = 0xff;
  image.green_mask = 0xff00;
  image.blue_mask = 0xff0000;

  if (pixmap_bpp_ == 32) {
    // If the X server depth is already 32-bits, then our job is easy.
    image.depth = visual_depth_;
    image.bits_per_pixel = 32;
    image.bytes_per_line = width * 4;
    image.data = static_cast<char*>(bitmap->memory());

    XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);
  } else if (pixmap_bpp_ == 24) {
    // In this case we just need to strip the alpha channel out of each
    // pixel. This is the case which covers VNC servers since they don't
    // support Xrender but typically have 24-bit visuals.
    //
    // It's possible to use some fancy SSE tricks here, but since this is the
    // slow path anyway, we do it slowly.

    uint8_t* bitmap24 = static_cast<uint8_t*>(malloc(3 * width * height));
    if (!bitmap24)
      return;
    const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory());
    for (int y = 0; y < height; ++y) {
      for (int x = 0; x < width; ++x) {
        const uint32_t pixel = *(bitmap_in++);
        bitmap24[0] = (pixel >> 16) & 0xff;
        bitmap24[1] = (pixel >> 8) & 0xff;
        bitmap24[2] = pixel & 0xff;
        bitmap24 += 3;
      }
    }

    image.depth = visual_depth_;
    image.bits_per_pixel = 24;
    image.bytes_per_line = width * 3;
    image.data = reinterpret_cast<char*>(bitmap24);

    XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);

    free(bitmap24);
  } else if (pixmap_bpp_ == 16) {
    // Some folks have VNC setups which still use 16-bit visuals and VNC
    // doesn't include Xrender.

    uint16_t* bitmap16 = static_cast<uint16_t*>(malloc(2 * width * height));
    if (!bitmap16)
      return;
    uint16_t* const orig_bitmap16 = bitmap16;
    const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory());
    for (int y = 0; y < height; ++y) {
      for (int x = 0; x < width; ++x) {
        const uint32_t pixel = *(bitmap_in++);
        uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
                             ((pixel >> 5) & 0x07e0) |
                             ((pixel >> 3) & 0x001f);
        *(bitmap16++) = out_pixel;
      }
    }

    image.depth = visual_depth_;
    image.bits_per_pixel = 16;
    image.bytes_per_line = width * 2;
    image.data = reinterpret_cast<char*>(orig_bitmap16);

    image.red_mask = 0xf800;
    image.green_mask = 0x07e0;
    image.blue_mask = 0x001f;

    XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);
    free(orig_bitmap16);
  } else {
    CHECK(false) << "Sorry, we don't support your visual depth without "
                    "Xrender support (depth:" << visual_depth_
                 << " bpp:" << pixmap_bpp_ << ")";
  }

  XCopyArea(display_, pixmap /* source */, pixmap_ /* target */,
            static_cast<GC>(pixmap_gc_),
            0, 0 /* source x, y */, bitmap_rect.width(), bitmap_rect.height(),
            bitmap_rect.x(), bitmap_rect.y() /* dest x, y */);

  XFreePixmap(display_, pixmap);
}

void BackingStore::PaintRect(base::ProcessHandle process,
                             TransportDIB* bitmap,
                             const gfx::Rect& bitmap_rect) {
  if (!display_)
    return;

  if (bitmap_rect.IsEmpty())
    return;

  const int width = bitmap_rect.width();
  const int height = bitmap_rect.height();
  // Assume that somewhere along the line, someone will do width * height * 4
  // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 =
  // 2**29 and floor(sqrt(2**29)) = 23170.
  if (width > 23170 || height > 23170)
    return;

  if (!use_render_)
    return PaintRectWithoutXrender(bitmap, bitmap_rect);

  Picture picture;
  Pixmap pixmap;

  if (use_shared_memory_) {
    const XID shmseg = bitmap->MapToX(display_);

    XShmSegmentInfo shminfo;
    memset(&shminfo, 0, sizeof(shminfo));
    shminfo.shmseg = shmseg;

    // The NULL in the following is the |data| pointer: this is an artifact of
    // Xlib trying to be helpful, rather than just exposing the X protocol. It
    // assumes that we have the shared memory segment mapped into our memory,
    // which we don't, and it's trying to calculate an offset by taking the
    // difference between the |data| pointer and the address of the mapping in
    // |shminfo|. Since both are NULL, the offset will be calculated to be 0,
    // which is correct for us.
    pixmap = XShmCreatePixmap(display_, root_window_, NULL, &shminfo, width,
                              height, 32);
  } else {
    // No shared memory support, we have to copy the bitmap contents to the X
    // server. Xlib wraps the underlying PutImage call behind several layers of
    // functions which try to convert the image into the format which the X
    // server expects. The following values hopefully disable all conversions.
    XImage image;
    memset(&image, 0, sizeof(image));

    image.width = width;
    image.height = height;
    image.depth = 32;
    image.bits_per_pixel = 32;
    image.format = ZPixmap;
    image.byte_order = LSBFirst;
    image.bitmap_unit = 8;
    image.bitmap_bit_order = LSBFirst;
    image.bytes_per_line = width * 4;
    image.red_mask = 0xff;
    image.green_mask = 0xff00;
    image.blue_mask = 0xff0000;
    image.data = static_cast<char*>(bitmap->memory());

    pixmap = XCreatePixmap(display_, root_window_, width, height, 32);
    GC gc = XCreateGC(display_, pixmap, 0, NULL);
    XPutImage(display_, pixmap, gc, &image,
              0, 0 /* source x, y */, 0, 0 /* dest x, y */,
              width, height);
    XFreeGC(display_, gc);
  }

  picture = x11_util::CreatePictureFromSkiaPixmap(display_, pixmap);
  XRenderComposite(display_, PictOpSrc, picture /* source */, 0 /* mask */,
                   picture_ /* dest */, 0, 0 /* source x, y */,
                   0, 0 /* mask x, y */,
                   bitmap_rect.x(), bitmap_rect.y() /* target x, y */,
                   width, height);

  // In the case of shared memory, we wait for the composite to complete so that
  // we are sure that the X server has finished reading.
  if (use_shared_memory_)
    XSync(display_, False);

  XRenderFreePicture(display_, picture);
  XFreePixmap(display_, pixmap);
}

void BackingStore::ScrollRect(base::ProcessHandle process,
                              TransportDIB* bitmap,
                              const gfx::Rect& bitmap_rect,
                              int dx, int dy,
                              const gfx::Rect& clip_rect,
                              const gfx::Size& view_size) {
  if (!display_)
    return;

  // We only support scrolling in one direction at a time.
  DCHECK(dx == 0 || dy == 0);

  if (dy) {
    // Positive values of |dy| scroll up
    if (abs(dy) < clip_rect.height()) {
      XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
                clip_rect.x() /* source x */,
                std::max(clip_rect.y(), clip_rect.y() - dy),
                clip_rect.width(),
                clip_rect.height() - abs(dy),
                clip_rect.x() /* dest x */,
                std::max(clip_rect.y(), clip_rect.y() + dy) /* dest y */);
    }
  } else if (dx) {
    // Positive values of |dx| scroll right
    if (abs(dx) < clip_rect.width()) {
      XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
                std::max(clip_rect.x(), clip_rect.x() - dx),
                clip_rect.y() /* source y */,
                clip_rect.width() - abs(dx),
                clip_rect.height(),
                std::max(clip_rect.x(), clip_rect.x() + dx) /* dest x */,
                clip_rect.y() /* dest x */);
    }
  }

  PaintRect(process, bitmap, bitmap_rect);
}

void BackingStore::ShowRect(const gfx::Rect& rect, XID target) {
  XCopyArea(display_, pixmap_, target, static_cast<GC>(pixmap_gc_),
            rect.x(), rect.y(), rect.width(), rect.height(),
            rect.x(), rect.y());
}

SkBitmap* BackingStore::PaintRectToBitmap(const gfx::Rect& rect) {
  static const int kBytesPerPixel = 4;

  const int width = rect.width();
  const int height = rect.height();
  XImage* image = XGetImage(display_, pixmap_,
                            rect.x(), rect.y(),
                            width, height,
                            AllPlanes, ZPixmap);
  // TODO(jhawkins): Need to convert the image data if the image bits per pixel
  // is not 32.
  if (image->bits_per_pixel != 32) {
    XFree(image);
    return NULL;
  }

  SkBitmap* bitmap = new SkBitmap();
  bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
  bitmap->allocPixels();
  unsigned char* bitmap_data =
    reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0));
  memcpy(bitmap_data, image->data, width * height * kBytesPerPixel);

  XFree(image);
  return bitmap;
}
<|endoftext|>


<commit_before>/*
** Copyright 2011-2013,2015 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <cstring>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/modules/handle.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::modules;

/**************************************
*                                     *
*           Static Objects            *
*                                     *
**************************************/

// Routine symbols.
char const* handle::deinitialization("broker_module_deinit");
char const* handle::initialization("broker_module_init");
char const* handle::updatization("broker_module_update");
char const* handle::versionning("broker_module_version");

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
handle::handle() {}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
handle::handle(handle const& other) {
  this->open(other._handle.fileName().toStdString());
}

/**
 *  Destructor.
 */
handle::~handle() {
  try {
    this->close();
  }
  catch (std::exception const& e) {
    logging::error(logging::high) << e.what();
  }
  catch (...) {
    logging::error(logging::high) << "modules: unknown error while " \
      "unloading '" << _handle.fileName() << "'";
  }
}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
handle& handle::operator=(handle const& other) {
  this->close();
  this->open(other._handle.fileName().toStdString());
  return (*this);
}

/**
 *  @brief Close the library object.
 *
 *  If the underlying library object is open, this method will call the
 *  module's deinitialization routine (if it exists) and then unload the
 *  library.
 */
void handle::close() {
  if (is_open()) {
    // Log message.
    logging::info(logging::medium) << "modules: closing '"
      << _handle.fileName() << "'";

    // Find deinitialization routine.
    logging::debug(logging::low) << "modules: searching " \
         "deinitialization routine (symbol " << deinitialization
      << ") in '" << _handle.fileName() << "'";
    union {
      void (* code)();
      void*   data;
    } sym;
    sym.data = _handle.resolve(deinitialization);

    // Could not find deinitialization routine.
    if (!sym.data) {
      QString error_str(_handle.errorString());
      logging::info(logging::medium) << "modules: could not find " \
           "deinitialization routine in '" << _handle.fileName()
        << "': " << error_str;
    }
    // Call deinitialization routine.
    else {
      (*(sym.code))();
      logging::debug(logging::low) << "modules: deinitialization " \
           "routine of '" << _handle.fileName()
        << "' successfully completed";
    }

    // Reset library handle.
    logging::debug(logging::low) << "modules: unloading library '"
      << _handle.fileName() << "'";
    // Library was not unloaded.
    if (!_handle.unload()) {
      QString error_str(_handle.errorString());
      logging::info(logging::medium)
        << "modules: could not unload library '"
        << _handle.fileName() << "': " << error_str;
    }
    // Library was unloaded.
    else
      logging::info(logging::medium) << "modules: library '"
        << _handle.fileName() << "' unloaded";
  }
  return ;
}

/**
 *  Check if the library is loaded.
 *
 *  @return true if the library is loaded, false otherwise.
 */
bool handle::is_open() const {
  return (_handle.isLoaded());
}

/**
 *  Load a library file.
 *
 *  @param[in] filename Library filename.
 *  @param[in] arg      Library argument.
 */
void handle::open(std::string const& filename, void const* arg) {
  // Close library if previously open.
  this->close();

  // Load library.
  logging::debug(logging::medium) << "modules: loading library '"
    << filename << "'";
  _handle.setFileName(filename.c_str());
  _handle.setLoadHints(QLibrary::ResolveAllSymbolsHint
    | QLibrary::ExportExternalSymbolsHint);

  // Could not load library.
  if (!_handle.load())
    throw (exceptions::msg() << "modules: could not load library '"
             << filename << "': " << _handle.errorString());
  logging::info(logging::medium) << "modules: library '"
    << filename << "' loaded";

  // Initialize module.
  _check_version();
  _init(arg);

  return ;
}

/**
 *  Update a library file.
 *
 *  @param[in] arg Library argument.
 */
void handle::update(void const* arg) {
  // Check that library is loaded.
  if (!is_open())
    throw (exceptions::msg() << "modules: could not update "
                                "module that is not loaded");

  // Find update routine.
  logging::debug(logging::low) << "modules: searching update "
    << "routine (symbol " << updatization << ") in '"
    << _handle.fileName() << "'";
  union {
    void (* code)();
    void*   data;
  } sym;
  sym.data = _handle.resolve(updatization);

  // Found routine.
  if (sym.data) {
    (*(void (*)(void const*))(sym.code))(arg);
    logging::debug(logging::low) << "modules: update routine of '"
      << _handle.fileName() << "' successfully completed";
  }
  // Routine not found.
  else
    logging::info(logging::medium) << "modules: could not find update "
      << "routine of module '" << _handle.fileName() << "'";

  return ;
}

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Check that the module has the correct version.
 */
void handle::_check_version() {
  // Find version symbol.
  logging::debug(logging::low) << "modules: searching "
       "version (symbol " << versionning
    << ") in '" << _handle.fileName() << "'";

  const char* version = (const char*)_handle.resolve(versionning);

  // Could not find version symbol.
  if (!version) {
    QString error_str(_handle.errorString());
    throw (exceptions::msg() << "modules: could not find " \
                "version in '" << _handle.fileName()
             << "' (not a Centreon Broker module ?): " << error_str);
  }

  // Check version.
  if (::strcmp(CENTREON_BROKER_VERSION, version) != 0)
    throw (exceptions::msg()
           << "modules: version mismatch in '" << _handle.fileName()
           << "': expected '" << CENTREON_BROKER_VERSION
           <<  "', found '" << version << "'");
}

/**
 *  Call the module's initialization routine.
 *
 *  @param[in] arg Module argument.
 */
void handle::_init(void const* arg) {
  // Find initialization routine.
  logging::debug(logging::low) << "modules: searching "
       "initialization routine (symbol " << initialization
    << ") in '" << _handle.fileName() << "'";
  union {
    void (* code)();
    void*   data;
  } sym;
  sym.data = _handle.resolve(initialization);

  // Could not find initialization routine.
  if (!sym.data) {
    QString error_str(_handle.errorString());
    throw (exceptions::msg() << "modules: could not find " \
                "initialization routine in '" << _handle.fileName()
             << "' (not a Centreon Broker module ?): " << error_str);
  }

  // Call initialization routine.
  (*(void (*)(void const*))(sym.code))(arg);
  logging::debug(logging::medium) << "modules: initialization " \
    "routine of '" << _handle.fileName() << "' successfully completed";

  return ;
}
<commit_msg>core: fix module version checking routine.<commit_after>/*
** Copyright 2011-2013,2015 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <cstring>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/modules/handle.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::modules;

/**************************************
*                                     *
*           Static Objects            *
*                                     *
**************************************/

// Routine symbols.
char const* handle::deinitialization("broker_module_deinit");
char const* handle::initialization("broker_module_init");
char const* handle::updatization("broker_module_update");
char const* handle::versionning("broker_module_version");

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
handle::handle() {}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
handle::handle(handle const& other) {
  this->open(other._handle.fileName().toStdString());
}

/**
 *  Destructor.
 */
handle::~handle() {
  try {
    this->close();
  }
  catch (std::exception const& e) {
    logging::error(logging::high) << e.what();
  }
  catch (...) {
    logging::error(logging::high) << "modules: unknown error while " \
      "unloading '" << _handle.fileName() << "'";
  }
}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
handle& handle::operator=(handle const& other) {
  this->close();
  this->open(other._handle.fileName().toStdString());
  return (*this);
}

/**
 *  @brief Close the library object.
 *
 *  If the underlying library object is open, this method will call the
 *  module's deinitialization routine (if it exists) and then unload the
 *  library.
 */
void handle::close() {
  if (is_open()) {
    // Log message.
    logging::info(logging::medium) << "modules: closing '"
      << _handle.fileName() << "'";

    // Find deinitialization routine.
    logging::debug(logging::low) << "modules: searching " \
         "deinitialization routine (symbol " << deinitialization
      << ") in '" << _handle.fileName() << "'";
    union {
      void (* code)();
      void*   data;
    } sym;
    sym.data = _handle.resolve(deinitialization);

    // Could not find deinitialization routine.
    if (!sym.data) {
      QString error_str(_handle.errorString());
      logging::info(logging::medium) << "modules: could not find " \
           "deinitialization routine in '" << _handle.fileName()
        << "': " << error_str;
    }
    // Call deinitialization routine.
    else {
      (*(sym.code))();
      logging::debug(logging::low) << "modules: deinitialization " \
           "routine of '" << _handle.fileName()
        << "' successfully completed";
    }

    // Reset library handle.
    logging::debug(logging::low) << "modules: unloading library '"
      << _handle.fileName() << "'";
    // Library was not unloaded.
    if (!_handle.unload()) {
      QString error_str(_handle.errorString());
      logging::info(logging::medium)
        << "modules: could not unload library '"
        << _handle.fileName() << "': " << error_str;
    }
    // Library was unloaded.
    else
      logging::info(logging::medium) << "modules: library '"
        << _handle.fileName() << "' unloaded";
  }
  return ;
}

/**
 *  Check if the library is loaded.
 *
 *  @return true if the library is loaded, false otherwise.
 */
bool handle::is_open() const {
  return (_handle.isLoaded());
}

/**
 *  Load a library file.
 *
 *  @param[in] filename Library filename.
 *  @param[in] arg      Library argument.
 */
void handle::open(std::string const& filename, void const* arg) {
  // Close library if previously open.
  this->close();

  // Load library.
  logging::debug(logging::medium) << "modules: loading library '"
    << filename << "'";
  _handle.setFileName(filename.c_str());
  _handle.setLoadHints(QLibrary::ResolveAllSymbolsHint
    | QLibrary::ExportExternalSymbolsHint);

  // Could not load library.
  if (!_handle.load())
    throw (exceptions::msg() << "modules: could not load library '"
             << filename << "': " << _handle.errorString());
  logging::info(logging::medium) << "modules: library '"
    << filename << "' loaded";

  // Initialize module.
  _check_version();
  _init(arg);

  return ;
}

/**
 *  Update a library file.
 *
 *  @param[in] arg Library argument.
 */
void handle::update(void const* arg) {
  // Check that library is loaded.
  if (!is_open())
    throw (exceptions::msg() << "modules: could not update "
                                "module that is not loaded");

  // Find update routine.
  logging::debug(logging::low) << "modules: searching update "
    << "routine (symbol " << updatization << ") in '"
    << _handle.fileName() << "'";
  union {
    void (* code)();
    void*   data;
  } sym;
  sym.data = _handle.resolve(updatization);

  // Found routine.
  if (sym.data) {
    (*(void (*)(void const*))(sym.code))(arg);
    logging::debug(logging::low) << "modules: update routine of '"
      << _handle.fileName() << "' successfully completed";
  }
  // Routine not found.
  else
    logging::info(logging::medium) << "modules: could not find update "
      << "routine of module '" << _handle.fileName() << "'";

  return ;
}

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Check that the module has the correct version.
 */
void handle::_check_version() {
  // Find version symbol.
  logging::debug(logging::low) << "modules: searching "
       "version (symbol " << versionning
    << ") in '" << _handle.fileName() << "'";

  char const** version = (char const**)_handle.resolve(versionning);

  // Could not find version symbol.
  if (!version) {
    QString error_str(_handle.errorString());
    throw (exceptions::msg() << "modules: could not find " \
                "version in '" << _handle.fileName()
             << "' (not a Centreon Broker module ?): " << error_str);
  }
  if (!*version)
    throw (exceptions::msg() << "modules: version symbol of module '"
           << _handle.fileName()
           << "' is empty (not a Centreon Broker module ?)");

  // Check version.
  if (::strcmp(CENTREON_BROKER_VERSION, *version) != 0)
    throw (exceptions::msg()
           << "modules: version mismatch in '" << _handle.fileName()
           << "': expected '" << CENTREON_BROKER_VERSION
           <<  "', found '" << version << "'");
}

/**
 *  Call the module's initialization routine.
 *
 *  @param[in] arg Module argument.
 */
void handle::_init(void const* arg) {
  // Find initialization routine.
  logging::debug(logging::low) << "modules: searching "
       "initialization routine (symbol " << initialization
    << ") in '" << _handle.fileName() << "'";
  union {
    void (* code)();
    void*   data;
  } sym;
  sym.data = _handle.resolve(initialization);

  // Could not find initialization routine.
  if (!sym.data) {
    QString error_str(_handle.errorString());
    throw (exceptions::msg() << "modules: could not find " \
                "initialization routine in '" << _handle.fileName()
             << "' (not a Centreon Broker module ?): " << error_str);
  }

  // Call initialization routine.
  (*(void (*)(void const*))(sym.code))(arg);
  logging::debug(logging::medium) << "modules: initialization " \
    "routine of '" << _handle.fileName() << "' successfully completed";

  return ;
}
<|endoftext|>