<commit_before>/*
 * (C) Copyright 2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE WebRtcEndpoint
#include <boost/test/unit_test.hpp>
#include <MediaPipelineImpl.hpp>
#include <objects/WebRtcEndpointImpl.hpp>
#include <IceCandidate.hpp>
#include <mutex>
#include <condition_variable>
#include <ModuleManager.hpp>
#include <KurentoException.hpp>
#include <MediaSet.hpp>

using namespace kurento;

boost::property_tree::ptree config;
std::string mediaPipelineId;
ModuleManager moduleManager;
std::once_flag init_flag;

static void
init_internal()
{
  boost::property_tree::ptree ac, audioCodecs, vc, videoCodecs;
  gst_init (NULL, NULL);

  moduleManager.loadModulesFromDirectories ("../../src/server");

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.numAudioMedias", 1);
  config.add ("modules.kurento.SdpEndpoint.numVideoMedias", 1);

  ac.put ("name", "opus/48000/2");
  audioCodecs.push_back (std::make_pair ("", ac) );
  config.add_child ("modules.kurento.SdpEndpoint.audioCodecs", audioCodecs);

  vc.put ("name", "VP8/90000");
  videoCodecs.push_back (std::make_pair ("", vc) );
  config.add_child ("modules.kurento.SdpEndpoint.videoCodecs", videoCodecs);

  mediaPipelineId = moduleManager.getFactory ("MediaPipeline")->createObject (
                      config, "",
                      Json::Value() )->getId();
}

static void
init()
{
  std::call_once (init_flag, init_internal);
}

static std::shared_ptr <WebRtcEndpointImpl>
createWebrtc (void)
{
  std::shared_ptr <kurento::MediaObjectImpl> webrtcEndpoint;
  Json::Value constructorParams;

  constructorParams ["mediaPipeline"] = mediaPipelineId;

  webrtcEndpoint = moduleManager.getFactory ("WebRtcEndpoint")->createObject (
                     config, "",
                     constructorParams );

  return std::dynamic_pointer_cast <WebRtcEndpointImpl> (webrtcEndpoint);
}

static void
releaseWebRtc (std::shared_ptr<WebRtcEndpointImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

BOOST_AUTO_TEST_CASE (gathering_done)
{
  init ();

  std::atomic<bool> gathering_done (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);
  std::shared_ptr <WebRtcEndpointImpl> webRtcEp = createWebrtc();

  webRtcEp->signalOnIceGatheringDone.connect ([&] (OnIceGatheringDone event) {
    gathering_done = true;
    cv.notify_one();
  });

  webRtcEp->generateOffer ();
  webRtcEp->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return gathering_done.load();
  });

  if (!gathering_done) {
    BOOST_ERROR ("Gathering not done");
  }

  releaseWebRtc (webRtcEp);
}

BOOST_AUTO_TEST_CASE (ice_state_changes)
{
  init ();

  std::atomic<bool> ice_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();

  webRtcEpOfferer->setName ("offerer");
  webRtcEpAnswerer->setName ("answerer");

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceComponentStateChanged.connect ([&] (
  OnIceComponentStateChanged event) {
    ice_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  std::string answer = webRtcEpAnswerer->processOffer (offer);
  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return ice_state_changed.load();
  });

  if (!ice_state_changed) {
    BOOST_ERROR ("ICE state not chagned");
  }

  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

BOOST_AUTO_TEST_CASE (stun_turn_properties)
{
  std::string stunServerAddress ("10.0.0.1");
  int stunServerPort = 2345;
  std::string turnUrl ("user0:pass0@10.0.0.2:3456");

  init ();

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp  = createWebrtc();

  webRtcEp->setStunServerAddress (stunServerAddress);
  std::string stunServerAddressRet = webRtcEp->getStunServerAddress ();
  BOOST_CHECK (stunServerAddressRet == stunServerAddress);

  webRtcEp->setStunServerPort (stunServerPort);
  int stunServerPortRet = webRtcEp->getStunServerPort ();
  BOOST_CHECK (stunServerPortRet == stunServerPort);

  webRtcEp->setTurnUrl (turnUrl);
  std::string turnUrlRet = webRtcEp->getTurnUrl ();
  BOOST_CHECK (turnUrlRet == turnUrl);

  releaseWebRtc (webRtcEp);
}
<commit_msg>webRtcEndpoint: Test media flow through WebRTC<commit_after>/*
 * (C) Copyright 2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE WebRtcEndpoint
#include <boost/test/unit_test.hpp>
#include <MediaPipelineImpl.hpp>
#include <objects/WebRtcEndpointImpl.hpp>
#include <IceCandidate.hpp>
#include <mutex>
#include <condition_variable>
#include <ModuleManager.hpp>
#include <KurentoException.hpp>
#include <MediaSet.hpp>
#include <MediaElementImpl.hpp>

using namespace kurento;

boost::property_tree::ptree config;
std::string mediaPipelineId;
ModuleManager moduleManager;
std::once_flag init_flag;

static void
init_internal()
{
  boost::property_tree::ptree ac, audioCodecs, vc, videoCodecs;
  gst_init (NULL, NULL);

  moduleManager.loadModulesFromDirectories ("../../src/server");

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.numAudioMedias", 1);
  config.add ("modules.kurento.SdpEndpoint.numVideoMedias", 1);

  ac.put ("name", "opus/48000/2");
  audioCodecs.push_back (std::make_pair ("", ac) );
  config.add_child ("modules.kurento.SdpEndpoint.audioCodecs", audioCodecs);

  vc.put ("name", "VP8/90000");
  videoCodecs.push_back (std::make_pair ("", vc) );
  config.add_child ("modules.kurento.SdpEndpoint.videoCodecs", videoCodecs);

  mediaPipelineId = moduleManager.getFactory ("MediaPipeline")->createObject (
                      config, "",
                      Json::Value() )->getId();
}

static void
init()
{
  std::call_once (init_flag, init_internal);
}

static std::shared_ptr <WebRtcEndpointImpl>
createWebrtc (void)
{
  std::shared_ptr <kurento::MediaObjectImpl> webrtcEndpoint;
  Json::Value constructorParams;

  constructorParams ["mediaPipeline"] = mediaPipelineId;

  webrtcEndpoint = moduleManager.getFactory ("WebRtcEndpoint")->createObject (
                     config, "",
                     constructorParams );

  return std::dynamic_pointer_cast <WebRtcEndpointImpl> (webrtcEndpoint);
}

static void
releaseWebRtc (std::shared_ptr<WebRtcEndpointImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

static std::shared_ptr <MediaElementImpl>
createTestSrc (void)
{
  std::shared_ptr <MediaElementImpl> src = std::dynamic_pointer_cast
      <MediaElementImpl> (MediaSet::getMediaSet()->ref (new  MediaElementImpl (
                            boost::property_tree::ptree(),
                            MediaSet::getMediaSet()->getMediaObject (mediaPipelineId),
                            "dummysrc") ) );

  g_object_set (src->getGstreamerElement(), "audio", TRUE, "video", TRUE, NULL);

  return std::dynamic_pointer_cast <MediaElementImpl> (src);
}

static void
releaseTestSrc (std::shared_ptr<MediaElementImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

BOOST_AUTO_TEST_CASE (gathering_done)
{
  init ();

  std::atomic<bool> gathering_done (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);
  std::shared_ptr <WebRtcEndpointImpl> webRtcEp = createWebrtc();

  webRtcEp->signalOnIceGatheringDone.connect ([&] (OnIceGatheringDone event) {
    gathering_done = true;
    cv.notify_one();
  });

  webRtcEp->generateOffer ();
  webRtcEp->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return gathering_done.load();
  });

  if (!gathering_done) {
    BOOST_ERROR ("Gathering not done");
  }

  releaseWebRtc (webRtcEp);
}

BOOST_AUTO_TEST_CASE (ice_state_changes)
{
  init ();

  std::atomic<bool> ice_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();

  webRtcEpOfferer->setName ("offerer");
  webRtcEpAnswerer->setName ("answerer");

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceComponentStateChanged.connect ([&] (
  OnIceComponentStateChanged event) {
    ice_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  std::string answer = webRtcEpAnswerer->processOffer (offer);
  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {
    return ice_state_changed.load();
  });

  if (!ice_state_changed) {
    BOOST_ERROR ("ICE state not chagned");
  }

  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

BOOST_AUTO_TEST_CASE (stun_turn_properties)
{
  std::string stunServerAddress ("10.0.0.1");
  int stunServerPort = 2345;
  std::string turnUrl ("user0:pass0@10.0.0.2:3456");

  init ();

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp  = createWebrtc();

  webRtcEp->setStunServerAddress (stunServerAddress);
  std::string stunServerAddressRet = webRtcEp->getStunServerAddress ();
  BOOST_CHECK (stunServerAddressRet == stunServerAddress);

  webRtcEp->setStunServerPort (stunServerPort);
  int stunServerPortRet = webRtcEp->getStunServerPort ();
  BOOST_CHECK (stunServerPortRet == stunServerPort);

  webRtcEp->setTurnUrl (turnUrl);
  std::string turnUrlRet = webRtcEp->getTurnUrl ();
  BOOST_CHECK (turnUrlRet == turnUrl);

  releaseWebRtc (webRtcEp);
}

BOOST_AUTO_TEST_CASE (media_state_changes)
{
  std::atomic<bool> media_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  init ();

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();
  std::shared_ptr <MediaElementImpl> src = createTestSrc();

  src->connect (webRtcEpOfferer);

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Offerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Answerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Offerer: Gathering done");
  });

  webRtcEpAnswerer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Answerer: Gathering done");
  });

  webRtcEpAnswerer->signalMediaStateChanged.connect ([&] (
  MediaStateChanged event) {
    media_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  BOOST_TEST_MESSAGE ("offer: " + offer);

  std::string answer = webRtcEpAnswerer->processOffer (offer);
  BOOST_TEST_MESSAGE ("answer: " + answer);

  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait_for (lck, std::chrono::seconds (5), [&] () {

    return media_state_changed.load();
  });

  if (!media_state_changed) {
    BOOST_ERROR ("Not media state chagned");
  }

  releaseTestSrc (src);
  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}
<|endoftext|>


<commit_before><commit_msg>Mark NPAPITesterBase.GetURLRedirectNotification test as flaky on linux.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 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/path_service.h"
#include "build/build_config.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "webkit/glue/plugins/plugin_switches.h"

namespace {

// Platform-specific filename relative to the chrome executable.
#if defined(OS_WIN)
const wchar_t library_name[] = L"ppapi_tests.dll";
#elif defined(OS_MACOSX)
const char library_name[] = "ppapi_tests.plugin";
#elif defined(OS_POSIX)
const char library_name[] = "libppapi_tests.so";
#endif

}  // namespace

class PPAPITest : public UITest {
 public:
  PPAPITest() {
    // Append the switch to register the pepper plugin.
    // library name = <out dir>/<test_name>.<library_extension>
    // MIME type = application/x-ppapi-<test_name>
    FilePath plugin_dir;
    PathService::Get(base::DIR_EXE, &plugin_dir);

    FilePath plugin_lib = plugin_dir.Append(library_name);
    EXPECT_TRUE(file_util::PathExists(plugin_lib));
    FilePath::StringType pepper_plugin = plugin_lib.value();
    pepper_plugin.append(FILE_PATH_LITERAL(";application/x-ppapi-tests"));
    launch_arguments_.AppendSwitchNative(switches::kRegisterPepperPlugins,
                                         pepper_plugin);

    // The test sends us the result via a cookie.
    launch_arguments_.AppendSwitch(switches::kEnableFileCookies);

    // Some stuff is hung off of the testing interface which is not enabled
    // by default.
    launch_arguments_.AppendSwitch(switches::kEnablePepperTesting);

    // Give unlimited quota for files to Pepper tests.
    // TODO(dumi): remove this switch once we have a quota management
    // system in place.
    launch_arguments_.AppendSwitch(switches::kUnlimitedQuotaForFiles);
  }

  void RunTest(const std::string& test_case) {
    FilePath test_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("ppapi"));
    test_path = test_path.Append(FILE_PATH_LITERAL("tests"));
    test_path = test_path.Append(FILE_PATH_LITERAL("test_case.html"));

    // Sanity check the file name.
    EXPECT_TRUE(file_util::PathExists(test_path));

    GURL::Replacements replacements;
    replacements.SetQuery(test_case.c_str(),
                          url_parse::Component(0, test_case.size()));
    GURL test_url = net::FilePathToFileURL(test_path);
    RunTestURL(test_url.ReplaceComponents(replacements));
  }

  void RunTestViaHTTP(const std::string& test_case) {
    net::TestServer test_server(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("third_party/ppapi/tests")));
    ASSERT_TRUE(test_server.Start());
    RunTestURL(test_server.GetURL("files/test_case.html?" + test_case));
  }

 private:
  void RunTestURL(const GURL& test_url) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());
    ASSERT_TRUE(tab->NavigateToURL(test_url));
    std::string escaped_value =
        WaitUntilCookieNonEmpty(tab.get(), test_url,
            "COMPLETION_COOKIE", action_max_timeout_ms());
    EXPECT_STREQ("PASS", escaped_value.c_str());
  }
};

TEST_F(PPAPITest, FAILS_Instance) {
  RunTest("Instance");
}

TEST_F(PPAPITest, Graphics2D) {
  RunTest("Graphics2D");
}

// TODO(brettw) bug 51344: this is flaky on bots. Seems to timeout navigating.
// Possibly all the image allocations slow things down on a loaded bot too much.
TEST_F(PPAPITest, FLAKY_ImageData) {
  RunTest("ImageData");
}

TEST_F(PPAPITest, Buffer) {
  RunTest("Buffer");
}

// http://bugs.chromium.org/51345
TEST_F(PPAPITest, DISABLED_URLLoader) {
  RunTestViaHTTP("URLLoader");
}

// Flaky, http://crbug.com/51012
TEST_F(PPAPITest, FLAKY_PaintAggregator) {
  RunTestViaHTTP("PaintAggregator");
}

// Flaky, http://crbug.com/48544.
TEST_F(PPAPITest, FLAKY_Scrollbar) {
  RunTest("Scrollbar");
}

TEST_F(PPAPITest, UrlUtil) {
  RunTest("UrlUtil");
}

TEST_F(PPAPITest, CharSet) {
  RunTest("CharSet");
}

TEST_F(PPAPITest, Var) {
  RunTest("Var");
}

TEST_F(PPAPITest, FileRef) {
  RunTestViaHTTP("FileRef");
}

TEST_F(PPAPITest, FileIO) {
  RunTestViaHTTP("FileIO");
}

TEST_F(PPAPITest, DirectoryReader) {
  RunTestViaHTTP("DirectoryReader");
}
<commit_msg>Remove FileRef, FileIO and DirectoryReader PPAPI tests from ui_tests for now. It looks like run_testserver is crashing.<commit_after>// Copyright (c) 2010 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/path_service.h"
#include "build/build_config.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "webkit/glue/plugins/plugin_switches.h"

namespace {

// Platform-specific filename relative to the chrome executable.
#if defined(OS_WIN)
const wchar_t library_name[] = L"ppapi_tests.dll";
#elif defined(OS_MACOSX)
const char library_name[] = "ppapi_tests.plugin";
#elif defined(OS_POSIX)
const char library_name[] = "libppapi_tests.so";
#endif

}  // namespace

class PPAPITest : public UITest {
 public:
  PPAPITest() {
    // Append the switch to register the pepper plugin.
    // library name = <out dir>/<test_name>.<library_extension>
    // MIME type = application/x-ppapi-<test_name>
    FilePath plugin_dir;
    PathService::Get(base::DIR_EXE, &plugin_dir);

    FilePath plugin_lib = plugin_dir.Append(library_name);
    EXPECT_TRUE(file_util::PathExists(plugin_lib));
    FilePath::StringType pepper_plugin = plugin_lib.value();
    pepper_plugin.append(FILE_PATH_LITERAL(";application/x-ppapi-tests"));
    launch_arguments_.AppendSwitchNative(switches::kRegisterPepperPlugins,
                                         pepper_plugin);

    // The test sends us the result via a cookie.
    launch_arguments_.AppendSwitch(switches::kEnableFileCookies);

    // Some stuff is hung off of the testing interface which is not enabled
    // by default.
    launch_arguments_.AppendSwitch(switches::kEnablePepperTesting);

    // Give unlimited quota for files to Pepper tests.
    // TODO(dumi): remove this switch once we have a quota management
    // system in place.
    launch_arguments_.AppendSwitch(switches::kUnlimitedQuotaForFiles);
  }

  void RunTest(const std::string& test_case) {
    FilePath test_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("ppapi"));
    test_path = test_path.Append(FILE_PATH_LITERAL("tests"));
    test_path = test_path.Append(FILE_PATH_LITERAL("test_case.html"));

    // Sanity check the file name.
    EXPECT_TRUE(file_util::PathExists(test_path));

    GURL::Replacements replacements;
    replacements.SetQuery(test_case.c_str(),
                          url_parse::Component(0, test_case.size()));
    GURL test_url = net::FilePathToFileURL(test_path);
    RunTestURL(test_url.ReplaceComponents(replacements));
  }

  void RunTestViaHTTP(const std::string& test_case) {
    net::TestServer test_server(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("third_party/ppapi/tests")));
    ASSERT_TRUE(test_server.Start());
    RunTestURL(test_server.GetURL("files/test_case.html?" + test_case));
  }

 private:
  void RunTestURL(const GURL& test_url) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());
    ASSERT_TRUE(tab->NavigateToURL(test_url));
    std::string escaped_value =
        WaitUntilCookieNonEmpty(tab.get(), test_url,
            "COMPLETION_COOKIE", action_max_timeout_ms());
    EXPECT_STREQ("PASS", escaped_value.c_str());
  }
};

TEST_F(PPAPITest, FAILS_Instance) {
  RunTest("Instance");
}

TEST_F(PPAPITest, Graphics2D) {
  RunTest("Graphics2D");
}

// TODO(brettw) bug 51344: this is flaky on bots. Seems to timeout navigating.
// Possibly all the image allocations slow things down on a loaded bot too much.
TEST_F(PPAPITest, FLAKY_ImageData) {
  RunTest("ImageData");
}

TEST_F(PPAPITest, Buffer) {
  RunTest("Buffer");
}

// http://bugs.chromium.org/51345
TEST_F(PPAPITest, DISABLED_URLLoader) {
  RunTestViaHTTP("URLLoader");
}

// Flaky, http://crbug.com/51012
TEST_F(PPAPITest, FLAKY_PaintAggregator) {
  RunTestViaHTTP("PaintAggregator");
}

// Flaky, http://crbug.com/48544.
TEST_F(PPAPITest, FLAKY_Scrollbar) {
  RunTest("Scrollbar");
}

TEST_F(PPAPITest, UrlUtil) {
  RunTest("UrlUtil");
}

TEST_F(PPAPITest, CharSet) {
  RunTest("CharSet");
}

TEST_F(PPAPITest, Var) {
  RunTest("Var");
}
<|endoftext|>


<commit_before><commit_msg>Disable WorkerHttpLayoutTests which is flaky (both debug and release winxp).<commit_after><|endoftext|>


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

#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"

static const char kTestCompleteCookie[] = "status";
static const char kTestCompleteSuccess[] = "OK";

class WorkerTest : public UILayoutTest {
 protected:
  virtual ~WorkerTest() { }

  void RunTest(const std::wstring& test_case) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }
};

TEST_F(WorkerTest, SingleWorker) {
  RunTest(L"single_worker.html");
}

TEST_F(WorkerTest, MultipleWorkers) {
  RunTest(L"multi_worker.html");
}

// WorkerFastLayoutTests works on the linux try servers, but fails on the
// build bots and fails on mac valgrind.
#if !defined(OS_WIN)
#define WorkerFastLayoutTests DISABLED_WorkerFastLayoutTests
#endif

TEST_F(WorkerTest, WorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "stress-js-execution.html",
#if defined(OS_WIN)
    // Workers don't properly initialize the V8 stack guard.
    // (http://code.google.com/p/chromium/issues/detail?id=21653).
    "use-machine-stack.html",
#endif
    "worker-call.html",
    // Disabled because cloning ports are too slow in Chromium to meet the
    // thresholds in this test.
    // http://code.google.com/p/chromium/issues/detail?id=22780
    // "worker-cloneport.html",

    "worker-close.html",
    "worker-constructor.html",
    "worker-context-gc.html",
    "worker-context-multi-port.html",
    "worker-event-listener.html",
    "worker-gc.html",
    // worker-lifecycle.html relies on layoutTestController.workerThreadCount
    // which is not currently implemented.
    // "worker-lifecycle.html",
    "worker-location.html",
    "worker-messageport.html",
    // Disabled after r27089 (WebKit merge), http://crbug.com/22947
    // "worker-messageport-gc.html",
    "worker-multi-port.html",
    "worker-navigator.html",
    "worker-replace-global-constructor.html",
    "worker-replace-self.html",
    "worker-script-error.html",
    "worker-terminate.html",
    "worker-timeout.html"
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

TEST_F(WorkerTest, WorkerHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    // flakey? BUG 16934 "text-encoding.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "worker-importScripts.html",
#endif
    "worker-redirect.html",
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "abort-exception-assert.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "close.html",
#endif
    //"methods-async.html",
    //"methods.html",
    "xmlhttprequest-file-not-found.html"
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("xmlhttprequest");
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, DISABLED_MessagePorts) {
  static const char* kLayoutTestFiles[] = {
    "message-channel-gc.html",
    "message-channel-gc-2.html",
    "message-channel-gc-3.html",
    "message-channel-gc-4.html",
    "message-port.html",
    "message-port-clone.html",
    "message-port-constructor-for-deleted-document.html",
    "message-port-deleted-document.html",
    "message-port-deleted-frame.html",
    "message-port-inactive-document.html",
    "message-port-multi.html",
    "message-port-no-wrapper.html",
    // Only works with run-webkit-tests --leaks.
    //"message-channel-listener-circular-ownership.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("events");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // MessagePort tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

// Disable LimitPerPage on Linux. Seems to work on Mac though:
// http://code.google.com/p/chromium/issues/detail?id=22608
#if !defined(OS_LINUX)
TEST_F(WorkerTest, LimitPerPage) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));

  EXPECT_EQ(max_workers_per_tab + 1 + (UITest::in_process_renderer() ? 0 : 1),
            UITest::GetBrowserProcessCount());
}
#endif

// Disable LimitTotal on Linux and Mac.
// http://code.google.com/p/chromium/issues/detail?id=22608
#if defined(OS_WIN)
TEST_F(WorkerTest, LimitTotal) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  int total_workers = WorkerService::kMaxWorkersWhenSeparate;

  int tab_count = (total_workers / max_workers_per_tab) + 1;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  for (int i = 1; i < tab_count; ++i)
    window->AppendTab(url);

  // Check that we didn't create more than the max number of workers.
  EXPECT_EQ(total_workers + 1 + (UITest::in_process_renderer() ? 0 : tab_count),
            UITest::GetBrowserProcessCount());

  // Now close the first tab and check that the queued workers were started.
  tab->Close(true);
  tab->NavigateToURL(GetTestUrl(L"google", L"google.html"));

  EXPECT_EQ(total_workers + 1 + (UITest::in_process_renderer() ? 0 : tab_count),
            UITest::GetBrowserProcessCount());
}
#endif
<commit_msg>Disable WorkerTest.WorkerFastLayoutTests.<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/worker_host/worker_service.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"

static const char kTestCompleteCookie[] = "status";
static const char kTestCompleteSuccess[] = "OK";

class WorkerTest : public UILayoutTest {
 protected:
  virtual ~WorkerTest() { }

  void RunTest(const std::wstring& test_case) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }
};

TEST_F(WorkerTest, SingleWorker) {
  RunTest(L"single_worker.html");
}

TEST_F(WorkerTest, MultipleWorkers) {
  RunTest(L"multi_worker.html");
}

// WorkerFastLayoutTests works on the linux try servers, but fails on the
// build bots and fails on mac valgrind.
#if !defined(OS_WIN)
#define WorkerFastLayoutTests DISABLED_WorkerFastLayoutTests
#endif

// WorkerFastLayoutTests failed on all platforms since r27553.
// http://crbug.com/23391
TEST_F(WorkerTest, DISABLED_WorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "stress-js-execution.html",
#if defined(OS_WIN)
    // Workers don't properly initialize the V8 stack guard.
    // (http://code.google.com/p/chromium/issues/detail?id=21653).
    "use-machine-stack.html",
#endif
    "worker-call.html",
    // Disabled because cloning ports are too slow in Chromium to meet the
    // thresholds in this test.
    // http://code.google.com/p/chromium/issues/detail?id=22780
    // "worker-cloneport.html",

    "worker-close.html",
    "worker-constructor.html",
    "worker-context-gc.html",
    "worker-context-multi-port.html",
    "worker-event-listener.html",
    "worker-gc.html",
    // worker-lifecycle.html relies on layoutTestController.workerThreadCount
    // which is not currently implemented.
    // "worker-lifecycle.html",
    "worker-location.html",
    "worker-messageport.html",
    // Disabled after r27089 (WebKit merge), http://crbug.com/22947
    // "worker-messageport-gc.html",
    "worker-multi-port.html",
    "worker-navigator.html",
    "worker-replace-global-constructor.html",
    "worker-replace-self.html",
    "worker-script-error.html",
    "worker-terminate.html",
    "worker-timeout.html"
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

TEST_F(WorkerTest, WorkerHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    // flakey? BUG 16934 "text-encoding.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "worker-importScripts.html",
#endif
    "worker-redirect.html",
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "abort-exception-assert.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "close.html",
#endif
    //"methods-async.html",
    //"methods.html",
    "xmlhttprequest-file-not-found.html"
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("xmlhttprequest");
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, DISABLED_MessagePorts) {
  static const char* kLayoutTestFiles[] = {
    "message-channel-gc.html",
    "message-channel-gc-2.html",
    "message-channel-gc-3.html",
    "message-channel-gc-4.html",
    "message-port.html",
    "message-port-clone.html",
    "message-port-constructor-for-deleted-document.html",
    "message-port-deleted-document.html",
    "message-port-deleted-frame.html",
    "message-port-inactive-document.html",
    "message-port-multi.html",
    "message-port-no-wrapper.html",
    // Only works with run-webkit-tests --leaks.
    //"message-channel-listener-circular-ownership.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("events");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // MessagePort tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

// Disable LimitPerPage on Linux. Seems to work on Mac though:
// http://code.google.com/p/chromium/issues/detail?id=22608
#if !defined(OS_LINUX)
TEST_F(WorkerTest, LimitPerPage) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));

  EXPECT_EQ(max_workers_per_tab + 1 + (UITest::in_process_renderer() ? 0 : 1),
            UITest::GetBrowserProcessCount());
}
#endif

// Disable LimitTotal on Linux and Mac.
// http://code.google.com/p/chromium/issues/detail?id=22608
#if defined(OS_WIN)
TEST_F(WorkerTest, LimitTotal) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  int total_workers = WorkerService::kMaxWorkersWhenSeparate;

  int tab_count = (total_workers / max_workers_per_tab) + 1;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  for (int i = 1; i < tab_count; ++i)
    window->AppendTab(url);

  // Check that we didn't create more than the max number of workers.
  EXPECT_EQ(total_workers + 1 + (UITest::in_process_renderer() ? 0 : tab_count),
            UITest::GetBrowserProcessCount());

  // Now close the first tab and check that the queued workers were started.
  tab->Close(true);
  tab->NavigateToURL(GetTestUrl(L"google", L"google.html"));

  EXPECT_EQ(total_workers + 1 + (UITest::in_process_renderer() ? 0 : tab_count),
            UITest::GetBrowserProcessCount());
}
#endif
<|endoftext|>


<commit_before><commit_msg>Disable Worker*.WorkerFastLayoutTests for now.<commit_after><|endoftext|>


<commit_before>#ifndef ALEPH_MATH_KAHAN_SUMMATION_HH__
#define ALEPH_MATH_KAHAN_SUMMATION_HH__

#include <algorithm>
#include <vector>

namespace aleph
{

namespace math
{

template <class T> class KahanSummation
{
public:
  KahanSummation( T initial = T() )
    : _sum( initial )
    , _c( T() )
  {
  }

  KahanSummation& operator+= ( T v )
  {
    T y  = v - _c;
    T t  = _sum + y;
    _c   = ( t - _sum ) - y;
    _sum = t;

    return *this;
  }

  KahanSummation& operator-= ( T v )
  {
    return this->operator+=( -v );
  }

  KahanSummation& operator*= ( T v )
  {
    _sum *= v;
    return *this;
  }

  KahanSummation& operator/= ( T v )
  {
    _sum /= v;
    return *this;
  }

  operator const T () const
  {
    return _sum;
  }

private:
  T _sum;
  T _c;
};

// ---------------------------------------------------------------------

/**
  Accumulation function modelled after \c std::accumulate. Instead of summing
  up the values without regards to floating point cancellation, this function
  uses the Kahan summation algorithm on a sorted range of numbers. This gives
  better stability guarantees for the sum.
*/

template <class InputIterator, class T> T accumulate_kahan( InputIterator first, InputIterator last, T init )
{
  KahanSummation<T> sum = init;

  std::vector<T> values( first, last );
  std::sort( values.begin(), values.end() );

  for( auto&& value : values )
    sum += value;

  return sum;
}

} // namespace math

} // namespace aleph

#endif
<commit_msg>Extended Kahan summation for sorted ranges<commit_after>#ifndef ALEPH_MATH_KAHAN_SUMMATION_HH__
#define ALEPH_MATH_KAHAN_SUMMATION_HH__

#include <algorithm>
#include <vector>

namespace aleph
{

namespace math
{

template <class T> class KahanSummation
{
public:
  KahanSummation( T initial = T() )
    : _sum( initial )
    , _c( T() )
  {
  }

  KahanSummation& operator+= ( T v )
  {
    T y  = v - _c;
    T t  = _sum + y;
    _c   = ( t - _sum ) - y;
    _sum = t;

    return *this;
  }

  KahanSummation& operator-= ( T v )
  {
    return this->operator+=( -v );
  }

  KahanSummation& operator*= ( T v )
  {
    _sum *= v;
    return *this;
  }

  KahanSummation& operator/= ( T v )
  {
    _sum /= v;
    return *this;
  }

  operator const T () const
  {
    return _sum;
  }

private:
  T _sum;
  T _c;
};

// ---------------------------------------------------------------------

/**
  Accumulation function modelled after \c std::accumulate. Instead of summing
  up the values without regards to floating point cancellation, this function
  uses the Kahan summation algorithm on a sorted range of numbers. This gives
  better stability guarantees for the sum.
*/

template <class InputIterator, class T> T accumulate_kahan( InputIterator first, InputIterator last, T init )
{
  KahanSummation<T> sum = init;

  for( auto it = first; it != last; ++it )
    sum += *it;

  return sum;
}

/**
  Kahan summation with sorted values. This further increases the precision
  of the summation algorithm but incurs a higher run-time complexity.
*/

template <class InputIterator, class T> T accumulate_kahan_sorted( InputIterator first, InputIterator last, T init )
{
  KahanSummation<T> sum = init;

  std::vector<T> values( first, last );
  std::sort( values.begin(), values.end() );

  for( auto&& value : values )
    sum += value;

  return sum;
}

} // namespace math

} // namespace aleph

#endif
<|endoftext|>


<commit_before>///
/// @file MessageControllerFull.cpp
/// @date 8/5/2008
/// @author TuanQuang Nguyen
///
///

/**************** Include module header files *******************/
// #include <BasicMessage.h>
#include <net/message-framework/MessageControllerFull.h>
#include <net/message-framework/MessageFrameworkConfiguration.h>
#include <net/message-framework/ServiceMessage.h>
#include <net/message-framework/MessageType.h>
#include <net/message-framework/ServiceRegistrationMessage.h>
#include <net/message-framework/ServiceRegistrationReplyMessage.h>
#include <net/message-framework/ClientIdReplyMessage.h>
#include <net/message-framework/ServicePermissionInfo.h>
#include <boost/filesystem.hpp>

/**************** Include boost header files *******************/
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>

/**************** Include std header files *******************/
#include <iostream>

/**************** Include sf1lib header files *******************/

const static string AvailServiceFileName = "_ctr_services.dat";

namespace messageframework {
//static member variables
std::string MessageControllerFullSingleton::controllerName_("");
unsigned int MessageControllerFullSingleton::controllerPort_ = 0;
boost::scoped_ptr<MessageControllerFull>
		MessageControllerFullSingleton::messageController_(0);
boost::once_flag MessageControllerFullSingleton::flag= BOOST_ONCE_INIT;

MessageControllerFull::MessageControllerFull(const std::string& controllerName,
		unsigned int servicePort) :
	messageDispatcher_(this, this, this, this, this), asyncConnector_(this,
			io_service_) {
	ownerManager_ = controllerName;

	servicePort_ = servicePort;
	asyncConnector_.listen(servicePort_);
	ipAddress_ = getLocalHostIp(io_service_);

	saveLoadAvailableServiceList_(AvailServiceFileName, false);

	// timeout is 1 second
	timeOutMilliSecond_ = 1000;

	//serviceResultReply_ = false;

	// start from 1, so 0 is a invalid client id
	nxtClientId_ = 1;

	// create thread for I/O operations
	ioThread_ = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
}

MessageControllerFull::~MessageControllerFull() {
	asyncConnector_.shutdown();
	ioThread_->join();
	delete ioThread_;
	saveLoadAvailableServiceList_(AvailServiceFileName, true);
}

void MessageControllerFull::saveLoadAvailableServiceList_(
		const string& fileName, bool bStore) {
	if (bStore) {
		std::ofstream ofs(fileName.data(), ios::binary | ios::trunc);
		boost::archive::binary_oarchive oa(ofs);
		oa & availableServiceList_;
	} else {
		if ( ! boost::filesystem::exists(fileName) )
			return;

		std::ifstream ifs(fileName.data(), ios::binary);
		boost::archive::binary_iarchive ia(ifs);
		ia & availableServiceList_;

		std::map<std::string, ServicePermissionInfo>::iterator it;
		it = availableServiceList_.begin();
		for(; it != availableServiceList_.begin(); it++){
			cout<<"!!!!!!!!1"<<endl;
			cout<<it->first<<endl;
		    it->second.display();
		}
	}
}

/******************************************************************************
 Description: This function processes all the waiting service registration requests.
 It registers all the services from MessageServer (IP address, port number,
 a list of service which can be provided by the MessageServer).
 *******************************************************************************/
void MessageControllerFull::processServiceRegistrationRequest(void) {
	try
	{
		boost::mutex::scoped_lock serviceRegistrationRequestQueueLock(
				serviceRegistrationRequestQueueMutex_);

		while(true)
		{
			newRegistrationEvent_.wait(serviceRegistrationRequestQueueLock);
#ifdef _LOGGING_
			WriteToLog("log.log", "=============processServiceRegistrationRequest===========");
#endif
			while(!serviceRegistrationRequestQueue_.empty())
			{
				std::pair<ServiceRegistrationMessage, MessageFrameworkNode> request =
				serviceRegistrationRequestQueue_.front();
				serviceRegistrationRequestQueue_.pop();
				serviceRegistrationRequestQueueLock.unlock();

				{
					// check if the sevice has been registered
					string serviceName = request.first.getServiceInfo().getServiceName();
					MessageFrameworkNode server = request.first.getServiceInfo().getServer();

					boost::mutex::scoped_lock availableServiceListLock(availableServiceListMutex_);

					std::cout<<"ServiceRegistrationRequest: "<<serviceName<<std::endl;
					if( availableServiceList_.find(serviceName) != availableServiceList_.end() )
					{
#ifdef SF1_DEBUG
						std::cout << "[Controller:" << getName();
						std::cout << "] ServiceInfo " << request.first.getServiceName() << " already exists.";
						std::cout << "New data overwrites old data." << std::endl;
#endif

						availableServiceList_[serviceName].setServer(request.first.getAgentInfo(), server);
					} else
					{
						ServicePermissionInfo permissionInfo;
						permissionInfo.setServiceName(serviceName);
						permissionInfo.setServer(request.first.getAgentInfo(), server);
						availableServiceList_[serviceName] = permissionInfo;
					}

					//availableServiceList_[serviceName].display();
					sendServiceRegistrationResult(request.second, request.first.getServiceInfo(), true);
				}

				saveLoadAvailableServiceList_(AvailServiceFileName, true);
#ifdef SF1_DEBUG
				std::cout << "[Controller:" << getName() << "] ServiceInfo [" << request.first.getServiceName();
				std::cout << ", " << request.first.getServer().nodeIP_ << ":";
				std::cout << request.first.getServer().nodePort_ << "] is successfully registerd." << std::endl;
#endif
				// connection to server
				if(!messageDispatcher_.isExist(request.first.getServer()))
				{
					asyncConnector_.connect(request.first.getServer().nodeIP_,
							request.first.getServer().nodePort_);
				}
				serviceRegistrationRequestQueueLock.lock();
			}
		}// end of while true
	}
	catch(MessageFrameworkException& e)
	{
		e.output(std::cout);
	}
	catch (boost::system::error_code& e)
	{
		std::cerr << "Exception: " << e << std::endl;
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: "<< e.what() << std::endl;
	}
}

/******************************************************************************
 Description: This function processes all the waiting service permission requests.
 It determines whether it is available to process the service and issues
 permission to the MessageClient. If the service needs to use the direct
 connection, MessageControllerFull sends the permission to the MessageServer.
 ******************************************************************************/

bool MessageControllerFull::checkAgentInfo_(
		ServicePermissionInfo& permissionInfo) {
	const std::map<std::string, MessageFrameworkNode>& agentInfoMap =
			permissionInfo.getServerMap();
	std::map<std::string, MessageFrameworkNode>::const_iterator it =
			agentInfoMap.begin();

	for (; it != agentInfoMap.end(); it++) {
		if ( !messageDispatcher_.isExist(it->second) ) {
			DLOG(ERROR)<<"ServicePermissionInfo:"<<it->first<<" -> server:"
					<<it->second<<"not exists";
			permissionInfo.removeServer(it->first);
			saveLoadAvailableServiceList_(AvailServiceFileName, true);
		}
	}
	if (it != agentInfoMap.end() )
		return false;
	return true;

}

void MessageControllerFull::processServicePermissionRequest(void) {
	try
	{
		std::pair<std::string, MessageFrameworkNode> requestItem;
		ServiceInfo serviceInfo;

		boost::mutex::scoped_lock permissionRequestQueueLock(servicePermissionRequestQueueMutex_);
		while(true)
		{
			newPermissionRequestEvent_.wait(permissionRequestQueueLock);
#ifdef _LOGGING_
			WriteToLog("log.log", "============= processServicePermissionRequest ===========");
#endif
			// process all the waiting requests
			while(!servicePermissionRequestQueue_.empty())
			{
				requestItem = servicePermissionRequestQueue_.front();
				servicePermissionRequestQueue_.pop();

				permissionRequestQueueLock.unlock();

				if( availableServiceList_.find(requestItem.first) != availableServiceList_.end() )
				{
					boost::mutex::scoped_lock availableServiceListLock(availableServiceListMutex_);
					checkAgentInfo_( availableServiceList_[requestItem.first] );
					sendPermissionOfServiceResult(requestItem.second, availableServiceList_[requestItem.first] );
					availableServiceList_[requestItem.first].display();
					// to improve performance, direct connection to
					// server is always made
					//serviceInfo.setPermissionFlag(SERVE_AT_SERVER);
					// serviceInfo.setServer(ipAddress_, servicePort_);

				} else
				{
					ServicePermissionInfo permission;
					permission.setServiceName(requestItem.first);
					//serviceInfo.setPermissionFlag(UNKNOWN_PERMISSION_FLAG);
#ifdef SF1_DEBUG
					std::cout << " [Controller:" << getName();
					std::cout << "] Service " << requestItem.first;
					std::cout << " is not listed." << std::endl;
#endif
					sendPermissionOfServiceResult(requestItem.second, permission );
					cout<<"!!! no listed"<<endl;
					availableServiceList_[requestItem.first].display();
				}

#ifdef SF1_DEBUG
				std::cout << "[Controller:" << getName();
				std::cout << "] Permission of " << requestItem.first;
				std::cout << " is successfully sent to ";
				std::cout << requestItem.second.nodeIP_ << ":" << requestItem.second.nodePort_ << std::endl;
#endif
				permissionRequestQueueLock.lock();
			}// end of while(!servicePermissionRequestQueue_.empty())
		}// end of while(true)
	}
	catch(MessageFrameworkException& e)
	{
		e.output(std::cout);
	}
	catch (boost::system::error_code& e)
	{
		std::cerr << "Exception: " << e << std::endl;
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: "<< e.what() << std::endl;
	}

}

/******************************************************************************
 Description: When a new request of get client id comes, this function is called
 in order to notify the server
 ******************************************************************************/
void MessageControllerFull::receiveClientIdRequest(
		const MessageFrameworkNode& requester) {
	{
		boost::mutex::scoped_lock lock(nxtClientIdMutex_);
		if (nxtClientId_ == MF_FULL_MAX_CLIENT_ID) {
			std::cout << "Max Client ID reached" << std::endl;
			throw MessageFrameworkException(SF1_MSGFRK_LOGIC_ERROR, __LINE__, __FILE__);
		}
		std::cout << "DEBUG: MessageControllerFull:: dispatch nxtClientId_="
				<<nxtClientId_ << std::endl;
		sendClientIdResult(requester, nxtClientId_);
		nxtClientId_ ++;
	}
}

/******************************************************************************
 Description: This function replies to a request from ClientIdRequester
 ******************************************************************************/
void MessageControllerFull::sendClientIdResult(
		const MessageFrameworkNode& requester, const int& clientId) {
	ClientIdReplyMessage message(clientId);
	messageDispatcher_.sendDataToLowerLayer(CLIENT_ID_REPLY_MSG, message,
			requester);
}

/******************************************************************************
 Description: This function put a request to get  permission of service into the
 waiting queue. The requests in the waitiing queue will be processed in function
 processServicePermissionRequest().
 ******************************************************************************/
void MessageControllerFull::receivePermissionOfServiceRequest(
		const MessageFrameworkNode& requester, const std::string& serviceName) {
#ifdef SF1_DEBUG
	std::cout << "[Controller:" << getName() << "] Receive permission request of ";
	std::cout << serviceName << " from " << requester.nodeName_ << std::endl;
#endif
	{
		boost::mutex::scoped_lock lock(servicePermissionRequestQueueMutex_);
		servicePermissionRequestQueue_.push(std::pair<std::string, MessageFrameworkNode>(serviceName, requester));
	}
	newPermissionRequestEvent_.notify_all();
}

/******************************************************************************
 Description: This function inserts a ServiceInfo to the serviceRegistrationRequestQueue_.
 It returns false if the data alread exists in the queue.
 Input:
 serviceInfo - data to add
 ******************************************************************************/
void MessageControllerFull::receiveServiceRegistrationRequest(const MessageFrameworkNode& localEndPoint,
const ServiceRegistrationMessage& registMessage)
{
	try
	{
		{
			boost::mutex::scoped_lock lock(serviceRegistrationRequestQueueMutex_);
			serviceRegistrationRequestQueue_.push(
			std::pair<ServiceRegistrationMessage, MessageFrameworkNode>(registMessage, localEndPoint));
		}
		newRegistrationEvent_.notify_all();
	}
	catch (boost::system::error_code& e)
	{
		std::cerr << "Exception: " << e << std::endl;
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: "<< e.what() << std::endl;
	}

}

/**
 * @brief This function replies to a registration request from ServiceRegistrationRequester. It
 * will sends registration result to the ServiceRegistrationRequester.
 * @param localEndPoint the end point that connects to the ServiceRegistrationClient.
 * @param serviceInfo the service information to register
 * @param success the registration result
 */
void MessageControllerFull::sendServiceRegistrationResult(const MessageFrameworkNode& localEndPoint, const ServiceInfo& serviceInfo,
bool success)
{
	ServiceRegistrationReplyMessage message(serviceInfo.getServiceName(), success);

	messageDispatcher_.sendDataToLowerLayer(SERVICE_REGISTRATION_REPLY_MSG, message, localEndPoint);
}

/**
 * @brief This function replies to a request from PermissionRequester
 */
void MessageControllerFull::sendPermissionOfServiceResult(const MessageFrameworkNode& requester,
const ServicePermissionInfo & permission)
{
	messageDispatcher_.sendDataToLowerLayer(PERMISSION_OF_SERVICE_REPLY_MSG,
	permission, requester);
}

/**
 * @brief This function create a new AsyncStream that is based on tcp::socket
 */
AsyncStream* MessageControllerFull::createAsyncStream(boost::shared_ptr<tcp::socket> sock)
{
	// tcp::endpoint endpoint = sock->local_endpoint();
	tcp::endpoint endpoint = sock->remote_endpoint();
	std::cout << "Remote IP = " << endpoint.address().to_string();
	std::cout << ", port = " << endpoint.port() << std::endl;

	return new AsyncStream(&messageDispatcher_, sock);
}

}// end of namespace messageframework

<commit_msg>disable load permisioninfo in controller<commit_after>///
/// @file MessageControllerFull.cpp
/// @date 8/5/2008
/// @author TuanQuang Nguyen
///
///

/**************** Include module header files *******************/
// #include <BasicMessage.h>
#include <net/message-framework/MessageControllerFull.h>
#include <net/message-framework/MessageFrameworkConfiguration.h>
#include <net/message-framework/ServiceMessage.h>
#include <net/message-framework/MessageType.h>
#include <net/message-framework/ServiceRegistrationMessage.h>
#include <net/message-framework/ServiceRegistrationReplyMessage.h>
#include <net/message-framework/ClientIdReplyMessage.h>
#include <net/message-framework/ServicePermissionInfo.h>
#include <boost/filesystem.hpp>

/**************** Include boost header files *******************/
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>

/**************** Include std header files *******************/
#include <iostream>

/**************** Include sf1lib header files *******************/

const static string AvailServiceFileName = "_ctr_services.dat";

namespace messageframework {
//static member variables
std::string MessageControllerFullSingleton::controllerName_("");
unsigned int MessageControllerFullSingleton::controllerPort_ = 0;
boost::scoped_ptr<MessageControllerFull>
		MessageControllerFullSingleton::messageController_(0);
boost::once_flag MessageControllerFullSingleton::flag= BOOST_ONCE_INIT;

MessageControllerFull::MessageControllerFull(const std::string& controllerName,
		unsigned int servicePort) :
	messageDispatcher_(this, this, this, this, this), asyncConnector_(this,
			io_service_) {
	ownerManager_ = controllerName;

	servicePort_ = servicePort;
	asyncConnector_.listen(servicePort_);
	ipAddress_ = getLocalHostIp(io_service_);

	saveLoadAvailableServiceList_(AvailServiceFileName, false);

	// timeout is 1 second
	timeOutMilliSecond_ = 1000;

	//serviceResultReply_ = false;

	// start from 1, so 0 is a invalid client id
	nxtClientId_ = 1;

	// create thread for I/O operations
	ioThread_ = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
}

MessageControllerFull::~MessageControllerFull() {
	asyncConnector_.shutdown();
	ioThread_->join();
	delete ioThread_;
	saveLoadAvailableServiceList_(AvailServiceFileName, true);
}

void MessageControllerFull::saveLoadAvailableServiceList_(
		const string& fileName, bool bStore) {
//	if (bStore) {
//		std::ofstream ofs(fileName.data(), ios::binary | ios::trunc);
//		boost::archive::binary_oarchive oa(ofs);
//		oa & availableServiceList_;
//	} else {
//		if ( ! boost::filesystem::exists(fileName) )
//			return;
//
//		std::ifstream ifs(fileName.data(), ios::binary);
//		boost::archive::binary_iarchive ia(ifs);
//		ia & availableServiceList_;
//
//		std::map<std::string, ServicePermissionInfo>::iterator it;
//		it = availableServiceList_.begin();
//		for(; it != availableServiceList_.end(); it++){
//			cout<<"!!!!!!!!1"<<endl;
//			cout<<it->first<<endl;
//		    it->second.display();
//		}
//	}
}

/******************************************************************************
 Description: This function processes all the waiting service registration requests.
 It registers all the services from MessageServer (IP address, port number,
 a list of service which can be provided by the MessageServer).
 *******************************************************************************/
void MessageControllerFull::processServiceRegistrationRequest(void) {
	try
	{
		boost::mutex::scoped_lock serviceRegistrationRequestQueueLock(
				serviceRegistrationRequestQueueMutex_);

		while(true)
		{
			newRegistrationEvent_.wait(serviceRegistrationRequestQueueLock);
#ifdef _LOGGING_
			WriteToLog("log.log", "=============processServiceRegistrationRequest===========");
#endif
			while(!serviceRegistrationRequestQueue_.empty())
			{
				std::pair<ServiceRegistrationMessage, MessageFrameworkNode> request =
				serviceRegistrationRequestQueue_.front();
				serviceRegistrationRequestQueue_.pop();
				serviceRegistrationRequestQueueLock.unlock();

				{
					// check if the sevice has been registered
					string serviceName = request.first.getServiceInfo().getServiceName();
					MessageFrameworkNode server = request.first.getServiceInfo().getServer();

					boost::mutex::scoped_lock availableServiceListLock(availableServiceListMutex_);

					std::cout<<"ServiceRegistrationRequest: "<<serviceName<<std::endl;
					if( availableServiceList_.find(serviceName) != availableServiceList_.end() )
					{
#ifdef SF1_DEBUG
						std::cout << "[Controller:" << getName();
						std::cout << "] ServiceInfo " << request.first.getServiceName() << " already exists.";
						std::cout << "New data overwrites old data." << std::endl;
#endif

						availableServiceList_[serviceName].setServer(request.first.getAgentInfo(), server);
					} else
					{
						ServicePermissionInfo permissionInfo;
						permissionInfo.setServiceName(serviceName);
						permissionInfo.setServer(request.first.getAgentInfo(), server);
						availableServiceList_[serviceName] = permissionInfo;
					}

					//availableServiceList_[serviceName].display();
					sendServiceRegistrationResult(request.second, request.first.getServiceInfo(), true);
				}

				saveLoadAvailableServiceList_(AvailServiceFileName, true);
#ifdef SF1_DEBUG
				std::cout << "[Controller:" << getName() << "] ServiceInfo [" << request.first.getServiceName();
				std::cout << ", " << request.first.getServer().nodeIP_ << ":";
				std::cout << request.first.getServer().nodePort_ << "] is successfully registerd." << std::endl;
#endif
				// connection to server
				if(!messageDispatcher_.isExist(request.first.getServer()))
				{
					asyncConnector_.connect(request.first.getServer().nodeIP_,
							request.first.getServer().nodePort_);
				}
				serviceRegistrationRequestQueueLock.lock();
			}
		}// end of while true
	}
	catch(MessageFrameworkException& e)
	{
		e.output(std::cout);
	}
	catch (boost::system::error_code& e)
	{
		std::cerr << "Exception: " << e << std::endl;
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: "<< e.what() << std::endl;
	}
}

/******************************************************************************
 Description: This function processes all the waiting service permission requests.
 It determines whether it is available to process the service and issues
 permission to the MessageClient. If the service needs to use the direct
 connection, MessageControllerFull sends the permission to the MessageServer.
 ******************************************************************************/

bool MessageControllerFull::checkAgentInfo_(
		ServicePermissionInfo& permissionInfo) {
	const std::map<std::string, MessageFrameworkNode>& agentInfoMap =
			permissionInfo.getServerMap();
	std::map<std::string, MessageFrameworkNode>::const_iterator it =
			agentInfoMap.begin();

	for (; it != agentInfoMap.end(); it++) {
		if ( !messageDispatcher_.isExist(it->second) ) {
			DLOG(ERROR)<<"ServicePermissionInfo:"<<it->first<<" -> server:"
					<<it->second<<"not exists";
			permissionInfo.removeServer(it->first);
			saveLoadAvailableServiceList_(AvailServiceFileName, true);
		}
	}
	if (it != agentInfoMap.end() )
		return false;
	return true;

}

void MessageControllerFull::processServicePermissionRequest(void) {
	try
	{
		std::pair<std::string, MessageFrameworkNode> requestItem;
		ServiceInfo serviceInfo;

		boost::mutex::scoped_lock permissionRequestQueueLock(servicePermissionRequestQueueMutex_);
		while(true)
		{
			newPermissionRequestEvent_.wait(permissionRequestQueueLock);
#ifdef _LOGGING_
			WriteToLog("log.log", "============= processServicePermissionRequest ===========");
#endif
			// process all the waiting requests
			while(!servicePermissionRequestQueue_.empty())
			{
				requestItem = servicePermissionRequestQueue_.front();
				servicePermissionRequestQueue_.pop();

				permissionRequestQueueLock.unlock();

				if( availableServiceList_.find(requestItem.first) != availableServiceList_.end() )
				{
					boost::mutex::scoped_lock availableServiceListLock(availableServiceListMutex_);
					checkAgentInfo_( availableServiceList_[requestItem.first] );
					sendPermissionOfServiceResult(requestItem.second, availableServiceList_[requestItem.first] );
					availableServiceList_[requestItem.first].display();
					// to improve performance, direct connection to
					// server is always made
					//serviceInfo.setPermissionFlag(SERVE_AT_SERVER);
					// serviceInfo.setServer(ipAddress_, servicePort_);

				} else
				{
					ServicePermissionInfo permission;
					permission.setServiceName(requestItem.first);
					//serviceInfo.setPermissionFlag(UNKNOWN_PERMISSION_FLAG);
#ifdef SF1_DEBUG
					std::cout << " [Controller:" << getName();
					std::cout << "] Service " << requestItem.first;
					std::cout << " is not listed." << std::endl;
#endif
					sendPermissionOfServiceResult(requestItem.second, permission );
					cout<<"!!! no listed"<<endl;
					availableServiceList_[requestItem.first].display();
				}

#ifdef SF1_DEBUG
				std::cout << "[Controller:" << getName();
				std::cout << "] Permission of " << requestItem.first;
				std::cout << " is successfully sent to ";
				std::cout << requestItem.second.nodeIP_ << ":" << requestItem.second.nodePort_ << std::endl;
#endif
				permissionRequestQueueLock.lock();
			}// end of while(!servicePermissionRequestQueue_.empty())
		}// end of while(true)
	}
	catch(MessageFrameworkException& e)
	{
		e.output(std::cout);
	}
	catch (boost::system::error_code& e)
	{
		std::cerr << "Exception: " << e << std::endl;
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: "<< e.what() << std::endl;
	}

}

/******************************************************************************
 Description: When a new request of get client id comes, this function is called
 in order to notify the server
 ******************************************************************************/
void MessageControllerFull::receiveClientIdRequest(
		const MessageFrameworkNode& requester) {
	{
		boost::mutex::scoped_lock lock(nxtClientIdMutex_);
		if (nxtClientId_ == MF_FULL_MAX_CLIENT_ID) {
			std::cout << "Max Client ID reached" << std::endl;
			throw MessageFrameworkException(SF1_MSGFRK_LOGIC_ERROR, __LINE__, __FILE__);
		}
		std::cout << "DEBUG: MessageControllerFull:: dispatch nxtClientId_="
				<<nxtClientId_ << std::endl;
		sendClientIdResult(requester, nxtClientId_);
		nxtClientId_ ++;
	}
}

/******************************************************************************
 Description: This function replies to a request from ClientIdRequester
 ******************************************************************************/
void MessageControllerFull::sendClientIdResult(
		const MessageFrameworkNode& requester, const int& clientId) {
	ClientIdReplyMessage message(clientId);
	messageDispatcher_.sendDataToLowerLayer(CLIENT_ID_REPLY_MSG, message,
			requester);
}

/******************************************************************************
 Description: This function put a request to get  permission of service into the
 waiting queue. The requests in the waitiing queue will be processed in function
 processServicePermissionRequest().
 ******************************************************************************/
void MessageControllerFull::receivePermissionOfServiceRequest(
		const MessageFrameworkNode& requester, const std::string& serviceName) {
#ifdef SF1_DEBUG
	std::cout << "[Controller:" << getName() << "] Receive permission request of ";
	std::cout << serviceName << " from " << requester.nodeName_ << std::endl;
#endif
	{
		boost::mutex::scoped_lock lock(servicePermissionRequestQueueMutex_);
		servicePermissionRequestQueue_.push(std::pair<std::string, MessageFrameworkNode>(serviceName, requester));
	}
	newPermissionRequestEvent_.notify_all();
}

/******************************************************************************
 Description: This function inserts a ServiceInfo to the serviceRegistrationRequestQueue_.
 It returns false if the data alread exists in the queue.
 Input:
 serviceInfo - data to add
 ******************************************************************************/
void MessageControllerFull::receiveServiceRegistrationRequest(const MessageFrameworkNode& localEndPoint,
const ServiceRegistrationMessage& registMessage)
{
	try
	{
		{
			boost::mutex::scoped_lock lock(serviceRegistrationRequestQueueMutex_);
			serviceRegistrationRequestQueue_.push(
			std::pair<ServiceRegistrationMessage, MessageFrameworkNode>(registMessage, localEndPoint));
		}
		newRegistrationEvent_.notify_all();
	}
	catch (boost::system::error_code& e)
	{
		std::cerr << "Exception: " << e << std::endl;
	}
	catch (std::exception& e)
	{
		std::cerr << "Exception: "<< e.what() << std::endl;
	}

}

/**
 * @brief This function replies to a registration request from ServiceRegistrationRequester. It
 * will sends registration result to the ServiceRegistrationRequester.
 * @param localEndPoint the end point that connects to the ServiceRegistrationClient.
 * @param serviceInfo the service information to register
 * @param success the registration result
 */
void MessageControllerFull::sendServiceRegistrationResult(const MessageFrameworkNode& localEndPoint, const ServiceInfo& serviceInfo,
bool success)
{
	ServiceRegistrationReplyMessage message(serviceInfo.getServiceName(), success);

	messageDispatcher_.sendDataToLowerLayer(SERVICE_REGISTRATION_REPLY_MSG, message, localEndPoint);
}

/**
 * @brief This function replies to a request from PermissionRequester
 */
void MessageControllerFull::sendPermissionOfServiceResult(const MessageFrameworkNode& requester,
const ServicePermissionInfo & permission)
{
	messageDispatcher_.sendDataToLowerLayer(PERMISSION_OF_SERVICE_REPLY_MSG,
	permission, requester);
}

/**
 * @brief This function create a new AsyncStream that is based on tcp::socket
 */
AsyncStream* MessageControllerFull::createAsyncStream(boost::shared_ptr<tcp::socket> sock)
{
	// tcp::endpoint endpoint = sock->local_endpoint();
	tcp::endpoint endpoint = sock->remote_endpoint();
	std::cout << "Remote IP = " << endpoint.address().to_string();
	std::cout << ", port = " << endpoint.port() << std::endl;

	return new AsyncStream(&messageDispatcher_, sock);
}

}// end of namespace messageframework

<|endoftext|>


<commit_before>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#pragma once

#include <agency/detail/config.hpp>
#include <agency/cuda/detail/feature_test.hpp>
#include <agency/cuda/detail/terminate.hpp>
#include <agency/cuda/detail/unique_ptr.hpp>
#include <agency/cuda/detail/then_kernel.hpp>
#include <agency/cuda/detail/launch_kernel.hpp>
#include <agency/cuda/detail/workaround_unused_variable_warning.hpp>
#include <agency/future.hpp>
#include <agency/detail/type_traits.hpp>
#include <utility>
#include <type_traits>

namespace agency
{
namespace cuda
{
namespace detail
{

template<class T, class... Args>
struct is_constructible_or_void
  : std::integral_constant<
      bool,
      std::is_constructible<T,Args...>::value ||
      (std::is_void<T>::value && (sizeof...(Args) == 0))
    >
{};

template<class T>
struct state_requires_storage
  : std::integral_constant<
      bool,
      std::is_empty<T>::value || std::is_void<T>::value || agency::detail::is_empty_tuple<T>::value
   >
{};

// XXX should maybe call this asynchronous_state to match the nomenclature of the std
template<class T,
         bool requires_storage = state_requires_storage<T>::value>
class future_state
{
  public:
    __host__ __device__
    future_state() = default;

    template<class Arg1, class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Arg1,Args...>::value
             >::type
            >
    __host__ __device__
    future_state(cudaStream_t s, Arg1&& ready_arg1, Args&&... ready_args)
      : data_(make_unique<T>(s, std::forward<Arg1>(ready_arg1), std::forward<Args>(ready_args)...))
    {}

    __host__ __device__
    future_state(cudaStream_t s)
      : future_state(s, T{})
    {}

    __host__ __device__
    future_state(future_state&& other) : data_(std::move(other.data_)) {}

    __host__ __device__
    future_state& operator=(future_state&& other)
    {
      data_ = std::move(other.data_);
      return *this;
    }

    __host__ __device__
    T* data()
    {
      return data_.get();
    }

    __host__ __device__
    T get()
    {
      T result = std::move(*data_);

      data_.reset();

      return std::move(result);
    }

    __host__ __device__
    bool valid() const
    {
      return data_;
    }

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args...>::value
             >::type>
    __host__ __device__
    void set_valid(cudaStream_t s, Args&&... ready_args)
    {
      data_ = make_unique<T>(s, std::forward<Args>(ready_args)...);
    }

    __host__ __device__
    void swap(future_state& other)
    {
      data_.swap(other.data_);
    }

  private:
    unique_ptr<T> data_;
};

// when a type is empty, we can create it on the fly upon dereference
template<class T>
struct empty_type_ptr : T
{
  using element_type = T;

  __host__ __device__
  T& operator*()
  {
    return *this;
  }

  __host__ __device__
  const T& operator*() const
  {
    return *this;
  }
};

template<>
struct empty_type_ptr<void> : unit_ptr {};

// zero storage optimization
template<class T>
class future_state<T,true>
{
  public:
    __host__ __device__
    future_state() : valid_(false) {}

    // constructs a valid state
    template<class U,
             class = typename std::enable_if<
               std::is_constructible<T,U>::value
             >::type>
    __host__ __device__
    future_state(cudaStream_t, U&&) : valid_(true) {}

    // constructs a valid state
    __host__ __device__
    future_state(cudaStream_t) : valid_(true) {}

    __host__ __device__
    future_state(future_state&& other) : valid_(false)
    {
      valid_ = other.valid_;
      other.valid_ = false;
    }

    // 1. allow moves to void states (this simply discards the state)
    // 2. allow moves to empty types if the type can be constructed from an empty argument list
    template<class U,
             class T1 = T,
             class = typename std::enable_if<
               std::is_void<T1>::value ||
               (std::is_empty<T>::value && std::is_void<U>::value && std::is_constructible<T>::value)
             >::type>
    __host__ __device__
    future_state(future_state<U>&& other)
      : valid_(other.valid())
    {
      if(valid())
      {
        // invalidate the old state by calling .get() if it was valid when we received it
        other.get();
      }
    }

    __host__ __device__
    future_state& operator=(future_state&& other)
    {
      valid_ = other.valid_;
      other.valid_ = false;

      return *this;
    }

    __host__ __device__
    empty_type_ptr<T> data()
    {
      return empty_type_ptr<T>();
    }

    __host__ __device__
    T get()
    {
      valid_ = false;

      return get_impl(std::is_void<T>());
    }

    __host__ __device__
    bool valid() const
    {
      return valid_;
    }

    // constructor arguments are simply ignored
    // XXX if the constructor has a side effect, we probably need to actually invoke it, even though
    //     the type has no state and requires no storage
    template<class... Args>
    __host__ __device__
    void set_valid(cudaStream_t, Args&&...)
    {
      valid_ = true;
    }

    __host__ __device__
    void swap(future_state& other)
    {
      bool other_valid_old = other.valid_;
      other.valid_ = valid_;
      valid_ = other_valid_old;
    }

  private:
    __host__ __device__
    static T get_impl(std::false_type)
    {
      return T{};
    }

    __host__ __device__
    static T get_impl(std::true_type)
    {
      return;
    }

    bool valid_;
};

// declare this so future may befriend it
template<class Shape, class Index, class ThisIndexFunction>
class basic_grid_executor;

} // end detail

template<typename T>
class future
{
  private:
    cudaStream_t stream_;
    cudaEvent_t event_;
    detail::future_state<T> state_;

  public:
    // XXX this should be private
    __host__ __device__
    future(cudaStream_t s) : future(s, 0) {}

    // XXX stream_ should default to per-thread default stream
    __host__ __device__
    future() : future(0) {}

    __host__ __device__
    future(future&& other)
      : future()
    {
      future::swap(stream_, other.stream_);
      future::swap(event_,  other.event_);
      state_.swap(other.state_);
    } // end future()

    __host__ __device__
    future &operator=(future&& other)
    {
      future::swap(stream_, other.stream_);
      future::swap(event_,  other.event_);
      future::swap(state_,  other.state_);
      return *this;
    } // end operator=()

    template<class U,
             class = typename std::enable_if<
               std::is_constructible<
                 detail::future_state<T>,
                 detail::future_state<U>&&
               >::value
             >::type>
    __host__ __device__
    future(future<U>&& other)
      : stream_(),
        event_(),
        state_(std::move(other.state_))
    {
      future::swap(stream_, other.stream_);
      future::swap(event_,  other.event_);
    } // end future()

    __host__ __device__
    ~future()
    {
      if(valid())
      {
        destroy_event();
      } // end if
    } // end ~future()

    __host__ __device__
    void wait() const
    {
      // XXX should probably check for valid() here

#if __cuda_lib_has_cudart

#ifndef __CUDA_ARCH__
      // XXX need to capture the error as an exception and then throw it in .get()
      detail::throw_on_error(cudaEventSynchronize(event_), "cudaEventSynchronize in agency::cuda<void>::future::wait");
#else
      // XXX need to capture the error as an exception and then throw it in .get()
      detail::throw_on_error(cudaDeviceSynchronize(), "cudaDeviceSynchronize in agency::cuda<void>::future::wait");
#endif // __CUDA_ARCH__

#else
      detail::terminate_with_message("agency::cuda::future<void>::wait() requires CUDART");
#endif // __cuda_lib_has_cudart
    } // end wait()

    __host__ __device__
    T get()
    {
      wait();

      return state_.get();
    } // end get()

    __host__ __device__
    bool valid() const
    {
      return (event_ != 0) && state_.valid();
    } // end valid()

    __host__ __device__
    cudaEvent_t event() const
    {
      return event_;
    } // end event()

    __host__ __device__
    cudaStream_t stream() const
    {
      return stream_;
    } // end stream()

    template<class... Args,
             class = typename std::enable_if<
               detail::is_constructible_or_void<T,Args...>::value
             >::type>
    __host__ __device__
    static future make_ready(Args&&... args)
    {
      cudaEvent_t ready_event = 0;

#if __cuda_lib_has_cudart
      detail::throw_on_error(cudaEventCreateWithFlags(&ready_event, event_create_flags), "cudaEventCreateWithFlags in agency::cuda::future<void>::make_ready");
#else
      detail::terminate_with_message("agency::cuda::future<void>::make_ready() requires CUDART");
#endif

      future result;
      result.set_valid(ready_event, std::forward<Args>(args)...);

      return result;
    }

    // XXX this is only used by grid_executor::then_execute()
    __host__ __device__
    auto data() -> decltype(state_.data())
    {
      return state_.data();
    }

    template<class Function>
    __host__ __device__
    future<agency::detail::result_of_continuation_t<Function,future>>
      then(Function f)
    {
      // create state for the continuation's result
      using result_type = agency::detail::result_of_continuation_t<Function,future>;
      detail::future_state<result_type> result_state(stream());

      // get a pointer to the continuation's kernel
      using result_ptr_type = decltype(result_state.data());
      using arg_ptr_type = decltype(data());
      void (*kernel_ptr)(result_ptr_type, Function, arg_ptr_type) = detail::then_kernel<result_ptr_type, Function, arg_ptr_type>;
      detail::workaround_unused_variable_warning(kernel_ptr);

      // launch the continuation
      cudaEvent_t next_event = detail::checked_launch_kernel_after_event_returning_next_event(reinterpret_cast<void*>(kernel_ptr), dim3{1}, dim3{1}, 0, stream(), event(), result_state.data(), f, data());

      // this future's event is no longer usable
      // note this invalidates this future
      destroy_event();

      // return the continuation's future
      return future<result_type>(stream(), next_event, std::move(result_state));
    }

    // XXX set_valid() should only be available to friends
    //     such as future<U> and grid_executor
    template<class... Args,
             class = typename std::enable_if<
               detail::is_constructible_or_void<T,Args...>::value
             >::type>
    __host__ __device__
    void set_valid(cudaEvent_t e, Args&&... args)
    {
      event_ = e;
      state_.set_valid(stream(), std::forward<Args>(args)...);
    }

  private:
    template<class U> friend class future;
    template<class Shape, class Index, class ThisIndexFunction> friend class agency::cuda::detail::basic_grid_executor;

    __host__ __device__
    future(cudaStream_t s, cudaEvent_t e, detail::future_state<T>&& state)
      : stream_(s), event_(e), state_(std::move(state))
    {}

    template<class... Args,
             class = typename std::enable_if<
               detail::is_constructible_or_void<T,Args...>::value
             >::type>
    __host__ __device__
    future(cudaStream_t s, cudaEvent_t e, Args&&... ready_args)
      : future(s, e, detail::future_state<T>(s, std::forward<Args>(ready_args)...))
    {}

    // implement swap to avoid depending on thrust::swap
    template<class U>
    __host__ __device__
    static void swap(U& a, U& b)
    {
      U tmp{a};
      a = b;
      b = tmp;
    }

    static const int event_create_flags = cudaEventDisableTiming;

    __host__ __device__
    void destroy_event()
    {
#if __cuda_lib_has_cudart
      // since this will likely be called from destructors, swallow errors
      cudaError_t e = cudaEventDestroy(event_);
      event_ = 0;

#if __cuda_lib_has_printf
      if(e)
      {
        printf("CUDA error after cudaEventDestroy in agency::cuda::future<void> dtor: %s", cudaGetErrorString(e));
      } // end if
#endif // __cuda_lib_has_printf
#endif // __cuda_lib_has_cudart
    }
};

inline __host__ __device__
future<void> make_ready_future()
{
  return future<void>::make_ready();
} // end make_ready_future()

template<class T>
inline __host__ __device__
future<typename std::decay<T>::type> make_ready_future(T&& value)
{
  return future<typename std::decay<T>::type>::make_ready(std::forward<T>(value));
} // end make_ready_future()

} // end namespace cuda
} // end namespace agency

<commit_msg>Simplify some of future_state's members<commit_after>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#pragma once

#include <agency/detail/config.hpp>
#include <agency/cuda/detail/feature_test.hpp>
#include <agency/cuda/detail/terminate.hpp>
#include <agency/cuda/detail/unique_ptr.hpp>
#include <agency/cuda/detail/then_kernel.hpp>
#include <agency/cuda/detail/launch_kernel.hpp>
#include <agency/cuda/detail/workaround_unused_variable_warning.hpp>
#include <agency/future.hpp>
#include <agency/detail/type_traits.hpp>
#include <utility>
#include <type_traits>

namespace agency
{
namespace cuda
{
namespace detail
{

template<class T, class... Args>
struct is_constructible_or_void
  : std::integral_constant<
      bool,
      std::is_constructible<T,Args...>::value ||
      (std::is_void<T>::value && (sizeof...(Args) == 0))
    >
{};

template<class T>
struct state_requires_storage
  : std::integral_constant<
      bool,
      std::is_empty<T>::value || std::is_void<T>::value || agency::detail::is_empty_tuple<T>::value
   >
{};

// XXX should maybe call this asynchronous_state to match the nomenclature of the std
template<class T,
         bool requires_storage = state_requires_storage<T>::value>
class future_state
{
  public:
    __host__ __device__
    future_state() = default;

    template<class Arg1, class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Arg1,Args...>::value
             >::type
            >
    __host__ __device__
    future_state(cudaStream_t s, Arg1&& ready_arg1, Args&&... ready_args)
      : data_(make_unique<T>(s, std::forward<Arg1>(ready_arg1), std::forward<Args>(ready_args)...))
    {}

    __host__ __device__
    future_state(cudaStream_t s)
      : future_state(s, T{})
    {}

    __host__ __device__
    future_state(future_state&& other) = default;

    __host__ __device__
    future_state& operator=(future_state&&) = default;

    __host__ __device__
    T* data()
    {
      return data_.get();
    }

    __host__ __device__
    T get()
    {
      T result = std::move(*data_);

      data_.reset();

      return std::move(result);
    }

    __host__ __device__
    bool valid() const
    {
      return data_;
    }

    template<class... Args,
             class = typename std::enable_if<
               std::is_constructible<T,Args...>::value
             >::type>
    __host__ __device__
    void set_valid(cudaStream_t s, Args&&... ready_args)
    {
      data_ = make_unique<T>(s, std::forward<Args>(ready_args)...);
    }

    __host__ __device__
    void swap(future_state& other)
    {
      data_.swap(other.data_);
    }

  private:
    unique_ptr<T> data_;
};

// when a type is empty, we can create it on the fly upon dereference
template<class T>
struct empty_type_ptr : T
{
  using element_type = T;

  __host__ __device__
  T& operator*()
  {
    return *this;
  }

  __host__ __device__
  const T& operator*() const
  {
    return *this;
  }
};

template<>
struct empty_type_ptr<void> : unit_ptr {};

// zero storage optimization
template<class T>
class future_state<T,true>
{
  public:
    __host__ __device__
    future_state() : valid_(false) {}

    // constructs a valid state
    template<class U,
             class = typename std::enable_if<
               std::is_constructible<T,U>::value
             >::type>
    __host__ __device__
    future_state(cudaStream_t, U&&) : valid_(true) {}

    // constructs a valid state
    __host__ __device__
    future_state(cudaStream_t) : valid_(true) {}

    __host__ __device__
    future_state(future_state&& other) : valid_(other.valid_)
    {
      other.valid_ = false;
    }

    // 1. allow moves to void states (this simply discards the state)
    // 2. allow moves to empty types if the type can be constructed from an empty argument list
    template<class U,
             class T1 = T,
             class = typename std::enable_if<
               std::is_void<T1>::value ||
               (std::is_empty<T>::value && std::is_void<U>::value && std::is_constructible<T>::value)
             >::type>
    __host__ __device__
    future_state(future_state<U>&& other)
      : valid_(other.valid())
    {
      if(valid())
      {
        // invalidate the old state by calling .get() if it was valid when we received it
        other.get();
      }
    }

    __host__ __device__
    future_state& operator=(future_state&& other)
    {
      valid_ = other.valid_;
      other.valid_ = false;

      return *this;
    }

    __host__ __device__
    empty_type_ptr<T> data()
    {
      return empty_type_ptr<T>();
    }

    __host__ __device__
    T get()
    {
      valid_ = false;

      return get_impl(std::is_void<T>());
    }

    __host__ __device__
    bool valid() const
    {
      return valid_;
    }

    // constructor arguments are simply ignored
    // XXX if the constructor has a side effect, we probably need to actually invoke it, even though
    //     the type has no state and requires no storage
    template<class... Args>
    __host__ __device__
    void set_valid(cudaStream_t, Args&&...)
    {
      valid_ = true;
    }

    __host__ __device__
    void swap(future_state& other)
    {
      bool other_valid_old = other.valid_;
      other.valid_ = valid_;
      valid_ = other_valid_old;
    }

  private:
    __host__ __device__
    static T get_impl(std::false_type)
    {
      return T{};
    }

    __host__ __device__
    static T get_impl(std::true_type)
    {
      return;
    }

    bool valid_;
};

// declare this so future may befriend it
template<class Shape, class Index, class ThisIndexFunction>
class basic_grid_executor;

} // end detail

template<typename T>
class future
{
  private:
    cudaStream_t stream_;
    cudaEvent_t event_;
    detail::future_state<T> state_;

  public:
    // XXX this should be private
    __host__ __device__
    future(cudaStream_t s) : future(s, 0) {}

    // XXX stream_ should default to per-thread default stream
    __host__ __device__
    future() : future(0) {}

    __host__ __device__
    future(future&& other)
      : future()
    {
      future::swap(stream_, other.stream_);
      future::swap(event_,  other.event_);
      state_.swap(other.state_);
    } // end future()

    __host__ __device__
    future &operator=(future&& other)
    {
      future::swap(stream_, other.stream_);
      future::swap(event_,  other.event_);
      future::swap(state_,  other.state_);
      return *this;
    } // end operator=()

    template<class U,
             class = typename std::enable_if<
               std::is_constructible<
                 detail::future_state<T>,
                 detail::future_state<U>&&
               >::value
             >::type>
    __host__ __device__
    future(future<U>&& other)
      : stream_(),
        event_(),
        state_(std::move(other.state_))
    {
      future::swap(stream_, other.stream_);
      future::swap(event_,  other.event_);
    } // end future()

    __host__ __device__
    ~future()
    {
      if(valid())
      {
        destroy_event();
      } // end if
    } // end ~future()

    __host__ __device__
    void wait() const
    {
      // XXX should probably check for valid() here

#if __cuda_lib_has_cudart

#ifndef __CUDA_ARCH__
      // XXX need to capture the error as an exception and then throw it in .get()
      detail::throw_on_error(cudaEventSynchronize(event_), "cudaEventSynchronize in agency::cuda<void>::future::wait");
#else
      // XXX need to capture the error as an exception and then throw it in .get()
      detail::throw_on_error(cudaDeviceSynchronize(), "cudaDeviceSynchronize in agency::cuda<void>::future::wait");
#endif // __CUDA_ARCH__

#else
      detail::terminate_with_message("agency::cuda::future<void>::wait() requires CUDART");
#endif // __cuda_lib_has_cudart
    } // end wait()

    __host__ __device__
    T get()
    {
      wait();

      return state_.get();
    } // end get()

    __host__ __device__
    bool valid() const
    {
      return (event_ != 0) && state_.valid();
    } // end valid()

    __host__ __device__
    cudaEvent_t event() const
    {
      return event_;
    } // end event()

    __host__ __device__
    cudaStream_t stream() const
    {
      return stream_;
    } // end stream()

    template<class... Args,
             class = typename std::enable_if<
               detail::is_constructible_or_void<T,Args...>::value
             >::type>
    __host__ __device__
    static future make_ready(Args&&... args)
    {
      cudaEvent_t ready_event = 0;

#if __cuda_lib_has_cudart
      detail::throw_on_error(cudaEventCreateWithFlags(&ready_event, event_create_flags), "cudaEventCreateWithFlags in agency::cuda::future<void>::make_ready");
#else
      detail::terminate_with_message("agency::cuda::future<void>::make_ready() requires CUDART");
#endif

      future result;
      result.set_valid(ready_event, std::forward<Args>(args)...);

      return result;
    }

    // XXX this is only used by grid_executor::then_execute()
    __host__ __device__
    auto data() -> decltype(state_.data())
    {
      return state_.data();
    }

    template<class Function>
    __host__ __device__
    future<agency::detail::result_of_continuation_t<Function,future>>
      then(Function f)
    {
      // create state for the continuation's result
      using result_type = agency::detail::result_of_continuation_t<Function,future>;
      detail::future_state<result_type> result_state(stream());

      // get a pointer to the continuation's kernel
      using result_ptr_type = decltype(result_state.data());
      using arg_ptr_type = decltype(data());
      void (*kernel_ptr)(result_ptr_type, Function, arg_ptr_type) = detail::then_kernel<result_ptr_type, Function, arg_ptr_type>;
      detail::workaround_unused_variable_warning(kernel_ptr);

      // launch the continuation
      cudaEvent_t next_event = detail::checked_launch_kernel_after_event_returning_next_event(reinterpret_cast<void*>(kernel_ptr), dim3{1}, dim3{1}, 0, stream(), event(), result_state.data(), f, data());

      // this future's event is no longer usable
      // note this invalidates this future
      destroy_event();

      // return the continuation's future
      return future<result_type>(stream(), next_event, std::move(result_state));
    }

    // XXX set_valid() should only be available to friends
    //     such as future<U> and grid_executor
    template<class... Args,
             class = typename std::enable_if<
               detail::is_constructible_or_void<T,Args...>::value
             >::type>
    __host__ __device__
    void set_valid(cudaEvent_t e, Args&&... args)
    {
      event_ = e;
      state_.set_valid(stream(), std::forward<Args>(args)...);
    }

  private:
    template<class U> friend class future;
    template<class Shape, class Index, class ThisIndexFunction> friend class agency::cuda::detail::basic_grid_executor;

    __host__ __device__
    future(cudaStream_t s, cudaEvent_t e, detail::future_state<T>&& state)
      : stream_(s), event_(e), state_(std::move(state))
    {}

    template<class... Args,
             class = typename std::enable_if<
               detail::is_constructible_or_void<T,Args...>::value
             >::type>
    __host__ __device__
    future(cudaStream_t s, cudaEvent_t e, Args&&... ready_args)
      : future(s, e, detail::future_state<T>(s, std::forward<Args>(ready_args)...))
    {}

    // implement swap to avoid depending on thrust::swap
    template<class U>
    __host__ __device__
    static void swap(U& a, U& b)
    {
      U tmp{a};
      a = b;
      b = tmp;
    }

    static const int event_create_flags = cudaEventDisableTiming;

    __host__ __device__
    void destroy_event()
    {
#if __cuda_lib_has_cudart
      // since this will likely be called from destructors, swallow errors
      cudaError_t e = cudaEventDestroy(event_);
      event_ = 0;

#if __cuda_lib_has_printf
      if(e)
      {
        printf("CUDA error after cudaEventDestroy in agency::cuda::future<void> dtor: %s", cudaGetErrorString(e));
      } // end if
#endif // __cuda_lib_has_printf
#endif // __cuda_lib_has_cudart
    }
};

inline __host__ __device__
future<void> make_ready_future()
{
  return future<void>::make_ready();
} // end make_ready_future()

} // end namespace cuda
} // end namespace agency

<|endoftext|>