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

#include "chrome/browser/printing/print_dialog_gtk.h"

#include <gtk/gtkprintjob.h>
#include <gtk/gtkprintunixdialog.h>
#include <gtk/gtkpagesetupunixdialog.h>

#include "base/file_util.h"
#include "base/logging.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"

namespace {

// This is a temporary infobar designed to help gauge how many users are trying
// to print to printers that don't support PDF.
class PdfUnsupportedInfoBarDelegate : public LinkInfoBarDelegate {
 public:
  explicit PdfUnsupportedInfoBarDelegate(Browser* browser)
     : LinkInfoBarDelegate(NULL),
       browser_(browser) {
  }

  virtual ~PdfUnsupportedInfoBarDelegate() {}

  virtual std::wstring GetMessageTextWithOffset(size_t* link_offset) const {
    std::wstring message(L"Oops! Your printer does not support PDF. Please "
                         L"report this to us .");
    *link_offset = message.length() - 1;
    return message;
  }

  virtual std::wstring GetLinkText() const {
    return std::wstring(L"here");
  }

  virtual Type GetInfoBarType() {
    return ERROR_TYPE;
  }

  virtual bool LinkClicked(WindowOpenDisposition disposition) {
    browser_->OpenURL(
        GURL("http://code.google.com/p/chromium/issues/detail?id=22027"),
        GURL(), NEW_FOREGROUND_TAB, PageTransition::TYPED);
    return true;
  }

 private:
  Browser* browser_;
};

}  // namespace

// static
void PrintDialogGtk::CreatePrintDialogForPdf(const FilePath& path) {
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableFunction(&PrintDialogGtk::CreateDialogImpl, path));
}

// static
void PrintDialogGtk::CreateDialogImpl(const FilePath& path) {
  new PrintDialogGtk(path);
}

PrintDialogGtk::PrintDialogGtk(const FilePath& path_to_pdf)
    : path_to_pdf_(path_to_pdf),
      browser_(BrowserList::GetLastActive()) {
  GtkWindow* parent = browser_->window()->GetNativeHandle();

  // TODO(estade): We need a window title here.
  dialog_ = gtk_print_unix_dialog_new(NULL, parent);
  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);

  gtk_widget_show_all(dialog_);
}

PrintDialogGtk::~PrintDialogGtk() {
}

void PrintDialogGtk::OnResponse(gint response_id) {
  gtk_widget_hide(dialog_);

  switch (response_id) {
    case GTK_RESPONSE_OK: {
      GtkPrinter* printer =
          gtk_print_unix_dialog_get_selected_printer(
              GTK_PRINT_UNIX_DIALOG(dialog_));
      if (!gtk_printer_accepts_pdf(printer)) {
        browser_->GetSelectedTabContents()->AddInfoBar(
            new PdfUnsupportedInfoBarDelegate(browser_));
        break;
      }

      GtkPrintSettings* settings =
          gtk_print_unix_dialog_get_settings(
              GTK_PRINT_UNIX_DIALOG(dialog_));
      GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(
              GTK_PRINT_UNIX_DIALOG(dialog_));

      GtkPrintJob* job =
          gtk_print_job_new(path_to_pdf_.value().c_str(), printer,
                            settings, setup);
      gtk_print_job_set_source_file(job, path_to_pdf_.value().c_str(), NULL);
      gtk_print_job_send(job, OnJobCompletedThunk, this, NULL);
      g_object_unref(settings);
      // Success; return early.
      return;
    }
    case GTK_RESPONSE_DELETE_EVENT:  // Fall through.
    case GTK_RESPONSE_CANCEL: {
      break;
    }
    case GTK_RESPONSE_APPLY:
    default: {
      NOTREACHED();
    }
  }

  // Delete this dialog.
  OnJobCompleted(NULL, NULL);
}

void PrintDialogGtk::OnJobCompleted(GtkPrintJob* job, GError* error) {
  gtk_widget_destroy(dialog_);

  if (error)
    LOG(ERROR) << "Printing failed: " << error->message;

  if (job)
    g_object_unref(job);

  file_util::Delete(path_to_pdf_, false);

  delete this;
}
<commit_msg>Linux: Don't show all of the print dialog's children, including widgets normally not displayed.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/printing/print_dialog_gtk.h"

#include <gtk/gtkprintjob.h>
#include <gtk/gtkprintunixdialog.h>
#include <gtk/gtkpagesetupunixdialog.h>

#include "base/file_util.h"
#include "base/logging.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"

namespace {

// This is a temporary infobar designed to help gauge how many users are trying
// to print to printers that don't support PDF.
class PdfUnsupportedInfoBarDelegate : public LinkInfoBarDelegate {
 public:
  explicit PdfUnsupportedInfoBarDelegate(Browser* browser)
     : LinkInfoBarDelegate(NULL),
       browser_(browser) {
  }

  virtual ~PdfUnsupportedInfoBarDelegate() {}

  virtual std::wstring GetMessageTextWithOffset(size_t* link_offset) const {
    std::wstring message(L"Oops! Your printer does not support PDF. Please "
                         L"report this to us .");
    *link_offset = message.length() - 1;
    return message;
  }

  virtual std::wstring GetLinkText() const {
    return std::wstring(L"here");
  }

  virtual Type GetInfoBarType() {
    return ERROR_TYPE;
  }

  virtual bool LinkClicked(WindowOpenDisposition disposition) {
    browser_->OpenURL(
        GURL("http://code.google.com/p/chromium/issues/detail?id=22027"),
        GURL(), NEW_FOREGROUND_TAB, PageTransition::TYPED);
    return true;
  }

 private:
  Browser* browser_;
};

}  // namespace

// static
void PrintDialogGtk::CreatePrintDialogForPdf(const FilePath& path) {
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableFunction(&PrintDialogGtk::CreateDialogImpl, path));
}

// static
void PrintDialogGtk::CreateDialogImpl(const FilePath& path) {
  new PrintDialogGtk(path);
}

PrintDialogGtk::PrintDialogGtk(const FilePath& path_to_pdf)
    : path_to_pdf_(path_to_pdf),
      browser_(BrowserList::GetLastActive()) {
  GtkWindow* parent = browser_->window()->GetNativeHandle();

  // TODO(estade): We need a window title here.
  dialog_ = gtk_print_unix_dialog_new(NULL, parent);
  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);

  gtk_widget_show(dialog_);
}

PrintDialogGtk::~PrintDialogGtk() {
}

void PrintDialogGtk::OnResponse(gint response_id) {
  gtk_widget_hide(dialog_);

  switch (response_id) {
    case GTK_RESPONSE_OK: {
      GtkPrinter* printer =
          gtk_print_unix_dialog_get_selected_printer(
              GTK_PRINT_UNIX_DIALOG(dialog_));
      if (!gtk_printer_accepts_pdf(printer)) {
        browser_->GetSelectedTabContents()->AddInfoBar(
            new PdfUnsupportedInfoBarDelegate(browser_));
        break;
      }

      GtkPrintSettings* settings =
          gtk_print_unix_dialog_get_settings(
              GTK_PRINT_UNIX_DIALOG(dialog_));
      GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(
              GTK_PRINT_UNIX_DIALOG(dialog_));

      GtkPrintJob* job =
          gtk_print_job_new(path_to_pdf_.value().c_str(), printer,
                            settings, setup);
      gtk_print_job_set_source_file(job, path_to_pdf_.value().c_str(), NULL);
      gtk_print_job_send(job, OnJobCompletedThunk, this, NULL);
      g_object_unref(settings);
      // Success; return early.
      return;
    }
    case GTK_RESPONSE_DELETE_EVENT:  // Fall through.
    case GTK_RESPONSE_CANCEL: {
      break;
    }
    case GTK_RESPONSE_APPLY:
    default: {
      NOTREACHED();
    }
  }

  // Delete this dialog.
  OnJobCompleted(NULL, NULL);
}

void PrintDialogGtk::OnJobCompleted(GtkPrintJob* job, GError* error) {
  gtk_widget_destroy(dialog_);

  if (error)
    LOG(ERROR) << "Printing failed: " << error->message;

  if (job)
    g_object_unref(job);

  file_util::Delete(path_to_pdf_, false);

  delete this;
}
<|endoftext|>


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

#include "chrome/common/safe_browsing/zip_analyzer.h"

#include "base/logging.h"
#include "chrome/common/safe_browsing/download_protection_util.h"
#include "components/zip/zip_reader.h"

namespace safe_browsing {
namespace zip_analyzer {

void AnalyzeZipFile(base::PlatformFile zip_file, Results* results) {
  zip::ZipReader reader;
  if (!reader.OpenFromPlatformFile(zip_file)) {
    VLOG(1) << "Failed to open zip file";
    return;
  }

  for (; reader.HasMore(); reader.AdvanceToNextEntry()) {
    if (!reader.OpenCurrentEntryInZip()) {
      VLOG(1) << "Failed to open current entry in zip file";
      continue;
    }
    const base::FilePath& file = reader.current_entry_info()->file_path();
    if (download_protection_util::IsBinaryFile(file)) {
      // Don't consider an archived archive to be executable, but record
      // a histogram.
      if (download_protection_util::IsArchiveFile(file)) {
        results->has_archive = true;
      } else {
        VLOG(2) << "Downloaded a zipped executable: " << file.value();
        results->has_executable = true;
        break;
      }
    } else {
      VLOG(3) << "Ignoring non-binary file: " << file.value();
    }
  }
  results->success = true;
}

}  // namespace zip_analyzer
}  // namespace safe_browsing
<commit_msg>Check for errors when calling ZipReader::AdvanceToNextEntry in Safe Browsing download checks.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/safe_browsing/zip_analyzer.h"

#include "base/logging.h"
#include "chrome/common/safe_browsing/download_protection_util.h"
#include "components/zip/zip_reader.h"

namespace safe_browsing {
namespace zip_analyzer {

void AnalyzeZipFile(base::PlatformFile zip_file, Results* results) {
  zip::ZipReader reader;
  if (!reader.OpenFromPlatformFile(zip_file)) {
    VLOG(1) << "Failed to open zip file";
    return;
  }

  bool advanced = true;
  for (; reader.HasMore(); advanced = reader.AdvanceToNextEntry()) {
    if (!advanced) {
      VLOG(1) << "Could not advance to next entry, aborting zip scan.";
      return;
    }
    if (!reader.OpenCurrentEntryInZip()) {
      VLOG(1) << "Failed to open current entry in zip file";
      continue;
    }
    const base::FilePath& file = reader.current_entry_info()->file_path();
    if (download_protection_util::IsBinaryFile(file)) {
      // Don't consider an archived archive to be executable, but record
      // a histogram.
      if (download_protection_util::IsArchiveFile(file)) {
        results->has_archive = true;
      } else {
        VLOG(2) << "Downloaded a zipped executable: " << file.value();
        results->has_executable = true;
        break;
      }
    } else {
      VLOG(3) << "Ignoring non-binary file: " << file.value();
    }
  }
  results->success = true;
}

}  // namespace zip_analyzer
}  // namespace safe_browsing
<|endoftext|>


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

#include "base/file_util.h"
#include "base/gfx/rect.h"
#include "base/path_service.h"
#include "base/perftimer.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"

using base::TimeDelta;

namespace {

class NewTabUIStartupTest : public UITest {
 public:
  NewTabUIStartupTest() {
    show_window_ = true;
  }

  void SetUp() {}
  void TearDown() {}

  static const int kNumCycles = 5;

  void UseReferenceBuild() {
    FilePath dir;
    PathService::Get(chrome::DIR_TEST_TOOLS, &dir);
    dir = dir.AppendASCII("reference_build");
#if defined(OS_WIN)
    dir = dir.AppendASCII("chrome");
#elif defined(OS_LINUX)
    dir = dir.AppendASCII("chrome_linux");
#elif defined(OS_MACOSX)
    dir = dir.AppendASCII("chrome_mac");
#endif
    browser_directory_ = dir;
  }

  void PrintTimings(const char* label, TimeDelta timings[kNumCycles],
                    bool important) {
    std::string times;
    for (int i = 0; i < kNumCycles; ++i)
      StringAppendF(&times, "%.2f,", timings[i].InMillisecondsF());
    PrintResultList("new_tab", "", label, times, "ms", important);
  }

  void InitProfile(UITest::ProfileType profile_type) {
    profile_type_ = profile_type;

    // Install the location of the test profile file.
    set_template_user_data(UITest::ComputeTypicalUserDataSource(
        profile_type));

    // Disable the first run notification because it has an animation which
    // masks any real performance regressions.
    launch_arguments_.AppendSwitch(switches::kDisableNewTabFirstRun);
  }

  // Run the test, by bringing up a browser and timing the new tab startup.
  // |want_warm| is true if we should output warm-disk timings, false if
  // we should report cold timings.
  void RunStartupTest(const char* label, bool want_warm, bool important,
                      UITest::ProfileType profile_type) {
    InitProfile(profile_type);

    TimeDelta timings[kNumCycles];
    for (int i = 0; i < kNumCycles; ++i) {
      UITest::SetUp();

      // Switch to the "new tab" tab, which should be any new tab after the
      // first (the first is about:blank).
      scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
      ASSERT_TRUE(window.get());

      // We resize the window so that we hit the normal layout of the NTP and
      // not the small layout mode.
#if defined(OS_WIN)
      // TODO(port): SetBounds returns false when not implemented.
      // It is OK to comment out the resize since it will still be useful to
      // test the default size of the window.
      ASSERT_TRUE(window->GetWindow().get()->SetBounds(gfx::Rect(1000, 1000)));
#endif
      int tab_count = -1;
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(1, tab_count);

      // Hit ctl-t and wait for the tab to load.
      window->RunCommand(IDC_NEW_TAB);
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(2, tab_count);
      int load_time;
      ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

      if (want_warm) {
        // Bring up a second tab, now that we've already shown one tab.
        window->RunCommand(IDC_NEW_TAB);
        ASSERT_TRUE(window->GetTabCount(&tab_count));
        ASSERT_EQ(3, tab_count);
        ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));
      }
      timings[i] = TimeDelta::FromMilliseconds(load_time);

      window = NULL;
      UITest::TearDown();
    }

    PrintTimings(label, timings, important);
  }

  void RunNewTabTimingTest() {
    InitProfile(UITest::DEFAULT_THEME);

    TimeDelta scriptstart_times[kNumCycles];
    TimeDelta domcontentloaded_times[kNumCycles];
    TimeDelta onload_times[kNumCycles];

    for (int i = 0; i < kNumCycles; ++i) {
      UITest::SetUp();

      // Switch to the "new tab" tab, which should be any new tab after the
      // first (the first is about:blank).
      scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
      ASSERT_TRUE(window.get());

      // We resize the window so that we hit the normal layout of the NTP and
      // not the small layout mode.
#if defined(OS_WIN)
      // TODO(port): SetBounds returns false when not implemented.
      // It is OK to comment out the resize since it will still be useful to
      // test the default size of the window.
      ASSERT_TRUE(window->GetWindow().get()->SetBounds(gfx::Rect(1000, 1000)));
#endif
      int tab_count = -1;
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(1, tab_count);

      // Hit ctl-t and wait for the tab to load.
      window->RunCommand(IDC_NEW_TAB);
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(2, tab_count);
      int duration;
      ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&duration));

      // Collect the timing information.
      ASSERT_TRUE(automation()->GetMetricEventDuration("Tab.NewTabScriptStart",
          &duration));
      scriptstart_times[i] = TimeDelta::FromMilliseconds(duration);

      ASSERT_TRUE(automation()->GetMetricEventDuration(
          "Tab.NewTabDOMContentLoaded", &duration));
      domcontentloaded_times[i] = TimeDelta::FromMilliseconds(duration);

      ASSERT_TRUE(automation()->GetMetricEventDuration("Tab.NewTabOnload",
          &duration));
      onload_times[i] = TimeDelta::FromMilliseconds(duration);

      window = NULL;
      UITest::TearDown();
    }

    PrintTimings("script_start", scriptstart_times, false /* important */);
    PrintTimings("domcontent_loaded", domcontentloaded_times,
                 false /* important */);
    PrintTimings("onload", onload_times, false /* important */);
  }
};

#if !defined(OS_MACOSX)
// TODO(tc): Update the Mac reference build to support
// WaitForInitialNewTabUILoad.
TEST_F(NewTabUIStartupTest, PerfRefCold) {
  UseReferenceBuild();
  RunStartupTest("tab_cold_ref", false /* cold */, true /* important */,
                 UITest::DEFAULT_THEME);
}
#endif

TEST_F(NewTabUIStartupTest, PerfCold) {
  RunStartupTest("tab_cold", false /* cold */, true /* important */,
                 UITest::DEFAULT_THEME);
}

#if !defined(OS_MACOSX)
// TODO(tc): Update the Mac reference build to support
// WaitForInitialNewTabUILoad.
TEST_F(NewTabUIStartupTest, PerfRefWarm) {
  UseReferenceBuild();
  RunStartupTest("tab_warm_ref", true /* warm */, true /* not important */,
                 UITest::DEFAULT_THEME);
}
#endif

TEST_F(NewTabUIStartupTest, PerfWarm) {
  RunStartupTest("tab_warm", true /* warm */, true /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(NewTabUIStartupTest, ComplexThemeCold) {
  RunStartupTest("tab_complex_theme_cold", false /* cold */,
                 false /* not important */,
                 UITest::COMPLEX_THEME);
}

TEST_F(NewTabUIStartupTest, NewTabTimingTestsCold) {
  RunNewTabTimingTest();
}

#if defined(OS_LINUX)
TEST_F(NewTabUIStartupTest, GtkThemeCold) {
  RunStartupTest("tab_gtk_theme_cold", false /* cold */,
                 false /* not important */,
                 UITest::NATIVE_THEME);
}

TEST_F(NewTabUIStartupTest, NativeFrameCold) {
  RunStartupTest("tab_custom_frame_cold", false /* cold */,
                 false /* not important */,
                 UITest::CUSTOM_FRAME);
}

TEST_F(NewTabUIStartupTest, NativeFrameGtkThemeCold) {
  RunStartupTest("tab_custom_frame_gtk_theme_cold", false /* cold */,
                 false /* not important */,
                 UITest::CUSTOM_FRAME_NATIVE_THEME);
}
#endif

}  // namespace
<commit_msg>Disable New Tab UI Warm ref test on Linux too, it's failing there too.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/gfx/rect.h"
#include "base/path_service.h"
#include "base/perftimer.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"

using base::TimeDelta;

namespace {

class NewTabUIStartupTest : public UITest {
 public:
  NewTabUIStartupTest() {
    show_window_ = true;
  }

  void SetUp() {}
  void TearDown() {}

  static const int kNumCycles = 5;

  void UseReferenceBuild() {
    FilePath dir;
    PathService::Get(chrome::DIR_TEST_TOOLS, &dir);
    dir = dir.AppendASCII("reference_build");
#if defined(OS_WIN)
    dir = dir.AppendASCII("chrome");
#elif defined(OS_LINUX)
    dir = dir.AppendASCII("chrome_linux");
#elif defined(OS_MACOSX)
    dir = dir.AppendASCII("chrome_mac");
#endif
    browser_directory_ = dir;
  }

  void PrintTimings(const char* label, TimeDelta timings[kNumCycles],
                    bool important) {
    std::string times;
    for (int i = 0; i < kNumCycles; ++i)
      StringAppendF(&times, "%.2f,", timings[i].InMillisecondsF());
    PrintResultList("new_tab", "", label, times, "ms", important);
  }

  void InitProfile(UITest::ProfileType profile_type) {
    profile_type_ = profile_type;

    // Install the location of the test profile file.
    set_template_user_data(UITest::ComputeTypicalUserDataSource(
        profile_type));

    // Disable the first run notification because it has an animation which
    // masks any real performance regressions.
    launch_arguments_.AppendSwitch(switches::kDisableNewTabFirstRun);
  }

  // Run the test, by bringing up a browser and timing the new tab startup.
  // |want_warm| is true if we should output warm-disk timings, false if
  // we should report cold timings.
  void RunStartupTest(const char* label, bool want_warm, bool important,
                      UITest::ProfileType profile_type) {
    InitProfile(profile_type);

    TimeDelta timings[kNumCycles];
    for (int i = 0; i < kNumCycles; ++i) {
      UITest::SetUp();

      // Switch to the "new tab" tab, which should be any new tab after the
      // first (the first is about:blank).
      scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
      ASSERT_TRUE(window.get());

      // We resize the window so that we hit the normal layout of the NTP and
      // not the small layout mode.
#if defined(OS_WIN)
      // TODO(port): SetBounds returns false when not implemented.
      // It is OK to comment out the resize since it will still be useful to
      // test the default size of the window.
      ASSERT_TRUE(window->GetWindow().get()->SetBounds(gfx::Rect(1000, 1000)));
#endif
      int tab_count = -1;
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(1, tab_count);

      // Hit ctl-t and wait for the tab to load.
      window->RunCommand(IDC_NEW_TAB);
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(2, tab_count);
      int load_time;
      ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

      if (want_warm) {
        // Bring up a second tab, now that we've already shown one tab.
        window->RunCommand(IDC_NEW_TAB);
        ASSERT_TRUE(window->GetTabCount(&tab_count));
        ASSERT_EQ(3, tab_count);
        ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));
      }
      timings[i] = TimeDelta::FromMilliseconds(load_time);

      window = NULL;
      UITest::TearDown();
    }

    PrintTimings(label, timings, important);
  }

  void RunNewTabTimingTest() {
    InitProfile(UITest::DEFAULT_THEME);

    TimeDelta scriptstart_times[kNumCycles];
    TimeDelta domcontentloaded_times[kNumCycles];
    TimeDelta onload_times[kNumCycles];

    for (int i = 0; i < kNumCycles; ++i) {
      UITest::SetUp();

      // Switch to the "new tab" tab, which should be any new tab after the
      // first (the first is about:blank).
      scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
      ASSERT_TRUE(window.get());

      // We resize the window so that we hit the normal layout of the NTP and
      // not the small layout mode.
#if defined(OS_WIN)
      // TODO(port): SetBounds returns false when not implemented.
      // It is OK to comment out the resize since it will still be useful to
      // test the default size of the window.
      ASSERT_TRUE(window->GetWindow().get()->SetBounds(gfx::Rect(1000, 1000)));
#endif
      int tab_count = -1;
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(1, tab_count);

      // Hit ctl-t and wait for the tab to load.
      window->RunCommand(IDC_NEW_TAB);
      ASSERT_TRUE(window->GetTabCount(&tab_count));
      ASSERT_EQ(2, tab_count);
      int duration;
      ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&duration));

      // Collect the timing information.
      ASSERT_TRUE(automation()->GetMetricEventDuration("Tab.NewTabScriptStart",
          &duration));
      scriptstart_times[i] = TimeDelta::FromMilliseconds(duration);

      ASSERT_TRUE(automation()->GetMetricEventDuration(
          "Tab.NewTabDOMContentLoaded", &duration));
      domcontentloaded_times[i] = TimeDelta::FromMilliseconds(duration);

      ASSERT_TRUE(automation()->GetMetricEventDuration("Tab.NewTabOnload",
          &duration));
      onload_times[i] = TimeDelta::FromMilliseconds(duration);

      window = NULL;
      UITest::TearDown();
    }

    PrintTimings("script_start", scriptstart_times, false /* important */);
    PrintTimings("domcontent_loaded", domcontentloaded_times,
                 false /* important */);
    PrintTimings("onload", onload_times, false /* important */);
  }
};

#if !defined(OS_MACOSX)
// TODO(tc): Update the Mac reference build to support
// WaitForInitialNewTabUILoad.
TEST_F(NewTabUIStartupTest, PerfRefCold) {
  UseReferenceBuild();
  RunStartupTest("tab_cold_ref", false /* cold */, true /* important */,
                 UITest::DEFAULT_THEME);
}
#endif

TEST_F(NewTabUIStartupTest, PerfCold) {
  RunStartupTest("tab_cold", false /* cold */, true /* important */,
                 UITest::DEFAULT_THEME);
}

#if defined(OS_WIN)
// TODO(tc): Update the Mac reference build to support
// WaitForInitialNewTabUILoad.
// TODO(tc): This is failing on Linux too.
TEST_F(NewTabUIStartupTest, PerfRefWarm) {
  UseReferenceBuild();
  RunStartupTest("tab_warm_ref", true /* warm */, true /* not important */,
                 UITest::DEFAULT_THEME);
}
#endif

TEST_F(NewTabUIStartupTest, PerfWarm) {
  RunStartupTest("tab_warm", true /* warm */, true /* not important */,
                 UITest::DEFAULT_THEME);
}

TEST_F(NewTabUIStartupTest, ComplexThemeCold) {
  RunStartupTest("tab_complex_theme_cold", false /* cold */,
                 false /* not important */,
                 UITest::COMPLEX_THEME);
}

TEST_F(NewTabUIStartupTest, NewTabTimingTestsCold) {
  RunNewTabTimingTest();
}

#if defined(OS_LINUX)
TEST_F(NewTabUIStartupTest, GtkThemeCold) {
  RunStartupTest("tab_gtk_theme_cold", false /* cold */,
                 false /* not important */,
                 UITest::NATIVE_THEME);
}

TEST_F(NewTabUIStartupTest, NativeFrameCold) {
  RunStartupTest("tab_custom_frame_cold", false /* cold */,
                 false /* not important */,
                 UITest::CUSTOM_FRAME);
}

TEST_F(NewTabUIStartupTest, NativeFrameGtkThemeCold) {
  RunStartupTest("tab_custom_frame_gtk_theme_cold", false /* cold */,
                 false /* not important */,
                 UITest::CUSTOM_FRAME_NATIVE_THEME);
}
#endif

}  // namespace
<|endoftext|>


<commit_before>/*
  Firmata.cpp - Firmata library
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.
*/

//******************************************************************************
//* Includes
//******************************************************************************

#include "BLE_Firmata.h"

extern "C" {
#include <string.h>
#include <stdlib.h>
}

//******************************************************************************
//* Support Functions
//******************************************************************************

void BLE_FirmataClass::sendValueAsTwo7bitBytes(int value)
{
  FirmataSerial.write(value & B01111111); // LSB
  FirmataSerial.write(value >> 7 & B01111111); // MSB
}

void BLE_FirmataClass::startSysex(void)
{
  FirmataSerial.write(START_SYSEX);
}

void BLE_FirmataClass::endSysex(void)
{
  FirmataSerial.write(END_SYSEX);
}

//******************************************************************************
//* Constructors
//******************************************************************************

BLE_FirmataClass::BLE_FirmataClass(Adafruit_BLE_UART &s) : FirmataSerial(s)
{
  firmwareVersionCount = 0;
  systemReset();
}

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

/* begin method for overriding default serial bitrate */
void BLE_FirmataClass::begin(void)
{
  blinkVersion();
  printVersion();
  printFirmwareVersion();
}

void BLE_FirmataClass::begin(Adafruit_BLE_UART &s)
{
  FirmataSerial = s;
  systemReset();
  printVersion();
  printFirmwareVersion();
}

// output the protocol version message to the serial port
void BLE_FirmataClass::printVersion(void) {
  FirmataSerial.write(REPORT_VERSION);
  FirmataSerial.write(FIRMATA_MAJOR_VERSION);
  FirmataSerial.write(FIRMATA_MINOR_VERSION);
}

void BLE_FirmataClass::blinkVersion(void)
{
  // flash the pin with the protocol version
  pinMode(VERSION_BLINK_PIN,OUTPUT);
  pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210);
  delay(250);
  pin13strobe(FIRMATA_MINOR_VERSION, 40, 210);
  delay(125);
}

void BLE_FirmataClass::printFirmwareVersion(void)
{
  byte i;

  if(firmwareVersionCount) { // make sure that the name has been set before reporting
    startSysex();
    FirmataSerial.write(REPORT_FIRMWARE);
    FirmataSerial.write(firmwareVersionVector[0]); // major version number
    FirmataSerial.write(firmwareVersionVector[1]); // minor version number
    for(i=2; i<firmwareVersionCount; ++i) {
      sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
    }
    endSysex();
  }
}

void BLE_FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{
  const char *filename;
  char *extension;

  // parse out ".cpp" and "applet/" that comes from using __FILE__
  extension = strstr(name, ".cpp");
  filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
  // add two bytes for version numbers
  if(extension && filename) {
    firmwareVersionCount = extension - filename + 2;
  } else {
    firmwareVersionCount = strlen(name) + 2;
    filename = name;
  }
  firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
  firmwareVersionVector[firmwareVersionCount] = 0;
  firmwareVersionVector[0] = major;
  firmwareVersionVector[1] = minor;
  strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
  // alas, no snprintf on Arduino
  //    snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
  //             (char)major, (char)minor, firmwareVersionVector);
}

//------------------------------------------------------------------------------
// Serial Receive Handling

int BLE_FirmataClass::available(void)
{
  return FirmataSerial.available();
}

void BLE_FirmataClass::processSysexMessage(void)
{
  switch(storedInputData[0]) { //first byte in buffer is command
  case REPORT_FIRMWARE:
    printFirmwareVersion();
    break;
  case STRING_DATA:
    if(currentStringCallback) {
      byte bufferLength = (sysexBytesRead - 1) / 2;
      char *buffer = (char*)malloc(bufferLength * sizeof(char));
      byte i = 1;
      byte j = 0;
      while(j < bufferLength) {
        buffer[j] = (char)storedInputData[i];
        i++;
        buffer[j] += (char)(storedInputData[i] << 7);
        i++;
        j++;
      }
      (*currentStringCallback)(buffer);
    }
    break;
  default:
    if(currentSysexCallback)
      (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
  }
}

void BLE_FirmataClass::processInput(void)
{
  int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data
  int command;

  if (inputData == -1) return;

  Serial.print("0x"); Serial.print(inputData, HEX); Serial.println(" ");

  if (parsingSysex) {
    if(inputData == END_SYSEX) {
      //stop sysex byte
      parsingSysex = false;
      //fire off handler function
      processSysexMessage();
    } else {
      //normal data byte - add to buffer
      storedInputData[sysexBytesRead] = inputData;
      sysexBytesRead++;
    }
  } else if( (waitForData > 0) && (inputData < 128) ) {
    waitForData--;
    storedInputData[waitForData] = inputData;
    if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
      switch(executeMultiByteCommand) {
      case ANALOG_MESSAGE:
        if(currentAnalogCallback) {
          (*currentAnalogCallback)(multiByteChannel,
                                   (storedInputData[0] << 7)
                                   + storedInputData[1]);
        }
        break;
      case DIGITAL_MESSAGE:
        if(currentDigitalCallback) {
          (*currentDigitalCallback)(multiByteChannel,
                                    (storedInputData[0] << 7)
                                    + storedInputData[1]);
        }
        break;
      case SET_PIN_MODE:
        if(currentPinModeCallback)
          (*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
        break;
      case REPORT_ANALOG:
        if(currentReportAnalogCallback)
          (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
        break;
      case REPORT_DIGITAL:
        if(currentReportDigitalCallback)
          (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
        break;
      }
      executeMultiByteCommand = 0;
    }
  } else {
    // remove channel info from command byte if less than 0xF0
    if(inputData < 0xF0) {
      command = inputData & 0xF0;
      multiByteChannel = inputData & 0x0F;
    } else {
      command = inputData;
      // commands in the 0xF* range don't use channel data
    }
    switch (command) {
    case ANALOG_MESSAGE:
    case DIGITAL_MESSAGE:
    case SET_PIN_MODE:
      waitForData = 2; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case REPORT_ANALOG:
    case REPORT_DIGITAL:
      waitForData = 1; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case START_SYSEX:
      parsingSysex = true;
      sysexBytesRead = 0;
      break;
    case SYSTEM_RESET:
      systemReset();
      break;
    case REPORT_VERSION:
      printVersion();
      break;
    }
  }
}

//------------------------------------------------------------------------------
// Serial Send Handling

// send an analog message
void BLE_FirmataClass::sendAnalog(byte pin, int value)
{
  // pin can only be 0-15, so chop higher bits
  FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF));
  sendValueAsTwo7bitBytes(value);
}

// send a single digital pin in a digital message
void BLE_FirmataClass::sendDigital(byte pin, int value)
{
  /* TODO add single pin digital messages to the protocol, this needs to
   * track the last digital data sent so that it can be sure to change just
   * one bit in the packet.  This is complicated by the fact that the
   * numbering of the pins will probably differ on Arduino, Wiring, and
   * other boards.  The DIGITAL_MESSAGE sends 14 bits at a time, but it is
   * probably easier to send 8 bit ports for any board with more than 14
   * digital pins.
   */

  // TODO: the digital message should not be sent on the serial port every
  // time sendDigital() is called.  Instead, it should add it to an int
  // which will be sent on a schedule.  If a pin changes more than once
  // before the digital message is sent on the serial port, it should send a
  // digital message for each change.

  //    if(value == 0)
  //        sendDigitalPortPair();
}

// send 14-bits in a single digital message (protocol v1)
// send an 8-bit port in a single digital message (protocol v2)
void BLE_FirmataClass::sendDigitalPort(byte portNumber, int portData)
{
  // create a three byte buffer
  uint8_t sendbuffer[3];

  sendbuffer[0] = DIGITAL_MESSAGE | (portNumber & 0xF);
  sendbuffer[1] = (byte)portData % 128; // Tx bits 0-6
  sendbuffer[2] = portData >> 7;  // Tx bits 7-13
  FirmataSerial.write(sendbuffer, 3);
}

void BLE_FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{
  byte i;
  startSysex();
  FirmataSerial.write(command);
  for(i=0; i<bytec; i++) {
    sendValueAsTwo7bitBytes(bytev[i]);
  }
  endSysex();
}

void BLE_FirmataClass::sendString(byte command, const char* string)
{
  sendSysex(command, strlen(string), (byte *)string);
}

// send a string as the protocol string type
void BLE_FirmataClass::sendString(const char* string)
{
  sendString(STRING_DATA, string);
}

// Internal Actions/////////////////////////////////////////////////////////////

// generic callbacks
void BLE_FirmataClass::attach(byte command, callbackFunction newFunction)
{
  switch(command) {
  case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
  case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
  case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
  case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
  case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
  }
}

void BLE_FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
  }
}

void BLE_FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{
  switch(command) {
  case STRING_DATA: currentStringCallback = newFunction; break;
  }
}

void BLE_FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{
  currentSysexCallback = newFunction;
}

void BLE_FirmataClass::detach(byte command)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
  case STRING_DATA: currentStringCallback = NULL; break;
  case START_SYSEX: currentSysexCallback = NULL; break;
  default:
    attach(command, (callbackFunction)NULL);
  }
}

// sysex callbacks
/*
 * this is too complicated for analogReceive, but maybe for Sysex?
 void BLE_FirmataClass::attachSysex(sysexFunction newFunction)
 {
 byte i;
 byte tmpCount = analogReceiveFunctionCount;
 analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
 analogReceiveFunctionCount++;
 analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
 for(i = 0; i < tmpCount; i++) {
 analogReceiveFunctionArray[i] = tmpArray[i];
 }
 analogReceiveFunctionArray[tmpCount] = newFunction;
 free(tmpArray);
 }
*/

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

// resets the system state upon a SYSTEM_RESET message from the host software
void BLE_FirmataClass::systemReset(void)
{
  byte i;

  waitForData = 0; // this flag says the next serial input will be data
  executeMultiByteCommand = 0; // execute this after getting multi-byte data
  multiByteChannel = 0; // channel data for multiByteCommands

  for(i=0; i<MAX_DATA_BYTES; i++) {
    storedInputData[i] = 0;
  }

  parsingSysex = false;
  sysexBytesRead = 0;

  if(currentSystemResetCallback)
    (*currentSystemResetCallback)();

  //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
}

// =============================================================================
// used for flashing the pin for the version number
void BLE_FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{
  byte i;
  pinMode(VERSION_BLINK_PIN, OUTPUT);
  for(i=0; i<count; i++) {
    delay(offInterval);
    digitalWrite(VERSION_BLINK_PIN, HIGH);
    delay(onInterval);
    digitalWrite(VERSION_BLINK_PIN, LOW);
  }
}

<commit_msg>format received messages nicer<commit_after>/*
  Firmata.cpp - Firmata library
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.
*/

//******************************************************************************
//* Includes
//******************************************************************************

#include "BLE_Firmata.h"

extern "C" {
#include <string.h>
#include <stdlib.h>
}

//******************************************************************************
//* Support Functions
//******************************************************************************

void BLE_FirmataClass::sendValueAsTwo7bitBytes(int value)
{
  FirmataSerial.write(value & B01111111); // LSB
  FirmataSerial.write(value >> 7 & B01111111); // MSB
}

void BLE_FirmataClass::startSysex(void)
{
  FirmataSerial.write(START_SYSEX);
}

void BLE_FirmataClass::endSysex(void)
{
  FirmataSerial.write(END_SYSEX);
}

//******************************************************************************
//* Constructors
//******************************************************************************

BLE_FirmataClass::BLE_FirmataClass(Adafruit_BLE_UART &s) : FirmataSerial(s)
{
  firmwareVersionCount = 0;
  systemReset();
}

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

/* begin method for overriding default serial bitrate */
void BLE_FirmataClass::begin(void)
{
  blinkVersion();
  printVersion();
  printFirmwareVersion();
}

void BLE_FirmataClass::begin(Adafruit_BLE_UART &s)
{
  FirmataSerial = s;
  systemReset();
  printVersion();
  printFirmwareVersion();
}

// output the protocol version message to the serial port
void BLE_FirmataClass::printVersion(void) {
  FirmataSerial.write(REPORT_VERSION);
  FirmataSerial.write(FIRMATA_MAJOR_VERSION);
  FirmataSerial.write(FIRMATA_MINOR_VERSION);
}

void BLE_FirmataClass::blinkVersion(void)
{
  // flash the pin with the protocol version
  pinMode(VERSION_BLINK_PIN,OUTPUT);
  pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210);
  delay(250);
  pin13strobe(FIRMATA_MINOR_VERSION, 40, 210);
  delay(125);
}

void BLE_FirmataClass::printFirmwareVersion(void)
{
  byte i;

  if(firmwareVersionCount) { // make sure that the name has been set before reporting
    startSysex();
    FirmataSerial.write(REPORT_FIRMWARE);
    FirmataSerial.write(firmwareVersionVector[0]); // major version number
    FirmataSerial.write(firmwareVersionVector[1]); // minor version number
    for(i=2; i<firmwareVersionCount; ++i) {
      sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
    }
    endSysex();
  }
}

void BLE_FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{
  const char *filename;
  char *extension;

  // parse out ".cpp" and "applet/" that comes from using __FILE__
  extension = strstr(name, ".cpp");
  filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
  // add two bytes for version numbers
  if(extension && filename) {
    firmwareVersionCount = extension - filename + 2;
  } else {
    firmwareVersionCount = strlen(name) + 2;
    filename = name;
  }
  firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
  firmwareVersionVector[firmwareVersionCount] = 0;
  firmwareVersionVector[0] = major;
  firmwareVersionVector[1] = minor;
  strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
  // alas, no snprintf on Arduino
  //    snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
  //             (char)major, (char)minor, firmwareVersionVector);
}

//------------------------------------------------------------------------------
// Serial Receive Handling

int BLE_FirmataClass::available(void)
{
  return FirmataSerial.available();
}

void BLE_FirmataClass::processSysexMessage(void)
{
  switch(storedInputData[0]) { //first byte in buffer is command
  case REPORT_FIRMWARE:
    printFirmwareVersion();
    break;
  case STRING_DATA:
    if(currentStringCallback) {
      byte bufferLength = (sysexBytesRead - 1) / 2;
      char *buffer = (char*)malloc(bufferLength * sizeof(char));
      byte i = 1;
      byte j = 0;
      while(j < bufferLength) {
        buffer[j] = (char)storedInputData[i];
        i++;
        buffer[j] += (char)(storedInputData[i] << 7);
        i++;
        j++;
      }
      (*currentStringCallback)(buffer);
    }
    break;
  default:
    if(currentSysexCallback)
      (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
  }
}

void BLE_FirmataClass::processInput(void)
{
  int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data
  int command;

  if (inputData == -1) return;

  Serial.print("0x"); Serial.print(inputData, HEX); Serial.print(" ");

  if (parsingSysex) {
    if(inputData == END_SYSEX) {
      //stop sysex byte
      parsingSysex = false;
      //fire off handler function
      processSysexMessage();
    } else {
      //normal data byte - add to buffer
      storedInputData[sysexBytesRead] = inputData;
      sysexBytesRead++;
    }
  } else if( (waitForData > 0) && (inputData < 128) ) {
    waitForData--;
    storedInputData[waitForData] = inputData;
    if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message

      Serial.println();

      switch(executeMultiByteCommand) {
      case ANALOG_MESSAGE:
        if(currentAnalogCallback) {
          (*currentAnalogCallback)(multiByteChannel,
                                   (storedInputData[0] << 7)
                                   + storedInputData[1]);
        }
        break;
      case DIGITAL_MESSAGE:
        if(currentDigitalCallback) {
          (*currentDigitalCallback)(multiByteChannel,
                                    (storedInputData[0] << 7)
                                    + storedInputData[1]);
        }
        break;
      case SET_PIN_MODE:
        if(currentPinModeCallback)
          (*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
        break;
      case REPORT_ANALOG:
        if(currentReportAnalogCallback)
          (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
        break;
      case REPORT_DIGITAL:
        if(currentReportDigitalCallback)
          (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
        break;
      }
      executeMultiByteCommand = 0;
    }
  } else {
    // remove channel info from command byte if less than 0xF0
    if(inputData < 0xF0) {
      command = inputData & 0xF0;
      multiByteChannel = inputData & 0x0F;
    } else {
      command = inputData;
      // commands in the 0xF* range don't use channel data
    }
    switch (command) {
    case ANALOG_MESSAGE:
    case DIGITAL_MESSAGE:
    case SET_PIN_MODE:
      waitForData = 2; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case REPORT_ANALOG:
    case REPORT_DIGITAL:
      waitForData = 1; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case START_SYSEX:
      parsingSysex = true;
      sysexBytesRead = 0;
      break;
    case SYSTEM_RESET:
      systemReset();
      break;
    case REPORT_VERSION:
      printVersion();
      break;
    }
  }
}

//------------------------------------------------------------------------------
// Serial Send Handling

// send an analog message
void BLE_FirmataClass::sendAnalog(byte pin, int value)
{
  // pin can only be 0-15, so chop higher bits
  FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF));
  sendValueAsTwo7bitBytes(value);
}

// send a single digital pin in a digital message
void BLE_FirmataClass::sendDigital(byte pin, int value)
{
  /* TODO add single pin digital messages to the protocol, this needs to
   * track the last digital data sent so that it can be sure to change just
   * one bit in the packet.  This is complicated by the fact that the
   * numbering of the pins will probably differ on Arduino, Wiring, and
   * other boards.  The DIGITAL_MESSAGE sends 14 bits at a time, but it is
   * probably easier to send 8 bit ports for any board with more than 14
   * digital pins.
   */

  // TODO: the digital message should not be sent on the serial port every
  // time sendDigital() is called.  Instead, it should add it to an int
  // which will be sent on a schedule.  If a pin changes more than once
  // before the digital message is sent on the serial port, it should send a
  // digital message for each change.

  //    if(value == 0)
  //        sendDigitalPortPair();
}

// send 14-bits in a single digital message (protocol v1)
// send an 8-bit port in a single digital message (protocol v2)
void BLE_FirmataClass::sendDigitalPort(byte portNumber, int portData)
{
  // create a three byte buffer
  uint8_t sendbuffer[3];

  sendbuffer[0] = DIGITAL_MESSAGE | (portNumber & 0xF);
  sendbuffer[1] = (byte)portData % 128; // Tx bits 0-6
  sendbuffer[2] = portData >> 7;  // Tx bits 7-13
  FirmataSerial.write(sendbuffer, 3);
}

void BLE_FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{
  byte i;
  startSysex();
  FirmataSerial.write(command);
  for(i=0; i<bytec; i++) {
    sendValueAsTwo7bitBytes(bytev[i]);
  }
  endSysex();
}

void BLE_FirmataClass::sendString(byte command, const char* string)
{
  sendSysex(command, strlen(string), (byte *)string);
}

// send a string as the protocol string type
void BLE_FirmataClass::sendString(const char* string)
{
  sendString(STRING_DATA, string);
}

// Internal Actions/////////////////////////////////////////////////////////////

// generic callbacks
void BLE_FirmataClass::attach(byte command, callbackFunction newFunction)
{
  switch(command) {
  case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
  case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
  case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
  case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
  case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
  }
}

void BLE_FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
  }
}

void BLE_FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{
  switch(command) {
  case STRING_DATA: currentStringCallback = newFunction; break;
  }
}

void BLE_FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{
  currentSysexCallback = newFunction;
}

void BLE_FirmataClass::detach(byte command)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
  case STRING_DATA: currentStringCallback = NULL; break;
  case START_SYSEX: currentSysexCallback = NULL; break;
  default:
    attach(command, (callbackFunction)NULL);
  }
}

// sysex callbacks
/*
 * this is too complicated for analogReceive, but maybe for Sysex?
 void BLE_FirmataClass::attachSysex(sysexFunction newFunction)
 {
 byte i;
 byte tmpCount = analogReceiveFunctionCount;
 analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
 analogReceiveFunctionCount++;
 analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
 for(i = 0; i < tmpCount; i++) {
 analogReceiveFunctionArray[i] = tmpArray[i];
 }
 analogReceiveFunctionArray[tmpCount] = newFunction;
 free(tmpArray);
 }
*/

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

// resets the system state upon a SYSTEM_RESET message from the host software
void BLE_FirmataClass::systemReset(void)
{
  byte i;

  waitForData = 0; // this flag says the next serial input will be data
  executeMultiByteCommand = 0; // execute this after getting multi-byte data
  multiByteChannel = 0; // channel data for multiByteCommands

  for(i=0; i<MAX_DATA_BYTES; i++) {
    storedInputData[i] = 0;
  }

  parsingSysex = false;
  sysexBytesRead = 0;

  if(currentSystemResetCallback)
    (*currentSystemResetCallback)();

  //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
}

// =============================================================================
// used for flashing the pin for the version number
void BLE_FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{
  byte i;
  pinMode(VERSION_BLINK_PIN, OUTPUT);
  for(i=0; i<count; i++) {
    delay(offInterval);
    digitalWrite(VERSION_BLINK_PIN, HIGH);
    delay(onInterval);
    digitalWrite(VERSION_BLINK_PIN, LOW);
  }
}

<|endoftext|>


<commit_before><commit_msg>coverity#707714: Uninitialized pointer<commit_after><|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

/*
 * Slot
 * Wrapper for functions connected to slots.
 * All this is needed so that a member_function_slot can keep a pointer to the address of the member function it wraps.
 */

#include <functional>
#include <utility>

namespace skui
{
  namespace core
  {
    namespace implementation
    {
      template<typename... ArgTypes>
      class slot
      {
      public:
        virtual ~slot() = default;

        virtual void operator()(const void* object, ArgTypes...) const = 0;

      protected:
        slot() = default;
      };

      template<typename Callable, typename... ArgTypes>
      class callable_slot : public slot<ArgTypes...>
      {
      public:
        callable_slot(Callable function_pointer_or_lambda) : callable(function_pointer_or_lambda) {}

        virtual void operator()(const void*, ArgTypes... args) const override { callable(args...); }

      private:
        Callable callable;
      };

      template<typename Callable>
      class callable_slot<Callable> : public slot<>
      {
      public:
        callable_slot(Callable function_pointer_or_lambda) : callable(function_pointer_or_lambda) {}

        virtual void operator()(const void*) const override { callable(); }

      private:
        Callable callable;
      };

      template<typename Callable, typename... ArgTypes>
      using function_slot = callable_slot<Callable, ArgTypes...>;

      template<typename Class, typename... ArgTypes>
      class member_function_slot : public slot<ArgTypes...>
      {
        using member_function_pointer = void(Class::*)(ArgTypes...);

      public:
        member_function_slot(member_function_pointer member_function)
          : member_function_ptr(member_function)
        {}

        void operator()(const void* object, ArgTypes... args) const override
        {
          return (const_cast<Class*>(static_cast<const Class*>(object))->*member_function_ptr)(args...);
        }

      private:
        member_function_pointer member_function_ptr;
      };

      template<typename Class>
      class member_function_slot<Class> : public slot<>
      {
        using member_function_pointer = void(Class::*)();

      public:
        member_function_slot(member_function_pointer member_function)
          : member_function_ptr(member_function)
        {}

        virtual void operator()(const void* object) const override
        {
          // Slot objects are stored as pointers to const, but the original connection was to a non-const object and member function
          return (const_cast<Class*>(static_cast<const Class*>(object))->*member_function_ptr)();
        }

      private:
        member_function_pointer member_function_ptr;
      };

      template<typename Class, typename... ArgTypes>
      class const_member_function_slot : public slot<ArgTypes...>
      {
        using const_member_function_pointer = void(Class::*)(ArgTypes...) const;

      public:
        const_member_function_slot(const_member_function_pointer const_member_function)
          : const_member_function_ptr(const_member_function)
        {}

        virtual void operator()(const void* object, ArgTypes... args) const override
        {
          return (static_cast<const Class*>(object)->*const_member_function_ptr)(args...);
        }

      private:
        const_member_function_pointer const_member_function_ptr;
      };

      template<typename Class>
      class const_member_function_slot<Class> : public slot<>
      {
        using const_member_function_pointer = void(Class::*)() const;

      public:
        const_member_function_slot(const_member_function_pointer const_member_function)
          : const_member_function_ptr(const_member_function)
        {}

        virtual void operator()(const void* object) const override
        {
          return (static_cast<const Class*>(object)->*const_member_function_ptr)();
        }

      private:
        const_member_function_pointer const_member_function_ptr;
      };
    }
  }
}
<commit_msg>Add missing header guards.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

/*
 * Slot
 * Wrapper for functions connected to slots.
 * All this is needed so that a member_function_slot can keep a pointer to the address of the member function it wraps.
 */

#ifndef SKUI_CORE_SLOT_H
#define SKUI_CORE_SLOT_H

#include <functional>
#include <utility>

namespace skui
{
  namespace core
  {
    namespace implementation
    {
      template<typename... ArgTypes>
      class slot
      {
      public:
        virtual ~slot() = default;

        virtual void operator()(const void* object, ArgTypes...) const = 0;

      protected:
        slot() = default;
      };

      template<typename Callable, typename... ArgTypes>
      class callable_slot : public slot<ArgTypes...>
      {
      public:
        callable_slot(Callable function_pointer_or_lambda) : callable(function_pointer_or_lambda) {}

        virtual void operator()(const void*, ArgTypes... args) const override { callable(args...); }

      private:
        Callable callable;
      };

      template<typename Callable>
      class callable_slot<Callable> : public slot<>
      {
      public:
        callable_slot(Callable function_pointer_or_lambda) : callable(function_pointer_or_lambda) {}

        virtual void operator()(const void*) const override { callable(); }

      private:
        Callable callable;
      };

      template<typename Callable, typename... ArgTypes>
      using function_slot = callable_slot<Callable, ArgTypes...>;

      template<typename Class, typename... ArgTypes>
      class member_function_slot : public slot<ArgTypes...>
      {
        using member_function_pointer = void(Class::*)(ArgTypes...);

      public:
        member_function_slot(member_function_pointer member_function)
          : member_function_ptr(member_function)
        {}

        void operator()(const void* object, ArgTypes... args) const override
        {
          return (const_cast<Class*>(static_cast<const Class*>(object))->*member_function_ptr)(args...);
        }

      private:
        member_function_pointer member_function_ptr;
      };

      template<typename Class>
      class member_function_slot<Class> : public slot<>
      {
        using member_function_pointer = void(Class::*)();

      public:
        member_function_slot(member_function_pointer member_function)
          : member_function_ptr(member_function)
        {}

        virtual void operator()(const void* object) const override
        {
          // Slot objects are stored as pointers to const, but the original connection was to a non-const object and member function
          return (const_cast<Class*>(static_cast<const Class*>(object))->*member_function_ptr)();
        }

      private:
        member_function_pointer member_function_ptr;
      };

      template<typename Class, typename... ArgTypes>
      class const_member_function_slot : public slot<ArgTypes...>
      {
        using const_member_function_pointer = void(Class::*)(ArgTypes...) const;

      public:
        const_member_function_slot(const_member_function_pointer const_member_function)
          : const_member_function_ptr(const_member_function)
        {}

        virtual void operator()(const void* object, ArgTypes... args) const override
        {
          return (static_cast<const Class*>(object)->*const_member_function_ptr)(args...);
        }

      private:
        const_member_function_pointer const_member_function_ptr;
      };

      template<typename Class>
      class const_member_function_slot<Class> : public slot<>
      {
        using const_member_function_pointer = void(Class::*)() const;

      public:
        const_member_function_slot(const_member_function_pointer const_member_function)
          : const_member_function_ptr(const_member_function)
        {}

        virtual void operator()(const void* object) const override
        {
          return (static_cast<const Class*>(object)->*const_member_function_ptr)();
        }

      private:
        const_member_function_pointer const_member_function_ptr;
      };
    }
  }
}

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "BasicThread.h"
#include "Autowired.h"
#include "BasicThreadStateBlock.h"
#include "fast_pointer_cast.h"
#include "move_only.h"
#include <boost/thread.hpp>

// Explicit instantiation of supported time point types:
template<> bool BasicThread::WaitUntil(boost::chrono::high_resolution_clock::time_point);
template<> bool BasicThread::WaitUntil(boost::chrono::system_clock::time_point);

BasicThread::BasicThread(const char* pName):
  ContextMember(pName),
  m_priority(ThreadPriority::Default),
  m_state(std::make_shared<BasicThreadStateBlock>()),
  m_stop(false),
  m_running(false),
  m_completed(false)
{}

boost::mutex& BasicThread::GetLock(void) {
  return m_state->m_lock;
}

void BasicThread::DoRun(std::shared_ptr<Object>&& refTracker) {
  assert(m_running);

  // Make our own session current before we do anything else:
  CurrentContextPusher pusher(GetContext());

  // Set the thread name no matter what:
  if(GetName())
    SetCurrentThreadName();

  // Now we wait for the thread to be good to go:
  try {
    Run();
  }
  catch(dispatch_aborted_exception&) {
    // Okay, this is fine, a dispatcher is terminating--this is a normal way to
    // end a dispatcher loop.
  }
  catch(...) {
    try {
      // Ask that the enclosing context filter this exception, if possible:
      GetContext()->FilterException();
    }
    catch(...) {
      // Generic exception, unhandled, we can't do anything about this
    }

    // Signal shutdown on the enclosing context--cannot wait, if we wait we WILL deadlock
    GetContext()->SignalShutdown(false);
  }

  // Run loop is over, time to clean up
  DoRunLoopCleanup(pusher.Pop(), std::move(refTracker));
}

void BasicThread::DoRunLoopCleanup(std::shared_ptr<CoreContext>&& ctxt, std::shared_ptr<Object>&& refTracker) {
  // Take a copy of our state condition shared pointer while we still hold a reference to
  // ourselves.  This is the only member out of our collection of members that we actually
  // need to hold a reference to.
  auto state = m_state;

  // Notify everyone that we're completed:
  boost::lock_guard<boost::mutex> lk(state->m_lock);
  m_stop = true;
  m_completed = true;
  m_running = false;

  // Perform a manual notification of teardown listeners
  NotifyTeardownListeners();

  // No longer running, we MUST release the thread pointer to ensure proper teardown order
  state->m_thisThread.detach();

  // Release our hold on the context.  After this point, we have to be VERY CAREFUL that we
  // don't try to refer to any of our own member variables, because our own object may have
  // already gone out of scope.  [this] is potentially dangling.
  ctxt.reset();

  // Clear our reference tracker, which will notify anyone who is asleep and also maybe
  // will destroy the entire underlying context.
  refTracker.reset();

  // Notify other threads that we are done.  At this point, any held references that might
  // still exist are held by entities other than ourselves.
  state->m_stateCondition.notify_all();
}

void BasicThread::WaitForStateUpdate(const std::function<bool()>& fn) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  m_state->m_stateCondition.wait(
    lk,
    [&fn, this] {
      return fn() || ShouldStop();
    }
  );
  if(ShouldStop())
    throw dispatch_aborted_exception();
}

void BasicThread::PerformStatusUpdate(const std::function<void()>& fn) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  fn();
  m_state->m_stateCondition.notify_all();
}

bool BasicThread::ShouldStop(void) const {
  shared_ptr<CoreContext> context = ContextMember::GetContext();
  return m_stop || !context || context->IsShutdown();
}

bool BasicThread::IsRunning(void) const {
  boost::lock_guard<boost::mutex> lk(m_state->m_lock);
  return m_running;
}

bool BasicThread::ThreadSleep(boost::chrono::nanoseconds timeout) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  return m_state->m_stateCondition.wait_for(lk, timeout, [this] { return ShouldStop(); });
}

bool BasicThread::Start(std::shared_ptr<Object> outstanding) {
  std::shared_ptr<CoreContext> context = m_context.lock();
  if(!context)
    return false;

  {
    boost::lock_guard<boost::mutex> lk(m_state->m_lock);
    if(m_running)
      // Already running, short-circuit
      return true;

    if(m_completed)
      // Already completed (perhaps cancelled), short-circuit
      return false;

    // Currently running:
    m_running = true;
    m_state->m_stateCondition.notify_all();
  }

  // Kick off a thread and return here
  MoveOnly<std::shared_ptr<Object>> out(std::move(outstanding));
  m_state->m_thisThread = boost::thread(
    [this, out] {
      this->DoRun(std::move(out.value));
    }
  );
  return true;
}

void BasicThread::Wait(void) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  m_state->m_stateCondition.wait(
    lk,
    [this] {return this->m_completed; }
  );
}

bool BasicThread::WaitFor(boost::chrono::nanoseconds duration) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  return m_state->m_stateCondition.wait_for(
    lk,
    duration,
    [this] {return this->m_completed; }
  );
}

template<class TimeType>
bool BasicThread::WaitUntil(TimeType timepoint) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  return m_state->m_stateCondition.wait_until(
    lk,
    timepoint,
    [this] {return this->m_completed; }
  );
}

void BasicThread::Stop(bool graceful) {
  {
    boost::lock_guard<boost::mutex> lk(m_state->m_lock);

    // Trivial return check:
    if(m_stop)
      return;

    // If we're not running, mark ourselves complete
    if(!m_running)
      m_completed = true;

    // Now we send the appropriate trigger:
    m_stop = true;
    m_state->m_stateCondition.notify_all();
  }

  // Event notification takes place outside of the context of a lock
  OnStop();
}

void BasicThread::ForceCoreThreadReidentify(void) {
  AutoGlobalContext global;
  global->EnumerateChildContexts(
    [](std::shared_ptr<CoreContext> ctxt) {
      auto threadListCpy = ctxt->CopyBasicThreadList();
      for(auto q = threadListCpy.begin(); q != threadListCpy.end(); q++) {
        (**q).SetCurrentThreadName();
      }
    }
  );
}

void ForceCoreThreadReidentify(void) {
  BasicThread::ForceCoreThreadReidentify();
}
<commit_msg>Teardown notification now happens before the state of the object is marked as Stopped<commit_after>#include "stdafx.h"
#include "BasicThread.h"
#include "Autowired.h"
#include "BasicThreadStateBlock.h"
#include "fast_pointer_cast.h"
#include "move_only.h"
#include <boost/thread.hpp>

// Explicit instantiation of supported time point types:
template<> bool BasicThread::WaitUntil(boost::chrono::high_resolution_clock::time_point);
template<> bool BasicThread::WaitUntil(boost::chrono::system_clock::time_point);

BasicThread::BasicThread(const char* pName):
  ContextMember(pName),
  m_priority(ThreadPriority::Default),
  m_state(std::make_shared<BasicThreadStateBlock>()),
  m_stop(false),
  m_running(false),
  m_completed(false)
{}

boost::mutex& BasicThread::GetLock(void) {
  return m_state->m_lock;
}

void BasicThread::DoRun(std::shared_ptr<Object>&& refTracker) {
  assert(m_running);

  // Make our own session current before we do anything else:
  CurrentContextPusher pusher(GetContext());

  // Set the thread name no matter what:
  if(GetName())
    SetCurrentThreadName();

  // Now we wait for the thread to be good to go:
  try {
    Run();
  }
  catch(dispatch_aborted_exception&) {
    // Okay, this is fine, a dispatcher is terminating--this is a normal way to
    // end a dispatcher loop.
  }
  catch(...) {
    try {
      // Ask that the enclosing context filter this exception, if possible:
      GetContext()->FilterException();
    }
    catch(...) {
      // Generic exception, unhandled, we can't do anything about this
    }

    // Signal shutdown on the enclosing context--cannot wait, if we wait we WILL deadlock
    GetContext()->SignalShutdown(false);
  }

  // Run loop is over, time to clean up
  DoRunLoopCleanup(pusher.Pop(), std::move(refTracker));
}

void BasicThread::DoRunLoopCleanup(std::shared_ptr<CoreContext>&& ctxt, std::shared_ptr<Object>&& refTracker) {
  // Take a copy of our state condition shared pointer while we still hold a reference to
  // ourselves.  This is the only member out of our collection of members that we actually
  // need to hold a reference to.
  auto state = m_state;

  // Perform a manual notification of teardown listeners
  NotifyTeardownListeners();

  // Notify everyone that we're completed:
  boost::lock_guard<boost::mutex> lk(state->m_lock);
  m_stop = true;
  m_completed = true;
  m_running = false;

  // No longer running, we MUST release the thread pointer to ensure proper teardown order
  state->m_thisThread.detach();

  // Release our hold on the context.  After this point, we have to be VERY CAREFUL that we
  // don't try to refer to any of our own member variables, because our own object may have
  // already gone out of scope.  [this] is potentially dangling.
  ctxt.reset();

  // Clear our reference tracker, which will notify anyone who is asleep and also maybe
  // will destroy the entire underlying context.
  refTracker.reset();

  // Notify other threads that we are done.  At this point, any held references that might
  // still exist are held by entities other than ourselves.
  state->m_stateCondition.notify_all();
}

void BasicThread::WaitForStateUpdate(const std::function<bool()>& fn) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  m_state->m_stateCondition.wait(
    lk,
    [&fn, this] {
      return fn() || ShouldStop();
    }
  );
  if(ShouldStop())
    throw dispatch_aborted_exception();
}

void BasicThread::PerformStatusUpdate(const std::function<void()>& fn) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  fn();
  m_state->m_stateCondition.notify_all();
}

bool BasicThread::ShouldStop(void) const {
  shared_ptr<CoreContext> context = ContextMember::GetContext();
  return m_stop || !context || context->IsShutdown();
}

bool BasicThread::IsRunning(void) const {
  boost::lock_guard<boost::mutex> lk(m_state->m_lock);
  return m_running;
}

bool BasicThread::ThreadSleep(boost::chrono::nanoseconds timeout) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  return m_state->m_stateCondition.wait_for(lk, timeout, [this] { return ShouldStop(); });
}

bool BasicThread::Start(std::shared_ptr<Object> outstanding) {
  std::shared_ptr<CoreContext> context = m_context.lock();
  if(!context)
    return false;

  {
    boost::lock_guard<boost::mutex> lk(m_state->m_lock);
    if(m_running)
      // Already running, short-circuit
      return true;

    if(m_completed)
      // Already completed (perhaps cancelled), short-circuit
      return false;

    // Currently running:
    m_running = true;
    m_state->m_stateCondition.notify_all();
  }

  // Kick off a thread and return here
  MoveOnly<std::shared_ptr<Object>> out(std::move(outstanding));
  m_state->m_thisThread = boost::thread(
    [this, out] {
      this->DoRun(std::move(out.value));
    }
  );
  return true;
}

void BasicThread::Wait(void) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  m_state->m_stateCondition.wait(
    lk,
    [this] {return this->m_completed; }
  );
}

bool BasicThread::WaitFor(boost::chrono::nanoseconds duration) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  return m_state->m_stateCondition.wait_for(
    lk,
    duration,
    [this] {return this->m_completed; }
  );
}

template<class TimeType>
bool BasicThread::WaitUntil(TimeType timepoint) {
  boost::unique_lock<boost::mutex> lk(m_state->m_lock);
  return m_state->m_stateCondition.wait_until(
    lk,
    timepoint,
    [this] {return this->m_completed; }
  );
}

void BasicThread::Stop(bool graceful) {
  {
    boost::lock_guard<boost::mutex> lk(m_state->m_lock);

    // Trivial return check:
    if(m_stop)
      return;

    // If we're not running, mark ourselves complete
    if(!m_running)
      m_completed = true;

    // Now we send the appropriate trigger:
    m_stop = true;
    m_state->m_stateCondition.notify_all();
  }

  // Event notification takes place outside of the context of a lock
  OnStop();
}

void BasicThread::ForceCoreThreadReidentify(void) {
  AutoGlobalContext global;
  global->EnumerateChildContexts(
    [](std::shared_ptr<CoreContext> ctxt) {
      auto threadListCpy = ctxt->CopyBasicThreadList();
      for(auto q = threadListCpy.begin(); q != threadListCpy.end(); q++) {
        (**q).SetCurrentThreadName();
      }
    }
  );
}

void ForceCoreThreadReidentify(void) {
  BasicThread::ForceCoreThreadReidentify();
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_DENSE_LAYER_INL
#define DLL_DENSE_LAYER_INL

#include "cpp_utils/assert.hpp"             //Assertions

#include "etl/etl.hpp"

#include "tmp.hpp"
#include "layer_traits.hpp"

namespace dll {

template<typename Desc>
struct dense_layer final {
    using desc = Desc;
    using weight = typename desc::weight;
    using this_type = dense_layer<desc>;

    static constexpr const std::size_t num_visible = desc::num_visible;
    static constexpr const std::size_t num_hidden = desc::num_hidden;

    static constexpr const bool dbn_only = layer_traits<this_type>::is_dbn_only();

    static constexpr const function activation_function = desc::activation_function;

    //Weights and biases
    etl::fast_matrix<weight, num_visible, num_hidden> w;    //!< Weights
    etl::fast_vector<weight, num_hidden> b;                 //!< Hidden biases

    //No copying
    dense_layer(const dense_layer& layer) = delete;
    dense_layer& operator=(const dense_layer& layer) = delete;

    //No moving
    dense_layer(dense_layer&& layer) = delete;
    dense_layer& operator=(dense_layer&& layer) = delete;

    /*!
     * \brief Initialize a dense layer with basic weights.
     *
     * The weights are initialized from a normal distribution of
     * zero-mean and unit variance.
     */
    dense_layer(){
        //Initialize the weights and biases following Lecun approach
        //to initialization [lecun-98b]

        b = etl::normal_generator<weight>(0.0, 1.0 / std::sqrt(double(num_visible)));
        w = etl::normal_generator<weight>(0.0, 1.0 / std::sqrt(double(num_visible)));
    }

    static constexpr std::size_t input_size() noexcept {
        return num_visible;
    }

    static constexpr std::size_t output_size() noexcept {
        return num_hidden;
    }

    static constexpr std::size_t parameters() noexcept {
        return num_visible * num_hidden;
    }

    static std::string to_short_string(){
        return "Dense: " + std::to_string(num_visible) + " -> (" + "TODO:function" + ") -> " + std::to_string(num_hidden);
    }

    void display() const {
        std::cout << to_short_string() << std::endl;
    }

    template<typename H1, typename V>
    void activate_hidden(H1&& output, const V& v) const {
        switch(activation_function){
            case function::IDENTITY:
                output = b + v * w;
                break;
            case function::SIGMOID:
                output = etl::sigmoid(b + v * w);
                break;
            case function::TANH:
                output = etl::tanh(b + v * w);
                break;
        }
    }

    //Utilities to be used by DBNs

    using input_one_t = etl::fast_dyn_matrix<weight, num_visible>;
    using output_one_t = etl::fast_dyn_matrix<weight, num_hidden>;
    using input_t = std::vector<input_one_t>;
    using output_t = std::vector<output_one_t>;

    template<typename Sample>
    input_one_t convert_sample(const Sample& sample) const {
        return input_one_t{sample};
    }

    template<typename Input>
    output_one_t prepare_one_output(bool /*is_last*/ = false, std::size_t /*labels*/ = 0) const {
        return {};
    }

    void activate_one(const input_one_t& input, output_one_t& h_a) const {
        activate_hidden(h_a, input);
    }
};

//Allow odr-use of the constexpr static members

template<typename Desc>
const std::size_t dense_layer<Desc>::num_visible;

template<typename Desc>
const std::size_t dense_layer<Desc>::num_hidden;

} //end of dll namespace

#endif
<commit_msg>Batch activation<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_DENSE_LAYER_INL
#define DLL_DENSE_LAYER_INL

#include "cpp_utils/assert.hpp"             //Assertions

#include "etl/etl.hpp"

#include "tmp.hpp"
#include "layer_traits.hpp"

namespace dll {

template<typename Desc>
struct dense_layer final {
    using desc = Desc;
    using weight = typename desc::weight;
    using this_type = dense_layer<desc>;

    static constexpr const std::size_t num_visible = desc::num_visible;
    static constexpr const std::size_t num_hidden = desc::num_hidden;

    static constexpr const bool dbn_only = layer_traits<this_type>::is_dbn_only();

    static constexpr const function activation_function = desc::activation_function;

    //Weights and biases
    etl::fast_matrix<weight, num_visible, num_hidden> w;    //!< Weights
    etl::fast_vector<weight, num_hidden> b;                 //!< Hidden biases

    //No copying
    dense_layer(const dense_layer& layer) = delete;
    dense_layer& operator=(const dense_layer& layer) = delete;

    //No moving
    dense_layer(dense_layer&& layer) = delete;
    dense_layer& operator=(dense_layer&& layer) = delete;

    /*!
     * \brief Initialize a dense layer with basic weights.
     *
     * The weights are initialized from a normal distribution of
     * zero-mean and unit variance.
     */
    dense_layer(){
        //Initialize the weights and biases following Lecun approach
        //to initialization [lecun-98b]

        b = etl::normal_generator<weight>(0.0, 1.0 / std::sqrt(double(num_visible)));
        w = etl::normal_generator<weight>(0.0, 1.0 / std::sqrt(double(num_visible)));
    }

    static constexpr std::size_t input_size() noexcept {
        return num_visible;
    }

    static constexpr std::size_t output_size() noexcept {
        return num_hidden;
    }

    static constexpr std::size_t parameters() noexcept {
        return num_visible * num_hidden;
    }

    static std::string to_short_string(){
        return "Dense: " + std::to_string(num_visible) + " -> (" + "TODO:function" + ") -> " + std::to_string(num_hidden);
    }

    void display() const {
        std::cout << to_short_string() << std::endl;
    }

    template<typename H1, typename V>
    void activate_hidden(H1&& output, const V& v) const {
        switch(activation_function){
            case function::IDENTITY:
                output = b + v * w;
                break;
            case function::SIGMOID:
                output = etl::sigmoid(b + v * w);
                break;
            case function::TANH:
                output = etl::tanh(b + v * w);
                break;
        }
    }

    template<typename H1, typename V>
    void batch_activate_hidden(H1&& output, const V& v) const {
        const auto Batch = etl::dim<0>(v);

        cpp_assert(etl::dim<0>(output) == Batch, "The number of samples must be consistent");

        switch(activation_function){
            case function::IDENTITY:
                output = etl::rep_l(b, Batch) + v * w;
                break;
            case function::SIGMOID:
                output = etl::sigmoid(etl::rep_l(b, Batch) + v * w);
                break;
            case function::TANH:
                output = etl::tanh(etl::rep_l(b, Batch) + v * w);
                break;
        }
    }

    //Utilities to be used by DBNs

    using input_one_t = etl::fast_dyn_matrix<weight, num_visible>;
    using output_one_t = etl::fast_dyn_matrix<weight, num_hidden>;
    using input_t = std::vector<input_one_t>;
    using output_t = std::vector<output_one_t>;

    template<typename Sample>
    input_one_t convert_sample(const Sample& sample) const {
        return input_one_t{sample};
    }

    template<typename Input>
    output_one_t prepare_one_output(bool /*is_last*/ = false, std::size_t /*labels*/ = 0) const {
        return {};
    }

    void activate_one(const input_one_t& input, output_one_t& h_a) const {
        activate_hidden(h_a, input);
    }
};

//Allow odr-use of the constexpr static members

template<typename Desc>
const std::size_t dense_layer<Desc>::num_visible;

template<typename Desc>
const std::size_t dense_layer<Desc>::num_hidden;

} //end of dll namespace

#endif
<|endoftext|>