<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <vector>
#include <seastar/core/future-util.hh>

#include "list_permissions_statement.hh"
#include "auth/authorizer.hh"
#include "auth/common.hh"
#include "cql3/result_set.hh"
#include "transport/messages/result_message.hh"

cql3::statements::list_permissions_statement::list_permissions_statement(
        auth::permission_set permissions,
        std::optional<auth::resource> resource,
        std::optional<sstring> username, bool recursive)
            : _permissions(permissions)
            , _resource(std::move(resource))
            , _username(std::move(username))
            , _recursive(recursive) {
}

void cql3::statements::list_permissions_statement::validate(
        distributed<service::storage_proxy>& proxy,
        const service::client_state& state) {
    // a check to ensure the existence of the user isn't being leaked by user existence check.
    state.ensure_not_anonymous();
}

future<> cql3::statements::list_permissions_statement::check_access(const service::client_state& state) {
    //
    // TODO(jhaberku): The existence checks should be in `execute()`. `check_access` should be restricted to
    // authorization checking.
    //

    auto f = make_ready_future();
    if (_username) {
        f = state.get_auth_service()->underlying_role_manager().exists(*_username).then([this](bool exists) {
            if (!exists) {
                throw exceptions::invalid_request_exception(sprint("User %s doesn't exist", *_username));
            }
        });
    }
    return f.then([this, &state] {
        if (_resource) {
            maybe_correct_resource(*_resource, state);
            return state.ensure_exists(*_resource);
        }

        return make_ready_future<>();
    }).then([this, &state] {
        const auto& as = *state.get_auth_service();

        return auth::has_superuser(as, *state.user()).then([this, &state, &as](bool has_super) {
            if (has_super) {
                return make_ready_future<>();
            }

            if (!_username) {
                return make_exception_future<>(
                        exceptions::unauthorized_exception("You are not authorized to view everyone's permissions"));
            }

            return auth::has_role(as, *state.user(), *_username).then([this](bool has_role) {
                if (!has_role) {
                    return make_exception_future<>(
                            exceptions::unauthorized_exception(
                                    sprint("You are not authorized to view %s's permissions", *_username)));
                }

                return make_ready_future<>();
            });
        });
    });
}

future<::shared_ptr<cql_transport::messages::result_message>>
cql3::statements::list_permissions_statement::execute(
        distributed<service::storage_proxy>& proxy,
        service::query_state& state,
        const query_options& options) {
    static auto make_column = [](sstring name) {
        return ::make_shared<column_specification>(
                auth::meta::AUTH_KS,
                "permissions",
                ::make_shared<column_identifier>(std::move(name), true),
                utf8_type);
    };

    static thread_local const std::vector<::shared_ptr<column_specification>> metadata({
        make_column("role"), make_column("resource"), make_column("permission")
    });

    typedef std::optional<auth::resource> opt_resource;

    std::vector<opt_resource> resources;

    auto r = _resource;
    for (;;) {
        resources.emplace_back(r);
        if (!r || !_recursive) {
            break;
        }

        auto parent = r->parent();
        if (!parent) {
            break;
        }

        r = std::move(parent);
    }

    return map_reduce(
            resources,
            [&state, this](opt_resource r) {
                return do_with(std::move(r), [this, &state](const opt_resource& r) {
                    auto& auth_service = *state.get_client_state().get_auth_service();
                    return auth_service.underlying_authorizer().list(_permissions, r, _username, auth_service);
                });
            },
            std::vector<auth::permission_details>(),
            [](std::vector<auth::permission_details> details, std::vector<auth::permission_details> pd) {
                details.insert(details.end(), pd.begin(), pd.end());
                return details;
            }).then([this](std::vector<auth::permission_details> details) {
                std::sort(details.begin(), details.end());

                auto rs = std::make_unique<result_set>(metadata);

                for (auto& v : details) {
                    // Make sure names are sorted.
                    auto names = auth::permissions::to_strings(v.permissions);
                    for (auto& p : std::set<sstring>(names.begin(), names.end())) {
                        rs->add_row(
                                std::vector<bytes_opt>{
                                        utf8_type->decompose(v.user),
                                        utf8_type->decompose(sstring(sprint("%s", v.resource))),
                                        utf8_type->decompose(p)});
                    }
                }

                auto rows = ::make_shared<cql_transport::messages::result_message::rows>(std::move(rs));
                return ::shared_ptr<cql_transport::messages::result_message>(std::move(rows));
            });
}
<commit_msg>cql3: Fix error handling in LIST PERMISSIONS<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <vector>
#include <seastar/core/future-util.hh>

#include "list_permissions_statement.hh"
#include "auth/authorizer.hh"
#include "auth/common.hh"
#include "cql3/result_set.hh"
#include "transport/messages/result_message.hh"

cql3::statements::list_permissions_statement::list_permissions_statement(
        auth::permission_set permissions,
        std::optional<auth::resource> resource,
        std::optional<sstring> username, bool recursive)
            : _permissions(permissions)
            , _resource(std::move(resource))
            , _username(std::move(username))
            , _recursive(recursive) {
}

void cql3::statements::list_permissions_statement::validate(
        distributed<service::storage_proxy>& proxy,
        const service::client_state& state) {
    // a check to ensure the existence of the user isn't being leaked by user existence check.
    state.ensure_not_anonymous();
}

future<> cql3::statements::list_permissions_statement::check_access(const service::client_state& state) {
    if (_resource) {
        maybe_correct_resource(*_resource, state);
        return state.ensure_exists(*_resource);
    }

    const auto& as = *state.get_auth_service();

    return auth::has_superuser(as, *state.user()).then([this, &state, &as](bool has_super) {
        if (has_super) {
            return make_ready_future<>();
        }

        if (!_username) {
            return make_exception_future<>(
                    exceptions::unauthorized_exception("You are not authorized to view everyone's permissions"));
        }

        return auth::has_role(as, *state.user(), *_username).then([this](bool has_role) {
            if (!has_role) {
                return make_exception_future<>(
                        exceptions::unauthorized_exception(
                                sprint("You are not authorized to view %s's permissions", *_username)));
            }

            return make_ready_future<>();
        }).handle_exception_type([](const auth::nonexistant_role& e) {
            return make_exception_future<>(exceptions::invalid_request_exception(e.what()));
        });
    });
}

future<::shared_ptr<cql_transport::messages::result_message>>
cql3::statements::list_permissions_statement::execute(
        distributed<service::storage_proxy>& proxy,
        service::query_state& state,
        const query_options& options) {
    static auto make_column = [](sstring name) {
        return ::make_shared<column_specification>(
                auth::meta::AUTH_KS,
                "permissions",
                ::make_shared<column_identifier>(std::move(name), true),
                utf8_type);
    };

    static thread_local const std::vector<::shared_ptr<column_specification>> metadata({
        make_column("role"), make_column("resource"), make_column("permission")
    });

    typedef std::optional<auth::resource> opt_resource;

    std::vector<opt_resource> resources;

    auto r = _resource;
    for (;;) {
        resources.emplace_back(r);
        if (!r || !_recursive) {
            break;
        }

        auto parent = r->parent();
        if (!parent) {
            break;
        }

        r = std::move(parent);
    }

    return map_reduce(
            resources,
            [&state, this](opt_resource r) {
                return do_with(std::move(r), [this, &state](const opt_resource& r) {
                    auto& auth_service = *state.get_client_state().get_auth_service();
                    return auth_service.underlying_authorizer().list(
                            _permissions,
                            r,
                            _username,
                            auth_service).handle_exception_type([](const auth::nonexistant_role& e) {
                        return make_exception_future<std::vector<auth::permission_details>>(
                                exceptions::invalid_request_exception(e.what()));
                    });
                });
            },
            std::vector<auth::permission_details>(),
            [](std::vector<auth::permission_details> details, std::vector<auth::permission_details> pd) {
                details.insert(details.end(), pd.begin(), pd.end());
                return details;
            }).then([this](std::vector<auth::permission_details> details) {
                std::sort(details.begin(), details.end());

                auto rs = std::make_unique<result_set>(metadata);

                for (auto& v : details) {
                    // Make sure names are sorted.
                    auto names = auth::permissions::to_strings(v.permissions);
                    for (auto& p : std::set<sstring>(names.begin(), names.end())) {
                        rs->add_row(
                                std::vector<bytes_opt>{
                                        utf8_type->decompose(v.user),
                                        utf8_type->decompose(sstring(sprint("%s", v.resource))),
                                        utf8_type->decompose(p)});
                    }
                }

                auto rows = ::make_shared<cql_transport::messages::result_message::rows>(std::move(rs));
                return ::shared_ptr<cql_transport::messages::result_message>(std::move(rows));
            });
}
<|endoftext|>


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

#include <stdexcept>

#include <folly/ExceptionWrapper.h>
#include <folly/Conv.h>
#include <folly/Portability.h>
#include <folly/portability/GTest.h>

using namespace folly;

class AbstractIntException : public std::exception {
 public:
  virtual int getInt() const = 0;
};

class IntException : public AbstractIntException {
 public:
  explicit IntException(int i) : i_(i) {}

  int getInt() const override { return i_; }
  const char* what() const noexcept override {
    what_ = folly::to<std::string>("int == ", i_);
    return what_.c_str();
  }

 private:
  int i_;
  mutable std::string what_;
};

const static std::string kExceptionClassName =
    demangle(typeid(std::exception)).toStdString();
const static std::string kRuntimeErrorClassName =
    demangle(typeid(std::runtime_error)).toStdString();
const static std::string kIntExceptionClassName =
    demangle(typeid(IntException)).toStdString();
const static std::string kIntClassName = demangle(typeid(int)).toStdString();

// Tests that when we call throwException, the proper type is thrown (derived)
TEST(ExceptionWrapper, throw_test) {
  std::runtime_error e("payload");
  auto ew = make_exception_wrapper<std::runtime_error>(e);

  std::vector<exception_wrapper> container;
  container.push_back(ew);

  try {
    container[0].throwException();
  } catch (std::runtime_error& e) {
    std::string expected = "payload";
    std::string actual = e.what();
    EXPECT_EQ(expected, actual);
  }
}

TEST(ExceptionWrapper, members) {
  auto ew = exception_wrapper();
  EXPECT_FALSE(bool(ew));
  EXPECT_EQ(ew.what(), "");
  EXPECT_EQ(ew.class_name(), "");
  ew = make_exception_wrapper<std::runtime_error>("payload");
  EXPECT_TRUE(bool(ew));
  EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
  EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
}

TEST(ExceptionWrapper, equals) {
  std::runtime_error e("payload");
  auto ew1 = make_exception_wrapper<std::runtime_error>(e);
  auto ew2 = ew1;
  EXPECT_EQ(ew1, ew2);

  auto ew3 = try_and_catch<std::exception>([&]() {
    throw std::runtime_error("payload");
  });
  auto ew4 = try_and_catch<std::exception>([&]() {
    ew3.throwException();
  });
  EXPECT_EQ(ew3, ew4);
}

TEST(ExceptionWrapper, not_equals) {
  std::runtime_error e1("payload");
  std::runtime_error e2("payload");
  auto ew1 = make_exception_wrapper<std::runtime_error>(e1);
  auto ew2 = make_exception_wrapper<std::runtime_error>(e2);
  EXPECT_NE(ew1, ew2);

  auto ew3 = make_exception_wrapper<std::runtime_error>(e1);
  auto ew4 = make_exception_wrapper<std::runtime_error>(e1);
  EXPECT_NE(ew3, ew4);

  auto ew5 = try_and_catch<std::exception>([&]() {
    throw e1;
  });
  auto ew6 = try_and_catch<std::exception>([&]() {
    throw e1;
  });
  EXPECT_NE(ew5, ew6);
}

TEST(ExceptionWrapper, try_and_catch_test) {
  std::string expected = "payload";

  // Catch rightmost matching exception type
  exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
    [=]() {
      throw std::runtime_error(expected);
    });
  EXPECT_TRUE(bool(ew));
  EXPECT_TRUE(ew.getCopied());
  EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
  EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
  auto rep = ew.is_compatible_with<std::runtime_error>();
  EXPECT_TRUE(rep);

  // Changing order is like catching in wrong order. Beware of this in your
  // code.
  auto ew2 = try_and_catch<std::runtime_error, std::exception>([=]() {
    throw std::runtime_error(expected);
  });
  EXPECT_TRUE(bool(ew2));
  // We are catching a std::exception, not std::runtime_error.
  EXPECT_FALSE(ew2.getCopied());
  // But, we can still get the actual type if we want it.
  rep = ew2.is_compatible_with<std::runtime_error>();
  EXPECT_TRUE(rep);

  // Catches even if not rightmost.
  auto ew3 = try_and_catch<std::exception, std::runtime_error>([]() {
    throw std::exception();
  });
  EXPECT_TRUE(bool(ew3));
  EXPECT_EQ(ew3.what(), kExceptionClassName + ": std::exception");
  EXPECT_EQ(ew3.class_name(), kExceptionClassName);
  rep = ew3.is_compatible_with<std::runtime_error>();
  EXPECT_FALSE(rep);

  // If does not catch, throws.
  EXPECT_THROW(
    try_and_catch<std::runtime_error>([]() {
      throw std::exception();
    }),
    std::exception);
}

TEST(ExceptionWrapper, with_exception_test) {
  int expected = 23;

  // This works, and doesn't slice.
  exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
    [=]() {
      throw IntException(expected);
    });
  EXPECT_TRUE(bool(ew));
  EXPECT_EQ(ew.what(), kIntExceptionClassName + ": int == 23");
  EXPECT_EQ(ew.class_name(), kIntExceptionClassName);
  EXPECT_TRUE(ew.with_exception(
      [&](const IntException& ie) { EXPECT_EQ(ie.getInt(), expected); }));

  // I can try_and_catch a non-copyable base class.  This will use
  // std::exception_ptr internally.
  exception_wrapper ew2 = try_and_catch<AbstractIntException>(
    [=]() {
      throw IntException(expected);
    });
  EXPECT_TRUE(bool(ew2));
  EXPECT_EQ(ew2.what(), kIntExceptionClassName + ": int == 23");
  EXPECT_EQ(ew2.class_name(), kIntExceptionClassName);
  EXPECT_TRUE(ew2.with_exception([&](AbstractIntException& ie) {
    EXPECT_EQ(ie.getInt(), expected);
    EXPECT_TRUE(dynamic_cast<IntException*>(&ie));
  }));

  // Test with const this.  If this compiles and does not crash due to
  // infinite loop when it runs, it succeeds.
  const exception_wrapper& cew = ew;
  EXPECT_TRUE(
      cew.with_exception([&](const IntException& /* ie */) { SUCCEED(); }));

  // Test with empty ew.
  exception_wrapper empty_ew;
  EXPECT_FALSE(
      empty_ew.with_exception([&](const std::exception& /* ie */) { FAIL(); }));

  // This won't even compile.  You can't use a function which takes a
  // non-const reference with a const exception_wrapper.
/*
  cew.with_exception([&](IntException& ie) {
      SUCCEED();
    });
*/
}

TEST(ExceptionWrapper, getExceptionPtr_test) {
  int expected = 23;

  // This works, and doesn't slice.
  exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
      [=]() { throw IntException(expected); });
  std::exception_ptr eptr = ew.getExceptionPtr();
  EXPECT_THROW(std::rethrow_exception(eptr), IntException);

  // I can try_and_catch a non-copyable base class.  This will use
  // std::exception_ptr internally.
  exception_wrapper ew2 = try_and_catch<AbstractIntException>(
      [=]() { throw IntException(expected); });
  eptr = ew2.getExceptionPtr();
  EXPECT_THROW(std::rethrow_exception(eptr), IntException);

  // Test with const this.
  const exception_wrapper& cew = ew;
  eptr = cew.getExceptionPtr();
  EXPECT_THROW(std::rethrow_exception(eptr), IntException);

  // Test with empty ew.

  // Disabling pending fix for fbandroid: t13822116
  /*
  exception_wrapper empty_ew;
  eptr = empty_ew.getExceptionPtr();
  EXPECT_DEATH(std::rethrow_exception(eptr), "exception");
  */
}

TEST(ExceptionWrapper, with_exception_deduction) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
  EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
  EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
}

TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
  EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
  EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
}

TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
  const auto cew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
  EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
  EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
}

TEST(ExceptionWrapper, with_exception_deduction_returning) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
  EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
  EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
}

namespace {
template <typename T>
T& r_to_l(T v) { return std::ref(v); }
}

TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
  EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
  EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
}

TEST(ExceptionWrapper, non_std_exception_test) {
  int expected = 17;

  exception_wrapper ew = try_and_catch<std::exception, int>(
    [=]() {
      throw expected;
    });
  EXPECT_TRUE(bool(ew));
  EXPECT_FALSE(ew.is_compatible_with<std::exception>());
  EXPECT_EQ(ew.what(), kIntClassName);
  EXPECT_EQ(ew.class_name(), kIntClassName);
  // non-std::exception types are supported, but the only way to
  // access their value is to explicity rethrow and catch it.
  try {
    ew.throwException();
  } catch /* nolint */ (int& i) {
    EXPECT_EQ(i, expected);
  }
}

TEST(ExceptionWrapper, exceptionStr) {
  auto ew = make_exception_wrapper<std::runtime_error>("argh");
  EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
}

TEST(ExceptionWrapper, throwException_noException) {
  exception_wrapper ew;
  ASSERT_DEATH(ew.throwException(), "empty folly::exception_wrapper");
}

namespace {
class TestException : public std::exception { };
void testEW(const exception_wrapper& ew) {
  EXPECT_THROW(ew.throwException(), TestException);
}
}  // namespace

TEST(ExceptionWrapper, implicitConstruction) {
  // Try with both lvalue and rvalue references
  TestException e;
  testEW(e);
  testEW(TestException());
}
<commit_msg>Fix for ExceptionWrapperTest<commit_after>/*
 * Copyright 2016 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdexcept>

#include <folly/ExceptionWrapper.h>
#include <folly/Conv.h>
#include <folly/Portability.h>
#include <folly/portability/GTest.h>

using namespace folly;

class AbstractIntException : public std::exception {
 public:
  virtual int getInt() const = 0;
};

class IntException : public AbstractIntException {
 public:
  explicit IntException(int i) : i_(i) {}

  int getInt() const override { return i_; }
  const char* what() const noexcept override {
    what_ = folly::to<std::string>("int == ", i_);
    return what_.c_str();
  }

 private:
  int i_;
  mutable std::string what_;
};

const static std::string kExceptionClassName =
    demangle(typeid(std::exception)).toStdString();
const static std::string kRuntimeErrorClassName =
    demangle(typeid(std::runtime_error)).toStdString();
const static std::string kIntExceptionClassName =
    demangle(typeid(IntException)).toStdString();
const static std::string kIntClassName = demangle(typeid(int)).toStdString();

// Tests that when we call throwException, the proper type is thrown (derived)
TEST(ExceptionWrapper, throw_test) {
  std::runtime_error e("payload");
  auto ew = make_exception_wrapper<std::runtime_error>(e);

  std::vector<exception_wrapper> container;
  container.push_back(ew);

  try {
    container[0].throwException();
  } catch (std::runtime_error& e) {
    std::string expected = "payload";
    std::string actual = e.what();
    EXPECT_EQ(expected, actual);
  }
}

TEST(ExceptionWrapper, members) {
  auto ew = exception_wrapper();
  EXPECT_FALSE(bool(ew));
  EXPECT_EQ(ew.what(), "");
  EXPECT_EQ(ew.class_name(), "");
  ew = make_exception_wrapper<std::runtime_error>("payload");
  EXPECT_TRUE(bool(ew));
  EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
  EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
}

TEST(ExceptionWrapper, equals) {
  std::runtime_error e("payload");
  auto ew1 = make_exception_wrapper<std::runtime_error>(e);
  auto ew2 = ew1;
  EXPECT_EQ(ew1, ew2);

  auto ew3 = try_and_catch<std::exception>([&]() {
    throw std::runtime_error("payload");
  });
  auto ew4 = try_and_catch<std::exception>([&]() {
    ew3.throwException();
  });
  EXPECT_EQ(ew3, ew4);
}

TEST(ExceptionWrapper, not_equals) {
  std::runtime_error e1("payload");
  std::runtime_error e2("payload");
  auto ew1 = make_exception_wrapper<std::runtime_error>(e1);
  auto ew2 = make_exception_wrapper<std::runtime_error>(e2);
  EXPECT_NE(ew1, ew2);

  auto ew3 = make_exception_wrapper<std::runtime_error>(e1);
  auto ew4 = make_exception_wrapper<std::runtime_error>(e1);
  EXPECT_NE(ew3, ew4);

  auto ew5 = try_and_catch<std::exception>([&]() {
    throw e1;
  });
  auto ew6 = try_and_catch<std::exception>([&]() {
    throw e1;
  });
  EXPECT_NE(ew5, ew6);
}

TEST(ExceptionWrapper, try_and_catch_test) {
  std::string expected = "payload";

  // Catch rightmost matching exception type
  exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
    [=]() {
      throw std::runtime_error(expected);
    });
  EXPECT_TRUE(bool(ew));
  EXPECT_TRUE(ew.getCopied());
  EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
  EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
  auto rep = ew.is_compatible_with<std::runtime_error>();
  EXPECT_TRUE(rep);

  // Changing order is like catching in wrong order. Beware of this in your
  // code.
  auto ew2 = try_and_catch<std::runtime_error, std::exception>([=]() {
    throw std::runtime_error(expected);
  });
  EXPECT_TRUE(bool(ew2));
  // We are catching a std::exception, not std::runtime_error.
  EXPECT_FALSE(ew2.getCopied());
  // But, we can still get the actual type if we want it.
  rep = ew2.is_compatible_with<std::runtime_error>();
  EXPECT_TRUE(rep);

  // Catches even if not rightmost.
  auto ew3 = try_and_catch<std::exception, std::runtime_error>([]() {
    throw std::exception();
  });
  EXPECT_TRUE(bool(ew3));
  EXPECT_EQ(ew3.what(), kExceptionClassName + ": std::exception");
  EXPECT_EQ(ew3.class_name(), kExceptionClassName);
  rep = ew3.is_compatible_with<std::runtime_error>();
  EXPECT_FALSE(rep);

  // If does not catch, throws.
  EXPECT_THROW(
    try_and_catch<std::runtime_error>([]() {
      throw std::exception();
    }),
    std::exception);
}

TEST(ExceptionWrapper, with_exception_test) {
  int expected = 23;

  // This works, and doesn't slice.
  exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
    [=]() {
      throw IntException(expected);
    });
  EXPECT_TRUE(bool(ew));
  EXPECT_EQ(ew.what(), kIntExceptionClassName + ": int == 23");
  EXPECT_EQ(ew.class_name(), kIntExceptionClassName);
  EXPECT_TRUE(ew.with_exception(
      [&](const IntException& ie) { EXPECT_EQ(ie.getInt(), expected); }));

  // I can try_and_catch a non-copyable base class.  This will use
  // std::exception_ptr internally.
  exception_wrapper ew2 = try_and_catch<AbstractIntException>(
    [=]() {
      throw IntException(expected);
    });
  EXPECT_TRUE(bool(ew2));
  EXPECT_EQ(ew2.what(), kIntExceptionClassName + ": int == 23");
  EXPECT_EQ(ew2.class_name(), kIntExceptionClassName);
  EXPECT_TRUE(ew2.with_exception([&](AbstractIntException& ie) {
    EXPECT_EQ(ie.getInt(), expected);
    EXPECT_TRUE(dynamic_cast<IntException*>(&ie));
  }));

  // Test with const this.  If this compiles and does not crash due to
  // infinite loop when it runs, it succeeds.
  const exception_wrapper& cew = ew;
  EXPECT_TRUE(
      cew.with_exception([&](const IntException& /* ie */) { SUCCEED(); }));

  // Test with empty ew.
  exception_wrapper empty_ew;
  EXPECT_FALSE(
      empty_ew.with_exception([&](const std::exception& /* ie */) { FAIL(); }));

  // This won't even compile.  You can't use a function which takes a
  // non-const reference with a const exception_wrapper.
/*
  cew.with_exception([&](IntException& ie) {
      SUCCEED();
    });
*/
}

TEST(ExceptionWrapper, getExceptionPtr_test) {
  int expected = 23;

  // This works, and doesn't slice.
  exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
      [=]() { throw IntException(expected); });
  std::exception_ptr eptr = ew.getExceptionPtr();
  EXPECT_THROW(std::rethrow_exception(eptr), IntException);

  // I can try_and_catch a non-copyable base class.  This will use
  // std::exception_ptr internally.
  exception_wrapper ew2 = try_and_catch<AbstractIntException>(
      [=]() { throw IntException(expected); });
  eptr = ew2.getExceptionPtr();
  EXPECT_THROW(std::rethrow_exception(eptr), IntException);

  // Test with const this.
  const exception_wrapper& cew = ew;
  eptr = cew.getExceptionPtr();
  EXPECT_THROW(std::rethrow_exception(eptr), IntException);

  // Test with empty ew.
  exception_wrapper empty_ew;
  eptr = empty_ew.getExceptionPtr();
  EXPECT_FALSE(eptr);
}

TEST(ExceptionWrapper, with_exception_deduction) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
  EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
  EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
}

TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
  EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
  EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
}

TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
  const auto cew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
  EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
  EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
}

TEST(ExceptionWrapper, with_exception_deduction_returning) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
  EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
  EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
}

namespace {
template <typename T>
T& r_to_l(T v) { return std::ref(v); }
}

TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
  auto ew = make_exception_wrapper<std::runtime_error>("hi");
  EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
  EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
  EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
}

TEST(ExceptionWrapper, non_std_exception_test) {
  int expected = 17;

  exception_wrapper ew = try_and_catch<std::exception, int>(
    [=]() {
      throw expected;
    });
  EXPECT_TRUE(bool(ew));
  EXPECT_FALSE(ew.is_compatible_with<std::exception>());
  EXPECT_EQ(ew.what(), kIntClassName);
  EXPECT_EQ(ew.class_name(), kIntClassName);
  // non-std::exception types are supported, but the only way to
  // access their value is to explicity rethrow and catch it.
  try {
    ew.throwException();
  } catch /* nolint */ (int& i) {
    EXPECT_EQ(i, expected);
  }
}

TEST(ExceptionWrapper, exceptionStr) {
  auto ew = make_exception_wrapper<std::runtime_error>("argh");
  EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
}

TEST(ExceptionWrapper, throwException_noException) {
  exception_wrapper ew;
  ASSERT_DEATH(ew.throwException(), "empty folly::exception_wrapper");
}

namespace {
class TestException : public std::exception { };
void testEW(const exception_wrapper& ew) {
  EXPECT_THROW(ew.throwException(), TestException);
}
}  // namespace

TEST(ExceptionWrapper, implicitConstruction) {
  // Try with both lvalue and rvalue references
  TestException e;
  testEW(e);
  testEW(TestException());
}
<|endoftext|>


<commit_before>// Copyright 2008, Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// The file contains the implementation of the File methods specific to
// POSIX platforms.

#include "kml/base/file.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

namespace kmlbase {

// Internal to the POSIX File class.
static bool StatFile(const char* path, struct stat* stat_data) {
  struct stat tmp;
  if (stat(path, &tmp) !=0) {
    return false;
  }
  *stat_data = tmp;
  return true;
}

bool File::Exists(const string& full_path) {
  struct stat stat_data;
  if (!StatFile(full_path.c_str(), &stat_data)) {
    return false;
  }
  return S_ISREG(stat_data.st_mode);
}

bool File::Delete(const string& filepath) {
  return unlink(filepath.c_str()) == 0;
}

bool File::CreateNewTempFile(string* path) {
  if (!path) {
    return false;
  }
  char temp_path[] = "/tmp/libkmlXXXXXX";
  int fd = mkstemp(temp_path);
  if (fd == -1) {
    return false;
  }
  close(fd);
  path->assign(temp_path, strlen(temp_path));
  return true;
}

}  // end namespace kmlbase
<commit_msg>BUG: missing include file<commit_after>// Copyright 2008, Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// The file contains the implementation of the File methods specific to
// POSIX platforms.

#include "kml/base/file.h"
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>

namespace kmlbase {

// Internal to the POSIX File class.
static bool StatFile(const char* path, struct stat* stat_data) {
  struct stat tmp;
  if (stat(path, &tmp) !=0) {
    return false;
  }
  *stat_data = tmp;
  return true;
}

bool File::Exists(const string& full_path) {
  struct stat stat_data;
  if (!StatFile(full_path.c_str(), &stat_data)) {
    return false;
  }
  return S_ISREG(stat_data.st_mode);
}

bool File::Delete(const string& filepath) {
  return unlink(filepath.c_str()) == 0;
}

bool File::CreateNewTempFile(string* path) {
  if (!path) {
    return false;
  }
  char temp_path[] = "/tmp/libkmlXXXXXX";
  int fd = mkstemp(temp_path);
  if (fd == -1) {
    return false;
  }
  close(fd);
  path->assign(temp_path, strlen(temp_path));
  return true;
}

}  // end namespace kmlbase
<|endoftext|>


<commit_before>// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/thread.h"

#include "vm/growable_array.h"
#include "vm/isolate.h"
#include "vm/lockers.h"
#include "vm/object.h"
#include "vm/os_thread.h"
#include "vm/profiler.h"
#include "vm/stub_code.h"
#include "vm/thread_interrupter.h"
#include "vm/thread_registry.h"

namespace dart {

// The single thread local key which stores all the thread local data
// for a thread.
ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey;

// Remove |thread| from each isolate's thread registry.
class ThreadPruner : public IsolateVisitor {
 public:
  explicit ThreadPruner(Thread* thread)
      : thread_(thread) {
    ASSERT(thread_ != NULL);
  }

  void VisitIsolate(Isolate* isolate) {
    ThreadRegistry* registry = isolate->thread_registry();
    ASSERT(registry != NULL);
    registry->PruneThread(thread_);
  }
 private:
  Thread* thread_;
};

static void DeleteThread(void* thread) {
  delete reinterpret_cast<Thread*>(thread);
}

Thread::~Thread() {
  // We should cleanly exit any isolate before destruction.
  ASSERT(isolate_ == NULL);
  // Clear |this| from all isolate's thread registry.
  ThreadPruner pruner(this);
  Isolate::VisitIsolates(&pruner);
}

void Thread::InitOnceBeforeIsolate() {
  ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
  thread_key_ = OSThread::CreateThreadLocal(DeleteThread);
  ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey);
  ASSERT(Thread::Current() == NULL);
  // Allocate a new Thread and postpone initialization of VM constants for
  // this first thread.
  Thread* thread = new Thread(false);
  // Verify that current thread was set.
  ASSERT(Thread::Current() == thread);
}

void Thread::InitOnceAfterObjectAndStubCode() {
  Thread* thread = Thread::Current();
  ASSERT(thread != NULL);
  ASSERT(thread->isolate() == Dart::vm_isolate());
  thread->InitVMConstants();
}

void Thread::SetCurrent(Thread* current) {
  OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
}

void Thread::EnsureInit() {
  if (Thread::Current() == NULL) {
    // Allocate a new Thread.
    Thread* thread = new Thread();
    // Verify that current thread was set.
    ASSERT(Thread::Current() == thread);
  }
}

#if defined(TARGET_OS_WINDOWS)
void Thread::CleanUp() {
  Thread* current = Current();
  if (current != NULL) {
    delete current;
  }
  SetCurrent(NULL);
}
#endif

Thread::Thread(bool init_vm_constants)
    : id_(OSThread::GetCurrentThreadId()),
      isolate_(NULL),
      store_buffer_block_(NULL) {
  ClearState();
#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
  member_name = default_init_value;
CACHED_CONSTANTS_LIST(DEFAULT_INIT)
#undef DEFAULT_INIT
  if (init_vm_constants) {
    InitVMConstants();
  }
  SetCurrent(this);
}

void Thread::InitVMConstants() {
#define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value)  \
  ASSERT((init_expr)->IsOldObject());
CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP)
#undef ASSERT_VM_HEAP

#define INIT_VALUE(type_name, member_name, init_expr, default_init_value)      \
  ASSERT(member_name == default_init_value);                                   \
  member_name = (init_expr);
CACHED_CONSTANTS_LIST(INIT_VALUE)
#undef INIT_VALUE
}

void Thread::Schedule(Isolate* isolate) {
  State st;
  if (isolate->thread_registry()->RestoreStateTo(this, &st)) {
    ASSERT(isolate->thread_registry()->Contains(this));
    state_ = st;
  }
}

void Thread::Unschedule() {
  ThreadRegistry* reg = isolate_->thread_registry();
  ASSERT(reg->Contains(this));
  reg->SaveStateFrom(this, state_);
  ClearState();
}

void Thread::EnterIsolate(Isolate* isolate) {
  Thread* thread = Thread::Current();
  ASSERT(thread != NULL);
  ASSERT(thread->isolate() == NULL);
  ASSERT(!isolate->HasMutatorThread());
  thread->isolate_ = isolate;
  isolate->MakeCurrentThreadMutator(thread);
  isolate->set_vm_tag(VMTag::kVMTagId);
  ASSERT(thread->store_buffer_block_ == NULL);
  thread->StoreBufferAcquire();
  ASSERT(isolate->heap() != NULL);
  thread->heap_ = isolate->heap();
  thread->Schedule(isolate);
  // TODO(koda): Migrate profiler interface to use Thread.
  Profiler::BeginExecution(isolate);
}

void Thread::ExitIsolate() {
  Thread* thread = Thread::Current();
  // TODO(koda): Audit callers; they should know whether they're in an isolate.
  if (thread == NULL || thread->isolate() == NULL) return;
  Isolate* isolate = thread->isolate();
  Profiler::EndExecution(isolate);
  thread->Unschedule();
  // TODO(koda): Move store_buffer_block_ into State.
  thread->StoreBufferRelease();
  if (isolate->is_runnable()) {
    isolate->set_vm_tag(VMTag::kIdleTagId);
  } else {
    isolate->set_vm_tag(VMTag::kLoadWaitTagId);
  }
  isolate->ClearMutatorThread();
  thread->isolate_ = NULL;
  ASSERT(Isolate::Current() == NULL);
  thread->heap_ = NULL;
}

void Thread::EnterIsolateAsHelper(Isolate* isolate) {
  Thread* thread = Thread::Current();
  ASSERT(thread != NULL);
  ASSERT(thread->isolate() == NULL);
  thread->isolate_ = isolate;
  ASSERT(thread->store_buffer_block_ == NULL);
  // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge.
  thread->store_buffer_block_ =
      thread->isolate()->store_buffer()->PopEmptyBlock();
  ASSERT(isolate->heap() != NULL);
  thread->heap_ = isolate->heap();
  ASSERT(thread->thread_state() == NULL);
  // Do not update isolate->mutator_thread, but perform sanity check:
  // this thread should not be both the main mutator and helper.
  ASSERT(!isolate->MutatorThreadIsCurrentThread());
  thread->Schedule(isolate);
}

void Thread::ExitIsolateAsHelper() {
  Thread* thread = Thread::Current();
  Isolate* isolate = thread->isolate();
  ASSERT(isolate != NULL);
  thread->Unschedule();
  // TODO(koda): Move store_buffer_block_ into State.
  thread->StoreBufferRelease();
  thread->set_thread_state(NULL);
  thread->isolate_ = NULL;
  thread->heap_ = NULL;
  ASSERT(!isolate->MutatorThreadIsCurrentThread());
}

// TODO(koda): Make non-static and invoke in SafepointThreads.
void Thread::PrepareForGC() {
  Thread* thread = Thread::Current();
  const bool kDoNotCheckThreshold = false;  // Prevent scheduling another GC.
  thread->StoreBufferRelease(kDoNotCheckThreshold);
  // Make sure to get an *empty* block; the isolate needs all entries
  // at GC time.
  // TODO(koda): Replace with an epilogue (PrepareAfterGC) that acquires.
  thread->store_buffer_block_ =
      thread->isolate()->store_buffer()->PopEmptyBlock();
}

void Thread::StoreBufferBlockProcess(bool check_threshold) {
  StoreBufferRelease(check_threshold);
  StoreBufferAcquire();
}

void Thread::StoreBufferAddObject(RawObject* obj) {
  store_buffer_block_->Push(obj);
  if (store_buffer_block_->IsFull()) {
    StoreBufferBlockProcess(true);
  }
}

void Thread::StoreBufferAddObjectGC(RawObject* obj) {
  store_buffer_block_->Push(obj);
  if (store_buffer_block_->IsFull()) {
    StoreBufferBlockProcess(false);
  }
}

void Thread::StoreBufferRelease(bool check_threshold) {
  StoreBufferBlock* block = store_buffer_block_;
  store_buffer_block_ = NULL;
  isolate_->store_buffer()->PushBlock(block, check_threshold);
}

void Thread::StoreBufferAcquire() {
  store_buffer_block_ = isolate()->store_buffer()->PopNonFullBlock();
}

CHA* Thread::cha() const {
  ASSERT(isolate_ != NULL);
  return isolate_->cha_;
}

void Thread::set_cha(CHA* value) {
  ASSERT(isolate_ != NULL);
  isolate_->cha_ = value;
}

void Thread::SetThreadInterrupter(ThreadInterruptCallback callback,
                                  void* data) {
  ASSERT(Thread::Current() == this);
  thread_interrupt_callback_ = callback;
  thread_interrupt_data_ = data;
}

bool Thread::IsThreadInterrupterEnabled(ThreadInterruptCallback* callback,
                                        void** data) const {
#if defined(TARGET_OS_WINDOWS)
  // On Windows we expect this to be called from the thread interrupter thread.
  ASSERT(id() != OSThread::GetCurrentThreadId());
#else
  // On posix platforms, we expect this to be called from signal handler.
  ASSERT(id() == OSThread::GetCurrentThreadId());
#endif
  ASSERT(callback != NULL);
  ASSERT(data != NULL);
  *callback = thread_interrupt_callback_;
  *data = thread_interrupt_data_;
  return (*callback != NULL) &&
         (*data != NULL);
}

bool Thread::CanLoadFromThread(const Object& object) {
#define CHECK_OBJECT(type_name, member_name, expr, default_init_value)         \
  if (object.raw() == expr) return true;
CACHED_VM_OBJECTS_LIST(CHECK_OBJECT)
#undef CHECK_OBJECT
  return false;
}

intptr_t Thread::OffsetFromThread(const Object& object) {
#define COMPUTE_OFFSET(type_name, member_name, expr, default_init_value)       \
  ASSERT((expr)->IsVMHeapObject());                                            \
  if (object.raw() == expr) return Thread::member_name##offset();
CACHED_VM_OBJECTS_LIST(COMPUTE_OFFSET)
#undef COMPUTE_OFFSET
  UNREACHABLE();
  return -1;
}

}  // namespace dart
<commit_msg>- Initialize fields used in the profiler interrupts.<commit_after>// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/thread.h"

#include "vm/growable_array.h"
#include "vm/isolate.h"
#include "vm/lockers.h"
#include "vm/object.h"
#include "vm/os_thread.h"
#include "vm/profiler.h"
#include "vm/stub_code.h"
#include "vm/thread_interrupter.h"
#include "vm/thread_registry.h"

namespace dart {

// The single thread local key which stores all the thread local data
// for a thread.
ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey;

// Remove |thread| from each isolate's thread registry.
class ThreadPruner : public IsolateVisitor {
 public:
  explicit ThreadPruner(Thread* thread)
      : thread_(thread) {
    ASSERT(thread_ != NULL);
  }

  void VisitIsolate(Isolate* isolate) {
    ThreadRegistry* registry = isolate->thread_registry();
    ASSERT(registry != NULL);
    registry->PruneThread(thread_);
  }
 private:
  Thread* thread_;
};

static void DeleteThread(void* thread) {
  delete reinterpret_cast<Thread*>(thread);
}

Thread::~Thread() {
  // We should cleanly exit any isolate before destruction.
  ASSERT(isolate_ == NULL);
  // Clear |this| from all isolate's thread registry.
  ThreadPruner pruner(this);
  Isolate::VisitIsolates(&pruner);
}

void Thread::InitOnceBeforeIsolate() {
  ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
  thread_key_ = OSThread::CreateThreadLocal(DeleteThread);
  ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey);
  ASSERT(Thread::Current() == NULL);
  // Allocate a new Thread and postpone initialization of VM constants for
  // this first thread.
  Thread* thread = new Thread(false);
  // Verify that current thread was set.
  ASSERT(Thread::Current() == thread);
}

void Thread::InitOnceAfterObjectAndStubCode() {
  Thread* thread = Thread::Current();
  ASSERT(thread != NULL);
  ASSERT(thread->isolate() == Dart::vm_isolate());
  thread->InitVMConstants();
}

void Thread::SetCurrent(Thread* current) {
  OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
}

void Thread::EnsureInit() {
  if (Thread::Current() == NULL) {
    // Allocate a new Thread.
    Thread* thread = new Thread();
    // Verify that current thread was set.
    ASSERT(Thread::Current() == thread);
  }
}

#if defined(TARGET_OS_WINDOWS)
void Thread::CleanUp() {
  Thread* current = Current();
  if (current != NULL) {
    delete current;
  }
  SetCurrent(NULL);
}
#endif

Thread::Thread(bool init_vm_constants)
    : id_(OSThread::GetCurrentThreadId()),
      thread_interrupt_callback_(NULL),
      thread_interrupt_data_(NULL),
      isolate_(NULL),
      heap_(NULL),
      store_buffer_block_(NULL) {
  ClearState();
#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
  member_name = default_init_value;
CACHED_CONSTANTS_LIST(DEFAULT_INIT)
#undef DEFAULT_INIT
  if (init_vm_constants) {
    InitVMConstants();
  }
  SetCurrent(this);
}

void Thread::InitVMConstants() {
#define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value)  \
  ASSERT((init_expr)->IsOldObject());
CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP)
#undef ASSERT_VM_HEAP

#define INIT_VALUE(type_name, member_name, init_expr, default_init_value)      \
  ASSERT(member_name == default_init_value);                                   \
  member_name = (init_expr);
CACHED_CONSTANTS_LIST(INIT_VALUE)
#undef INIT_VALUE
}

void Thread::Schedule(Isolate* isolate) {
  State st;
  if (isolate->thread_registry()->RestoreStateTo(this, &st)) {
    ASSERT(isolate->thread_registry()->Contains(this));
    state_ = st;
  }
}

void Thread::Unschedule() {
  ThreadRegistry* reg = isolate_->thread_registry();
  ASSERT(reg->Contains(this));
  reg->SaveStateFrom(this, state_);
  ClearState();
}

void Thread::EnterIsolate(Isolate* isolate) {
  Thread* thread = Thread::Current();
  ASSERT(thread != NULL);
  ASSERT(thread->isolate() == NULL);
  ASSERT(!isolate->HasMutatorThread());
  thread->isolate_ = isolate;
  isolate->MakeCurrentThreadMutator(thread);
  isolate->set_vm_tag(VMTag::kVMTagId);
  ASSERT(thread->store_buffer_block_ == NULL);
  thread->StoreBufferAcquire();
  ASSERT(isolate->heap() != NULL);
  thread->heap_ = isolate->heap();
  thread->Schedule(isolate);
  // TODO(koda): Migrate profiler interface to use Thread.
  Profiler::BeginExecution(isolate);
}

void Thread::ExitIsolate() {
  Thread* thread = Thread::Current();
  // TODO(koda): Audit callers; they should know whether they're in an isolate.
  if (thread == NULL || thread->isolate() == NULL) return;
  Isolate* isolate = thread->isolate();
  Profiler::EndExecution(isolate);
  thread->Unschedule();
  // TODO(koda): Move store_buffer_block_ into State.
  thread->StoreBufferRelease();
  if (isolate->is_runnable()) {
    isolate->set_vm_tag(VMTag::kIdleTagId);
  } else {
    isolate->set_vm_tag(VMTag::kLoadWaitTagId);
  }
  isolate->ClearMutatorThread();
  thread->isolate_ = NULL;
  ASSERT(Isolate::Current() == NULL);
  thread->heap_ = NULL;
}

void Thread::EnterIsolateAsHelper(Isolate* isolate) {
  Thread* thread = Thread::Current();
  ASSERT(thread != NULL);
  ASSERT(thread->isolate() == NULL);
  thread->isolate_ = isolate;
  ASSERT(thread->store_buffer_block_ == NULL);
  // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge.
  thread->store_buffer_block_ =
      thread->isolate()->store_buffer()->PopEmptyBlock();
  ASSERT(isolate->heap() != NULL);
  thread->heap_ = isolate->heap();
  ASSERT(thread->thread_state() == NULL);
  // Do not update isolate->mutator_thread, but perform sanity check:
  // this thread should not be both the main mutator and helper.
  ASSERT(!isolate->MutatorThreadIsCurrentThread());
  thread->Schedule(isolate);
}

void Thread::ExitIsolateAsHelper() {
  Thread* thread = Thread::Current();
  Isolate* isolate = thread->isolate();
  ASSERT(isolate != NULL);
  thread->Unschedule();
  // TODO(koda): Move store_buffer_block_ into State.
  thread->StoreBufferRelease();
  thread->set_thread_state(NULL);
  thread->isolate_ = NULL;
  thread->heap_ = NULL;
  ASSERT(!isolate->MutatorThreadIsCurrentThread());
}

// TODO(koda): Make non-static and invoke in SafepointThreads.
void Thread::PrepareForGC() {
  Thread* thread = Thread::Current();
  const bool kDoNotCheckThreshold = false;  // Prevent scheduling another GC.
  thread->StoreBufferRelease(kDoNotCheckThreshold);
  // Make sure to get an *empty* block; the isolate needs all entries
  // at GC time.
  // TODO(koda): Replace with an epilogue (PrepareAfterGC) that acquires.
  thread->store_buffer_block_ =
      thread->isolate()->store_buffer()->PopEmptyBlock();
}

void Thread::StoreBufferBlockProcess(bool check_threshold) {
  StoreBufferRelease(check_threshold);
  StoreBufferAcquire();
}

void Thread::StoreBufferAddObject(RawObject* obj) {
  store_buffer_block_->Push(obj);
  if (store_buffer_block_->IsFull()) {
    StoreBufferBlockProcess(true);
  }
}

void Thread::StoreBufferAddObjectGC(RawObject* obj) {
  store_buffer_block_->Push(obj);
  if (store_buffer_block_->IsFull()) {
    StoreBufferBlockProcess(false);
  }
}

void Thread::StoreBufferRelease(bool check_threshold) {
  StoreBufferBlock* block = store_buffer_block_;
  store_buffer_block_ = NULL;
  isolate_->store_buffer()->PushBlock(block, check_threshold);
}

void Thread::StoreBufferAcquire() {
  store_buffer_block_ = isolate()->store_buffer()->PopNonFullBlock();
}

CHA* Thread::cha() const {
  ASSERT(isolate_ != NULL);
  return isolate_->cha_;
}

void Thread::set_cha(CHA* value) {
  ASSERT(isolate_ != NULL);
  isolate_->cha_ = value;
}

void Thread::SetThreadInterrupter(ThreadInterruptCallback callback,
                                  void* data) {
  ASSERT(Thread::Current() == this);
  thread_interrupt_callback_ = callback;
  thread_interrupt_data_ = data;
}

bool Thread::IsThreadInterrupterEnabled(ThreadInterruptCallback* callback,
                                        void** data) const {
#if defined(TARGET_OS_WINDOWS)
  // On Windows we expect this to be called from the thread interrupter thread.
  ASSERT(id() != OSThread::GetCurrentThreadId());
#else
  // On posix platforms, we expect this to be called from signal handler.
  ASSERT(id() == OSThread::GetCurrentThreadId());
#endif
  ASSERT(callback != NULL);
  ASSERT(data != NULL);
  *callback = thread_interrupt_callback_;
  *data = thread_interrupt_data_;
  return (*callback != NULL) &&
         (*data != NULL);
}

bool Thread::CanLoadFromThread(const Object& object) {
#define CHECK_OBJECT(type_name, member_name, expr, default_init_value)         \
  if (object.raw() == expr) return true;
CACHED_VM_OBJECTS_LIST(CHECK_OBJECT)
#undef CHECK_OBJECT
  return false;
}

intptr_t Thread::OffsetFromThread(const Object& object) {
#define COMPUTE_OFFSET(type_name, member_name, expr, default_init_value)       \
  ASSERT((expr)->IsVMHeapObject());                                            \
  if (object.raw() == expr) return Thread::member_name##offset();
CACHED_VM_OBJECTS_LIST(COMPUTE_OFFSET)
#undef COMPUTE_OFFSET
  UNREACHABLE();
  return -1;
}

}  // namespace dart
<|endoftext|>


<commit_before>/*
    ircaccount.cpp - IRC Account

    Copyright (c) 2002      by Nick Betcher <nbetcher@kde.org>

    Kopete    (c) 2002      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/
#include <kaction.h>
#include <kaboutdata.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kinputdialog.h>
#include <kmessagebox.h>
#include <kpopupmenu.h>

#include "kopeteaway.h"
#include "kopetecontactlist.h"
#include "kopetemetacontact.h"

#include "ircaccount.h"
#include "ircprotocol.h"
#include "irccontactmanager.h"
#include "ircservercontact.h"
#include "ircchannelcontact.h"
#include "ircusercontact.h"
#include "ksparser.h"

IRCAccount::IRCAccount(IRCProtocol *protocol, const QString &accountId)
	: KopeteAccount(protocol, accountId)
{
	m_manager = 0L;
	m_protocol = protocol;

	mNickName = accountId.section('@',0,0);
	QString serverInfo = accountId.section('@',1);
	m_server = serverInfo.section(':',0,0);
	m_port = serverInfo.section(':',1).toUInt();

	m_engine = new KIRC( m_server, m_port );
	QString version=i18n("Kopete IRC Plugin %1 [http://kopete.kde.org]").arg(kapp->aboutData()->version());
	m_engine->setVersionString( version  );
	if( rememberPassword() )
		m_engine->setPassword( password() );

	QObject::connect(m_engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)),
			this, SLOT(successfullyChangedNick(const QString &, const QString &)));

	m_contactManager = new IRCContactManager(mNickName, m_server, this);
	m_mySelf = m_contactManager->mySelf();
	m_myServer = m_contactManager->myServer();
}

IRCAccount::~IRCAccount()
{
//	kdDebug(14120) << k_funcinfo << mServer << " " << engine() << endl;
	if ( engine()->isConnected() )
		engine()->quitIRC(i18n("Plugin Unloaded"), true);

	delete m_contactManager;
	delete m_engine;
}

void IRCAccount::loaded()
{
	m_engine->setUserName(userName());
}

QString IRCAccount::userName()
{
	return pluginData(protocol(), QString::fromLatin1("userName"));
}

void IRCAccount::setUserName(QString userName)
{
	m_engine->setUserName(userName);
	setPluginData(protocol(), QString::fromLatin1( "userName" ), userName);
}

KActionMenu *IRCAccount::actionMenu()
{
	QString menuTitle = QString::fromLatin1( " %1 <%2> " ).arg( accountId() ).arg( m_mySelf->onlineStatus().description() );

	KActionMenu *mActionMenu = new KActionMenu( accountId(),myself()->onlineStatus().iconFor(this), this, "IRCAccount::mActionMenu" );
	mActionMenu->popupMenu()->insertTitle( m_mySelf->onlineStatus().iconFor( m_mySelf ), menuTitle );

	mActionMenu->insert( new KAction ( i18n("Go Online"), m_protocol->m_UserStatusOnline.iconFor( this ), 0, this, SLOT(connect()), mActionMenu ) );
	mActionMenu->insert( new KAction ( i18n("Set Away"), m_protocol->m_UserStatusAway.iconFor( this ), 0, this, SLOT(slotGoAway()), mActionMenu ) );
	mActionMenu->insert( new KAction ( i18n("Go Offline"), m_protocol->m_UserStatusOffline.iconFor( this ), 0, this, SLOT(disconnect()), mActionMenu ) );
	mActionMenu->popupMenu()->insertSeparator();
	mActionMenu->insert( new KAction ( i18n("Join Channel..."), "", 0, this, SLOT(slotJoinChannel()), mActionMenu ) );
	mActionMenu->insert( new KAction ( i18n("Show Server Window"), "", 0, this, SLOT(slotShowServerWindow()), mActionMenu ) );

	return mActionMenu;
}

void IRCAccount::connect()
{
	if( m_engine->isConnected() )
	{
		if( isAway() )
			setAway( false );
	}
	else if( m_engine->isDisconnected() )
	{
		m_engine->connectToServer( m_mySelf->nickName() );
	}
}

void IRCAccount::disconnect()
{
	m_engine->quitIRC("Kopete IRC [http://kopete.kde.org]");
}

void IRCAccount::setAway( bool isAway, const QString &awayMessage )
{
	kdDebug(14120) << k_funcinfo << isAway << " " << awayMessage << endl;
	if(m_engine->isConnected())
	{
		m_mySelf->setAway( isAway );
		engine()->setAway( isAway, awayMessage );
	}
}

void IRCAccount::slotGoAway()
{
	setAway( true, KopeteAway::message() );
}

void IRCAccount::slotShowServerWindow()
{
	m_myServer->startServerChat();
}

bool IRCAccount::isConnected()
{
	return (m_mySelf->onlineStatus().status() == KopeteOnlineStatus::Online);
}

void IRCAccount::unregister(KopeteContact *contact)
{
	m_contactManager->unregister(contact);
}

IRCServerContact *IRCAccount::findServer( const QString &name, KopeteMetaContact *m )
{
	return m_contactManager->findServer(name, m);
}

void IRCAccount::unregisterServer( const QString &name )
{
	m_contactManager->unregisterServer(name);
}

IRCChannelContact *IRCAccount::findChannel( const QString &name, KopeteMetaContact *m )
{
	return m_contactManager->findChannel(name, m);
}

void IRCAccount::unregisterChannel( const QString &name )
{
	m_contactManager->unregisterChannel(name);
}

IRCUserContact *IRCAccount::findUser(const QString &name, KopeteMetaContact *m)
{
	return m_contactManager->findUser(name, m);
}

void IRCAccount::unregisterUser( const QString &name )
{
	m_contactManager->unregisterUser(name);
}

void IRCAccount::successfullyChangedNick(const QString &/*oldnick*/, const QString &newnick)
{
	kdDebug(14120) << k_funcinfo << "Changing nick to " << newnick << endl;
	m_mySelf->manager()->setDisplayName( m_mySelf->caption() );

	if( isConnected() )
		m_engine->changeNickname( newnick );
}

bool IRCAccount::addContactToMetaContact( const QString &contactId, const QString &displayName,
	 KopeteMetaContact *m )
{
//	kdDebug(14120) << k_funcinfo << contactId << "|" << displayName << endl;
	//FIXME: I think there are too many tests in this functions.  This function should be called ONLY by
	// KopeteAccount::addContact, where all test are already done. Can a irc developer look at this?   -Olivier
	IRCContact *c;

	if( !m )
	{//This should NEVER happen
		m = new KopeteMetaContact();
		KopeteContactList::contactList()->addMetaContact(m);
		m->setDisplayName( displayName );
	}

	if ( contactId.startsWith( QString::fromLatin1("#") ) )
		c = static_cast<IRCContact*>( findChannel(contactId, m) );
	else
	{
		m_contactManager->addToNotifyList( contactId );
		c = static_cast<IRCContact*>( findUser(contactId, m) );
	}

	if( c->metaContact() != m )
	{//This should NEVER happen
		KopeteMetaContact *old = c->metaContact();
		c->setMetaContact( m );
		KopeteContactPtrList children = old->contacts();
		if( children.isEmpty() )
			KopeteContactList::contactList()->removeMetaContact( old );
	}
	else if( c->metaContact()->isTemporary() ) //FIXME: if the metacontact is temporary, that mean this is a temporary contact
		m->setTemporary(false);

	return true;
}

void IRCAccount::slotJoinChannel()
{
	if(!isConnected())
		return;

	QString chan = KInputDialog::getText( i18n( "IRC Plugin" ),
		i18n( "Please enter name of the channel you want to join:" ), QString::null);
	if( !chan.isNull() )
	{
		if( chan.startsWith( QString::fromLatin1("#") ) )
			findChannel( chan )->startChat();
		else
			KMessageBox::error(0l, i18n("<qt>\"%1\" is an invalid channel. Channels must start with '#'.</qt>").arg(chan), i18n("IRC Plugin"));
	}
}

KopeteContact *IRCAccount::myself() const
{
	return m_mySelf;
}

IRCUserContact *IRCAccount::mySelf() const
{
	return m_mySelf;
}

IRCServerContact *IRCAccount::myServer() const
{
	return m_myServer;
}

#include "ircaccount.moc"
<commit_msg>Fix crash<commit_after>/*
    ircaccount.cpp - IRC Account

    Copyright (c) 2002      by Nick Betcher <nbetcher@kde.org>

    Kopete    (c) 2002      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/
#include <kaction.h>
#include <kaboutdata.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kinputdialog.h>
#include <kmessagebox.h>
#include <kpopupmenu.h>

#include "kopeteaway.h"
#include "kopetecontactlist.h"
#include "kopetemetacontact.h"

#include "ircaccount.h"
#include "ircprotocol.h"
#include "irccontactmanager.h"
#include "ircservercontact.h"
#include "ircchannelcontact.h"
#include "ircusercontact.h"
#include "ksparser.h"

IRCAccount::IRCAccount(IRCProtocol *protocol, const QString &accountId)
	: KopeteAccount(protocol, accountId)
{
	m_manager = 0L;
	m_protocol = protocol;

	mNickName = accountId.section('@',0,0);
	QString serverInfo = accountId.section('@',1);
	m_server = serverInfo.section(':',0,0);
	m_port = serverInfo.section(':',1).toUInt();

	m_engine = new KIRC( m_server, m_port );
	QString version=i18n("Kopete IRC Plugin %1 [http://kopete.kde.org]").arg(kapp->aboutData()->version());
	m_engine->setVersionString( version  );

	QObject::connect(m_engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)),
			this, SLOT(successfullyChangedNick(const QString &, const QString &)));

	m_contactManager = new IRCContactManager(mNickName, m_server, this);
	m_mySelf = m_contactManager->mySelf();
	m_myServer = m_contactManager->myServer();

	//Warning: requesting the password may ask to kwallet, this will open a dcop call and call QApplication::enter_loop
	if( rememberPassword() )
		m_engine->setPassword( password() );

}

IRCAccount::~IRCAccount()
{
//	kdDebug(14120) << k_funcinfo << mServer << " " << engine() << endl;
	if ( engine()->isConnected() )
		engine()->quitIRC(i18n("Plugin Unloaded"), true);

	delete m_contactManager;
	delete m_engine;
}

void IRCAccount::loaded()
{
	m_engine->setUserName(userName());
}

QString IRCAccount::userName()
{
	return pluginData(protocol(), QString::fromLatin1("userName"));
}

void IRCAccount::setUserName(QString userName)
{
	m_engine->setUserName(userName);
	setPluginData(protocol(), QString::fromLatin1( "userName" ), userName);
}

KActionMenu *IRCAccount::actionMenu()
{
	QString menuTitle = QString::fromLatin1( " %1 <%2> " ).arg( accountId() ).arg( m_mySelf->onlineStatus().description() );

	KActionMenu *mActionMenu = new KActionMenu( accountId(),myself()->onlineStatus().iconFor(this), this, "IRCAccount::mActionMenu" );
	mActionMenu->popupMenu()->insertTitle( m_mySelf->onlineStatus().iconFor( m_mySelf ), menuTitle );

	mActionMenu->insert( new KAction ( i18n("Go Online"), m_protocol->m_UserStatusOnline.iconFor( this ), 0, this, SLOT(connect()), mActionMenu ) );
	mActionMenu->insert( new KAction ( i18n("Set Away"), m_protocol->m_UserStatusAway.iconFor( this ), 0, this, SLOT(slotGoAway()), mActionMenu ) );
	mActionMenu->insert( new KAction ( i18n("Go Offline"), m_protocol->m_UserStatusOffline.iconFor( this ), 0, this, SLOT(disconnect()), mActionMenu ) );
	mActionMenu->popupMenu()->insertSeparator();
	mActionMenu->insert( new KAction ( i18n("Join Channel..."), "", 0, this, SLOT(slotJoinChannel()), mActionMenu ) );
	mActionMenu->insert( new KAction ( i18n("Show Server Window"), "", 0, this, SLOT(slotShowServerWindow()), mActionMenu ) );

	return mActionMenu;
}

void IRCAccount::connect()
{
	if( m_engine->isConnected() )
	{
		if( isAway() )
			setAway( false );
	}
	else if( m_engine->isDisconnected() )
	{
		m_engine->connectToServer( m_mySelf->nickName() );
	}
}

void IRCAccount::disconnect()
{
	m_engine->quitIRC("Kopete IRC [http://kopete.kde.org]");
}

void IRCAccount::setAway( bool isAway, const QString &awayMessage )
{
	kdDebug(14120) << k_funcinfo << isAway << " " << awayMessage << endl;
	if(m_engine->isConnected())
	{
		m_mySelf->setAway( isAway );
		engine()->setAway( isAway, awayMessage );
	}
}

void IRCAccount::slotGoAway()
{
	setAway( true, KopeteAway::message() );
}

void IRCAccount::slotShowServerWindow()
{
	m_myServer->startServerChat();
}

bool IRCAccount::isConnected()
{
	return (m_mySelf->onlineStatus().status() == KopeteOnlineStatus::Online);
}

void IRCAccount::unregister(KopeteContact *contact)
{
	m_contactManager->unregister(contact);
}

IRCServerContact *IRCAccount::findServer( const QString &name, KopeteMetaContact *m )
{
	return m_contactManager->findServer(name, m);
}

void IRCAccount::unregisterServer( const QString &name )
{
	m_contactManager->unregisterServer(name);
}

IRCChannelContact *IRCAccount::findChannel( const QString &name, KopeteMetaContact *m )
{
	return m_contactManager->findChannel(name, m);
}

void IRCAccount::unregisterChannel( const QString &name )
{
	m_contactManager->unregisterChannel(name);
}

IRCUserContact *IRCAccount::findUser(const QString &name, KopeteMetaContact *m)
{
	return m_contactManager->findUser(name, m);
}

void IRCAccount::unregisterUser( const QString &name )
{
	m_contactManager->unregisterUser(name);
}

void IRCAccount::successfullyChangedNick(const QString &/*oldnick*/, const QString &newnick)
{
	kdDebug(14120) << k_funcinfo << "Changing nick to " << newnick << endl;
	m_mySelf->manager()->setDisplayName( m_mySelf->caption() );

	if( isConnected() )
		m_engine->changeNickname( newnick );
}

bool IRCAccount::addContactToMetaContact( const QString &contactId, const QString &displayName,
	 KopeteMetaContact *m )
{
//	kdDebug(14120) << k_funcinfo << contactId << "|" << displayName << endl;
	//FIXME: I think there are too many tests in this functions.  This function should be called ONLY by
	// KopeteAccount::addContact, where all test are already done. Can a irc developer look at this?   -Olivier
	IRCContact *c;

	if( !m )
	{//This should NEVER happen
		m = new KopeteMetaContact();
		KopeteContactList::contactList()->addMetaContact(m);
		m->setDisplayName( displayName );
	}

	if ( contactId.startsWith( QString::fromLatin1("#") ) )
		c = static_cast<IRCContact*>( findChannel(contactId, m) );
	else
	{
		m_contactManager->addToNotifyList( contactId );
		c = static_cast<IRCContact*>( findUser(contactId, m) );
	}

	if( c->metaContact() != m )
	{//This should NEVER happen
		KopeteMetaContact *old = c->metaContact();
		c->setMetaContact( m );
		KopeteContactPtrList children = old->contacts();
		if( children.isEmpty() )
			KopeteContactList::contactList()->removeMetaContact( old );
	}
	else if( c->metaContact()->isTemporary() ) //FIXME: if the metacontact is temporary, that mean this is a temporary contact
		m->setTemporary(false);

	return true;
}

void IRCAccount::slotJoinChannel()
{
	if(!isConnected())
		return;

	QString chan = KInputDialog::getText( i18n( "IRC Plugin" ),
		i18n( "Please enter name of the channel you want to join:" ), QString::null);
	if( !chan.isNull() )
	{
		if( chan.startsWith( QString::fromLatin1("#") ) )
			findChannel( chan )->startChat();
		else
			KMessageBox::error(0l, i18n("<qt>\"%1\" is an invalid channel. Channels must start with '#'.</qt>").arg(chan), i18n("IRC Plugin"));
	}
}

KopeteContact *IRCAccount::myself() const
{
	return m_mySelf;
}

IRCUserContact *IRCAccount::mySelf() const
{
	return m_mySelf;
}

IRCServerContact *IRCAccount::myServer() const
{
	return m_myServer;
}

#include "ircaccount.moc"
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mwidgetmodel.h"
#include "mwidgetmodel_p.h"

#include <QMetaProperty>
#include <MDebug>

///////////////////
// PRIVATE CLASS //
///////////////////
MWidgetModelPrivate::MWidgetModelPrivate() :
    transactionInProgress(false),
    referenceCount(0)
{
}

MWidgetModelPrivate::~MWidgetModelPrivate()
{
}

//////////////////
// PUBLIC CLASS //
//////////////////

void MWidgetModel::memberModified(const char *const member)
{
    if (d_ptr->transactionInProgress) {
        d_ptr->modifiedMembers.enqueue(member);
    } else {
        QList<const char *> list;
        list.append(member);
        emit modified(list);
    }
}

void MWidgetModel::beginTransaction()
{
    if (d_ptr->transactionInProgress) {
        mWarning("MWidgetModel") << "beginTransaction() - transaction already started!";
        return;
    }

    d_ptr->transactionInProgress = true;
}

void MWidgetModel::commitTransaction()
{
    if (d_ptr->transactionInProgress == false) {
        mWarning("MWidgetModel") << "commitTransaction() - no transaction ongoing!";
        return;
    }

    d_ptr->transactionInProgress = false;
    emit modified(d_ptr->modifiedMembers);
    d_ptr->modifiedMembers.clear();
}

void MWidgetModel::increaseReferenceCount()
{
    ++d_ptr->referenceCount;
}

void MWidgetModel::decreaseReferenceCount()
{
    --d_ptr->referenceCount;
    if (d_ptr->referenceCount == 0)
        delete this;
}

QDataStream &operator<<(QDataStream &stream, const MWidgetModel &model)
{
    const QMetaObject *metaObject = model.metaObject();
    QString hashString = metaObject->className();

    int propertyCount = metaObject->propertyCount();
    for (int i = 0; i != propertyCount; ++i) {
        hashString += metaObject->property(i).name();
        hashString += metaObject->property(i).typeName();
    }

    uint hash = qHash(hashString);
    stream << hash;
    for (int i = 0; i != propertyCount; ++i) {
        stream << metaObject->property(i).read(&model);
    }

    return stream;
}

QDataStream &operator>>(QDataStream &stream, MWidgetModel &model)
{
    const QMetaObject *metaObject = model.metaObject();
    QString hashString = metaObject->className();

    int propertyCount = metaObject->propertyCount();
    for (int i = 0; i != propertyCount; ++i) {
        hashString += metaObject->property(i).name();
        hashString += metaObject->property(i).typeName();
    }

    uint realHash = qHash(hashString);
    uint hash;
    stream >> hash;
    if (hash != realHash) {
        qFatal("Deserializing of %s failed from QDataStream, Q_PROPERTY table doesn't match!", metaObject->className());
    }

    for (int i = 0; i != propertyCount; ++i) {
        QVariant v;
        stream >> v;
        metaObject->property(i).write(&model, v);
    }

    return stream;
}

<commit_msg>Revert "Fixes: Replace deleteLater with delete in mwidgetmodel"<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mwidgetmodel.h"
#include "mwidgetmodel_p.h"

#include <QMetaProperty>
#include <MDebug>

///////////////////
// PRIVATE CLASS //
///////////////////
MWidgetModelPrivate::MWidgetModelPrivate() :
    transactionInProgress(false),
    referenceCount(0)
{
}

MWidgetModelPrivate::~MWidgetModelPrivate()
{
}

//////////////////
// PUBLIC CLASS //
//////////////////

void MWidgetModel::memberModified(const char *const member)
{
    if (d_ptr->transactionInProgress) {
        d_ptr->modifiedMembers.enqueue(member);
    } else {
        QList<const char *> list;
        list.append(member);
        emit modified(list);
    }
}

void MWidgetModel::beginTransaction()
{
    if (d_ptr->transactionInProgress) {
        mWarning("MWidgetModel") << "beginTransaction() - transaction already started!";
        return;
    }

    d_ptr->transactionInProgress = true;
}

void MWidgetModel::commitTransaction()
{
    if (d_ptr->transactionInProgress == false) {
        mWarning("MWidgetModel") << "commitTransaction() - no transaction ongoing!";
        return;
    }

    d_ptr->transactionInProgress = false;
    emit modified(d_ptr->modifiedMembers);
    d_ptr->modifiedMembers.clear();
}

void MWidgetModel::increaseReferenceCount()
{
    ++d_ptr->referenceCount;
}

void MWidgetModel::decreaseReferenceCount()
{
    --d_ptr->referenceCount;
    if (d_ptr->referenceCount == 0)
        deleteLater();
}

QDataStream &operator<<(QDataStream &stream, const MWidgetModel &model)
{
    const QMetaObject *metaObject = model.metaObject();
    QString hashString = metaObject->className();

    int propertyCount = metaObject->propertyCount();
    for (int i = 0; i != propertyCount; ++i) {
        hashString += metaObject->property(i).name();
        hashString += metaObject->property(i).typeName();
    }

    uint hash = qHash(hashString);
    stream << hash;
    for (int i = 0; i != propertyCount; ++i) {
        stream << metaObject->property(i).read(&model);
    }

    return stream;
}

QDataStream &operator>>(QDataStream &stream, MWidgetModel &model)
{
    const QMetaObject *metaObject = model.metaObject();
    QString hashString = metaObject->className();

    int propertyCount = metaObject->propertyCount();
    for (int i = 0; i != propertyCount; ++i) {
        hashString += metaObject->property(i).name();
        hashString += metaObject->property(i).typeName();
    }

    uint realHash = qHash(hashString);
    uint hash;
    stream >> hash;
    if (hash != realHash) {
        qFatal("Deserializing of %s failed from QDataStream, Q_PROPERTY table doesn't match!", metaObject->className());
    }

    for (int i = 0; i != propertyCount; ++i) {
        QVariant v;
        stream >> v;
        metaObject->property(i).write(&model, v);
    }

    return stream;
}

<|endoftext|>


<commit_before>// @(#)root/peac:$Name:$:$Id:$
// Author: Maarten Ballintijn    21/10/2004
// Author: Kris Gulbrandsen      21/10/2004

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPEAC                                                                //
//                                                                      //
// This class implements the setup of a PROOF session using PEAC        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TPEAC.h"

#include "TClarens.h"
#include "TDSet.h"
#include "TEnv.h"
#include "TGM.h"
#include "TObjString.h"
#include "TPluginManager.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TUrl.h"
#include "TVirtualProof.h"

namespace {

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

struct TPEACStartup {
   TPEACStartup() {TPEAC::Init();}
} PEACStartup;

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

};

TPEAC *gPEAC = 0;

ClassImp(TPEAC)

//______________________________________________________________________________
TPEAC::TPEAC()
   : fGM(0), fProof(0)
{
   TClarens::Init();
}

//______________________________________________________________________________
TPEAC::~TPEAC()
{
   if (!fSessionID.IsNull()) EndSession();
   delete fGM;
}

//______________________________________________________________________________
void TPEAC::Init()
{
   if (gPEAC == 0) {
      gPEAC = new TPEAC;
   }
}

//______________________________________________________________________________
TDSet *TPEAC::StartSession(const Char_t *dataset)
{
   if (fGM == 0) {

      const Char_t *gmUrl = gEnv->GetValue("PEAC.GmUrl",
                                           "http://localhost:8080/clarens/");

      fGM = gClarens->CreateGM(gmUrl);

      if (!fGM) {
         Error("TPEAC", "Could not get Global Manager for URL: %s", gmUrl);
         return 0;
      }
   }

   if (!fSessionID.IsNull()) {
      Error("StartSession", "Session associated with dataset '%s' still open",
                            fDataSet.Data());
      Error("StartSession", "That session must end before"
                            " starting a new session");
      return 0;
   }

   if (gDebug > 0) fGM->Print();

   TList* files = 0;
   TString sessionid;
   TUrl purl("");
   if (!fGM->CreateSession(dataset, sessionid, files, purl)) {
      delete fGM;
      fGM = 0;
      return 0;
   }

   // session successfully created

   if (gDebug > 0) {
      Info("StartSession", "sessionid = %s @ %s", sessionid.Data(), purl.GetUrl());
      files->Print();
   }

   // construct TDSet
   TDSet *dset = 0;
   TIter NextFile(files);
   while (TGM::TFileParams *fp = dynamic_cast<TGM::TFileParams*>(NextFile())) {

      if (dset == 0) dset = new TDSet(fp->fObjClass, fp->fObjName, fp->fDir);

      dset->Add(fp->fFileName, fp->fObjName, fp->fDir, fp->fFirst, fp->fNum);
   }
   Int_t nfiles = files->GetSize();
   delete files;

   // save session id
   fSessionID = sessionid;
   fDataSet   = dataset;

   // start proof
   fProof = gROOT->Proof(TString(purl.GetUrl()), TString("peac:")+sessionid);

   if (!fProof || !fProof->IsValid()) {
      Error("StartSession", "PROOF session could not be started");
      EndSession();
      delete dset;
      return 0;
   }

   //call EndSession when proof is destroyed
   fProof->Connect("~TVirtualProof()", "TPEAC", this, "EndSessionCallback()");

   //wait until data is ready
   Long64_t totalbytes, bytesready;
   Bool_t dataready = fProof->IsDataReady(totalbytes, bytesready);

   //make a progress bar - either the user deletes it or it deletes itself
   if (!gROOT->IsBatch()) {
      if (TPluginManager *pm = gROOT->GetPluginManager()) {
         if (TPluginHandler *h = pm->FindHandler("TProofStartupDialog")) {
            if(h->LoadPlugin() != -1) {
               h->ExecPlugin(4, fProof, dataset, nfiles, totalbytes);
               //trigger progress atleast once
               dataready = fProof->IsDataReady(totalbytes, bytesready);
            }
         }
      }
   }

   if (!dataready) {
      gSystem->Sleep(500);
      while (!fProof->IsDataReady(totalbytes, bytesready)) {
         gSystem->Sleep(500);
      }
   }

   return dset;
}

//______________________________________________________________________________
void TPEAC::EndSessionCallback()
{
   if (fSessionID.IsNull()) {
      Error("EndSession", "No session active. Don't call EndSessionCallback() directly");
      return;
   }

   if (!fGM) {
      Error("EndSession", "Global manager does not exist");
      return;
   }

   if (fProof) {
      fProof->Disconnect("~TVirtualProof()", this, "EndSessionCallback()");
      fProof = 0;
   }
   fGM->DestroySession(fSessionID);
   fSessionID = "";
   fDataSet   = "";

}

//______________________________________________________________________________
void TPEAC::EndSession()
{
   if (fSessionID.IsNull()) {
      Info("EndSession", "No session active");
      return;
   }

   if (!fGM) {
      Error("EndSession", "Global manager does not exist");
      return;
   }

   if (fProof) {
      fProof->Disconnect("~TVirtualProof()", this, "EndSessionCallback()");
      delete fProof;
      fProof = 0;
   }
   fGM->DestroySession(fSessionID);
   fSessionID = "";
   fDataSet   = "";
}
<commit_msg>From Christian Holm: change gROOT->Proof() to TVirtualProof::Open().<commit_after>// @(#)root/peac:$Name:  $:$Id: TPEAC.cxx,v 1.1 2005/02/07 18:02:36 rdm Exp $
// Author: Maarten Ballintijn    21/10/2004
// Author: Kris Gulbrandsen      21/10/2004

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPEAC                                                                //
//                                                                      //
// This class implements the setup of a PROOF session using PEAC        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TPEAC.h"

#include "TClarens.h"
#include "TDSet.h"
#include "TEnv.h"
#include "TGM.h"
#include "TObjString.h"
#include "TPluginManager.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TUrl.h"
#include "TVirtualProof.h"

namespace {

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

struct TPEACStartup {
   TPEACStartup() {TPEAC::Init();}
} PEACStartup;

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

};

TPEAC *gPEAC = 0;

ClassImp(TPEAC)

//______________________________________________________________________________
TPEAC::TPEAC()
   : fGM(0), fProof(0)
{
   TClarens::Init();
}

//______________________________________________________________________________
TPEAC::~TPEAC()
{
   if (!fSessionID.IsNull()) EndSession();
   delete fGM;
}

//______________________________________________________________________________
void TPEAC::Init()
{
   if (gPEAC == 0) {
      gPEAC = new TPEAC;
   }
}

//______________________________________________________________________________
TDSet *TPEAC::StartSession(const Char_t *dataset)
{
   if (fGM == 0) {

      const Char_t *gmUrl = gEnv->GetValue("PEAC.GmUrl",
                                           "http://localhost:8080/clarens/");

      fGM = gClarens->CreateGM(gmUrl);

      if (!fGM) {
         Error("TPEAC", "Could not get Global Manager for URL: %s", gmUrl);
         return 0;
      }
   }

   if (!fSessionID.IsNull()) {
      Error("StartSession", "Session associated with dataset '%s' still open",
                            fDataSet.Data());
      Error("StartSession", "That session must end before"
                            " starting a new session");
      return 0;
   }

   if (gDebug > 0) fGM->Print();

   TList* files = 0;
   TString sessionid;
   TUrl purl("");
   if (!fGM->CreateSession(dataset, sessionid, files, purl)) {
      delete fGM;
      fGM = 0;
      return 0;
   }

   // session successfully created

   if (gDebug > 0) {
      Info("StartSession", "sessionid = %s @ %s", sessionid.Data(), purl.GetUrl());
      files->Print();
   }

   // construct TDSet
   TDSet *dset = 0;
   TIter NextFile(files);
   while (TGM::TFileParams *fp = dynamic_cast<TGM::TFileParams*>(NextFile())) {

      if (dset == 0) dset = new TDSet(fp->fObjClass, fp->fObjName, fp->fDir);

      dset->Add(fp->fFileName, fp->fObjName, fp->fDir, fp->fFirst, fp->fNum);
   }
   Int_t nfiles = files->GetSize();
   delete files;

   // save session id
   fSessionID = sessionid;
   fDataSet   = dataset;

   // start proof
   fProof = TVirtualProof::Open(purl.GetUrl(), Form("peac:%s", sessionid.Data()));

   if (!fProof || !fProof->IsValid()) {
      Error("StartSession", "PROOF session could not be started");
      EndSession();
      delete dset;
      return 0;
   }

   //call EndSession when proof is destroyed
   fProof->Connect("~TVirtualProof()", "TPEAC", this, "EndSessionCallback()");

   //wait until data is ready
   Long64_t totalbytes, bytesready;
   Bool_t dataready = fProof->IsDataReady(totalbytes, bytesready);

   //make a progress bar - either the user deletes it or it deletes itself
   if (!gROOT->IsBatch()) {
      if (TPluginManager *pm = gROOT->GetPluginManager()) {
         if (TPluginHandler *h = pm->FindHandler("TProofStartupDialog")) {
            if(h->LoadPlugin() != -1) {
               h->ExecPlugin(4, fProof, dataset, nfiles, totalbytes);
               //trigger progress atleast once
               dataready = fProof->IsDataReady(totalbytes, bytesready);
            }
         }
      }
   }

   if (!dataready) {
      gSystem->Sleep(500);
      while (!fProof->IsDataReady(totalbytes, bytesready)) {
         gSystem->Sleep(500);
      }
   }

   return dset;
}

//______________________________________________________________________________
void TPEAC::EndSessionCallback()
{
   if (fSessionID.IsNull()) {
      Error("EndSession", "No session active. Don't call EndSessionCallback() directly");
      return;
   }

   if (!fGM) {
      Error("EndSession", "Global manager does not exist");
      return;
   }

   if (fProof) {
      fProof->Disconnect("~TVirtualProof()", this, "EndSessionCallback()");
      fProof = 0;
   }
   fGM->DestroySession(fSessionID);
   fSessionID = "";
   fDataSet   = "";

}

//______________________________________________________________________________
void TPEAC::EndSession()
{
   if (fSessionID.IsNull()) {
      Info("EndSession", "No session active");
      return;
   }

   if (!fGM) {
      Error("EndSession", "Global manager does not exist");
      return;
   }

   if (fProof) {
      fProof->Disconnect("~TVirtualProof()", this, "EndSessionCallback()");
      delete fProof;
      fProof = 0;
   }
   fGM->DestroySession(fSessionID);
   fSessionID = "";
   fDataSet   = "";
}
<|endoftext|>