<commit_before>// Copyright (c) 2011 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/sync/signin_manager.h"

#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/net/gaia/token_service_unittest.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/sync/util/oauth.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/net/gaia/gaia_urls.h"
#include "chrome/test/base/signaling_task.h"
#include "chrome/test/base/testing_profile.h"
#include "content/test/test_url_fetcher_factory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"

#include "testing/gtest/include/gtest/gtest.h"

class SigninManagerTest : public TokenServiceTestHarness {
 public:
  virtual void SetUp() {
    TokenServiceTestHarness::SetUp();
    manager_.reset(new SigninManager());
    google_login_success_.ListenFor(
        chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
        Source<Profile>(profile_.get()));
    google_login_failure_.ListenFor(chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
                                    Source<Profile>(profile_.get()));
  }

  void SimulateValidResponseClientLogin() {
    DCHECK(!browser_sync::IsUsingOAuth());
    // Simulate the correct ClientLogin response.
    TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
    DCHECK(fetcher);
    DCHECK(fetcher->delegate());
    fetcher->delegate()->OnURLFetchComplete(
        fetcher, GURL(GaiaUrls::GetInstance()->client_login_url()),
        net::URLRequestStatus(), 200, net::ResponseCookies(),
        "SID=sid\nLSID=lsid\nAuth=auth");

    // Then simulate the correct GetUserInfo response for the canonical email.
    // A new URL fetcher is used for each call.
    fetcher = factory_.GetFetcherByID(0);
    DCHECK(fetcher);
    DCHECK(fetcher->delegate());
    fetcher->delegate()->OnURLFetchComplete(
        fetcher, GURL(GaiaUrls::GetInstance()->get_user_info_url()),
        net::URLRequestStatus(), 200, net::ResponseCookies(),
        "email=user@gmail.com");
  }

  void SimulateSigninStartOAuth() {
    DCHECK(browser_sync::IsUsingOAuth());
    // Simulate a valid OAuth-based signin
    manager_->OnGetOAuthTokenSuccess("oauth_token-Ev1Vu1hv");
    manager_->OnOAuthGetAccessTokenSuccess("oauth1_access_token-qOAmlrSM",
                                           "secret-NKKn1DuR");
    manager_->OnOAuthWrapBridgeSuccess(browser_sync::SyncServiceName(),
                                       "oauth2_wrap_access_token-R0Z3nRtw",
                                       "3600");
  }

  void SimulateOAuthUserInfoSuccess() {
    manager_->OnUserInfoSuccess("user-xZIuqTKu@gmail.com");
  }

  void SimulateValidSigninOAuth() {
    SimulateSigninStartOAuth();
    SimulateOAuthUserInfoSuccess();
  }

  TestURLFetcherFactory factory_;
  scoped_ptr<SigninManager> manager_;
  TestNotificationTracker google_login_success_;
  TestNotificationTracker google_login_failure_;
};

// NOTE: ClientLogin's "StartSignin" is called after collecting credentials
//       from the user.  See also SigninManagerTest::SignInOAuth.
TEST_F(SigninManagerTest, SignInClientLogin) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());

  manager_->StartSignIn("username", "password", "", "");
  EXPECT_FALSE(manager_->GetUsername().empty());

  SimulateValidResponseClientLogin();

  // Should go into token service and stop.
  EXPECT_EQ(1U, google_login_success_.size());
  EXPECT_EQ(0U, google_login_failure_.size());

  // Should persist across resets.
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_EQ("user@gmail.com", manager_->GetUsername());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

// NOTE: OAuth's "StartOAuthSignIn" is called before collecting credentials
//       from the user.  See also SigninManagerTest::SignInClientLogin.
TEST_F(SigninManagerTest, SignInOAuth) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(true);
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());

  SimulateValidSigninOAuth();
  EXPECT_FALSE(manager_->GetUsername().empty());

  // Should go into token service and stop.
  EXPECT_EQ(1U, google_login_success_.size());
  EXPECT_EQ(0U, google_login_failure_.size());

  // Should persist across resets.
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_EQ("user-xZIuqTKu@gmail.com", manager_->GetUsername());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, SignOutClientLogin) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  SimulateValidResponseClientLogin();
  manager_->OnClientLoginSuccess(credentials_);

  EXPECT_EQ("user@gmail.com", manager_->GetUsername());
  manager_->SignOut();
  EXPECT_TRUE(manager_->GetUsername().empty());
  // Should not be persisted anymore
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, SignOutOAuth) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(true);
  manager_->Initialize(profile_.get());

  SimulateValidSigninOAuth();
  EXPECT_FALSE(manager_->GetUsername().empty());

  EXPECT_EQ("user-xZIuqTKu@gmail.com", manager_->GetUsername());
  manager_->SignOut();
  EXPECT_TRUE(manager_->GetUsername().empty());

  // Should not be persisted anymore
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, SignInFailureClientLogin) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
  manager_->OnClientLoginFailure(error);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());

  EXPECT_TRUE(manager_->GetUsername().empty());

  // Should not be persisted
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, ProvideSecondFactorSuccess) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR);
  manager_->OnClientLoginFailure(error);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());

  EXPECT_FALSE(manager_->GetUsername().empty());

  manager_->ProvideSecondFactorAccessCode("access");
  SimulateValidResponseClientLogin();

  EXPECT_EQ(1U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, ProvideSecondFactorFailure) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  GoogleServiceAuthError error1(GoogleServiceAuthError::TWO_FACTOR);
  manager_->OnClientLoginFailure(error1);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());

  EXPECT_FALSE(manager_->GetUsername().empty());

  manager_->ProvideSecondFactorAccessCode("badaccess");
  GoogleServiceAuthError error2(
      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
  manager_->OnClientLoginFailure(error2);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(2U, google_login_failure_.size());
  EXPECT_FALSE(manager_->GetUsername().empty());

  manager_->ProvideSecondFactorAccessCode("badaccess");
  GoogleServiceAuthError error3(GoogleServiceAuthError::CONNECTION_FAILED);
  manager_->OnClientLoginFailure(error3);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(3U, google_login_failure_.size());
  EXPECT_TRUE(manager_->GetUsername().empty());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, SignOutMidConnect) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  manager_->SignOut();
  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(0U, google_login_failure_.size());

  EXPECT_TRUE(manager_->GetUsername().empty());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}

TEST_F(SigninManagerTest, SignOutOnUserInfoSucessRaceTest) {
  bool originally_using_oauth = browser_sync::IsUsingOAuth();
  browser_sync::SetIsUsingOAuthForTest(true);
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());

  SimulateSigninStartOAuth();
  manager_->SignOut();
  SimulateOAuthUserInfoSuccess();
  EXPECT_TRUE(manager_->GetUsername().empty());
  browser_sync::SetIsUsingOAuthForTest(originally_using_oauth);
}
<commit_msg>Use SetUp/TearDown to ensure IsOAuthState in SigninManagerTest<commit_after>// Copyright (c) 2011 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/sync/signin_manager.h"

#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/net/gaia/token_service_unittest.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/sync/util/oauth.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/net/gaia/gaia_urls.h"
#include "chrome/test/base/signaling_task.h"
#include "chrome/test/base/testing_profile.h"
#include "content/test/test_url_fetcher_factory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"

#include "testing/gtest/include/gtest/gtest.h"

class SigninManagerTest : public TokenServiceTestHarness {
 public:
  virtual void SetUp() OVERRIDE {
    TokenServiceTestHarness::SetUp();
    manager_.reset(new SigninManager());
    google_login_success_.ListenFor(
        chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
        Source<Profile>(profile_.get()));
    google_login_failure_.ListenFor(chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
                                    Source<Profile>(profile_.get()));
    originally_using_oauth_ = browser_sync::IsUsingOAuth();
  }

  virtual void TearDown() OVERRIDE {
    browser_sync::SetIsUsingOAuthForTest(originally_using_oauth_);
  }

  void SimulateValidResponseClientLogin() {
    DCHECK(!browser_sync::IsUsingOAuth());
    // Simulate the correct ClientLogin response.
    TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
    DCHECK(fetcher);
    DCHECK(fetcher->delegate());
    fetcher->delegate()->OnURLFetchComplete(
        fetcher, GURL(GaiaUrls::GetInstance()->client_login_url()),
        net::URLRequestStatus(), 200, net::ResponseCookies(),
        "SID=sid\nLSID=lsid\nAuth=auth");

    // Then simulate the correct GetUserInfo response for the canonical email.
    // A new URL fetcher is used for each call.
    fetcher = factory_.GetFetcherByID(0);
    DCHECK(fetcher);
    DCHECK(fetcher->delegate());
    fetcher->delegate()->OnURLFetchComplete(
        fetcher, GURL(GaiaUrls::GetInstance()->get_user_info_url()),
        net::URLRequestStatus(), 200, net::ResponseCookies(),
        "email=user@gmail.com");
  }

  void SimulateSigninStartOAuth() {
    DCHECK(browser_sync::IsUsingOAuth());
    // Simulate a valid OAuth-based signin
    manager_->OnGetOAuthTokenSuccess("oauth_token-Ev1Vu1hv");
    manager_->OnOAuthGetAccessTokenSuccess("oauth1_access_token-qOAmlrSM",
                                           "secret-NKKn1DuR");
    manager_->OnOAuthWrapBridgeSuccess(browser_sync::SyncServiceName(),
                                       "oauth2_wrap_access_token-R0Z3nRtw",
                                       "3600");
  }

  void SimulateOAuthUserInfoSuccess() {
    manager_->OnUserInfoSuccess("user-xZIuqTKu@gmail.com");
  }

  void SimulateValidSigninOAuth() {
    SimulateSigninStartOAuth();
    SimulateOAuthUserInfoSuccess();
  }

  TestURLFetcherFactory factory_;
  scoped_ptr<SigninManager> manager_;
  TestNotificationTracker google_login_success_;
  TestNotificationTracker google_login_failure_;
  bool originally_using_oauth_;
};

// NOTE: ClientLogin's "StartSignin" is called after collecting credentials
//       from the user.  See also SigninManagerTest::SignInOAuth.
TEST_F(SigninManagerTest, SignInClientLogin) {
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());

  manager_->StartSignIn("username", "password", "", "");
  EXPECT_FALSE(manager_->GetUsername().empty());

  SimulateValidResponseClientLogin();

  // Should go into token service and stop.
  EXPECT_EQ(1U, google_login_success_.size());
  EXPECT_EQ(0U, google_login_failure_.size());

  // Should persist across resets.
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_EQ("user@gmail.com", manager_->GetUsername());
}

// NOTE: OAuth's "StartOAuthSignIn" is called before collecting credentials
//       from the user.  See also SigninManagerTest::SignInClientLogin.
TEST_F(SigninManagerTest, SignInOAuth) {
  browser_sync::SetIsUsingOAuthForTest(true);
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());

  SimulateValidSigninOAuth();
  EXPECT_FALSE(manager_->GetUsername().empty());

  // Should go into token service and stop.
  EXPECT_EQ(1U, google_login_success_.size());
  EXPECT_EQ(0U, google_login_failure_.size());

  // Should persist across resets.
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_EQ("user-xZIuqTKu@gmail.com", manager_->GetUsername());
}

TEST_F(SigninManagerTest, SignOutClientLogin) {
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  SimulateValidResponseClientLogin();
  manager_->OnClientLoginSuccess(credentials_);

  EXPECT_EQ("user@gmail.com", manager_->GetUsername());
  manager_->SignOut();
  EXPECT_TRUE(manager_->GetUsername().empty());
  // Should not be persisted anymore
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());
}

TEST_F(SigninManagerTest, SignOutOAuth) {
  browser_sync::SetIsUsingOAuthForTest(true);
  manager_->Initialize(profile_.get());

  SimulateValidSigninOAuth();
  EXPECT_FALSE(manager_->GetUsername().empty());

  EXPECT_EQ("user-xZIuqTKu@gmail.com", manager_->GetUsername());
  manager_->SignOut();
  EXPECT_TRUE(manager_->GetUsername().empty());

  // Should not be persisted anymore
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());
}

TEST_F(SigninManagerTest, SignInFailureClientLogin) {
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
  manager_->OnClientLoginFailure(error);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());

  EXPECT_TRUE(manager_->GetUsername().empty());

  // Should not be persisted
  manager_.reset(new SigninManager());
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());
}

TEST_F(SigninManagerTest, ProvideSecondFactorSuccess) {
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR);
  manager_->OnClientLoginFailure(error);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());

  EXPECT_FALSE(manager_->GetUsername().empty());

  manager_->ProvideSecondFactorAccessCode("access");
  SimulateValidResponseClientLogin();

  EXPECT_EQ(1U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());
}

TEST_F(SigninManagerTest, ProvideSecondFactorFailure) {
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  GoogleServiceAuthError error1(GoogleServiceAuthError::TWO_FACTOR);
  manager_->OnClientLoginFailure(error1);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(1U, google_login_failure_.size());

  EXPECT_FALSE(manager_->GetUsername().empty());

  manager_->ProvideSecondFactorAccessCode("badaccess");
  GoogleServiceAuthError error2(
      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
  manager_->OnClientLoginFailure(error2);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(2U, google_login_failure_.size());
  EXPECT_FALSE(manager_->GetUsername().empty());

  manager_->ProvideSecondFactorAccessCode("badaccess");
  GoogleServiceAuthError error3(GoogleServiceAuthError::CONNECTION_FAILED);
  manager_->OnClientLoginFailure(error3);

  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(3U, google_login_failure_.size());
  EXPECT_TRUE(manager_->GetUsername().empty());
}

TEST_F(SigninManagerTest, SignOutMidConnect) {
  browser_sync::SetIsUsingOAuthForTest(false);
  manager_->Initialize(profile_.get());
  manager_->StartSignIn("username", "password", "", "");
  manager_->SignOut();
  EXPECT_EQ(0U, google_login_success_.size());
  EXPECT_EQ(0U, google_login_failure_.size());

  EXPECT_TRUE(manager_->GetUsername().empty());
}

TEST_F(SigninManagerTest, SignOutOnUserInfoSucessRaceTest) {
  browser_sync::SetIsUsingOAuthForTest(true);
  manager_->Initialize(profile_.get());
  EXPECT_TRUE(manager_->GetUsername().empty());

  SimulateSigninStartOAuth();
  manager_->SignOut();
  SimulateOAuthUserInfoSuccess();
  EXPECT_TRUE(manager_->GetUsername().empty());
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 Red Hat, Inc.
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <libdnf/plugin/plugin.h>
#include <libdnf/libdnf.h>
#include <libdnf/log.hpp>
#include <rhsm/rhsm.h>

#include <string>

#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// Information about this plugin
// Pointer to this structure is returned by pluginGetInfo().
static const PluginInfo info = {
    .name = "rhsm",
    .version = "1.0.0"
};

// plugin context private data
// Pointer to instance of this structure is returned by pluginInitContext() as handle.
struct _PluginHandle
{
    PluginMode mode;
    void * initData;  // store plugin context specific init data
};

const PluginInfo * pluginGetInfo(void)
{
    return &info;
}

PluginHandle * pluginInitHandle(int version, PluginMode mode, void * initData)
{
    auto logger(libdnf::Log::getLogger());
    if (version != 1) {
        auto msg = std::string(info.name) + ": " + __func__ + ": Error: Unsupported API version";
        logger->error(msg);
        return nullptr;
    }
    if (mode != PLUGIN_MODE_CONTEXT) {
        auto msg = std::string(info.name) + ": " + __func__ + ": Warning: Unsupported mode";
        logger->warning(msg);
        return nullptr;
    }
    auto handle = new PluginHandle;
    handle->mode = mode;
    handle->initData = initData;
    return handle;
}

void pluginFreeHandle(PluginHandle * handle)
{
    if (handle)
        delete handle;
}

/**
 * dnf_context_setup_enrollments:
 * @context: a #DnfContext instance.
 *
 * Resyncs the enrollment with the vendor system. This may change the contents
 * of files in repos.d according to subscription levels.
 *
 * Returns: %true for success, %false otherwise
 **/
static bool setupEnrollments(PluginHandle *handle)
{
    auto logger(libdnf::Log::getLogger());

    auto dnfContext = static_cast<DnfContext *>(handle->initData);

    /* Let's assume that alternative installation roots don't
     * require entitlement.  We only want to do system things if
     * we're actually affecting the system.  A more accurate test
     * here would be checking that we're using /etc/yum.repos.d or
     * so, but that can come later.
     */
    auto installRoot = dnf_context_get_install_root(dnfContext);
    if (installRoot && strcmp(installRoot, "/") != 0)
        return true;

    /* Also, all of the subman stuff only works as root, if we're not
     * root, assume we're running in the test suite, or we're part of
     * e.g. rpm-ostree which is trying to run totally as non-root.
     */
    if (getuid() != 0)
        return true;

    auto repoDir = dnf_context_get_repo_dir(dnfContext);
    g_autofree gchar *repofname = g_build_filename(repoDir, "redhat.repo", NULL);

    g_autoptr(RHSMContext) rhsm_ctx = rhsm_context_new();
    g_autoptr(GKeyFile) repofile = rhsm_utils_yum_repo_from_context(rhsm_ctx);

    /* We don't want rewrite "redhat.repo" file with the same content.
     * So we do a comparison of contents. Only If file is missing or
     * contents differs new content is written to the file.
     */
    bool sameContent = false;
    int fd;
    if ((fd = open(repofname, O_RDONLY)) != -1) {
        gsize length;
        g_autofree gchar *data = g_key_file_to_data(repofile, &length, NULL);
        auto fileLen = lseek(fd, 0, SEEK_END);
        if (fileLen == static_cast<long>(length)) {
            if (fileLen > 0) {
                auto addr = mmap(NULL, fileLen, PROT_READ, MAP_PRIVATE, fd, 0);
                if (addr != reinterpret_cast<void *>(-1)) {
                    sameContent = memcmp(addr, data, fileLen) == 0;
                    munmap(addr, fileLen);
                }
            } else {
                sameContent = true;
            }
        }
        close(fd);
    }
    if (!sameContent) {
        GError * error = nullptr;
        if (!g_key_file_save_to_file(repofile, repofname, &error)) {
            logger->error(std::string(info.name) + ": " + __func__ + ": Error: Can't save repo file: " + error->message);
            g_error_free(error);
            return false;
        }
    }

    return true;
}

int pluginHook(PluginHandle * handle, PluginHookId id, void * hookData, PluginHookError * error)
{
    if (!handle)
        return 1;

    switch (id) {
        case PLUGIN_HOOK_ID_CONTEXT_PRE_REPOS_RELOAD:
            return setupEnrollments(handle);
        default:
            break;
    }
    return 1;
}
<commit_msg>[plugins] RHSM: add cache only mode support<commit_after>/*
 * Copyright (C) 2018 Red Hat, Inc.
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <libdnf/plugin/plugin.h>
#include <libdnf/libdnf.h>
#include <libdnf/log.hpp>
#include <rhsm/rhsm.h>

#include <string>

#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// Information about this plugin
// Pointer to this structure is returned by pluginGetInfo().
static const PluginInfo info = {
    .name = "rhsm",
    .version = "1.0.0"
};

// plugin context private data
// Pointer to instance of this structure is returned by pluginInitContext() as handle.
struct _PluginHandle
{
    PluginMode mode;
    void * initData;  // store plugin context specific init data
};

const PluginInfo * pluginGetInfo(void)
{
    return &info;
}

PluginHandle * pluginInitHandle(int version, PluginMode mode, void * initData)
{
    auto logger(libdnf::Log::getLogger());
    if (version != 1) {
        auto msg = std::string(info.name) + ": " + __func__ + ": Error: Unsupported API version";
        logger->error(msg);
        return nullptr;
    }
    if (mode != PLUGIN_MODE_CONTEXT) {
        auto msg = std::string(info.name) + ": " + __func__ + ": Warning: Unsupported mode";
        logger->warning(msg);
        return nullptr;
    }
    auto handle = new PluginHandle;
    handle->mode = mode;
    handle->initData = initData;
    return handle;
}

void pluginFreeHandle(PluginHandle * handle)
{
    if (handle)
        delete handle;
}

/**
 * dnf_context_setup_enrollments:
 * @context: a #DnfContext instance.
 *
 * Resyncs the enrollment with the vendor system. This may change the contents
 * of files in repos.d according to subscription levels.
 *
 * Returns: %true for success, %false otherwise
 **/
static bool setupEnrollments(PluginHandle *handle)
{
    auto logger(libdnf::Log::getLogger());

    auto dnfContext = static_cast<DnfContext *>(handle->initData);

    if (dnf_context_get_cache_only(dnfContext))
        return true;

    /* Let's assume that alternative installation roots don't
     * require entitlement.  We only want to do system things if
     * we're actually affecting the system.  A more accurate test
     * here would be checking that we're using /etc/yum.repos.d or
     * so, but that can come later.
     */
    auto installRoot = dnf_context_get_install_root(dnfContext);
    if (installRoot && strcmp(installRoot, "/") != 0)
        return true;

    /* Also, all of the subman stuff only works as root, if we're not
     * root, assume we're running in the test suite, or we're part of
     * e.g. rpm-ostree which is trying to run totally as non-root.
     */
    if (getuid() != 0)
        return true;

    auto repoDir = dnf_context_get_repo_dir(dnfContext);
    g_autofree gchar *repofname = g_build_filename(repoDir, "redhat.repo", NULL);

    g_autoptr(RHSMContext) rhsm_ctx = rhsm_context_new();
    g_autoptr(GKeyFile) repofile = rhsm_utils_yum_repo_from_context(rhsm_ctx);

    /* We don't want rewrite "redhat.repo" file with the same content.
     * So we do a comparison of contents. Only If file is missing or
     * contents differs new content is written to the file.
     */
    bool sameContent = false;
    int fd;
    if ((fd = open(repofname, O_RDONLY)) != -1) {
        gsize length;
        g_autofree gchar *data = g_key_file_to_data(repofile, &length, NULL);
        auto fileLen = lseek(fd, 0, SEEK_END);
        if (fileLen == static_cast<long>(length)) {
            if (fileLen > 0) {
                auto addr = mmap(NULL, fileLen, PROT_READ, MAP_PRIVATE, fd, 0);
                if (addr != reinterpret_cast<void *>(-1)) {
                    sameContent = memcmp(addr, data, fileLen) == 0;
                    munmap(addr, fileLen);
                }
            } else {
                sameContent = true;
            }
        }
        close(fd);
    }
    if (!sameContent) {
        GError * error = nullptr;
        if (!g_key_file_save_to_file(repofile, repofname, &error)) {
            logger->error(std::string(info.name) + ": " + __func__ + ": Error: Can't save repo file: " + error->message);
            g_error_free(error);
            return false;
        }
    }

    return true;
}

int pluginHook(PluginHandle * handle, PluginHookId id, void * hookData, PluginHookError * error)
{
    if (!handle)
        return 1;

    switch (id) {
        case PLUGIN_HOOK_ID_CONTEXT_PRE_REPOS_RELOAD:
            return setupEnrollments(handle);
        default:
            break;
    }
    return 1;
}
<|endoftext|>


<commit_before>#include "ninja.h"

#include <getopt.h>
#include <stdio.h>

#include "graphviz.h"
#include "parsers.h"

option options[] = {
  { "help", no_argument, NULL, 'h' },
  { }
};

void usage() {
  fprintf(stderr,
"usage: ninja [options] target\n"
"\n"
"options:\n"
"  -g       output graphviz dot file for targets and exit\n"
"  -i FILE  specify input build file [default=build.ninja]\n"
          );
}

struct RealFileReader : public ManifestParser::FileReader {
  bool ReadFile(const string& path, string* content, string* err) {
    return ::ReadFile(path, content, err) == 0;
  }
};

int main(int argc, char** argv) {
  const char* input_file = "build.ninja";

  int opt;
  bool graph = false;
  while ((opt = getopt_long(argc, argv, "ghi:", options, NULL)) != -1) {
    switch (opt) {
      case 'g':
        graph = true;
        break;
      case 'i':
        input_file = optarg;
        break;
      case 'h':
      default:
        usage();
        return 1;
    }
  }
  if (optind >= argc) {
    fprintf(stderr, "expected target to build\n");
    usage();
    return 1;
  }
  argv += optind;
  argc -= optind;

  State state;
  RealFileReader file_reader;
  ManifestParser parser(&state, &file_reader);
  string err;
  if (!parser.Load(input_file, &err)) {
    fprintf(stderr, "error loading '%s': %s\n", input_file, err.c_str());
    return 1;
  }

  if (graph) {
    GraphViz graph;
    graph.Start();
    for (int i = 0; i < argc; ++i)
      graph.AddTarget(state.GetNode(argv[i]));
    graph.Finish();
    return 0;
  }

  Shell shell;
  Builder builder(&state);
  for (int i = 0; i < argc; ++i) {
    if (!builder.AddTarget(argv[i], &err)) {
      if (!err.empty()) {
        fprintf(stderr, "%s\n", err.c_str());
        return 1;
      } else {
        // Added a target that is already up-to-date; not really
        // an error.
      }
    }
  }

  bool success = builder.Build(&shell, &err);
  if (!err.empty()) {
    printf("%s\n", err.c_str());
  }

  return success ? 0 : 1;
}
<commit_msg>provide $root from getcwd<commit_after>#include "ninja.h"

#include <getopt.h>
#include <limits.h>
#include <stdio.h>

#include "graphviz.h"
#include "parsers.h"

option options[] = {
  { "help", no_argument, NULL, 'h' },
  { }
};

void usage() {
  fprintf(stderr,
"usage: ninja [options] target\n"
"\n"
"options:\n"
"  -g       output graphviz dot file for targets and exit\n"
"  -i FILE  specify input build file [default=build.ninja]\n"
          );
}

struct RealFileReader : public ManifestParser::FileReader {
  bool ReadFile(const string& path, string* content, string* err) {
    return ::ReadFile(path, content, err) == 0;
  }
};

int main(int argc, char** argv) {
  const char* input_file = "build.ninja";

  int opt;
  bool graph = false;
  while ((opt = getopt_long(argc, argv, "ghi:", options, NULL)) != -1) {
    switch (opt) {
      case 'g':
        graph = true;
        break;
      case 'i':
        input_file = optarg;
        break;
      case 'h':
      default:
        usage();
        return 1;
    }
  }
  if (optind >= argc) {
    fprintf(stderr, "expected target to build\n");
    usage();
    return 1;
  }
  argv += optind;
  argc -= optind;

  char cwd[PATH_MAX];
  if (!getcwd(cwd, sizeof(cwd))) {
    perror("getcwd");
    return 1;
  }

  State state;
  RealFileReader file_reader;
  ManifestParser parser(&state, &file_reader);
  parser.set_root(cwd);
  string err;
  if (!parser.Load(input_file, &err)) {
    fprintf(stderr, "error loading '%s': %s\n", input_file, err.c_str());
    return 1;
  }

  if (graph) {
    GraphViz graph;
    graph.Start();
    for (int i = 0; i < argc; ++i)
      graph.AddTarget(state.GetNode(argv[i]));
    graph.Finish();
    return 0;
  }

  Shell shell;
  Builder builder(&state);
  for (int i = 0; i < argc; ++i) {
    if (!builder.AddTarget(argv[i], &err)) {
      if (!err.empty()) {
        fprintf(stderr, "%s\n", err.c_str());
        return 1;
      } else {
        // Added a target that is already up-to-date; not really
        // an error.
      }
    }
  }

  bool success = builder.Build(&shell, &err);
  if (!err.empty()) {
    printf("%s\n", err.c_str());
  }

  return success ? 0 : 1;
}
<|endoftext|>


<commit_before>// $Id: petsc_linear_solver.C 2789 2008-04-13 02:24:40Z roystgnr $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2007  Benjamin S. Kirk, John W. Peterson

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

// 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.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh_common.h"

#ifdef HAVE_TRILINOS

// C++ includes

// Local Includes
#include "libmesh_logging.h"
#include "trilinos_aztec_linear_solver.h"
#include "trilinos_epetra_matrix.h"
#include "trilinos_epetra_vector.h"

/*----------------------- functions ----------------------------------*/
template <typename T>
void AztecLinearSolver<T>::clear ()
{
  if (this->initialized())
  {
    this->_is_initialized = false;

    // Mimic PETSc default solver and preconditioner
    this->_solver_type           = GMRES;

    if (libMesh::n_processors() == 1)
      this->_preconditioner_type = ILU_PRECOND;
    else
      this->_preconditioner_type = BLOCK_JACOBI_PRECOND;
  }
}

template <typename T>
void AztecLinearSolver<T>::init ()
{

  // Initialize the data structures if not done so already.
  if (!this->initialized())
  {
    this->_is_initialized = true;

    _linear_solver = new AztecOO();
  }

// // 2.1.x & earlier style
// #if PETSC_VERSION_LESS_THAN(2,2,0)

//       // Create the linear solver context
//       ierr = SLESCreate (libMesh::COMM_WORLD, &_sles);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Create the Krylov subspace & preconditioner contexts
//       ierr = SLESGetKSP       (_sles, &_ksp);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);
//       ierr = SLESGetPC        (_sles, &_pc);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Have the Krylov subspace method use our good initial guess rather than 0
//       ierr = KSPSetInitialGuessNonzero (_ksp, PETSC_TRUE);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Set user-specified  solver and preconditioner types
//       this->set_petsc_solver_type();
//       this->set_petsc_preconditioner_type();

//       // Set the options from user-input
//       // Set runtime options, e.g.,
//       //      -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol>
//       //  These options will override those specified above as long as
//       //  SLESSetFromOptions() is called _after_ any other customization
//       //  routines.

//       ierr = SLESSetFromOptions (_sles);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

// // 2.2.0 & newer style
// #else

//       // Create the linear solver context
//       ierr = KSPCreate (libMesh::COMM_WORLD, &_ksp);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Create the preconditioner context
//       ierr = KSPGetPC        (_ksp, &_pc);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Have the Krylov subspace method use our good initial guess rather than 0
//       ierr = KSPSetInitialGuessNonzero (_ksp, PETSC_TRUE);
//              CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Set user-specified  solver and preconditioner types
//       this->set_petsc_solver_type();
//       this->set_petsc_preconditioner_type();

//       // Set the options from user-input
//       // Set runtime options, e.g.,
//       //      -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol>
//       //  These options will override those specified above as long as
//       //  KSPSetFromOptions() is called _after_ any other customization
//       //  routines.

//       ierr = KSPSetFromOptions (_ksp);
//       CHKERRABORT(libMesh::COMM_WORLD,ierr);

//       // Not sure if this is necessary, or if it is already handled by KSPSetFromOptions?
//       // NOT NECESSARY!!!!
//       //ierr = PCSetFromOptions (_pc);
//       //CHKERRABORT(libMesh::COMM_WORLD,ierr);

// #endif

//       // Notify PETSc of location to store residual history.
//       // This needs to be called before any solves, since
//       // it sets the residual history length to zero.  The default
//       // behavior is for PETSc to allocate (internally) an array
//       // of size 1000 to hold the residual norm history.
//       ierr = KSPSetResidualHistory(_ksp,
// 				   PETSC_NULL,   // pointer to the array which holds the history
// 				   PETSC_DECIDE, // size of the array holding the history
// 				   PETSC_TRUE);  // Whether or not to reset the history for each solve.
//       CHKERRABORT(libMesh::COMM_WORLD,ierr);
//     }
}

template <typename T>
std::pair<unsigned int, Real>
AztecLinearSolver<T>::solve (SparseMatrix<T>& matrix_in,
			     SparseMatrix<T>& precond_in,
			     NumericVector<T>& solution_in,
			     NumericVector<T>& rhs_in,
			     const double tol,
			     const unsigned int m_its)
{
  START_LOG("solve()", "AztecLinearSolver");

  EpetraMatrix<T>* matrix   = dynamic_cast<EpetraMatrix<T>*>(&matrix_in);
  EpetraMatrix<T>* precond  = dynamic_cast<EpetraMatrix<T>*>(&precond_in);
  EpetraVector<T>* solution = dynamic_cast<EpetraVector<T>*>(&solution_in);
  EpetraVector<T>* rhs      = dynamic_cast<EpetraVector<T>*>(&rhs_in);

  // We cast to pointers so we can be sure that they succeeded
  // by comparing the result against NULL.
  libmesh_assert(matrix != NULL);
  libmesh_assert(precond != NULL);
  libmesh_assert(solution != NULL);
  libmesh_assert(rhs != NULL);

  this->init();

  // Close the matrices and vectors in case this wasn't already done.
  matrix->close ();
  precond->close ();
  solution->close ();
  rhs->close ();

  _linear_solver->SetAztecOption(AZ_max_iter,m_its);
  _linear_solver->SetAztecParam(AZ_tol,tol);

  Epetra_FECrsMatrix * emat = matrix->mat();
  Epetra_FEVector * esol = solution->vec();
  Epetra_FEVector * erhs = rhs->vec();

  _linear_solver->Iterate(emat, esol, erhs, m_its, tol);

  STOP_LOG("solve()", "AztecLinearSolver");

  // return the # of its. and the final residual norm.
  return std::make_pair(_linear_solver->NumIters(), _linear_solver->TrueResidual());
}

template <typename T>
void AztecLinearSolver<T>::get_residual_history(std::vector<double>& /* hist */)
{
  libmesh_not_implemented();

//   int ierr = 0;
//   int its  = 0;

//   // Fill the residual history vector with the residual norms
//   // Note that GetResidualHistory() does not copy any values, it
//   // simply sets the pointer p.  Note that for some Krylov subspace
//   // methods, the number of residuals returned in the history
//   // vector may be different from what you are expecting.  For
//   // example, TFQMR returns two residual values per iteration step.
//   PetscReal* p;
//   ierr = KSPGetResidualHistory(_ksp, &p, &its);
//   CHKERRABORT(libMesh::COMM_WORLD,ierr);

//   // Check for early return
//   if (its == 0) return;

//   // Create space to store the result
//   hist.resize(its);

//   // Copy history into the vector provided by the user.
//   for (int i=0; i<its; ++i)
//     {
//       hist[i] = *p;
//       p++;
//     }
}

template <typename T>
Real AztecLinearSolver<T>::get_initial_residual()
{
  return _linear_solver->TrueResidual();
}

template <typename T>
void AztecLinearSolver<T>::print_converged_reason()
{
  libmesh_not_implemented();

// #if PETSC_VERSION_LESS_THAN(2,3,1)
//   std::cout << "This method is currently not supported "
// 	    << "(but may work!) for Petsc 2.3.0 and earlier." << std::endl;
// #else
//   KSPConvergedReason reason;
//   KSPGetConvergedReason(_ksp, &reason);

//   //  KSP_CONVERGED_RTOL (residual 2-norm decreased by a factor of rtol, from 2-norm of right hand side)
//   //  KSP_CONVERGED_ATOL (residual 2-norm less than abstol)
//   //  KSP_CONVERGED_ITS (used by the preonly preconditioner that always uses ONE iteration)
//   //  KSP_CONVERGED_STEP_LENGTH
//   //  KSP_DIVERGED_ITS  (required more than its to reach convergence)
//   //  KSP_DIVERGED_DTOL (residual norm increased by a factor of divtol)
//   //  KSP_DIVERGED_NAN (residual norm became Not-a-number likely do to 0/0)
//   //  KSP_DIVERGED_BREAKDOWN (generic breakdown in method)

//   switch (reason)
//     {
//     case KSP_CONVERGED_RTOL:
//        {
// 	std::cout << "Linear solver converged, relative tolerance reached." << std::endl;
// 	break;
//        }
//     case KSP_CONVERGED_ATOL:
//        {
// 	 std::cout << "Linear solver converged, absolute tolerance reached." << std::endl;
// 	 break;
//        }

//       // Divergence
//     case KSP_DIVERGED_ITS:
//        {
// 	 std::cout << "Linear solver diverged, max no. of iterations reached." << std::endl;
// 	 break;
//        }
//     case KSP_DIVERGED_DTOL:
//        {
// 	 std::cout << "Linear solver diverged, residual norm increase by dtol (default 1.e5)." << std::endl;
// 	 break;
//        }
//     case KSP_DIVERGED_NAN:
//        {
// 	 std::cout << "Linear solver diverged, residual norm is NaN." << std::endl;
// 	 break;
//        }
//     case KSP_DIVERGED_BREAKDOWN:
//        {
// 	 std::cout << "Linear solver diverged, generic breakdown in the method." << std::endl;
// 	 break;
//        }
//     default:
//       {
// 	std::cout << "Unknown/unsupported con(di)vergence reason: " << reason << std::endl;
//       }
//     }
// #endif
}

//------------------------------------------------------------------
// Explicit instantiations
template class AztecLinearSolver<Number>;

#endif // #ifdef HAVE_TRILINOS
<commit_msg>turn on some preconditioning for aztec<commit_after>// $Id: petsc_linear_solver.C 2789 2008-04-13 02:24:40Z roystgnr $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2007  Benjamin S. Kirk, John W. Peterson

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

// 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.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh_common.h"

#ifdef HAVE_TRILINOS

// C++ includes

// Local Includes
#include "libmesh_logging.h"
#include "trilinos_aztec_linear_solver.h"
#include "trilinos_epetra_matrix.h"
#include "trilinos_epetra_vector.h"

/*----------------------- functions ----------------------------------*/
template <typename T>
void AztecLinearSolver<T>::clear ()
{
  if (this->initialized())
  {
    this->_is_initialized = false;

    // Mimic PETSc default solver and preconditioner
    this->_solver_type           = GMRES;

    if (libMesh::n_processors() == 1)
      this->_preconditioner_type = ILU_PRECOND;
    else
      this->_preconditioner_type = BLOCK_JACOBI_PRECOND;
  }
}

template <typename T>
void AztecLinearSolver<T>::init ()
{
  // Initialize the data structures if not done so already.
  if (!this->initialized())
  {
    this->_is_initialized = true;

    _linear_solver = new AztecOO();

    switch(this->_preconditioner_type)
    {
    case ILU_PRECOND:
      _linear_solver->SetAztecOption(AZ_precond,AZ_dom_decomp);
      break;
    case BLOCK_JACOBI_PRECOND:
      _linear_solver->SetAztecOption(AZ_precond,AZ_Jacobi);
      break;
    default:
      _linear_solver->SetAztecOption(AZ_precond,AZ_dom_decomp);
    }
  }
}

template <typename T>
std::pair<unsigned int, Real>
AztecLinearSolver<T>::solve (SparseMatrix<T>& matrix_in,
			     SparseMatrix<T>& precond_in,
			     NumericVector<T>& solution_in,
			     NumericVector<T>& rhs_in,
			     const double tol,
			     const unsigned int m_its)
{
  START_LOG("solve()", "AztecLinearSolver");

  EpetraMatrix<T>* matrix   = dynamic_cast<EpetraMatrix<T>*>(&matrix_in);
  EpetraMatrix<T>* precond  = dynamic_cast<EpetraMatrix<T>*>(&precond_in);
  EpetraVector<T>* solution = dynamic_cast<EpetraVector<T>*>(&solution_in);
  EpetraVector<T>* rhs      = dynamic_cast<EpetraVector<T>*>(&rhs_in);

  // We cast to pointers so we can be sure that they succeeded
  // by comparing the result against NULL.
  libmesh_assert(matrix != NULL);
  libmesh_assert(precond != NULL);
  libmesh_assert(solution != NULL);
  libmesh_assert(rhs != NULL);

  this->init();

  // Close the matrices and vectors in case this wasn't already done.
  matrix->close ();
  precond->close ();
  solution->close ();
  rhs->close ();

  _linear_solver->SetAztecOption(AZ_max_iter,m_its);
  _linear_solver->SetAztecParam(AZ_tol,tol);

  Epetra_FECrsMatrix * emat = matrix->mat();
  Epetra_FEVector * esol = solution->vec();
  Epetra_FEVector * erhs = rhs->vec();

  _linear_solver->Iterate(emat, esol, erhs, m_its, tol);

  STOP_LOG("solve()", "AztecLinearSolver");

  // return the # of its. and the final residual norm.
  return std::make_pair(_linear_solver->NumIters(), _linear_solver->TrueResidual());
}

template <typename T>
void AztecLinearSolver<T>::get_residual_history(std::vector<double>& /* hist */)
{
  libmesh_not_implemented();

//   int ierr = 0;
//   int its  = 0;

//   // Fill the residual history vector with the residual norms
//   // Note that GetResidualHistory() does not copy any values, it
//   // simply sets the pointer p.  Note that for some Krylov subspace
//   // methods, the number of residuals returned in the history
//   // vector may be different from what you are expecting.  For
//   // example, TFQMR returns two residual values per iteration step.
//   PetscReal* p;
//   ierr = KSPGetResidualHistory(_ksp, &p, &its);
//   CHKERRABORT(libMesh::COMM_WORLD,ierr);

//   // Check for early return
//   if (its == 0) return;

//   // Create space to store the result
//   hist.resize(its);

//   // Copy history into the vector provided by the user.
//   for (int i=0; i<its; ++i)
//     {
//       hist[i] = *p;
//       p++;
//     }
}

template <typename T>
Real AztecLinearSolver<T>::get_initial_residual()
{
  return _linear_solver->TrueResidual();
}

template <typename T>
void AztecLinearSolver<T>::print_converged_reason()
{
  libmesh_not_implemented();

// #if PETSC_VERSION_LESS_THAN(2,3,1)
//   std::cout << "This method is currently not supported "
// 	    << "(but may work!) for Petsc 2.3.0 and earlier." << std::endl;
// #else
//   KSPConvergedReason reason;
//   KSPGetConvergedReason(_ksp, &reason);

//   //  KSP_CONVERGED_RTOL (residual 2-norm decreased by a factor of rtol, from 2-norm of right hand side)
//   //  KSP_CONVERGED_ATOL (residual 2-norm less than abstol)
//   //  KSP_CONVERGED_ITS (used by the preonly preconditioner that always uses ONE iteration)
//   //  KSP_CONVERGED_STEP_LENGTH
//   //  KSP_DIVERGED_ITS  (required more than its to reach convergence)
//   //  KSP_DIVERGED_DTOL (residual norm increased by a factor of divtol)
//   //  KSP_DIVERGED_NAN (residual norm became Not-a-number likely do to 0/0)
//   //  KSP_DIVERGED_BREAKDOWN (generic breakdown in method)

//   switch (reason)
//     {
//     case KSP_CONVERGED_RTOL:
//        {
// 	std::cout << "Linear solver converged, relative tolerance reached." << std::endl;
// 	break;
//        }
//     case KSP_CONVERGED_ATOL:
//        {
// 	 std::cout << "Linear solver converged, absolute tolerance reached." << std::endl;
// 	 break;
//        }

//       // Divergence
//     case KSP_DIVERGED_ITS:
//        {
// 	 std::cout << "Linear solver diverged, max no. of iterations reached." << std::endl;
// 	 break;
//        }
//     case KSP_DIVERGED_DTOL:
//        {
// 	 std::cout << "Linear solver diverged, residual norm increase by dtol (default 1.e5)." << std::endl;
// 	 break;
//        }
//     case KSP_DIVERGED_NAN:
//        {
// 	 std::cout << "Linear solver diverged, residual norm is NaN." << std::endl;
// 	 break;
//        }
//     case KSP_DIVERGED_BREAKDOWN:
//        {
// 	 std::cout << "Linear solver diverged, generic breakdown in the method." << std::endl;
// 	 break;
//        }
//     default:
//       {
// 	std::cout << "Unknown/unsupported con(di)vergence reason: " << reason << std::endl;
//       }
//     }
// #endif
}

//------------------------------------------------------------------
// Explicit instantiations
template class AztecLinearSolver<Number>;

#endif // #ifdef HAVE_TRILINOS
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkNormalBevelSource.h"

#include "SkNormalSource.h"
#include "SkNormalSourcePriv.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "GrInvariantOutput.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "SkGr.h"

class NormalBevelFP : public GrFragmentProcessor {
public:
    NormalBevelFP(SkNormalSource::BevelType type, SkScalar width, SkScalar height)
        : fType(type)
        , fWidth(width)
        , fHeight(height) {
        this->initClassID<NormalBevelFP>();

        fUsesDistanceVectorField = true;
    }

    class GLSLNormalBevelFP : public GLSLNormalFP {
    public:
        GLSLNormalBevelFP() {
            fPrevWidth = SkFloatToScalar(0.0f);
            fPrevHeight = SkFloatToScalar(0.0f);
        }

        void onEmitCode(EmitArgs& args) override {
            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;

            const char* widthUniName = nullptr;
            fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
                    kDefault_GrSLPrecision, "Width", &widthUniName);

            const char* heightUniName = nullptr;
            fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
                    kDefault_GrSLPrecision, "Height", &heightUniName);

            fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 1.0, 0.0);", args.fOutputColor);
        }

        static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
                           GrProcessorKeyBuilder* b) {
            const NormalBevelFP& fp = proc.cast<NormalBevelFP>();
            b->add32(static_cast<int>(fp.fType));
        }

    protected:
        void setNormalData(const GrGLSLProgramDataManager& pdman,
                           const GrProcessor& proc) override {
            const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();

            if (fPrevWidth  != normalBevelFP.fWidth) {
                pdman.set1f(fWidthUni, normalBevelFP.fWidth);
                fPrevWidth = normalBevelFP.fWidth;
            }
            if (fPrevHeight != normalBevelFP.fHeight) {
                pdman.set1f(fHeightUni, normalBevelFP.fHeight);
                fPrevHeight = normalBevelFP.fHeight;
            }
        }

    private:
        SkScalar fPrevWidth;
        GrGLSLProgramDataManager::UniformHandle fWidthUni;

        SkScalar fPrevHeight;
        GrGLSLProgramDataManager::UniformHandle fHeightUni;
    };

    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
        GLSLNormalBevelFP::GenKey(*this, caps, b);
    }

    const char* name() const override { return "NormalBevelFP"; }

    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
        inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
    }

private:
    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalBevelFP; }

    bool onIsEqual(const GrFragmentProcessor& proc) const override {
        const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
        return fType   == normalBevelFP.fType &&
               fWidth  == normalBevelFP.fWidth &&
               fHeight == normalBevelFP.fHeight;
    }

    SkNormalSource::BevelType fType;
    SkScalar fWidth;
    SkScalar fHeight;
};

sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
        const SkShader::AsFPArgs&) const {

    return sk_make_sp<NormalBevelFP>(fType, fWidth, fHeight);
}

#endif // SK_SUPPORT_GPU

////////////////////////////////////////////////////////////////////////////

SkNormalBevelSourceImpl::Provider::Provider() {}

SkNormalBevelSourceImpl::Provider::~Provider() {}

SkNormalSource::Provider* SkNormalBevelSourceImpl::asProvider(const SkShader::ContextRec &rec,
                                                            void *storage) const {
    return new (storage) Provider();
}

size_t SkNormalBevelSourceImpl::providerSize(const SkShader::ContextRec&) const {
    return sizeof(Provider);
}

void SkNormalBevelSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
                                                   int count) const {
    for (int i = 0; i < count; i++) {
        output[i] = {0.0f, 0.0f, 1.0f};
    }
}

////////////////////////////////////////////////////////////////////////////////

sk_sp<SkFlattenable> SkNormalBevelSourceImpl::CreateProc(SkReadBuffer& buf) {

    auto type = static_cast<SkNormalSource::BevelType>(buf.readInt());
    SkScalar width = buf.readScalar();
    SkScalar height = buf.readScalar();

    return sk_make_sp<SkNormalBevelSourceImpl>(type, width, height);
}

void SkNormalBevelSourceImpl::flatten(SkWriteBuffer& buf) const {
    this->INHERITED::flatten(buf);

    buf.writeInt(static_cast<int>(fType));
    buf.writeScalar(fWidth);
    buf.writeScalar(fHeight);
}

////////////////////////////////////////////////////////////////////////////

sk_sp<SkNormalSource> SkNormalSource::MakeBevel(BevelType type, SkScalar width, SkScalar height) {
    /* TODO make sure this checks are tolerant enough to account for loss of conversion when GPUs
       use 16-bit float types. We don't want to assume stuff is non-zero on the GPU and be wrong.*/
    SkASSERT(width > 0.0f && !SkScalarNearlyZero(width));
    if (SkScalarNearlyZero(height)) {
        return SkNormalSource::MakeFlat();
    }

    return sk_make_sp<SkNormalBevelSourceImpl>(type, width, height);
}
<commit_msg>This CL's base is the CL that sets up the distance vector field req. exposure: https://codereview.chromium.org/2114993002/<commit_after>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkNormalBevelSource.h"

#include "SkNormalSource.h"
#include "SkNormalSourcePriv.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "GrInvariantOutput.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "SkGr.h"

/** \class NormalBevelFP
 *
 *  Fragment processor for the SkNormalBevelSource.
 *
 *  @param bevelType    type of the bevel
 *  @param bevelWidth   width of the bevel in device space
 *  @param bevelHeight  height of the bevel in device space
 */
class NormalBevelFP : public GrFragmentProcessor {
public:
    NormalBevelFP(SkNormalSource::BevelType bevelType, SkScalar bevelWidth, SkScalar bevelHeight)
        : fBevelType(bevelType)
        , fBevelWidth(bevelWidth)
        , fBevelHeight(bevelHeight) {
        this->initClassID<NormalBevelFP>();

        fUsesDistanceVectorField = true;
    }

    class GLSLNormalBevelFP : public GLSLNormalFP {
    public:
        GLSLNormalBevelFP() {
            fPrevWidth = SkFloatToScalar(0.0f);
            fPrevHeight = SkFloatToScalar(0.0f);
        }

        void onEmitCode(EmitArgs& args) override {
            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
            const NormalBevelFP& fp = args.fFp.cast<NormalBevelFP>();
            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;

            // Determining necessary uniforms and initializing them
            bool needWidth = true;
            bool needHeight = (fp.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
                               fp.fBevelType == SkNormalSource::BevelType::kRoundedIn);
            bool needNormalized = (fp.fBevelType == SkNormalSource::BevelType::kLinear);

            const char *widthUniName = nullptr;
            if (needWidth) {
                fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
                                                       kDefault_GrSLPrecision, "Width",
                                                       &widthUniName);
            }

            const char* heightUniName = nullptr;
            if (needHeight) {
                fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
                                                        kDefault_GrSLPrecision, "Height",
                                                        &heightUniName);
            }

            const char* normalizedWidthUniName = nullptr;
            const char* normalizedHeightUniName = nullptr;
            if (needNormalized) {
                fNormalizedWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                                 kFloat_GrSLType,
                                                                 kDefault_GrSLPrecision,
                                                                 "NormalizedWidth",
                                                                 &normalizedWidthUniName);
                fNormalizedHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                                  kFloat_GrSLType,
                                                                  kDefault_GrSLPrecision,
                                                                  "NormalizedHeight",
                                                                  &normalizedHeightUniName);
            }

            // Here we are splitting the distance vector into length and normalized direction
            // TODO: Output these values from the geometry processor frag code instead of the vector
            fragBuilder->codeAppendf("float dv_length = length(%s);",
                                     fragBuilder->distanceVectorName());
            fragBuilder->codeAppendf("vec2 dv_norm = normalize(%s);",
                                     fragBuilder->distanceVectorName());

            // Asserting presence of necessary uniforms
            SkASSERT(widthUniName);

            fragBuilder->codeAppend( "vec3 normal;");
            fragBuilder->codeAppendf("if (dv_length >= %s) {", widthUniName);
            fragBuilder->codeAppend( "    normal = vec3(0.0, 0.0, 1.0);");
            fragBuilder->codeAppend( "} else {");
            this->emitMath(fragBuilder, fp.fBevelType, widthUniName, heightUniName,
                           normalizedWidthUniName, normalizedHeightUniName);
            fragBuilder->codeAppend( "}");
            fragBuilder->codeAppendf("%s = vec4(normal, 0.0);", args.fOutputColor);
        }

        static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
                           GrProcessorKeyBuilder* b) {
            const NormalBevelFP& fp = proc.cast<NormalBevelFP>();
            b->add32(static_cast<int>(fp.fBevelType));
        }

    protected:
        void setNormalData(const GrGLSLProgramDataManager& pdman,
                           const GrProcessor& proc) override {
            const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();

            // Updating uniform if bevel type requires it and data has changed

            bool needWidth = true;
            bool needHeight = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
                               normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedIn);
            bool needNormalized = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kLinear);

            bool dirtyWidth = (fPrevWidth  != normalBevelFP.fBevelWidth);
            bool dirtyHeight = (fPrevHeight != normalBevelFP.fBevelHeight);
            bool dirtyNormalized = (dirtyHeight || dirtyWidth);

            if (needWidth && dirtyWidth) {
                pdman.set1f(fWidthUni, normalBevelFP.fBevelWidth);
                fPrevWidth = normalBevelFP.fBevelWidth;
            }
            if (needHeight && dirtyHeight) {
                pdman.set1f(fHeightUni, normalBevelFP.fBevelHeight);
                fPrevHeight = normalBevelFP.fBevelHeight;
            }
            if (needNormalized && dirtyNormalized) {
                SkScalar height = normalBevelFP.fBevelHeight;
                SkScalar width  = normalBevelFP.fBevelWidth;

                SkScalar length = SkScalarSqrt(SkScalarSquare(height) + SkScalarSquare(width));
                pdman.set1f(fNormalizedHeightUni, height/length);
                pdman.set1f(fNormalizedWidthUni, width/length);
            }
        }

        // This method emits the code that calculates the normal orthgonal to the simulated beveled
        // surface. In the comments inside the function, the math involved is described. For this
        // purpose, the d-axis is defined to be the axis co-linear to the distance vector, where the
        // origin is the end of the bevel inside the shape.
        void emitMath(GrGLSLFPFragmentBuilder* fb, SkNormalSource::BevelType type,
                      const char* width, const char* height, const char* normalizedWidth,
                      const char* normalizedHeight) {
            switch (type) {
                case SkNormalSource::BevelType::kLinear:
                    // Asserting presence of necessary uniforms
                    SkASSERT(normalizedHeight);
                    SkASSERT(normalizedWidth);

                    // Because the slope of the bevel is -height/width, the vector
                    // normalized(vec2(height, width)) is the d- and z-components of the normal
                    // vector that is orthogonal to the linear bevel. Multiplying the d-component
                    // to the normalized distance vector splits it into x- and y-components.
                    fb->codeAppendf("normal = vec3(%s * dv_norm, %s);",
                                    normalizedHeight, normalizedWidth);
                    break;
                case SkNormalSource::BevelType::kRoundedOut:
                    // Fall through
                case SkNormalSource::BevelType::kRoundedIn:
                    // Asserting presence of necessary uniforms
                    SkASSERT(height);
                    SkASSERT(width);

                    // Setting the current position in the d-axis to the distance from the end of
                    // the bevel as opposed to the beginning if the bevel is rounded in, essentially
                    // flipping the bevel calculations.
                    if ( type == SkNormalSource::BevelType::kRoundedIn ) {
                        fb->codeAppendf("float currentPos_d = %s - dv_length;", width);
                    } else if (type == SkNormalSource::BevelType::kRoundedOut) {
                        fb->codeAppendf("float currentPos_d = dv_length;");
                    }

                    fb->codeAppendf("float rootDOverW = sqrt(currentPos_d/%s);", width);

                    // Calculating the d- and z-components of the normal, where 'd' is the axis
                    // co-linear to the distance vector. Equation was derived from the formula for
                    // a bezier curve by solving the parametric equation for d(t) and z(t), then
                    // with those, calculate d'(t), z'(t) and t(d), and from these, d'(d) and z'(d).
                    // z'(d)/d'(d) results in the slope of the bevel at d, so we construct an
                    // orthogonal vector of slope -d'(d)/z'(d) and length 1.
                    fb->codeAppendf("vec2 unnormalizedNormal_dz = vec2(%s*(1.0-rootDOverW), "
                                                                       "%s*rootDOverW);",
                                    height, width);
                    fb->codeAppendf("vec2 normal_dz = normalize(unnormalizedNormal_dz);");

                    // Multiplying the d-component to the normalized distance vector splits it into
                    // x- and y-components.
                    fb->codeAppendf("normal = vec3(normal_dz.x*dv_norm, normal_dz.y);");

                    break;
                default:
                    SkDEBUGFAIL("Invalid bevel type passed to emitMath");
            }
        }

    private:
        SkScalar fPrevWidth;
        GrGLSLProgramDataManager::UniformHandle fWidthUni;

        SkScalar fPrevHeight;
        GrGLSLProgramDataManager::UniformHandle fHeightUni;

        // width / length(<width,height>)
        GrGLSLProgramDataManager::UniformHandle fNormalizedWidthUni;
        // height / length(<width,height>)
        GrGLSLProgramDataManager::UniformHandle fNormalizedHeightUni;
    };

    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
        GLSLNormalBevelFP::GenKey(*this, caps, b);
    }

    const char* name() const override { return "NormalBevelFP"; }

    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
        inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
    }

private:
    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalBevelFP; }

    bool onIsEqual(const GrFragmentProcessor& proc) const override {
        const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
        return fBevelType   == normalBevelFP.fBevelType &&
               fBevelWidth  == normalBevelFP.fBevelWidth &&
               fBevelHeight == normalBevelFP.fBevelHeight;
    }

    SkNormalSource::BevelType fBevelType;
    SkScalar fBevelWidth;
    SkScalar fBevelHeight;
};

sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
        const SkShader::AsFPArgs& args) const {

    SkScalar maxScale = args.fViewMatrix->getMaxScale();

    // Providing device-space width and height
    return sk_make_sp<NormalBevelFP>(fType, maxScale * fWidth, maxScale * fHeight);
}

#endif // SK_SUPPORT_GPU

////////////////////////////////////////////////////////////////////////////

SkNormalBevelSourceImpl::Provider::Provider() {}

SkNormalBevelSourceImpl::Provider::~Provider() {}

SkNormalSource::Provider* SkNormalBevelSourceImpl::asProvider(const SkShader::ContextRec &rec,
                                                            void *storage) const {
    return new (storage) Provider();
}

size_t SkNormalBevelSourceImpl::providerSize(const SkShader::ContextRec&) const {
    return sizeof(Provider);
}

void SkNormalBevelSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
                                                   int count) const {
    for (int i = 0; i < count; i++) {
        output[i] = {0.0f, 0.0f, 1.0f};
    }
}

////////////////////////////////////////////////////////////////////////////////

sk_sp<SkFlattenable> SkNormalBevelSourceImpl::CreateProc(SkReadBuffer& buf) {

    auto type = static_cast<SkNormalSource::BevelType>(buf.readInt());
    SkScalar width = buf.readScalar();
    SkScalar height = buf.readScalar();

    return sk_make_sp<SkNormalBevelSourceImpl>(type, width, height);
}

void SkNormalBevelSourceImpl::flatten(SkWriteBuffer& buf) const {
    this->INHERITED::flatten(buf);

    buf.writeInt(static_cast<int>(fType));
    buf.writeScalar(fWidth);
    buf.writeScalar(fHeight);
}

////////////////////////////////////////////////////////////////////////////

sk_sp<SkNormalSource> SkNormalSource::MakeBevel(BevelType type, SkScalar width, SkScalar height) {
    /* TODO make sure this checks are tolerant enough to account for loss of conversion when GPUs
       use 16-bit float types. We don't want to assume stuff is non-zero on the GPU and be wrong.*/
    SkASSERT(width > 0.0f && !SkScalarNearlyZero(width));
    if (SkScalarNearlyZero(height)) {
        return SkNormalSource::MakeFlat();
    }

    return sk_make_sp<SkNormalBevelSourceImpl>(type, width, height);
}
<|endoftext|>


<commit_before><commit_msg>[ReconstructType] Factor the giant switch out of VisitNode NFC<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 <iosfwd>
#include <sstream>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/port.h"
#include "build/build_config.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
#include "chrome/browser/sync/util/pthread_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"

using std::endl;
using std::ostream;
using std::string;
using std::stringstream;
using std::vector;

namespace {

class Pair;

struct TestEvent {
  Pair* source;
  enum {
    A_CHANGED, B_CHANGED, PAIR_BEING_DELETED,
  } what_happened;
  int old_value;
};

struct TestEventTraits {
  typedef TestEvent EventType;
  static bool IsChannelShutdownEvent(const TestEvent& event) {
    return TestEvent::PAIR_BEING_DELETED == event.what_happened;
  }
};

class Pair {
 public:
  typedef EventChannel<TestEventTraits> Channel;
  explicit Pair(const string& name) : name_(name), a_(0), b_(0) {
    TestEvent shutdown = { this, TestEvent::PAIR_BEING_DELETED, 0 };
    event_channel_ = new Channel(shutdown);
  }
  ~Pair() {
    delete event_channel_;
  }
  void set_a(int n) {
    TestEvent event = { this, TestEvent::A_CHANGED, a_ };
    a_ = n;
    event_channel_->NotifyListeners(event);
  }
  void set_b(int n) {
    TestEvent event = { this, TestEvent::B_CHANGED, b_ };
    b_ = n;
    event_channel_->NotifyListeners(event);
  }
  int a() const { return a_; }
  int b() const { return b_; }
  const string& name() { return name_; }
  Channel* event_channel() const { return event_channel_; }

 protected:
  const string name_;
  int a_;
  int b_;
  Channel* event_channel_;
};

class EventLogger {
 public:
  explicit EventLogger(ostream& out) : out_(out) { }
  ~EventLogger() {
    for (Hookups::iterator i = hookups_.begin(); i != hookups_.end(); ++i)
      delete *i;
  }

  void Hookup(const string name, Pair::Channel* channel) {
    hookups_.push_back(NewEventListenerHookup(channel, this,
                                              &EventLogger::HandlePairEvent,
                                              name));
  }

  void HandlePairEvent(const string& name, const TestEvent& event) {
    const char* what_changed;
    int new_value;
    Hookups::iterator dead;
    switch (event.what_happened) {
    case TestEvent::A_CHANGED:
      what_changed = "A";
      new_value = event.source->a();
      break;
    case TestEvent::B_CHANGED:
      what_changed = "B";
      new_value = event.source->b();
      break;
    case TestEvent::PAIR_BEING_DELETED:
      out_ << name << " heard " << event.source->name() << " being deleted."
           << endl;
      return;
    default:
      LOG(FATAL) << "Bad event.what_happened: " << event.what_happened;
      break;
    }
    out_ << name << " heard " << event.source->name() << "'s " << what_changed
         << " change from "
         << event.old_value << " to " << new_value << endl;
  }

  typedef vector<EventListenerHookup*> Hookups;
  Hookups hookups_;
  ostream& out_;
};

const char golden_result[] = "Larry heard Sally's B change from 0 to 2\n"
"Larry heard Sally's A change from 1 to 3\n"
"Lewis heard Sam's B change from 0 to 5\n"
"Larry heard Sally's A change from 3 to 6\n"
"Larry heard Sally being deleted.\n";

TEST(EventSys, Basic) {
  Pair sally("Sally"), sam("Sam");
  sally.set_a(1);
  stringstream log;
  EventLogger logger(log);
  logger.Hookup("Larry", sally.event_channel());
  sally.set_b(2);
  sally.set_a(3);
  sam.set_a(4);
  logger.Hookup("Lewis", sam.event_channel());
  sam.set_b(5);
  sally.set_a(6);
  // Test that disconnect within callback doesn't deadlock.
  TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 };
  sally.event_channel()->NotifyListeners(event);
  sally.set_a(7);
  ASSERT_EQ(log.str(), golden_result);
}

// This goes pretty far beyond the normal use pattern, so don't use
// ThreadTester as an example of what to do.
class ThreadTester : public EventListener<TestEvent> {
 public:
  explicit ThreadTester(Pair* pair)
    : pair_(pair), remove_event_bool_(false)  {
    pair_->event_channel()->AddListener(this);
  }
  ~ThreadTester() {
    pair_->event_channel()->RemoveListener(this);
    for (size_t i = 0; i < threads_.size(); i++) {
      CHECK(pthread_join(threads_[i].thread, NULL) == 0);
      delete threads_[i].completed;
    }
  }

  struct ThreadInfo {
    pthread_t thread;
    bool* completed;
  };

  struct ThreadArgs {
    ThreadTester* self;
    pthread_cond_t* thread_running_cond;
    pthread_mutex_t* thread_running_mutex;
    bool* thread_running;
    bool* completed;
  };

  pthread_t Go() {
    PThreadCondVar thread_running_cond;
    PThreadMutex thread_running_mutex;
    ThreadArgs args;
    ThreadInfo info;
    info.completed = new bool(false);
    args.self = this;
    args.completed = info.completed;
    args.thread_running_cond = &(thread_running_cond.condvar_);
    args.thread_running_mutex = &(thread_running_mutex.mutex_);
    args.thread_running = new bool(false);
    CHECK(0 ==
        pthread_create(&info.thread, NULL, ThreadTester::ThreadMain, &args));
    thread_running_mutex.Lock();
    while ((*args.thread_running) == false) {
      pthread_cond_wait(&(thread_running_cond.condvar_),
                        &(thread_running_mutex.mutex_));
    }
    thread_running_mutex.Unlock();
    delete args.thread_running;
    threads_.push_back(info);
    return info.thread;
  }

  static void* ThreadMain(void* arg) {
    // Make sure each thread gets a current MessageLoop in TLS.
    // This test should use chrome threads for testing, but I'll leave it like
    // this for the moment since it requires a big chunk of rewriting and I
    // want the test passing while I checkpoint my CL.  Technically speaking,
    // there should be no functional difference.
    MessageLoop message_loop;
    ThreadArgs args = *reinterpret_cast<ThreadArgs*>(arg);
    pthread_mutex_lock(args.thread_running_mutex);
    *args.thread_running = true;
    pthread_cond_signal(args.thread_running_cond);
    pthread_mutex_unlock(args.thread_running_mutex);

    args.self->remove_event_mutex_.Lock();
    while (args.self->remove_event_bool_ == false) {
      pthread_cond_wait(&args.self->remove_event_.condvar_,
                        &args.self->remove_event_mutex_.mutex_);
    }
    args.self->remove_event_mutex_.Unlock();

    // Normally, you'd just delete the hookup. This is very bad style, but
    // necessary for the test.
    args.self->pair_->event_channel()->RemoveListener(args.self);
    *args.completed = true;
    return 0;
  }

  void HandleEvent(const TestEvent& event) {
    remove_event_mutex_.Lock();
    remove_event_bool_ = true;
    pthread_cond_broadcast(&remove_event_.condvar_);
    remove_event_mutex_.Unlock();

    // Windows and posix use different functions to sleep.
#ifdef OS_WIN
    Sleep(1);
#else
    sleep(1);
#endif

    for (size_t i = 0; i < threads_.size(); i++) {
      if (*(threads_[i].completed))
        LOG(FATAL) << "A test thread exited too early.";
    }
  }

  Pair* pair_;
  PThreadCondVar remove_event_;
  PThreadMutex remove_event_mutex_;
  bool remove_event_bool_;
  vector<ThreadInfo> threads_;
};

TEST(EventSys, Multithreaded) {
  Pair sally("Sally");
  ThreadTester a(&sally);
  for (int i = 0; i < 3; ++i)
    a.Go();
  sally.set_b(99);
}

class HookupDeleter {
 public:
  void HandleEvent(const TestEvent& event) {
    delete hookup_;
    hookup_ = NULL;
  }
  EventListenerHookup* hookup_;
};

TEST(EventSys, InHandlerDeletion) {
  Pair sally("Sally");
  HookupDeleter deleter;
  deleter.hookup_ = NewEventListenerHookup(sally.event_channel(),
                                           &deleter,
                                           &HookupDeleter::HandleEvent);
  sally.set_a(1);
  ASSERT_TRUE(NULL == deleter.hookup_);
}

}  // namespace
<commit_msg>Remove pthreads from event_sys_unittest.<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 <iosfwd>
#include <sstream>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/port.h"
#include "build/build_config.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
#include "testing/gtest/include/gtest/gtest.h"

using std::endl;
using std::ostream;
using std::string;
using std::stringstream;
using std::vector;

namespace {

class Pair;

struct TestEvent {
  Pair* source;
  enum {
    A_CHANGED, B_CHANGED, PAIR_BEING_DELETED,
  } what_happened;
  int old_value;
};

struct TestEventTraits {
  typedef TestEvent EventType;
  static bool IsChannelShutdownEvent(const TestEvent& event) {
    return TestEvent::PAIR_BEING_DELETED == event.what_happened;
  }
};

class Pair {
 public:
  typedef EventChannel<TestEventTraits> Channel;
  explicit Pair(const string& name) : name_(name), a_(0), b_(0) {
    TestEvent shutdown = { this, TestEvent::PAIR_BEING_DELETED, 0 };
    event_channel_ = new Channel(shutdown);
  }
  ~Pair() {
    delete event_channel_;
  }
  void set_a(int n) {
    TestEvent event = { this, TestEvent::A_CHANGED, a_ };
    a_ = n;
    event_channel_->NotifyListeners(event);
  }
  void set_b(int n) {
    TestEvent event = { this, TestEvent::B_CHANGED, b_ };
    b_ = n;
    event_channel_->NotifyListeners(event);
  }
  int a() const { return a_; }
  int b() const { return b_; }
  const string& name() { return name_; }
  Channel* event_channel() const { return event_channel_; }

 protected:
  const string name_;
  int a_;
  int b_;
  Channel* event_channel_;
};

class EventLogger {
 public:
  explicit EventLogger(ostream& out) : out_(out) { }
  ~EventLogger() {
    for (Hookups::iterator i = hookups_.begin(); i != hookups_.end(); ++i)
      delete *i;
  }

  void Hookup(const string name, Pair::Channel* channel) {
    hookups_.push_back(NewEventListenerHookup(channel, this,
                                              &EventLogger::HandlePairEvent,
                                              name));
  }

  void HandlePairEvent(const string& name, const TestEvent& event) {
    const char* what_changed;
    int new_value;
    Hookups::iterator dead;
    switch (event.what_happened) {
    case TestEvent::A_CHANGED:
      what_changed = "A";
      new_value = event.source->a();
      break;
    case TestEvent::B_CHANGED:
      what_changed = "B";
      new_value = event.source->b();
      break;
    case TestEvent::PAIR_BEING_DELETED:
      out_ << name << " heard " << event.source->name() << " being deleted."
           << endl;
      return;
    default:
      LOG(FATAL) << "Bad event.what_happened: " << event.what_happened;
      break;
    }
    out_ << name << " heard " << event.source->name() << "'s " << what_changed
         << " change from "
         << event.old_value << " to " << new_value << endl;
  }

  typedef vector<EventListenerHookup*> Hookups;
  Hookups hookups_;
  ostream& out_;
};

const char golden_result[] = "Larry heard Sally's B change from 0 to 2\n"
"Larry heard Sally's A change from 1 to 3\n"
"Lewis heard Sam's B change from 0 to 5\n"
"Larry heard Sally's A change from 3 to 6\n"
"Larry heard Sally being deleted.\n";

TEST(EventSys, Basic) {
  Pair sally("Sally"), sam("Sam");
  sally.set_a(1);
  stringstream log;
  EventLogger logger(log);
  logger.Hookup("Larry", sally.event_channel());
  sally.set_b(2);
  sally.set_a(3);
  sam.set_a(4);
  logger.Hookup("Lewis", sam.event_channel());
  sam.set_b(5);
  sally.set_a(6);
  // Test that disconnect within callback doesn't deadlock.
  TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 };
  sally.event_channel()->NotifyListeners(event);
  sally.set_a(7);
  ASSERT_EQ(log.str(), golden_result);
}

// This goes pretty far beyond the normal use pattern, so don't use
// ThreadTester as an example of what to do.
class ThreadTester : public EventListener<TestEvent>,
                     public PlatformThread::Delegate {
 public:
  explicit ThreadTester(Pair* pair)
    : pair_(pair), remove_event_(&remove_event_mutex_),
      remove_event_bool_(false)  {
    pair_->event_channel()->AddListener(this);
  }
  ~ThreadTester() {
    pair_->event_channel()->RemoveListener(this);
    for (size_t i = 0; i < threads_.size(); i++) {
      PlatformThread::Join(threads_[i].thread);
    }
  }

  struct ThreadInfo {
    PlatformThreadHandle thread;
    bool* completed;
  };

  struct ThreadArgs {
    ConditionVariable* thread_running_cond;
    Lock* thread_running_mutex;
    bool thread_running;
    bool completed;
  };

  void Go() {
    Lock thread_running_mutex;
    ConditionVariable thread_running_cond(&thread_running_mutex);
    ThreadArgs args;
    ThreadInfo info;
    info.completed = false;
    args.completed = info.completed;
    args.thread_running_cond = &(thread_running_cond);
    args.thread_running_mutex = &(thread_running_mutex);
    args.thread_running = false;
    args_ = args;
    ASSERT_TRUE(PlatformThread::Create(0, this, &info.thread));
    thread_running_mutex.Acquire();
    while ((args_.thread_running) == false) {
      thread_running_cond.Wait();
    }
    thread_running_mutex.Release();
    threads_.push_back(info);
  }

  // PlatformThread::Delegate methods.
  virtual void ThreadMain() {
    // Make sure each thread gets a current MessageLoop in TLS.
    // This test should use chrome threads for testing, but I'll leave it like
    // this for the moment since it requires a big chunk of rewriting and I
    // want the test passing while I checkpoint my CL.  Technically speaking,
    // there should be no functional difference.
    MessageLoop message_loop;
    args_.thread_running_mutex->Acquire();
    args_.thread_running = true;
    args_.thread_running_mutex->Release();
    args_.thread_running_cond->Signal();

    remove_event_mutex_.Acquire();
    while (remove_event_bool_ == false) {
      remove_event_.Wait();
    }
    remove_event_mutex_.Release();

    // Normally, you'd just delete the hookup. This is very bad style, but
    // necessary for the test.
    pair_->event_channel()->RemoveListener(this);
    args_.completed = true;
  }

  void HandleEvent(const TestEvent& event) {
    remove_event_mutex_.Acquire();
    remove_event_bool_ = true;
    remove_event_mutex_.Release();
    remove_event_.Broadcast();

    // Windows and posix use different functions to sleep.
#ifdef OS_WIN
    Sleep(1);
#else
    sleep(1);
#endif

    for (size_t i = 0; i < threads_.size(); i++) {
      if (threads_[i].completed)
        LOG(FATAL) << "A test thread exited too early.";
    }
  }

  Pair* pair_;
  ConditionVariable remove_event_;
  Lock remove_event_mutex_;
  bool remove_event_bool_;
  vector<ThreadInfo> threads_;
  ThreadArgs args_;
};

TEST(EventSys, Multithreaded) {
  Pair sally("Sally");
  ThreadTester a(&sally);
  for (int i = 0; i < 3; ++i)
    a.Go();
  sally.set_b(99);
}

class HookupDeleter {
 public:
  void HandleEvent(const TestEvent& event) {
    delete hookup_;
    hookup_ = NULL;
  }
  EventListenerHookup* hookup_;
};

TEST(EventSys, InHandlerDeletion) {
  Pair sally("Sally");
  HookupDeleter deleter;
  deleter.hookup_ = NewEventListenerHookup(sally.event_channel(),
                                           &deleter,
                                           &HookupDeleter::HandleEvent);
  sally.set_a(1);
  ASSERT_TRUE(NULL == deleter.hookup_);
}

}  // namespace
<|endoftext|>


<commit_before><commit_msg>[analyzer] Fix HTMLRewriter style sheets to support non-webkit browsers.<commit_after><|endoftext|>


<commit_before>/**
 * @file   LoggerManager.hpp
 * @brief  LoggerManager class prototype.
 * @author zer0
 * @date   2016-07-15
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_LOG_DETAILS_LOGGERMANAGER_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_LOG_DETAILS_LOGGERMANAGER_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/pattern/Singleton2.hpp>
#include <libtbag/log/details/Logger.hpp>

#include <unordered_map>
#include <memory>
#include <string>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace log     {
namespace details {

/**
 * LoggerManager class prototype.
 *
 * @author zer0
 * @date   2016-07-15
 */
class TBAG_API LoggerManager
{
public:
    SINGLETON2_PROTOTYPE(LoggerManager);

public:
    using LoggerPtr  = std::unique_ptr<Logger>;
    using LoggerMap  = std::unordered_map<std::string, LoggerPtr>;
    using LoggerPair = LoggerMap::value_type;

private:
    LoggerMap _logs;

public:
    bool addLogger(std::string const & name, Logger * new_logger);
    bool removeLogger(std::string const & name);
    std::size_t getSize() const TBAG_NOEXCEPT;
    Logger * getLoggerPtr(std::string const & name);
};

} // namespace details
} // namespace log

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_LOG_DETAILS_LOGGERMANAGER_HPP__

<commit_msg>Fix the C2280 error in MSVC14.<commit_after>/**
 * @file   LoggerManager.hpp
 * @brief  LoggerManager class prototype.
 * @author zer0
 * @date   2016-07-15
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_LOG_DETAILS_LOGGERMANAGER_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_LOG_DETAILS_LOGGERMANAGER_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/pattern/Singleton2.hpp>
#include <libtbag/log/details/Logger.hpp>

#include <unordered_map>
#include <memory>
#include <string>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace log     {
namespace details {

/**
 * LoggerManager class prototype.
 *
 * @author zer0
 * @date   2016-07-15
 *
 * @remarks
 *  - Fix the C2280 error in MSVC14: Requires inheritance Noncopyable class.
 */
class TBAG_API LoggerManager : public Noncopyable
{
public:
    SINGLETON2_PROTOTYPE(LoggerManager);

public:
    using LoggerPtr  = std::unique_ptr<Logger>;
    using LoggerMap  = std::unordered_map<std::string, LoggerPtr>;
    using LoggerPair = LoggerMap::value_type;

private:
    LoggerMap _logs;

public:
    bool addLogger(std::string const & name, Logger * new_logger);
    bool removeLogger(std::string const & name);
    std::size_t getSize() const TBAG_NOEXCEPT;
    Logger * getLoggerPtr(std::string const & name);
};

} // namespace details
} // namespace log

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_LOG_DETAILS_LOGGERMANAGER_HPP__

<|endoftext|>


<commit_before>#include "core/rendering/spritemap.h"

#include <algorithm>

using namespace eversim::core::utility;

namespace eversim {
	namespace core {
		namespace rendering {
			Spritemap::Spritemap()
			{
				glGetIntegerv(GL_MAX_TEXTURE_SIZE, &resolution[0]);
				resolution[1] = resolution[0];
				const size_t max_size = 512;
				if (resolution[0] > max_size)
					resolution = { max_size,max_size };
				init();
			}

			Spritemap::Spritemap(const size_t res) : resolution({res,res})
			{
				init();
			}

			void Spritemap::init()
			{
				canvas_tex.init(resolution);
				canvas_tex.clear();
				divider = Areadivider(resolution);
			}

			glm::ivec2 Spritemap::add_texture(ShaderProgram& program, Texture& tex)
			{
				auto pos = divider.place_rectangle(tex.get_resolution());

				if (pos != glm::ivec2(-1, -1))
					canvas_tex.place_texture(program, tex, pos, glm::vec2(1, 1));

				return pos;
			}

			void Spritemap::bind() const
			{
				glBindTexture(GL_TEXTURE_2D, canvas_tex.get_texture_id());
			}
		}
	}
}
<commit_msg>Fixed Issue #26 spritemaps default to a transparent background if alpha blending is enabled Else it is white<commit_after>#include "core/rendering/spritemap.h"

#include <algorithm>

using namespace eversim::core::utility;

namespace eversim {
	namespace core {
		namespace rendering {
			Spritemap::Spritemap()
			{
				glGetIntegerv(GL_MAX_TEXTURE_SIZE, &resolution[0]);
				resolution[1] = resolution[0];
				const size_t max_size = 512;
				if (resolution[0] > max_size)
					resolution = { max_size,max_size };
				init();
			}

			Spritemap::Spritemap(const size_t res) : resolution({res,res})
			{
				init();
			}

			void Spritemap::init()
			{
				canvas_tex.init(resolution);
				canvas_tex.clear({ 1,1,1,0 });
				divider = Areadivider(resolution);
			}

			glm::ivec2 Spritemap::add_texture(ShaderProgram& program, Texture& tex)
			{
				auto pos = divider.place_rectangle(tex.get_resolution());

				if (pos != glm::ivec2(-1, -1))
					canvas_tex.place_texture(program, tex, pos, glm::vec2(1, 1));

				return pos;
			}

			void Spritemap::bind() const
			{
				glBindTexture(GL_TEXTURE_2D, canvas_tex.get_texture_id());
			}
		}
	}
}
<|endoftext|>


<commit_before>#include <cstring>
#include <csignal>
#include <cstdlib>

#include <caf/all.hpp>

#include "vast/logger.hpp"

#include "vast/system/signal_monitor.hpp"

using namespace caf;

namespace vast {
namespace system {
namespace {

// Keeps track of all signals 1--31 (0 unused).
bool signals[32];

extern "C" void signal_handler(int sig) {
  // Catch termination signals only once to allow forced termination by the OS
  // upon sending the signal a second time.
  if (sig == SIGINT || sig == SIGTERM)
    std::signal(sig, SIG_DFL);
  signals[sig] = true;
}

} // namespace <anonymous>

signal_monitor_type::behavior_type
signal_monitor(signal_monitor_type::stateful_pointer<signal_monitor_state> self,
               std::chrono::milliseconds monitoring_interval,
               actor receiver) {
  VAST_DEBUG(self, "sends signals to", receiver);
  for (auto s : {SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2}) {
    VAST_DEBUG(self, "registers signal handler for", ::strsignal(s));
    std::signal(s, &signal_handler);
  }
  self->send(self, run_atom::value);
  return {
    [=](run_atom) {
      for (int i = 0; i < 32; ++i) {
        if (signals[i]) {
          VAST_DEBUG(self, "caught signal", ::strsignal(i));
          signals[i] = false;
          self->anon_send(receiver, signal_atom::value, i);
        }
      }
      self->delayed_send(self, monitoring_interval, run_atom::value);
    }
  };
}

} // namespace system
} // namespace vast
<commit_msg>Perform small cosmetic optimization<commit_after>#include <cstring>
#include <csignal>
#include <cstdlib>

#include <caf/all.hpp>

#include "vast/logger.hpp"

#include "vast/system/signal_monitor.hpp"

using namespace caf;

namespace vast {
namespace system {
namespace {

// Keeps track of all signals by their value from 1 to 31. The flag at index 0
// is used to tell whether a signal has been raised or not.
bool signals[32];

extern "C" void signal_handler(int sig) {
  // Catch termination signals only once to allow forced termination by the OS
  // upon sending the signal a second time.
  if (sig == SIGINT || sig == SIGTERM)
    std::signal(sig, SIG_DFL);
  signals[0] = true;
  signals[sig] = true;
}

} // namespace <anonymous>

signal_monitor_type::behavior_type
signal_monitor(signal_monitor_type::stateful_pointer<signal_monitor_state> self,
               std::chrono::milliseconds monitoring_interval,
               actor receiver) {
  VAST_DEBUG(self, "sends signals to", receiver);
  for (auto s : {SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2}) {
    VAST_DEBUG(self, "registers signal handler for", ::strsignal(s));
    std::signal(s, &signal_handler);
  }
  self->send(self, run_atom::value);
  return {
    [=](run_atom) {
      if (signals[0]) {
        signals[0] = false;
        for (int i = 1; i < 32; ++i) {
          if (signals[i]) {
            VAST_DEBUG(self, "caught signal", ::strsignal(i));
            signals[i] = false;
            self->anon_send(receiver, signal_atom::value, i);
          }
        }
      }
      self->delayed_send(self, monitoring_interval, run_atom::value);
    }
  };
}

} // namespace system
} // namespace vast
<|endoftext|>