<commit_before>// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extension/extension_server.h"

#include <glob.h>
#include <glib.h>
#include <glib-unix.h>

#include <string>
#include <vector>

#include "common/logger.h"
#include "common/constants.h"
#include "common/file_utils.h"
#include "common/string_utils.h"
#include "common/command_line.h"
#include "extension/extension.h"

namespace wrt {

namespace {

const char kDBusIntrospectionXML[] =
  "<node>"
  "  <interface name='org.tizen.wrt.Extension'>"
  "    <method name='GetExtensions'>"
  "      <arg name='extensions' type='a(ssas)' direction='out' />"
  "    </method>"
  "    <method name='CreateInstance'>"
  "      <arg name='extension_name' type='s' direction='in' />"
  "      <arg name='instance_id' type='s' direction='out' />"
  "    </method>"
  "    <method name='DestroyInstance'>"
  "      <arg name='instance_id' type='s' direction='in' />"
  "      <arg name='instance_id' type='s' direction='out' />"
  "    </method>"
  "    <method name='PostMessage'>"
  "      <arg name='instance_id' type='s' direction='in' />"
  "      <arg name='msg' type='s' direction='in' />"
  "    </method>"
  "    <method name='SendSyncMessage'>"
  "      <arg name='instance_id' type='s' direction='in' />"
  "      <arg name='msg' type='s' direction='in' />"
  "      <arg name='reply' type='s' direction='out' />"
  "    </method>"
  "    <signal name='OnMessageToJS'>"
  "      <arg name='instance_id' type='s' />"
  "      <arg name='msg' type='s' />"
  "    </signal>"
  "  </interface>"
  "</node>";

}  // namespace

ExtensionServer::ExtensionServer(const std::string& uuid)
    : app_uuid_(uuid) {
}

ExtensionServer::~ExtensionServer() {
}

bool ExtensionServer::Start() {
  return Start(StringVector());
}

bool ExtensionServer::Start(const StringVector& paths) {
  // Connect to DBusServer for Application of Runtime
  if (!dbus_application_client_.ConnectByName(
          app_uuid_ + "." + std::string(kDBusNameForApplication))) {
    LOGGER(ERROR) << "Failed to connect to the dbus server for Application.";
    return false;
  }

  // Register system extensions to support Tizen Device APIs
  RegisterSystemExtensions();

  // Register user extensions
  for (auto it = paths.begin(); it != paths.end(); ++it) {
    if (utils::Exists(*it)) {
      RegisterExtension(*it);
    }
  }

  // Start DBusServer
  using std::placeholders::_1;
  using std::placeholders::_2;
  using std::placeholders::_3;
  using std::placeholders::_4;
  dbus_server_.SetIntrospectionXML(kDBusIntrospectionXML);
  dbus_server_.SetMethodCallback(
      kDBusInterfaceNameForExtension,
      std::bind(&ExtensionServer::HandleDBusMethod, this, _1, _2, _3, _4));
  dbus_server_.Start(app_uuid_ + "." + std::string(kDBusNameForExtension));

  // Send 'ready' signal to Injected Bundle.
  NotifyEPCreatedToApplication();

  return true;
}

void ExtensionServer::RegisterExtension(const std::string& path) {
  Extension* ext = new Extension(path, this);
  LOGGER(DEBUG) << "Register " << path;
  if (!ext->Initialize() || !RegisterSymbols(ext)) {
    delete ext;
    return;
  }
  extensions_[ext->name()] = ext;
}

void ExtensionServer::RegisterSystemExtensions() {
  std::string extension_path(kSystemExtensionPath);
  extension_path.append("/");
  extension_path.append(kExtensionPrefix);
  extension_path.append("*");
  extension_path.append(kExtensionSuffix);

  glob_t glob_result;
  glob(extension_path.c_str(), GLOB_TILDE, NULL, &glob_result);
  for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
    RegisterExtension(glob_result.gl_pathv[i]);
  }
}

bool ExtensionServer::RegisterSymbols(Extension* extension) {
  std::string name = extension->name();

  if (extension_symbols_.find(name) != extension_symbols_.end()) {
    LOGGER(WARN) << "Ignoring extension with name already registred. '"
                 << name << "'";
    return false;
  }

  Extension::StringVector entry_points = extension->entry_points();
  for (auto it = entry_points.begin(); it != entry_points.end(); ++it) {
    if (extension_symbols_.find(*it) != extension_symbols_.end()) {
      LOGGER(WARN) << "Ignoring extension with entry_point already registred. '"
                   << (*it) << "'";
      return false;
    }
  }

  for (auto it = entry_points.begin(); it != entry_points.end(); ++it) {
    extension_symbols_.insert(*it);
  }

  extension_symbols_.insert(name);

  return true;
}

void ExtensionServer::GetRuntimeVariable(const char* key, char* value,
    size_t value_len) {
  GVariant* ret = dbus_application_client_.Call(
      kDBusInterfaceNameForApplication, kMethodGetRuntimeVariable,
      g_variant_new("(s)", key), G_VARIANT_TYPE("(s)"));

  if (!ret) {
    LOGGER(ERROR) << "Failed to get runtime variable from Application. ("
                  << key << ")";
    return;
  }

  gchar* v;
  g_variant_get(ret, "(&s)", &v);
  strncpy(value, v, value_len);

  g_variant_unref(ret);
}

void ExtensionServer::NotifyEPCreatedToApplication() {
  dbus_application_client_.Call(
      kDBusInterfaceNameForApplication, kMethodNotifyEPCreated,
      g_variant_new("(s)", dbus_server_.GetClientAddress().c_str()),
      NULL);
}

void ExtensionServer::HandleDBusMethod(GDBusConnection* connection,
                                       const std::string& method_name,
                                       GVariant* parameters,
                                       GDBusMethodInvocation* invocation) {
  if (method_name == kMethodGetExtensions) {
    OnGetExtensions(invocation);
  } else if (method_name == kMethodCreateInstance) {
    gchar* extension_name;
    g_variant_get(parameters, "(&s)", &extension_name);
    OnCreateInstance(connection, extension_name, invocation);
  } else if (method_name == kMethodDestroyInstance) {
    gchar* instance_id;
    g_variant_get(parameters, "(&s)", &instance_id);
    OnDestroyInstance(instance_id, invocation);
  } else if (method_name == kMethodSendSyncMessage) {
    gchar* instance_id;
    gchar* msg;
    g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
    OnSendSyncMessage(instance_id, msg, invocation);
  } else if (method_name == kMethodPostMessage) {
    gchar* instance_id;
    gchar* msg;
    g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
    OnPostMessage(instance_id, msg);
  }
}

void ExtensionServer::OnGetExtensions(GDBusMethodInvocation* invocation) {
  GVariantBuilder builder;

  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

  // build an array of extensions
  auto it = extensions_.begin();
  for ( ; it != extensions_.end(); ++it) {
    Extension* ext = it->second;
    // open container for extension
    g_variant_builder_open(&builder, G_VARIANT_TYPE("(ssas)"));
    g_variant_builder_add(&builder, "s", ext->name().c_str());
    g_variant_builder_add(&builder, "s", ext->javascript_api().c_str());
    // open container for entry_point
    g_variant_builder_open(&builder, G_VARIANT_TYPE("as"));
    auto it_entry = ext->entry_points().begin();
    for ( ; it_entry != ext->entry_points().end(); ++it_entry) {
      g_variant_builder_add(&builder, "s", (*it_entry).c_str());
    }
    // close container('as') for entry_point
    g_variant_builder_close(&builder);
    // close container('(ssas)') for extension
    g_variant_builder_close(&builder);
  }

  GVariant* reply = NULL;
  if (extensions_.size() == 0) {
    reply = g_variant_new_array(G_VARIANT_TYPE("(ssas)"), NULL, 0);
  } else {
    reply = g_variant_builder_end(&builder);
  }

  g_dbus_method_invocation_return_value(
      invocation, g_variant_new_tuple(&reply, 1));
}

void ExtensionServer::OnCreateInstance(
    GDBusConnection* connection, const std::string& extension_name,
    GDBusMethodInvocation* invocation) {
  std::string instance_id = utils::GenerateUUID();

  // find extension with given the extension name
  auto it = extensions_.find(extension_name);
  if (it == extensions_.end()) {
    LOGGER(ERROR) << "Failed to find extension '" << extension_name << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Not found extension %s", extension_name.c_str());
    return;
  }

  // create instance
  ExtensionInstance* instance = it->second->CreateInstance();
  if (!instance) {
    LOGGER(ERROR) << "Failed to create instance of extension '"
                  << extension_name << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Failed to create instance of extension %s", extension_name.c_str());
    return;
  }

  // set callbacks
  using std::placeholders::_1;
  instance->SetSendSyncReplyCallback(
      std::bind(&ExtensionServer::SyncReplyCallback, this, _1, invocation));
  instance->SetPostMessageCallback(
      std::bind(&ExtensionServer::PostMessageToJSCallback,
                this, connection, instance_id, _1));

  instances_[instance_id] = instance;
  g_dbus_method_invocation_return_value(
      invocation, g_variant_new("(s)", instance_id.c_str()));
}

void ExtensionServer::OnDestroyInstance(
    const std::string& instance_id, GDBusMethodInvocation* invocation) {
  // find instance with the given instance id
  auto it = instances_.find(instance_id);
  if (it == instances_.end()) {
    LOGGER(ERROR) << "Failed to find instance '" << instance_id << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Not found instance %s", instance_id.c_str());
    return;
  }

  // destroy the instance
  ExtensionInstance* instance = it->second;
  delete instance;

  instances_.erase(it);

  g_dbus_method_invocation_return_value(
      invocation, g_variant_new("(s)", instance_id.c_str()));
}

void ExtensionServer::OnSendSyncMessage(
    const std::string& instance_id, const std::string& msg,
    GDBusMethodInvocation* invocation) {
  // find instance with the given instance id
  auto it = instances_.find(instance_id);
  if (it == instances_.end()) {
    LOGGER(ERROR) << "Failed to find instance '" << instance_id << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Not found instance %s", instance_id.c_str());
    return;
  }

  ExtensionInstance* instance = it->second;
  instance->HandleSyncMessage(msg);

  // reponse will be sent by SyncReplyCallback()
}

// async
void ExtensionServer::OnPostMessage(
    const std::string& instance_id, const std::string& msg) {
  auto it = instances_.find(instance_id);
  if (it == instances_.end()) {
    LOGGER(ERROR) << "Failed to find instance '" << instance_id << "'";
    return;
  }

  ExtensionInstance* instance = it->second;
  instance->HandleMessage(msg);
}

void ExtensionServer::SyncReplyCallback(
    const std::string& reply, GDBusMethodInvocation* invocation) {
  g_dbus_method_invocation_return_value(
      invocation, g_variant_new("(s)", reply.c_str()));
}

void ExtensionServer::PostMessageToJSCallback(
    GDBusConnection* connection, const std::string& instance_id,
    const std::string& msg) {
  if (!connection || g_dbus_connection_is_closed(connection)) {
    LOGGER(ERROR) << "Client connection is closed already.";
    return;
  }

  dbus_server_.SendSignal(connection,
                          kDBusInterfaceNameForExtension,
                          kSignalOnMessageToJS,
                          g_variant_new("(ss)",
                                        instance_id.c_str(),
                                        msg.c_str()));
}

// static
bool ExtensionServer::StartExtensionProcess() {
  GMainLoop* loop;

  loop = g_main_loop_new(NULL, FALSE);

  // Register Quit Signal Handlers
  auto quit_callback = [](gpointer data) -> gboolean {
    GMainLoop* loop = reinterpret_cast<GMainLoop*>(data);
    g_main_loop_quit(loop);
    return false;
  };
  g_unix_signal_add(SIGINT, quit_callback, loop);
  g_unix_signal_add(SIGTERM, quit_callback, loop);

  CommandLine* cmd = CommandLine::ForCurrentProcess();

  // TODO(wy80.choi): Receive extension paths for user defined extensions.

  // Receive AppID from arguments.
  if (cmd->arguments().size() < 1) {
    LOGGER(ERROR) << "uuid is required.";
    return false;
  }
  std::string uuid = cmd->arguments()[0];

  // Start ExtensionServer
  ExtensionServer server(uuid);
  if (!server.Start()) {
    LOGGER(ERROR) << "Failed to start extension server.";
    return false;
  }

  LOGGER(INFO) << "extension process has been started.";

  g_main_loop_run(loop);

  LOGGER(INFO) << "extension process is exiting.";

  g_main_loop_unref(loop);

  return true;
}

}  // namespace wrt
<commit_msg>Fix bug for reply of SendSyncMessage()<commit_after>// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extension/extension_server.h"

#include <glob.h>
#include <glib.h>
#include <glib-unix.h>

#include <string>
#include <vector>

#include "common/logger.h"
#include "common/constants.h"
#include "common/file_utils.h"
#include "common/string_utils.h"
#include "common/command_line.h"
#include "extension/extension.h"

namespace wrt {

namespace {

const char kDBusIntrospectionXML[] =
  "<node>"
  "  <interface name='org.tizen.wrt.Extension'>"
  "    <method name='GetExtensions'>"
  "      <arg name='extensions' type='a(ssas)' direction='out' />"
  "    </method>"
  "    <method name='CreateInstance'>"
  "      <arg name='extension_name' type='s' direction='in' />"
  "      <arg name='instance_id' type='s' direction='out' />"
  "    </method>"
  "    <method name='DestroyInstance'>"
  "      <arg name='instance_id' type='s' direction='in' />"
  "      <arg name='instance_id' type='s' direction='out' />"
  "    </method>"
  "    <method name='PostMessage'>"
  "      <arg name='instance_id' type='s' direction='in' />"
  "      <arg name='msg' type='s' direction='in' />"
  "    </method>"
  "    <method name='SendSyncMessage'>"
  "      <arg name='instance_id' type='s' direction='in' />"
  "      <arg name='msg' type='s' direction='in' />"
  "      <arg name='reply' type='s' direction='out' />"
  "    </method>"
  "    <signal name='OnMessageToJS'>"
  "      <arg name='instance_id' type='s' />"
  "      <arg name='msg' type='s' />"
  "    </signal>"
  "  </interface>"
  "</node>";

}  // namespace

ExtensionServer::ExtensionServer(const std::string& uuid)
    : app_uuid_(uuid) {
}

ExtensionServer::~ExtensionServer() {
}

bool ExtensionServer::Start() {
  return Start(StringVector());
}

bool ExtensionServer::Start(const StringVector& paths) {
  // Connect to DBusServer for Application of Runtime
  if (!dbus_application_client_.ConnectByName(
          app_uuid_ + "." + std::string(kDBusNameForApplication))) {
    LOGGER(ERROR) << "Failed to connect to the dbus server for Application.";
    return false;
  }

  // Register system extensions to support Tizen Device APIs
  RegisterSystemExtensions();

  // Register user extensions
  for (auto it = paths.begin(); it != paths.end(); ++it) {
    if (utils::Exists(*it)) {
      RegisterExtension(*it);
    }
  }

  // Start DBusServer
  using std::placeholders::_1;
  using std::placeholders::_2;
  using std::placeholders::_3;
  using std::placeholders::_4;
  dbus_server_.SetIntrospectionXML(kDBusIntrospectionXML);
  dbus_server_.SetMethodCallback(
      kDBusInterfaceNameForExtension,
      std::bind(&ExtensionServer::HandleDBusMethod, this, _1, _2, _3, _4));
  dbus_server_.Start(app_uuid_ + "." + std::string(kDBusNameForExtension));

  // Send 'ready' signal to Injected Bundle.
  NotifyEPCreatedToApplication();

  return true;
}

void ExtensionServer::RegisterExtension(const std::string& path) {
  Extension* ext = new Extension(path, this);
  if (!ext->Initialize() || !RegisterSymbols(ext)) {
    delete ext;
    return;
  }
  extensions_[ext->name()] = ext;
  LOGGER(DEBUG) << ext->name() << " is registered.";
}

void ExtensionServer::RegisterSystemExtensions() {
  std::string extension_path(kSystemExtensionPath);
  extension_path.append("/");
  extension_path.append(kExtensionPrefix);
  extension_path.append("*");
  extension_path.append(kExtensionSuffix);

  glob_t glob_result;
  glob(extension_path.c_str(), GLOB_TILDE, NULL, &glob_result);
  for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
    RegisterExtension(glob_result.gl_pathv[i]);
  }
}

bool ExtensionServer::RegisterSymbols(Extension* extension) {
  std::string name = extension->name();

  if (extension_symbols_.find(name) != extension_symbols_.end()) {
    LOGGER(WARN) << "Ignoring extension with name already registred. '"
                 << name << "'";
    return false;
  }

  Extension::StringVector entry_points = extension->entry_points();
  for (auto it = entry_points.begin(); it != entry_points.end(); ++it) {
    if (extension_symbols_.find(*it) != extension_symbols_.end()) {
      LOGGER(WARN) << "Ignoring extension with entry_point already registred. '"
                   << (*it) << "'";
      return false;
    }
  }

  for (auto it = entry_points.begin(); it != entry_points.end(); ++it) {
    extension_symbols_.insert(*it);
  }

  extension_symbols_.insert(name);

  return true;
}

void ExtensionServer::GetRuntimeVariable(const char* key, char* value,
    size_t value_len) {
  GVariant* ret = dbus_application_client_.Call(
      kDBusInterfaceNameForApplication, kMethodGetRuntimeVariable,
      g_variant_new("(s)", key), G_VARIANT_TYPE("(s)"));

  if (!ret) {
    LOGGER(ERROR) << "Failed to get runtime variable from Application. ("
                  << key << ")";
    return;
  }

  gchar* v;
  g_variant_get(ret, "(&s)", &v);
  strncpy(value, v, value_len);

  g_variant_unref(ret);
}

void ExtensionServer::NotifyEPCreatedToApplication() {
  dbus_application_client_.Call(
      kDBusInterfaceNameForApplication, kMethodNotifyEPCreated,
      g_variant_new("(s)", dbus_server_.GetClientAddress().c_str()),
      NULL);
}

void ExtensionServer::HandleDBusMethod(GDBusConnection* connection,
                                       const std::string& method_name,
                                       GVariant* parameters,
                                       GDBusMethodInvocation* invocation) {
  if (method_name == kMethodGetExtensions) {
    OnGetExtensions(invocation);
  } else if (method_name == kMethodCreateInstance) {
    gchar* extension_name;
    g_variant_get(parameters, "(&s)", &extension_name);
    OnCreateInstance(connection, extension_name, invocation);
  } else if (method_name == kMethodDestroyInstance) {
    gchar* instance_id;
    g_variant_get(parameters, "(&s)", &instance_id);
    OnDestroyInstance(instance_id, invocation);
  } else if (method_name == kMethodSendSyncMessage) {
    gchar* instance_id;
    gchar* msg;
    g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
    OnSendSyncMessage(instance_id, msg, invocation);
  } else if (method_name == kMethodPostMessage) {
    gchar* instance_id;
    gchar* msg;
    g_variant_get(parameters, "(&s&s)", &instance_id, &msg);
    OnPostMessage(instance_id, msg);
  }
}

void ExtensionServer::OnGetExtensions(GDBusMethodInvocation* invocation) {
  GVariantBuilder builder;

  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

  // build an array of extensions
  auto it = extensions_.begin();
  for ( ; it != extensions_.end(); ++it) {
    Extension* ext = it->second;
    // open container for extension
    g_variant_builder_open(&builder, G_VARIANT_TYPE("(ssas)"));
    g_variant_builder_add(&builder, "s", ext->name().c_str());
    g_variant_builder_add(&builder, "s", ext->javascript_api().c_str());
    // open container for entry_point
    g_variant_builder_open(&builder, G_VARIANT_TYPE("as"));
    auto it_entry = ext->entry_points().begin();
    for ( ; it_entry != ext->entry_points().end(); ++it_entry) {
      g_variant_builder_add(&builder, "s", (*it_entry).c_str());
    }
    // close container('as') for entry_point
    g_variant_builder_close(&builder);
    // close container('(ssas)') for extension
    g_variant_builder_close(&builder);
  }

  GVariant* reply = NULL;
  if (extensions_.size() == 0) {
    reply = g_variant_new_array(G_VARIANT_TYPE("(ssas)"), NULL, 0);
  } else {
    reply = g_variant_builder_end(&builder);
  }

  g_dbus_method_invocation_return_value(
      invocation, g_variant_new_tuple(&reply, 1));
}

void ExtensionServer::OnCreateInstance(
    GDBusConnection* connection, const std::string& extension_name,
    GDBusMethodInvocation* invocation) {
  std::string instance_id = utils::GenerateUUID();

  // find extension with given the extension name
  auto it = extensions_.find(extension_name);
  if (it == extensions_.end()) {
    LOGGER(ERROR) << "Failed to find extension '" << extension_name << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Not found extension %s", extension_name.c_str());
    return;
  }

  // create instance
  ExtensionInstance* instance = it->second->CreateInstance();
  if (!instance) {
    LOGGER(ERROR) << "Failed to create instance of extension '"
                  << extension_name << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Failed to create instance of extension %s", extension_name.c_str());
    return;
  }

  // set callbacks
  using std::placeholders::_1;
  instance->SetPostMessageCallback(
      std::bind(&ExtensionServer::PostMessageToJSCallback,
                this, connection, instance_id, _1));

  instances_[instance_id] = instance;
  g_dbus_method_invocation_return_value(
      invocation, g_variant_new("(s)", instance_id.c_str()));
}

void ExtensionServer::OnDestroyInstance(
    const std::string& instance_id, GDBusMethodInvocation* invocation) {
  // find instance with the given instance id
  auto it = instances_.find(instance_id);
  if (it == instances_.end()) {
    LOGGER(ERROR) << "Failed to find instance '" << instance_id << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Not found instance %s", instance_id.c_str());
    return;
  }

  // destroy the instance
  ExtensionInstance* instance = it->second;
  delete instance;

  instances_.erase(it);

  g_dbus_method_invocation_return_value(
      invocation, g_variant_new("(s)", instance_id.c_str()));
}

void ExtensionServer::OnSendSyncMessage(
    const std::string& instance_id, const std::string& msg,
    GDBusMethodInvocation* invocation) {
  // find instance with the given instance id
  auto it = instances_.find(instance_id);
  if (it == instances_.end()) {
    LOGGER(ERROR) << "Failed to find instance '" << instance_id << "'";
    g_dbus_method_invocation_return_error(
        invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
        "Not found instance %s", instance_id.c_str());
    return;
  }

  ExtensionInstance* instance = it->second;

  using std::placeholders::_1;
  instance->SetSendSyncReplyCallback(
      std::bind(&ExtensionServer::SyncReplyCallback, this, _1, invocation));

  instance->HandleSyncMessage(msg);

  // reponse will be sent by SyncReplyCallback()
}

// async
void ExtensionServer::OnPostMessage(
    const std::string& instance_id, const std::string& msg) {
  auto it = instances_.find(instance_id);
  if (it == instances_.end()) {
    LOGGER(ERROR) << "Failed to find instance '" << instance_id << "'";
    return;
  }

  ExtensionInstance* instance = it->second;
  instance->HandleMessage(msg);
}

void ExtensionServer::SyncReplyCallback(
    const std::string& reply, GDBusMethodInvocation* invocation) {
  g_dbus_method_invocation_return_value(
      invocation, g_variant_new("(s)", reply.c_str()));
}

void ExtensionServer::PostMessageToJSCallback(
    GDBusConnection* connection, const std::string& instance_id,
    const std::string& msg) {
  if (!connection || g_dbus_connection_is_closed(connection)) {
    LOGGER(ERROR) << "Client connection is closed already.";
    return;
  }

  dbus_server_.SendSignal(connection,
                          kDBusInterfaceNameForExtension,
                          kSignalOnMessageToJS,
                          g_variant_new("(ss)",
                                        instance_id.c_str(),
                                        msg.c_str()));
}

// static
bool ExtensionServer::StartExtensionProcess() {
  GMainLoop* loop;

  loop = g_main_loop_new(NULL, FALSE);

  // Register Quit Signal Handlers
  auto quit_callback = [](gpointer data) -> gboolean {
    GMainLoop* loop = reinterpret_cast<GMainLoop*>(data);
    g_main_loop_quit(loop);
    return false;
  };
  g_unix_signal_add(SIGINT, quit_callback, loop);
  g_unix_signal_add(SIGTERM, quit_callback, loop);

  CommandLine* cmd = CommandLine::ForCurrentProcess();

  // TODO(wy80.choi): Receive extension paths for user defined extensions.

  // Receive AppID from arguments.
  if (cmd->arguments().size() < 1) {
    LOGGER(ERROR) << "uuid is required.";
    return false;
  }
  std::string uuid = cmd->arguments()[0];

  // Start ExtensionServer
  ExtensionServer server(uuid);
  if (!server.Start()) {
    LOGGER(ERROR) << "Failed to start extension server.";
    return false;
  }

  LOGGER(INFO) << "extension process has been started.";

  g_main_loop_run(loop);

  LOGGER(INFO) << "extension process is exiting.";

  g_main_loop_unref(loop);

  return true;
}

}  // namespace wrt
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <set>
#include <unordered_set>
#include <vector>
#include <algorithm>
#include <vespa/vespalib/stllike/hash_set.hpp>

template <typename T>
class RoundRobinAllocator
{
public:
    typedef size_t     size_type;
    typedef ptrdiff_t  difference_type;
    typedef T *        pointer;
    typedef const T *  const_pointer;
    typedef T &        reference;
    typedef const T &  const_reference;
    typedef T          value_type;

    template<typename _Tp1>
    struct rebind {
        typedef RoundRobinAllocator<_Tp1> other;
    };
    RoundRobinAllocator() { }
    template<typename _Tp1>
    RoundRobinAllocator(const RoundRobinAllocator<_Tp1>&) throw() { }

    void construct(pointer p, const T& val) { new(static_cast<void*>(p)) T(val); }
    void destroy(pointer p) {
         p->~T();
    }
    pointer allocate(size_type n, const_pointer hint = 0) {
        (void) hint;
        if ((_w + n) < _sz) {
            pointer p(_memory + _w);
            _w += n;
            return p;
        }
        throw std::bad_alloc();
    }

    void deallocate(pointer p, size_type n) {
        if ((p - _memory) == long(_r)) {
            _r += n;
        }
    }
    size_type max_size() const throw() { return _sz; }

private:
    static size_t _r;
    static size_t _w;
    static size_t _sz;
    static T * _memory;
};

template <typename T>
size_t RoundRobinAllocator<T>::_r = 0;
template <typename T>
size_t RoundRobinAllocator<T>::_w = 0;
template <typename T>
size_t RoundRobinAllocator<T>::_sz = 10000000;
template <typename T>
T * RoundRobinAllocator<T>::_memory = static_cast<T *> (malloc(10000000*sizeof(T)));

class Gid
{
public:
  struct hash {
      size_t operator () (const Gid & g) const { return g.getGid()[0]; }
  };
  Gid(unsigned int v=0) : _gid() { _gid[0] = _gid[1] = _gid[2] = v; }
  const unsigned int * getGid() const { return _gid; }
  int cmp(const Gid & b) const { return memcmp(_gid, b._gid, sizeof(_gid)); }
  bool operator < (const Gid & b) const { return cmp(b) < 0; }
  bool operator == (const Gid & b) const { return cmp(b) == 0; }
private:
  unsigned int _gid[3];
};

class Slot
{
public:
  Slot(unsigned int v=0) : _gid(v) { }
  const Gid & getGid() const { return _gid; }
  int cmp(const Slot & b) const { return _gid.cmp(b.getGid()); }
private:
  Gid _gid;
};

struct IndirectCmp : public std::binary_function<Slot*, Slot*, bool> {
    bool operator()(const Slot* s1, const Slot* s2) {
        return s1->cmp(*s2) < 0;
    }
};

size_t benchMap(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::set<Gid> M;
    M set;
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchMapIntelligent(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::set<Gid> M;
    M set;
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashStl(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::unordered_set< Gid, Gid::hash > M;
    M set(v.size());
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashStlIntelligent(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::unordered_set< Gid, Gid::hash > M;
    M set(v.size());
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashStlFastAlloc(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    std::unordered_set< Gid, Gid::hash, std::equal_to<Gid>, RoundRobinAllocator<Gid> > set(v.size());
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashVespaLib(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef vespalib::hash_set< Gid, Gid::hash > M;
    M set(v.size()*2);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashVespaLibIntelligent(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef vespalib::hash_set< Gid, Gid::hash > M;
    M set(v.size()*2);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashVespaLibIntelligentAndFast(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef vespalib::hash_set< Gid, Gid::hash, std::equal_to<Gid>, vespalib::hashtable_base::and_modulator > M;
    M set(v.size()*2);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchSort(const std::vector<Slot *> & vOrg)
{
    IndirectCmp iCmp;
    std::vector<Slot *> v(vOrg);
    std::sort(v.begin(), v.end(), iCmp);
    Gid prev(0);
    size_t count(0);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (s.getGid().cmp(prev) != 0) {
            v[count++] = v[i];
            prev = s.getGid();
        }
    }
    v.resize(count);
    return count;
}

static char _type;

void*
runBenchMark(const std::vector<Slot *> * indirectSlotVector)
{
    int uniq(0);
    switch (_type) {
        case 'm': uniq = benchMap(*indirectSlotVector); break;
        case 'M': uniq = benchMapIntelligent(*indirectSlotVector); break;
        case 'v': uniq = benchSort(*indirectSlotVector); break;
        case 'h': uniq = benchHashStl(*indirectSlotVector); break;
        case 'H': uniq = benchHashStlIntelligent(*indirectSlotVector); break;
        case 'a': uniq = benchHashStlFastAlloc(*indirectSlotVector); break;
        case 'g': uniq = benchHashVespaLib(*indirectSlotVector); break;
        case 'G': uniq = benchHashVespaLibIntelligent(*indirectSlotVector); break;
        case 'J': uniq = benchHashVespaLibIntelligentAndFast(*indirectSlotVector); break;
        default: break;
    }
    return reinterpret_cast<void *>(uniq);
}

int main(int argc, char *argv[])
{
    typedef void* (*VFUNC)(void*);
    size_t count(10000000);
    size_t rep(10);
    size_t numThreads(0);
    char type('m');
    if (argc >= 2) {
        type = argv[1][0];
    }
    if (argc >= 3) {
        count = strtoul(argv[2], NULL, 0);
    }
    if (argc >= 4) {
        rep = strtoul(argv[3], NULL, 0);
    }
    if (argc >= 5) {
        numThreads = strtoul(argv[4], NULL, 0);
    }
    std::vector<Slot> slotVector(count);
    for (size_t i(0), m(slotVector.size()); i < m; i++) {
        slotVector[i] = Slot(rand());
    }
    std::vector<Slot *> indirectSlotVector(slotVector.size());
    for (size_t i(0), m(slotVector.size()); i < m; i++) {
        indirectSlotVector[i] = &slotVector[i];
    }
    std::vector<const char *> description(256);
    description['m'] = "std::set";
    description['M'] = "std::set with intelligent insert";
    description['v'] = "std::sort";
    description['h'] = "std::hash_set";
    description['H'] = "std::hash_set with intelligent insert";
    description['a'] = "std::hash_set with special allocator. Not threadsafe and hence not usable.";
    description['g'] = "vespalib::hash_set";
    description['G'] = "vespalib::hash_set with intelligent insert";
    description['J'] = "vespalib::hash_set with intelligent insert and fast modulator";
    size_t uniq(0);
    for (size_t i(0); i < rep; i++) {
        switch (type) {
           case 'm':
           case 'M':
           case 'v':
           case 'h':
           case 'H':
           case 'a':
           case 'g':
           case 'G':
           case 'J':
               _type = type;
               if (numThreads == 0) {
                   runBenchMark(&indirectSlotVector);
               } else {
                   std::vector<pthread_t> threads(numThreads);
                   for (size_t j(0); j < numThreads; j++) {
                       pthread_create(&threads[j], NULL, (VFUNC)runBenchMark, &indirectSlotVector);
                   }
                   for (size_t j(0); j < numThreads; j++) {
                       pthread_join(threads[j], NULL);
                   }
               }
            break;
        default:
            printf("'m' = %s\n", description[type]);
            printf("'M' = %s\n", description[type]);
            printf("'v' = %s\n", description[type]);
            printf("'h' = %s\n", description[type]);
            printf("'a' = %s\n", description[type]);
            printf("'H' = %s\n", description[type]);
            printf("'g' = %s\n", description[type]);
            printf("'G' = %s\n", description[type]);
            printf("'J' = %s\n", description[type]);
            printf("Unspecified type %c.\n", type);
            return 1;
        }
    }
    printf("Running test '%c' = %s, result = %ld unique values\n", type, description[type], uniq);
    return 0;
}
<commit_msg>Include pthread.h when using pthread functions.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <set>
#include <unordered_set>
#include <vector>
#include <algorithm>
#include <pthread.h>
#include <vespa/vespalib/stllike/hash_set.hpp>

template <typename T>
class RoundRobinAllocator
{
public:
    typedef size_t     size_type;
    typedef ptrdiff_t  difference_type;
    typedef T *        pointer;
    typedef const T *  const_pointer;
    typedef T &        reference;
    typedef const T &  const_reference;
    typedef T          value_type;

    template<typename _Tp1>
    struct rebind {
        typedef RoundRobinAllocator<_Tp1> other;
    };
    RoundRobinAllocator() { }
    template<typename _Tp1>
    RoundRobinAllocator(const RoundRobinAllocator<_Tp1>&) throw() { }

    void construct(pointer p, const T& val) { new(static_cast<void*>(p)) T(val); }
    void destroy(pointer p) {
         p->~T();
    }
    pointer allocate(size_type n, const_pointer hint = 0) {
        (void) hint;
        if ((_w + n) < _sz) {
            pointer p(_memory + _w);
            _w += n;
            return p;
        }
        throw std::bad_alloc();
    }

    void deallocate(pointer p, size_type n) {
        if ((p - _memory) == long(_r)) {
            _r += n;
        }
    }
    size_type max_size() const throw() { return _sz; }

private:
    static size_t _r;
    static size_t _w;
    static size_t _sz;
    static T * _memory;
};

template <typename T>
size_t RoundRobinAllocator<T>::_r = 0;
template <typename T>
size_t RoundRobinAllocator<T>::_w = 0;
template <typename T>
size_t RoundRobinAllocator<T>::_sz = 10000000;
template <typename T>
T * RoundRobinAllocator<T>::_memory = static_cast<T *> (malloc(10000000*sizeof(T)));

class Gid
{
public:
  struct hash {
      size_t operator () (const Gid & g) const { return g.getGid()[0]; }
  };
  Gid(unsigned int v=0) : _gid() { _gid[0] = _gid[1] = _gid[2] = v; }
  const unsigned int * getGid() const { return _gid; }
  int cmp(const Gid & b) const { return memcmp(_gid, b._gid, sizeof(_gid)); }
  bool operator < (const Gid & b) const { return cmp(b) < 0; }
  bool operator == (const Gid & b) const { return cmp(b) == 0; }
private:
  unsigned int _gid[3];
};

class Slot
{
public:
  Slot(unsigned int v=0) : _gid(v) { }
  const Gid & getGid() const { return _gid; }
  int cmp(const Slot & b) const { return _gid.cmp(b.getGid()); }
private:
  Gid _gid;
};

struct IndirectCmp : public std::binary_function<Slot*, Slot*, bool> {
    bool operator()(const Slot* s1, const Slot* s2) {
        return s1->cmp(*s2) < 0;
    }
};

size_t benchMap(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::set<Gid> M;
    M set;
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchMapIntelligent(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::set<Gid> M;
    M set;
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashStl(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::unordered_set< Gid, Gid::hash > M;
    M set(v.size());
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashStlIntelligent(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef std::unordered_set< Gid, Gid::hash > M;
    M set(v.size());
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashStlFastAlloc(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    std::unordered_set< Gid, Gid::hash, std::equal_to<Gid>, RoundRobinAllocator<Gid> > set(v.size());
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashVespaLib(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef vespalib::hash_set< Gid, Gid::hash > M;
    M set(v.size()*2);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (set.find(s.getGid()) == set.end()) {
            set.insert(s.getGid());
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashVespaLibIntelligent(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef vespalib::hash_set< Gid, Gid::hash > M;
    M set(v.size()*2);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchHashVespaLibIntelligentAndFast(const std::vector<Slot *> & v)
{
    size_t uniq(0);
    typedef vespalib::hash_set< Gid, Gid::hash, std::equal_to<Gid>, vespalib::hashtable_base::and_modulator > M;
    M set(v.size()*2);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        std::pair<M::iterator, bool> r = set.insert(s.getGid());
        if (r.second) {
            uniq++;
        }
    }
    return uniq;
}

size_t benchSort(const std::vector<Slot *> & vOrg)
{
    IndirectCmp iCmp;
    std::vector<Slot *> v(vOrg);
    std::sort(v.begin(), v.end(), iCmp);
    Gid prev(0);
    size_t count(0);
    for(size_t i(0), m(v.size()); i < m; i++) {
        const Slot & s = *v[i];
        if (s.getGid().cmp(prev) != 0) {
            v[count++] = v[i];
            prev = s.getGid();
        }
    }
    v.resize(count);
    return count;
}

static char _type;

void*
runBenchMark(const std::vector<Slot *> * indirectSlotVector)
{
    int uniq(0);
    switch (_type) {
        case 'm': uniq = benchMap(*indirectSlotVector); break;
        case 'M': uniq = benchMapIntelligent(*indirectSlotVector); break;
        case 'v': uniq = benchSort(*indirectSlotVector); break;
        case 'h': uniq = benchHashStl(*indirectSlotVector); break;
        case 'H': uniq = benchHashStlIntelligent(*indirectSlotVector); break;
        case 'a': uniq = benchHashStlFastAlloc(*indirectSlotVector); break;
        case 'g': uniq = benchHashVespaLib(*indirectSlotVector); break;
        case 'G': uniq = benchHashVespaLibIntelligent(*indirectSlotVector); break;
        case 'J': uniq = benchHashVespaLibIntelligentAndFast(*indirectSlotVector); break;
        default: break;
    }
    return reinterpret_cast<void *>(uniq);
}

int main(int argc, char *argv[])
{
    typedef void* (*VFUNC)(void*);
    size_t count(10000000);
    size_t rep(10);
    size_t numThreads(0);
    char type('m');
    if (argc >= 2) {
        type = argv[1][0];
    }
    if (argc >= 3) {
        count = strtoul(argv[2], NULL, 0);
    }
    if (argc >= 4) {
        rep = strtoul(argv[3], NULL, 0);
    }
    if (argc >= 5) {
        numThreads = strtoul(argv[4], NULL, 0);
    }
    std::vector<Slot> slotVector(count);
    for (size_t i(0), m(slotVector.size()); i < m; i++) {
        slotVector[i] = Slot(rand());
    }
    std::vector<Slot *> indirectSlotVector(slotVector.size());
    for (size_t i(0), m(slotVector.size()); i < m; i++) {
        indirectSlotVector[i] = &slotVector[i];
    }
    std::vector<const char *> description(256);
    description['m'] = "std::set";
    description['M'] = "std::set with intelligent insert";
    description['v'] = "std::sort";
    description['h'] = "std::hash_set";
    description['H'] = "std::hash_set with intelligent insert";
    description['a'] = "std::hash_set with special allocator. Not threadsafe and hence not usable.";
    description['g'] = "vespalib::hash_set";
    description['G'] = "vespalib::hash_set with intelligent insert";
    description['J'] = "vespalib::hash_set with intelligent insert and fast modulator";
    size_t uniq(0);
    for (size_t i(0); i < rep; i++) {
        switch (type) {
           case 'm':
           case 'M':
           case 'v':
           case 'h':
           case 'H':
           case 'a':
           case 'g':
           case 'G':
           case 'J':
               _type = type;
               if (numThreads == 0) {
                   runBenchMark(&indirectSlotVector);
               } else {
                   std::vector<pthread_t> threads(numThreads);
                   for (size_t j(0); j < numThreads; j++) {
                       pthread_create(&threads[j], NULL, (VFUNC)runBenchMark, &indirectSlotVector);
                   }
                   for (size_t j(0); j < numThreads; j++) {
                       pthread_join(threads[j], NULL);
                   }
               }
            break;
        default:
            printf("'m' = %s\n", description[type]);
            printf("'M' = %s\n", description[type]);
            printf("'v' = %s\n", description[type]);
            printf("'h' = %s\n", description[type]);
            printf("'a' = %s\n", description[type]);
            printf("'H' = %s\n", description[type]);
            printf("'g' = %s\n", description[type]);
            printf("'G' = %s\n", description[type]);
            printf("'J' = %s\n", description[type]);
            printf("Unspecified type %c.\n", type);
            return 1;
        }
    }
    printf("Running test '%c' = %s, result = %ld unique values\n", type, description[type], uniq);
    return 0;
}
<|endoftext|>


<commit_before>/*
*
* Copyright 2016 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context 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 Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <stdint.h>   // int64_t et al
#include <sys/time.h>

#include <utility>
#include <string>
#include <map>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/JsonHelper.h"
#include "metricsMgr/MetricsManager.h"

/* ****************************************************************************
*
* MetricsManager::MetricsManager -
*/
MetricsManager::MetricsManager(): on(false), semWaitStatistics(false), semWaitTime(0)
{
}

/* ****************************************************************************
*
* MetricsManager::init -
*
* NOTE
*   The semaphore is created even though the metrics manager is not turned on.
*   It's only one sys-call, and this way, the broker is prepared to receive 'on/off'
*   via REST.
*/
bool MetricsManager::init(bool _on, bool _semWaitStatistics)
{
  on                 = _on;
  semWaitStatistics  = _semWaitStatistics;

  if (sem_init(&sem, 0, 1) == -1)
  {
    LM_E(("Runtime Error (error initializing 'metrics mgr' semaphore: %s)", strerror(errno)));
    return false;
  }

  return true;
}

/* ****************************************************************************
*
* MetricsManager::semTake -
*/
void MetricsManager::semTake(void)
{
  if (semWaitStatistics)
  {
    struct timeval start;
    struct timeval end;

    gettimeofday(&start, NULL);
    sem_wait(&sem);
    gettimeofday(&end, NULL);

    // Add semaphore waiting time to the accumulator (semWaitTime is in microseconds)
    semWaitTime += (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
  }
  else
  {
    sem_wait(&sem);
  }
}

/* ****************************************************************************
*
* MetricsManager::semGive -
*/
void MetricsManager::semGive(void)
{
  sem_post(&sem);
}

/* ****************************************************************************
*
* MetricsManager::semWaitTimeGet -
*/
int64_t MetricsManager::semWaitTimeGet(void)
{
  return semWaitTime;
}

/* ****************************************************************************
*
* MetricsManager::add -
*/
void MetricsManager::add(const std::string& srv, const std::string& subServ, const std::string& metric, uint64_t value)
{
  if (on == false)
  {
    return;
  }

  //
  // Exclude the first '/' from the Sub Service
  // But, only if it starts with a '/'
  //
  const char* subService = subServ.c_str();

  if (subService[0] == '/')
  {
    subService = &subService[1];
  }

  semTake();

  // Do we have the service in the map?
  if (metrics.find(srv) == metrics.end())
  {
    // not found: create it
    metrics[srv] = new std::map<std::string, std::map<std::string, uint64_t>*>;
  }

  // Do we have the subservice in the map?
  if (metrics[srv]->find(subService) == metrics[srv]->end())
  {
    //
    // not found: create it
    // FIXME PR: this syntax should be simpler, closer to
    // metrics[srv][subService] = new std::map<std::string, uint64_t>;
    //
    metrics[srv]->insert(std::pair<std::string, std::map<std::string, uint64_t>*>
                         (subService,
                          new std::map<std::string, uint64_t>));
  }

  // Do we have the metric in the map?
  if (metrics[srv]->at(subService)->find(metric) == metrics[srv]->at(subService)->end())
  {
    //
    // not found: create it
    // FIXME PR: I don't like the at() and pair() syntax, I'd prefer a syntax closer to:
    // metrics[srv][subService][metric] = 0;
    //
    metrics[srv]->at(subService)->insert(std::pair<std::string, uint64_t>(metric, 0));
  }

  metrics[srv]->at(subService)->at(metric) += value;

  semGive();
}

/* ****************************************************************************
*
* MetricsManager::reset -
*/
void MetricsManager::reset(void)
{
  if (on == false)
  {
    return;
  }

  semTake();

  //
  // Three iterators needed to iterate over the 'triple-map' metrics:
  //   serviceIter      to iterate over all services
  //   subServiceIter   to iterate over all sub-services of a service
  //   metricIter       to iterate over all metrics of a sub-service
  //
  std::map<std::string, std::map<std::string, std::map<std::string, uint64_t>*>*>::iterator  serviceIter;
  std::map<std::string, std::map<std::string, uint64_t>*>::iterator                          subServiceIter;
  std::map<std::string, uint64_t>::iterator                                                  metricIter;

  for (serviceIter = metrics.begin(); serviceIter != metrics.end(); ++serviceIter)
  {
    std::map<std::string, std::map<std::string, uint64_t>*>* servMap  = serviceIter->second;

    for (subServiceIter = servMap->begin(); subServiceIter != servMap->end(); ++subServiceIter)
    {
      std::map<std::string, uint64_t>* metricMap  = subServiceIter->second;

      for (metricIter = metricMap->begin(); metricIter != metricMap->end(); ++metricIter)
      {
        metricIter->second = 0;
      }
    }
  }

  semGive();
}

/* ****************************************************************************
*
* metricsRender -
*/
static std::string metricsRender(std::map<std::string, uint64_t>& metricsMap)
{
  std::map<std::string, uint64_t>::iterator  it;
  uint64_t                                   incomingTransactions = 0;
  uint64_t                                   totalServiceTime     = 0;
  int                                        metricsAdded         = 0;
  JsonHelper                                 jh;

  for (it = metricsMap.begin();  it != metricsMap.end(); ++it)
  {
    std::string      metric = it->first;
    int64_t          value  = it->second;

    if (metric == _METRIC_TOTAL_SERVICE_TIME)
    {
      totalServiceTime = value;
    }
    else if (metric == METRIC_TRANS_IN)
    {
      incomingTransactions = value;
    }

    if ((totalServiceTime != 0) && (incomingTransactions != 0))
    {
      float mValue = (float) totalServiceTime / (float) (incomingTransactions * 1000000);

      jh.addFloat(METRIC_SERVICE_TIME, mValue);
      totalServiceTime     = 0;
      incomingTransactions = 0;
      ++metricsAdded;
    }

    if (metric != _METRIC_TOTAL_SERVICE_TIME)
    {
      if (value != 0)
      {
        jh.addNumber(metric, value);
        ++metricsAdded;
      }
    }
  }

  return jh.str();
}

/* ****************************************************************************
*
* MetricsManager::toJson -
*/
std::string MetricsManager::toJson(void)
{
  if (on == false)
  {
    return "";
  }

  semTake();

  //
  // Three iterators needed to iterate over the 'triple-map' metrics:
  //   serviceIter      to iterate over all services
  //   subServiceIter   to iterate over all sub-services of a service
  //   metricIter       to iterate over all metrics of a sub-service
  //
  std::map<std::string, std::map<std::string, std::map<std::string, uint64_t>*>*>::iterator  serviceIter;
  std::map<std::string, std::map<std::string, uint64_t>*>::iterator                          subServiceIter;
  std::map<std::string, uint64_t>::iterator                                                  metricIter;
  JsonHelper                                                                                top;
  JsonHelper                                                                                services;
  std::map<std::string, uint64_t>                                                            sum;

  for (serviceIter = metrics.begin(); serviceIter != metrics.end(); ++serviceIter)
  {
    JsonHelper                                                subServiceTop;
    JsonHelper                                                jhSubService;
    std::string                                               service        = serviceIter->first;
    std::map<std::string, std::map<std::string, uint64_t>*>*  servMap        = serviceIter->second;
    std::map<std::string, uint64_t>                           serviceSum;

    for (subServiceIter = servMap->begin(); subServiceIter != servMap->end(); ++subServiceIter)
    {
      JsonHelper                        jhMetrics;
      std::string                       subService           = subServiceIter->first;
      std::map<std::string, uint64_t>*  metricMap            = subServiceIter->second;

      for (metricIter = metricMap->begin(); metricIter != metricMap->end(); ++metricIter)
      {
        std::string  metric = metricIter->first;
        int64_t      value  = metricIter->second;

        // Add to 'sum-maps'
        if (value != 0)
        {
          serviceSum[metric] += value;
          sum[metric]        += value;
        }
      }

      std::string subServiceString = metricsRender(*metricMap);

      if (subServiceString != "{}")
      {
        jhSubService.addRaw(subService, subServiceString);
      }
    }

    subServiceTop.addRaw("subservs", jhSubService.str());

    std::string serviceSumString = metricsRender(serviceSum);

    subServiceTop.addRaw("sum", serviceSumString);
    services.addRaw(service, subServiceTop.str());
  }

  //
  // Sum for grand total
  //
  std::string sumString = metricsRender(sum);

  services.addRaw("sum", sumString);
  top.addRaw("services", services.str());

  semGive();

  return top.str();
}

/* ****************************************************************************
*
* isOn -
*/
bool MetricsManager::isOn(void)
{
  return on;
}

/* ****************************************************************************
*
* MetricsManager::semStateGet -
*/
const char* MetricsManager::semStateGet(void)
{
  int value;

  if (sem_getvalue(&sem, &value) == -1)
  {
    return "error";
  }

  if (value == 0)
  {
    return "taken";
  }

  return "free";
}

/* ****************************************************************************
*
* MetricsManager::release -
*/
void MetricsManager::release(void)
{
  if (on == false)
  {
    return;
  }

  semTake();

  //
  // Two iterators needed to iterate over metrics, clearing all maps:
  //   serviceIter      to iterate over all services
  //   subServiceIter   to iterate over all sub-services of a service
  //
  std::map<std::string, std::map<std::string, std::map<std::string, uint64_t>*>*>::iterator  serviceIter;
  std::map<std::string, std::map<std::string, uint64_t>*>::iterator                          subServiceIter;

  for (serviceIter = metrics.begin(); serviceIter != metrics.end(); ++serviceIter)
  {
    std::string                                              service  = serviceIter->first;
    std::map<std::string, std::map<std::string, uint64_t>*>* servMap  = serviceIter->second;

    for (subServiceIter = servMap->begin(); subServiceIter != servMap->end(); ++subServiceIter)
    {
      std::string                       subService = subServiceIter->first;
      std::map<std::string, uint64_t>*  metricMap  = subServiceIter->second;

      metricMap->clear();
      delete metricMap;
    }
    servMap->clear();
    delete servMap;
  }
  metrics.clear();

  semGive();
}
<commit_msg>metricsAdded counter removed. It was no longer used<commit_after>/*
*
* Copyright 2016 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context 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 Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <stdint.h>   // int64_t et al
#include <sys/time.h>

#include <utility>
#include <string>
#include <map>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/JsonHelper.h"
#include "metricsMgr/MetricsManager.h"

/* ****************************************************************************
*
* MetricsManager::MetricsManager -
*/
MetricsManager::MetricsManager(): on(false), semWaitStatistics(false), semWaitTime(0)
{
}

/* ****************************************************************************
*
* MetricsManager::init -
*
* NOTE
*   The semaphore is created even though the metrics manager is not turned on.
*   It's only one sys-call, and this way, the broker is prepared to receive 'on/off'
*   via REST.
*/
bool MetricsManager::init(bool _on, bool _semWaitStatistics)
{
  on                 = _on;
  semWaitStatistics  = _semWaitStatistics;

  if (sem_init(&sem, 0, 1) == -1)
  {
    LM_E(("Runtime Error (error initializing 'metrics mgr' semaphore: %s)", strerror(errno)));
    return false;
  }

  return true;
}

/* ****************************************************************************
*
* MetricsManager::semTake -
*/
void MetricsManager::semTake(void)
{
  if (semWaitStatistics)
  {
    struct timeval start;
    struct timeval end;

    gettimeofday(&start, NULL);
    sem_wait(&sem);
    gettimeofday(&end, NULL);

    // Add semaphore waiting time to the accumulator (semWaitTime is in microseconds)
    semWaitTime += (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
  }
  else
  {
    sem_wait(&sem);
  }
}

/* ****************************************************************************
*
* MetricsManager::semGive -
*/
void MetricsManager::semGive(void)
{
  sem_post(&sem);
}

/* ****************************************************************************
*
* MetricsManager::semWaitTimeGet -
*/
int64_t MetricsManager::semWaitTimeGet(void)
{
  return semWaitTime;
}

/* ****************************************************************************
*
* MetricsManager::add -
*/
void MetricsManager::add(const std::string& srv, const std::string& subServ, const std::string& metric, uint64_t value)
{
  if (on == false)
  {
    return;
  }

  //
  // Exclude the first '/' from the Sub Service
  // But, only if it starts with a '/'
  //
  const char* subService = subServ.c_str();

  if (subService[0] == '/')
  {
    subService = &subService[1];
  }

  semTake();

  // Do we have the service in the map?
  if (metrics.find(srv) == metrics.end())
  {
    // not found: create it
    metrics[srv] = new std::map<std::string, std::map<std::string, uint64_t>*>;
  }

  // Do we have the subservice in the map?
  if (metrics[srv]->find(subService) == metrics[srv]->end())
  {
    //
    // not found: create it
    // FIXME PR: this syntax should be simpler, closer to
    // metrics[srv][subService] = new std::map<std::string, uint64_t>;
    //
    metrics[srv]->insert(std::pair<std::string, std::map<std::string, uint64_t>*>
                         (subService,
                          new std::map<std::string, uint64_t>));
  }

  // Do we have the metric in the map?
  if (metrics[srv]->at(subService)->find(metric) == metrics[srv]->at(subService)->end())
  {
    //
    // not found: create it
    // FIXME PR: I don't like the at() and pair() syntax, I'd prefer a syntax closer to:
    // metrics[srv][subService][metric] = 0;
    //
    metrics[srv]->at(subService)->insert(std::pair<std::string, uint64_t>(metric, 0));
  }

  metrics[srv]->at(subService)->at(metric) += value;

  semGive();
}

/* ****************************************************************************
*
* MetricsManager::reset -
*/
void MetricsManager::reset(void)
{
  if (on == false)
  {
    return;
  }

  semTake();

  //
  // Three iterators needed to iterate over the 'triple-map' metrics:
  //   serviceIter      to iterate over all services
  //   subServiceIter   to iterate over all sub-services of a service
  //   metricIter       to iterate over all metrics of a sub-service
  //
  std::map<std::string, std::map<std::string, std::map<std::string, uint64_t>*>*>::iterator  serviceIter;
  std::map<std::string, std::map<std::string, uint64_t>*>::iterator                          subServiceIter;
  std::map<std::string, uint64_t>::iterator                                                  metricIter;

  for (serviceIter = metrics.begin(); serviceIter != metrics.end(); ++serviceIter)
  {
    std::map<std::string, std::map<std::string, uint64_t>*>* servMap  = serviceIter->second;

    for (subServiceIter = servMap->begin(); subServiceIter != servMap->end(); ++subServiceIter)
    {
      std::map<std::string, uint64_t>* metricMap  = subServiceIter->second;

      for (metricIter = metricMap->begin(); metricIter != metricMap->end(); ++metricIter)
      {
        metricIter->second = 0;
      }
    }
  }

  semGive();
}

/* ****************************************************************************
*
* metricsRender -
*/
static std::string metricsRender(std::map<std::string, uint64_t>& metricsMap)
{
  std::map<std::string, uint64_t>::iterator  it;
  uint64_t                                   incomingTransactions = 0;
  uint64_t                                   totalServiceTime     = 0;
  JsonHelper                                 jh;

  for (it = metricsMap.begin();  it != metricsMap.end(); ++it)
  {
    std::string      metric = it->first;
    int64_t          value  = it->second;

    if (metric == _METRIC_TOTAL_SERVICE_TIME)
    {
      totalServiceTime = value;
    }
    else if (metric == METRIC_TRANS_IN)
    {
      incomingTransactions = value;
    }

    if ((totalServiceTime != 0) && (incomingTransactions != 0))
    {
      float mValue = (float) totalServiceTime / (float) (incomingTransactions * 1000000);

      jh.addFloat(METRIC_SERVICE_TIME, mValue);
      totalServiceTime     = 0;
      incomingTransactions = 0;
    }

    if (metric != _METRIC_TOTAL_SERVICE_TIME)
    {
      if (value != 0)
      {
        jh.addNumber(metric, value);
      }
    }
  }

  return jh.str();
}

/* ****************************************************************************
*
* MetricsManager::toJson -
*/
std::string MetricsManager::toJson(void)
{
  if (on == false)
  {
    return "";
  }

  semTake();

  //
  // Three iterators needed to iterate over the 'triple-map' metrics:
  //   serviceIter      to iterate over all services
  //   subServiceIter   to iterate over all sub-services of a service
  //   metricIter       to iterate over all metrics of a sub-service
  //
  std::map<std::string, std::map<std::string, std::map<std::string, uint64_t>*>*>::iterator  serviceIter;
  std::map<std::string, std::map<std::string, uint64_t>*>::iterator                          subServiceIter;
  std::map<std::string, uint64_t>::iterator                                                  metricIter;
  JsonHelper                                                                                top;
  JsonHelper                                                                                services;
  std::map<std::string, uint64_t>                                                            sum;

  for (serviceIter = metrics.begin(); serviceIter != metrics.end(); ++serviceIter)
  {
    JsonHelper                                                subServiceTop;
    JsonHelper                                                jhSubService;
    std::string                                               service        = serviceIter->first;
    std::map<std::string, std::map<std::string, uint64_t>*>*  servMap        = serviceIter->second;
    std::map<std::string, uint64_t>                           serviceSum;

    for (subServiceIter = servMap->begin(); subServiceIter != servMap->end(); ++subServiceIter)
    {
      JsonHelper                        jhMetrics;
      std::string                       subService           = subServiceIter->first;
      std::map<std::string, uint64_t>*  metricMap            = subServiceIter->second;

      for (metricIter = metricMap->begin(); metricIter != metricMap->end(); ++metricIter)
      {
        std::string  metric = metricIter->first;
        int64_t      value  = metricIter->second;

        // Add to 'sum-maps'
        if (value != 0)
        {
          serviceSum[metric] += value;
          sum[metric]        += value;
        }
      }

      std::string subServiceString = metricsRender(*metricMap);

      if (subServiceString != "{}")
      {
        jhSubService.addRaw(subService, subServiceString);
      }
    }

    subServiceTop.addRaw("subservs", jhSubService.str());

    std::string serviceSumString = metricsRender(serviceSum);

    subServiceTop.addRaw("sum", serviceSumString);
    services.addRaw(service, subServiceTop.str());
  }

  //
  // Sum for grand total
  //
  std::string sumString = metricsRender(sum);

  services.addRaw("sum", sumString);
  top.addRaw("services", services.str());

  semGive();

  return top.str();
}

/* ****************************************************************************
*
* isOn -
*/
bool MetricsManager::isOn(void)
{
  return on;
}

/* ****************************************************************************
*
* MetricsManager::semStateGet -
*/
const char* MetricsManager::semStateGet(void)
{
  int value;

  if (sem_getvalue(&sem, &value) == -1)
  {
    return "error";
  }

  if (value == 0)
  {
    return "taken";
  }

  return "free";
}

/* ****************************************************************************
*
* MetricsManager::release -
*/
void MetricsManager::release(void)
{
  if (on == false)
  {
    return;
  }

  semTake();

  //
  // Two iterators needed to iterate over metrics, clearing all maps:
  //   serviceIter      to iterate over all services
  //   subServiceIter   to iterate over all sub-services of a service
  //
  std::map<std::string, std::map<std::string, std::map<std::string, uint64_t>*>*>::iterator  serviceIter;
  std::map<std::string, std::map<std::string, uint64_t>*>::iterator                          subServiceIter;

  for (serviceIter = metrics.begin(); serviceIter != metrics.end(); ++serviceIter)
  {
    std::string                                              service  = serviceIter->first;
    std::map<std::string, std::map<std::string, uint64_t>*>* servMap  = serviceIter->second;

    for (subServiceIter = servMap->begin(); subServiceIter != servMap->end(); ++subServiceIter)
    {
      std::string                       subService = subServiceIter->first;
      std::map<std::string, uint64_t>*  metricMap  = subServiceIter->second;

      metricMap->clear();
      delete metricMap;
    }
    servMap->clear();
    delete servMap;
  }
  metrics.clear();

  semGive();
}
<|endoftext|>


<commit_before>#include "precompiled.h"
//
// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.

#include "libGLESv2/renderer/SwapChain9.h"
#include "libGLESv2/renderer/renderer9_utils.h"
#include "libGLESv2/renderer/Renderer9.h"

namespace rx
{

SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle,
                       GLenum backBufferFormat, GLenum depthBufferFormat)
    : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat)
{
    mSwapChain = NULL;
    mBackBuffer = NULL;
    mDepthStencil = NULL;
    mRenderTarget = NULL;
    mOffscreenTexture = NULL;
    mWidth = -1;
    mHeight = -1;
    mSwapInterval = -1;
}

SwapChain9::~SwapChain9()
{
    release();
}

void SwapChain9::release()
{
    if (mSwapChain)
    {
        mSwapChain->Release();
        mSwapChain = NULL;
    }

    if (mBackBuffer)
    {
        mBackBuffer->Release();
        mBackBuffer = NULL;
    }

    if (mDepthStencil)
    {
        mDepthStencil->Release();
        mDepthStencil = NULL;
    }

    if (mRenderTarget)
    {
        mRenderTarget->Release();
        mRenderTarget = NULL;
    }

    if (mOffscreenTexture)
    {
        mOffscreenTexture->Release();
        mOffscreenTexture = NULL;
    }

    if (mWindow)
        mShareHandle = NULL;
}

static DWORD convertInterval(EGLint interval)
{
#if ANGLE_FORCE_VSYNC_OFF
    return D3DPRESENT_INTERVAL_IMMEDIATE;
#else
    switch(interval)
    {
      case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
      case 1: return D3DPRESENT_INTERVAL_ONE;
      case 2: return D3DPRESENT_INTERVAL_TWO;
      case 3: return D3DPRESENT_INTERVAL_THREE;
      case 4: return D3DPRESENT_INTERVAL_FOUR;
      default: UNREACHABLE();
    }

    return D3DPRESENT_INTERVAL_DEFAULT;
#endif
}

EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
{
    // D3D9 does not support resizing swap chains without recreating them
    return reset(backbufferWidth, backbufferHeight, mSwapInterval);
}

EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
{
    IDirect3DDevice9 *device = mRenderer->getDevice();

    if (device == NULL)
    {
        return EGL_BAD_ACCESS;
    }

    // Evict all non-render target textures to system memory and release all resources
    // before reallocating them to free up as much video memory as possible.
    device->EvictManagedResources();

    HRESULT result;

    // Release specific resources to free up memory for the new render target, while the
    // old render target still exists for the purpose of preserving its contents.
    if (mSwapChain)
    {
        mSwapChain->Release();
        mSwapChain = NULL;
    }

    if (mBackBuffer)
    {
        mBackBuffer->Release();
        mBackBuffer = NULL;
    }

    if (mOffscreenTexture)
    {
        mOffscreenTexture->Release();
        mOffscreenTexture = NULL;
    }

    if (mDepthStencil)
    {
        mDepthStencil->Release();
        mDepthStencil = NULL;
    }

    HANDLE *pShareHandle = NULL;
    if (!mWindow && mRenderer->getShareHandleSupport())
    {
        pShareHandle = &mShareHandle;
    }

    result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
                                   gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat), D3DPOOL_DEFAULT,
                                   &mOffscreenTexture, pShareHandle);
    if (FAILED(result))
    {
        ERR("Could not create offscreen texture: %08lX", result);
        release();

        if (d3d9::isDeviceLostError(result))
        {
            return EGL_CONTEXT_LOST;
        }
        else
        {
            return EGL_BAD_ALLOC;
        }
    }

    IDirect3DSurface9 *oldRenderTarget = mRenderTarget;

    result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
    ASSERT(SUCCEEDED(result));

    if (oldRenderTarget)
    {
        RECT rect =
        {
            0, 0,
            mWidth, mHeight
        };

        if (rect.right > static_cast<LONG>(backbufferWidth))
        {
            rect.right = backbufferWidth;
        }

        if (rect.bottom > static_cast<LONG>(backbufferHeight))
        {
            rect.bottom = backbufferHeight;
        }

        mRenderer->endScene();

        result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
        ASSERT(SUCCEEDED(result));

        oldRenderTarget->Release();
    }

    if (mWindow)
    {
        D3DPRESENT_PARAMETERS presentParameters = {0};
        presentParameters.AutoDepthStencilFormat = gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat);
        presentParameters.BackBufferCount = 1;
        presentParameters.BackBufferFormat = gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat);
        presentParameters.EnableAutoDepthStencil = FALSE;
        presentParameters.Flags = 0;
        presentParameters.hDeviceWindow = mWindow;
        presentParameters.MultiSampleQuality = 0;                  // FIXME: Unimplemented
        presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;   // FIXME: Unimplemented
        presentParameters.PresentationInterval = convertInterval(swapInterval);
        presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
        presentParameters.Windowed = TRUE;
        presentParameters.BackBufferWidth = backbufferWidth;
        presentParameters.BackBufferHeight = backbufferHeight;

        // http://crbug.com/140239
        // http://crbug.com/143434
        //
        // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
        // when using the integrated Intel. This rounds the width up rather than down.
        //
        // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
        // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur.
        if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL)
        {
            presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
        }

        result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);

        if (FAILED(result))
        {
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);

            ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
            release();

            if (d3d9::isDeviceLostError(result))
            {
                return EGL_CONTEXT_LOST;
            }
            else
            {
                return EGL_BAD_ALLOC;
            }
        }

        result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
        ASSERT(SUCCEEDED(result));
        InvalidateRect(mWindow, NULL, FALSE);
    }

    if (mDepthBufferFormat != GL_NONE)
    {
        result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
                                                   gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat),
                                                   D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);

        if (FAILED(result))
        {
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);

            ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
            release();

            if (d3d9::isDeviceLostError(result))
            {
                return EGL_CONTEXT_LOST;
            }
            else
            {
                return EGL_BAD_ALLOC;
            }
        }
    }

    mWidth = backbufferWidth;
    mHeight = backbufferHeight;
    mSwapInterval = swapInterval;

    return EGL_SUCCESS;
}

// parameters should be validated/clamped by caller
EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
{
    if (!mSwapChain)
    {
        return EGL_SUCCESS;
    }

    IDirect3DDevice9 *device = mRenderer->getDevice();

    // Disable all pipeline operations
    device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
    device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
    device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
    device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
    device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
    device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
    device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
    device->SetPixelShader(NULL);
    device->SetVertexShader(NULL);

    device->SetRenderTarget(0, mBackBuffer);
    device->SetDepthStencilSurface(NULL);

    device->SetTexture(0, mOffscreenTexture);
    device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
    device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
    device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
    device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
    device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
    device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
    device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);

    D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
    device->SetViewport(&viewport);

    float x1 = x - 0.5f;
    float y1 = (mHeight - y - height) - 0.5f;
    float x2 = (x + width) - 0.5f;
    float y2 = (mHeight - y) - 0.5f;

    float u1 = x / float(mWidth);
    float v1 = y / float(mHeight);
    float u2 = (x + width) / float(mWidth);
    float v2 = (y + height) / float(mHeight);

    float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
                        {x2, y1, 0.0f, 1.0f, u2, v2},
                        {x2, y2, 0.0f, 1.0f, u2, v1},
                        {x1, y2, 0.0f, 1.0f, u1, v1}};   // x, y, z, rhw, u, v

    mRenderer->startScene();
    device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
    mRenderer->endScene();

    device->SetTexture(0, NULL);

    RECT rect =
    {
        x, mHeight - y - height,
        x + width, mHeight - y
    };

    HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);

    mRenderer->markAllStateDirty();

    if (d3d9::isDeviceLostError(result))
    {
        return EGL_CONTEXT_LOST;
    }

    if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
    {
        return EGL_BAD_ALLOC;
    }

    ASSERT(SUCCEEDED(result));

    return EGL_SUCCESS;
}

// Increments refcount on surface.
// caller must Release() the returned surface
IDirect3DSurface9 *SwapChain9::getRenderTarget()
{
    if (mRenderTarget)
    {
        mRenderTarget->AddRef();
    }

    return mRenderTarget;
}

// Increments refcount on surface.
// caller must Release() the returned surface
IDirect3DSurface9 *SwapChain9::getDepthStencil()
{
    if (mDepthStencil)
    {
        mDepthStencil->AddRef();
    }

    return mDepthStencil;
}

// Increments refcount on texture.
// caller must Release() the returned texture
IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
{
    if (mOffscreenTexture)
    {
        mOffscreenTexture->AddRef();
    }

    return mOffscreenTexture;
}

SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain)
{
    ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain));
    return static_cast<rx::SwapChain9*>(swapChain);
}

void SwapChain9::recreate()
{
    if (!mSwapChain)
    {
        return;
    }

    IDirect3DDevice9 *device = mRenderer->getDevice();
    if (device == NULL)
    {
        return;
    }

    D3DPRESENT_PARAMETERS presentParameters;
    HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
    ASSERT(SUCCEEDED(result));

    IDirect3DSwapChain9* newSwapChain = NULL;
    result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
    if (FAILED(result))
    {
        return;
    }

    mSwapChain->Release();
    mSwapChain = newSwapChain;

    mBackBuffer->Release();
    result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
    ASSERT(SUCCEEDED(result));
}

}
<commit_msg>Ensure stream source frequency for stream 0 is set to 1 in swapRect for D3D9.<commit_after>#include "precompiled.h"
//
// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.

#include "libGLESv2/renderer/SwapChain9.h"
#include "libGLESv2/renderer/renderer9_utils.h"
#include "libGLESv2/renderer/Renderer9.h"

namespace rx
{

SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle,
                       GLenum backBufferFormat, GLenum depthBufferFormat)
    : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat)
{
    mSwapChain = NULL;
    mBackBuffer = NULL;
    mDepthStencil = NULL;
    mRenderTarget = NULL;
    mOffscreenTexture = NULL;
    mWidth = -1;
    mHeight = -1;
    mSwapInterval = -1;
}

SwapChain9::~SwapChain9()
{
    release();
}

void SwapChain9::release()
{
    if (mSwapChain)
    {
        mSwapChain->Release();
        mSwapChain = NULL;
    }

    if (mBackBuffer)
    {
        mBackBuffer->Release();
        mBackBuffer = NULL;
    }

    if (mDepthStencil)
    {
        mDepthStencil->Release();
        mDepthStencil = NULL;
    }

    if (mRenderTarget)
    {
        mRenderTarget->Release();
        mRenderTarget = NULL;
    }

    if (mOffscreenTexture)
    {
        mOffscreenTexture->Release();
        mOffscreenTexture = NULL;
    }

    if (mWindow)
        mShareHandle = NULL;
}

static DWORD convertInterval(EGLint interval)
{
#if ANGLE_FORCE_VSYNC_OFF
    return D3DPRESENT_INTERVAL_IMMEDIATE;
#else
    switch(interval)
    {
      case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
      case 1: return D3DPRESENT_INTERVAL_ONE;
      case 2: return D3DPRESENT_INTERVAL_TWO;
      case 3: return D3DPRESENT_INTERVAL_THREE;
      case 4: return D3DPRESENT_INTERVAL_FOUR;
      default: UNREACHABLE();
    }

    return D3DPRESENT_INTERVAL_DEFAULT;
#endif
}

EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
{
    // D3D9 does not support resizing swap chains without recreating them
    return reset(backbufferWidth, backbufferHeight, mSwapInterval);
}

EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
{
    IDirect3DDevice9 *device = mRenderer->getDevice();

    if (device == NULL)
    {
        return EGL_BAD_ACCESS;
    }

    // Evict all non-render target textures to system memory and release all resources
    // before reallocating them to free up as much video memory as possible.
    device->EvictManagedResources();

    HRESULT result;

    // Release specific resources to free up memory for the new render target, while the
    // old render target still exists for the purpose of preserving its contents.
    if (mSwapChain)
    {
        mSwapChain->Release();
        mSwapChain = NULL;
    }

    if (mBackBuffer)
    {
        mBackBuffer->Release();
        mBackBuffer = NULL;
    }

    if (mOffscreenTexture)
    {
        mOffscreenTexture->Release();
        mOffscreenTexture = NULL;
    }

    if (mDepthStencil)
    {
        mDepthStencil->Release();
        mDepthStencil = NULL;
    }

    HANDLE *pShareHandle = NULL;
    if (!mWindow && mRenderer->getShareHandleSupport())
    {
        pShareHandle = &mShareHandle;
    }

    result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
                                   gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat), D3DPOOL_DEFAULT,
                                   &mOffscreenTexture, pShareHandle);
    if (FAILED(result))
    {
        ERR("Could not create offscreen texture: %08lX", result);
        release();

        if (d3d9::isDeviceLostError(result))
        {
            return EGL_CONTEXT_LOST;
        }
        else
        {
            return EGL_BAD_ALLOC;
        }
    }

    IDirect3DSurface9 *oldRenderTarget = mRenderTarget;

    result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
    ASSERT(SUCCEEDED(result));

    if (oldRenderTarget)
    {
        RECT rect =
        {
            0, 0,
            mWidth, mHeight
        };

        if (rect.right > static_cast<LONG>(backbufferWidth))
        {
            rect.right = backbufferWidth;
        }

        if (rect.bottom > static_cast<LONG>(backbufferHeight))
        {
            rect.bottom = backbufferHeight;
        }

        mRenderer->endScene();

        result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
        ASSERT(SUCCEEDED(result));

        oldRenderTarget->Release();
    }

    if (mWindow)
    {
        D3DPRESENT_PARAMETERS presentParameters = {0};
        presentParameters.AutoDepthStencilFormat = gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat);
        presentParameters.BackBufferCount = 1;
        presentParameters.BackBufferFormat = gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat);
        presentParameters.EnableAutoDepthStencil = FALSE;
        presentParameters.Flags = 0;
        presentParameters.hDeviceWindow = mWindow;
        presentParameters.MultiSampleQuality = 0;                  // FIXME: Unimplemented
        presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;   // FIXME: Unimplemented
        presentParameters.PresentationInterval = convertInterval(swapInterval);
        presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
        presentParameters.Windowed = TRUE;
        presentParameters.BackBufferWidth = backbufferWidth;
        presentParameters.BackBufferHeight = backbufferHeight;

        // http://crbug.com/140239
        // http://crbug.com/143434
        //
        // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
        // when using the integrated Intel. This rounds the width up rather than down.
        //
        // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
        // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur.
        if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL)
        {
            presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
        }

        result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);

        if (FAILED(result))
        {
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);

            ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
            release();

            if (d3d9::isDeviceLostError(result))
            {
                return EGL_CONTEXT_LOST;
            }
            else
            {
                return EGL_BAD_ALLOC;
            }
        }

        result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
        ASSERT(SUCCEEDED(result));
        InvalidateRect(mWindow, NULL, FALSE);
    }

    if (mDepthBufferFormat != GL_NONE)
    {
        result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
                                                   gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat),
                                                   D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);

        if (FAILED(result))
        {
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);

            ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
            release();

            if (d3d9::isDeviceLostError(result))
            {
                return EGL_CONTEXT_LOST;
            }
            else
            {
                return EGL_BAD_ALLOC;
            }
        }
    }

    mWidth = backbufferWidth;
    mHeight = backbufferHeight;
    mSwapInterval = swapInterval;

    return EGL_SUCCESS;
}

// parameters should be validated/clamped by caller
EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
{
    if (!mSwapChain)
    {
        return EGL_SUCCESS;
    }

    IDirect3DDevice9 *device = mRenderer->getDevice();

    // Disable all pipeline operations
    device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
    device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
    device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
    device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
    device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
    device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
    device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
    device->SetPixelShader(NULL);
    device->SetVertexShader(NULL);

    device->SetRenderTarget(0, mBackBuffer);
    device->SetDepthStencilSurface(NULL);

    device->SetTexture(0, mOffscreenTexture);
    device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
    device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
    device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
    device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
    device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
    device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
    device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);

    for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++)
    {
        device->SetStreamSourceFreq(streamIndex, 1);
    }

    D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
    device->SetViewport(&viewport);

    float x1 = x - 0.5f;
    float y1 = (mHeight - y - height) - 0.5f;
    float x2 = (x + width) - 0.5f;
    float y2 = (mHeight - y) - 0.5f;

    float u1 = x / float(mWidth);
    float v1 = y / float(mHeight);
    float u2 = (x + width) / float(mWidth);
    float v2 = (y + height) / float(mHeight);

    float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
                        {x2, y1, 0.0f, 1.0f, u2, v2},
                        {x2, y2, 0.0f, 1.0f, u2, v1},
                        {x1, y2, 0.0f, 1.0f, u1, v1}};   // x, y, z, rhw, u, v

    mRenderer->startScene();
    device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
    mRenderer->endScene();

    device->SetTexture(0, NULL);

    RECT rect =
    {
        x, mHeight - y - height,
        x + width, mHeight - y
    };

    HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);

    mRenderer->markAllStateDirty();

    if (d3d9::isDeviceLostError(result))
    {
        return EGL_CONTEXT_LOST;
    }

    if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
    {
        return EGL_BAD_ALLOC;
    }

    ASSERT(SUCCEEDED(result));

    return EGL_SUCCESS;
}

// Increments refcount on surface.
// caller must Release() the returned surface
IDirect3DSurface9 *SwapChain9::getRenderTarget()
{
    if (mRenderTarget)
    {
        mRenderTarget->AddRef();
    }

    return mRenderTarget;
}

// Increments refcount on surface.
// caller must Release() the returned surface
IDirect3DSurface9 *SwapChain9::getDepthStencil()
{
    if (mDepthStencil)
    {
        mDepthStencil->AddRef();
    }

    return mDepthStencil;
}

// Increments refcount on texture.
// caller must Release() the returned texture
IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
{
    if (mOffscreenTexture)
    {
        mOffscreenTexture->AddRef();
    }

    return mOffscreenTexture;
}

SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain)
{
    ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain));
    return static_cast<rx::SwapChain9*>(swapChain);
}

void SwapChain9::recreate()
{
    if (!mSwapChain)
    {
        return;
    }

    IDirect3DDevice9 *device = mRenderer->getDevice();
    if (device == NULL)
    {
        return;
    }

    D3DPRESENT_PARAMETERS presentParameters;
    HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
    ASSERT(SUCCEEDED(result));

    IDirect3DSwapChain9* newSwapChain = NULL;
    result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
    if (FAILED(result))
    {
        return;
    }

    mSwapChain->Release();
    mSwapChain = newSwapChain;

    mBackBuffer->Release();
    result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
    ASSERT(SUCCEEDED(result));
}

}
<|endoftext|>