You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2019/01/08 14:29:31 UTC
svn commit: r1850753 - in /subversion/trunk/subversion/bindings/cxx:
include/svnxx/ src/ src/aprwrap/ src/private/ tests/
Author: brane
Date: Tue Jan 8 14:29:31 2019
New Revision: 1850753
URL: http://svn.apache.org/viewvc?rev=1850753&view=rev
Log:
Keep the SVN++ global pool alive as long as there are any users.
[in subversion/bindings/cxx]
* include/svnxx/init.hpp
(detail::global_state): Renamed from detail::context.
(init): Derive directly from the global_state shared pointer.
(init::~init): Add explicit destructor (for debugging).
* src/private/init_private.hpp: Do not include svn_private_config.h.
(detail::global_state): Renamed from detail::context.
(detail::global_state::get): Don't try to translate the exception
message, because neither APR nor the localisation library are
likely to have been initialized.
* src/aprwrap/pool.hpp: Include init_private.hpp.
(apr::pool::pool): Add a constructor overload that uses the global
pool from a known global state reference.
* src/aprwrap/impl.cpp
(apr::pool::get_root_pool): Rename detail::context to detail::global_state.
* src/debug.cpp,
src/private/debug_private.hpp: New files.
* src/private/client_context_private.hpp: Include init_private.hpp.
(client::context::state): New member, keeps the global state alive as
long as the client context is viable.
(client::context::get_state): New accessor.
(client::context::get_ctx): Renamed from 'get'.
(impl::unwrap): Make the context_wrapper a final class.
* src/init.cpp:
Include debug_private.hpp and apr_pools.h instead of svn_pools.h.
(init::init): Use global_state and add pool debugging logs.
(init::~init): Implement, with pool debugging logs.
(notify_root_pool_cleanup): New; tracks the global pool's destruction.
(create_root_pool): Add pool debugging logs. Avoid leaking the root pool.
(detail::global_state): Add pool debugging logs.
* src/client_status.cpp
(client::status): use the client context's renamed get_ctx() accessor.
* tests/test_init.cpp: Rename detail::context to detail::global_state.
Added:
subversion/trunk/subversion/bindings/cxx/src/debug.cpp (with props)
subversion/trunk/subversion/bindings/cxx/src/private/debug_private.hpp (with props)
Modified:
subversion/trunk/subversion/bindings/cxx/include/svnxx/init.hpp
subversion/trunk/subversion/bindings/cxx/src/aprwrap/impl.cpp
subversion/trunk/subversion/bindings/cxx/src/aprwrap/pool.hpp
subversion/trunk/subversion/bindings/cxx/src/client_status.cpp
subversion/trunk/subversion/bindings/cxx/src/init.cpp
subversion/trunk/subversion/bindings/cxx/src/private/client_context_private.hpp
subversion/trunk/subversion/bindings/cxx/src/private/init_private.hpp
subversion/trunk/subversion/bindings/cxx/tests/test_init.cpp
Modified: subversion/trunk/subversion/bindings/cxx/include/svnxx/init.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/include/svnxx/init.hpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/include/svnxx/init.hpp (original)
+++ subversion/trunk/subversion/bindings/cxx/include/svnxx/init.hpp Tue Jan 8 14:29:31 2019
@@ -33,7 +33,7 @@ namespace svnxx {
namespace detail {
// Forward declaration of the private API context.
-class context;
+class global_state;
} // namespace detail
/**
@@ -44,13 +44,13 @@ class context;
* create an @c init object before you can use the SVN++ API. It is
* safe to create create any number of these objects.
*/
-class init
+class init : private std::shared_ptr<detail::global_state>
{
+ using state = std::shared_ptr<detail::global_state>;
+
public:
init();
-
-private:
- std::shared_ptr<detail::context> context;
+ ~init() noexcept;
};
} // namespace svnxx
Modified: subversion/trunk/subversion/bindings/cxx/src/aprwrap/impl.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/aprwrap/impl.cpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/aprwrap/impl.cpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/aprwrap/impl.cpp Tue Jan 8 14:29:31 2019
@@ -37,8 +37,8 @@ namespace apr {
apr_pool_t* pool::get_root_pool()
{
- auto ctx = detail::context::get();
- return ctx->get_root_pool();
+ auto state = detail::global_state::get();
+ return state->get_root_pool();
}
//
Modified: subversion/trunk/subversion/bindings/cxx/src/aprwrap/pool.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/aprwrap/pool.hpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/aprwrap/pool.hpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/aprwrap/pool.hpp Tue Jan 8 14:29:31 2019
@@ -31,6 +31,8 @@
#include "svnxx/exception.hpp"
#include "svnxx/detail/noncopyable.hpp"
+#include "../private/init_private.hpp"
+
#include "svn_pools.h"
namespace apache {
@@ -101,6 +103,13 @@ public:
{}
/**
+ * Create a pool as a child of the global pool in @a state.
+ */
+ explicit pool(const detail::global_state::ptr& state)
+ : pool_ptr(svn_pool_create(state->get_root_pool()))
+ {}
+
+ /**
* Clear the pool.
*/
void clear()
Modified: subversion/trunk/subversion/bindings/cxx/src/client_status.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/client_status.cpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/client_status.cpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/client_status.cpp Tue Jan 8 14:29:31 2019
@@ -68,7 +68,7 @@ status(context& ctx_, const char* path,
svn_revnum_t result;
impl::checked_call(
- svn_client_status6(&result, ctx.get(), path, &rev,
+ svn_client_status6(&result, ctx.get_ctx(), path, &rev,
impl::convert(depth),
bool(flags & status_flags::get_all),
bool(flags & status_flags::check_out_of_date),
Added: subversion/trunk/subversion/bindings/cxx/src/debug.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/debug.cpp?rev=1850753&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/debug.cpp (added)
+++ subversion/trunk/subversion/bindings/cxx/src/debug.cpp Tue Jan 8 14:29:31 2019
@@ -0,0 +1,37 @@
+/**
+ * @copyright
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#include "private/debug_private.hpp"
+
+namespace apache {
+namespace subversion {
+namespace svnxx {
+namespace impl {
+
+const char root_pool_tag[] = "svn++ root pool";
+const char root_pool_key[] = "SVN++ 30F4B67A-CAB4-1337-F00D-DEADBEEFA78F";
+
+} // namespace impl
+} // namespace svnxx
+} // namespace subversion
+} // namespace apache
Propchange: subversion/trunk/subversion/bindings/cxx/src/debug.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/trunk/subversion/bindings/cxx/src/init.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/init.cpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/init.cpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/init.cpp Tue Jan 8 14:29:31 2019
@@ -24,18 +24,30 @@
#include <sstream>
#include "svnxx/exception.hpp"
+#include "private/debug_private.hpp"
#include "private/init_private.hpp"
#include <apr_general.h>
-#include "svn_pools.h"
+#include <apr_pools.h>
namespace apache {
namespace subversion {
namespace svnxx {
init::init()
- : context(detail::context::create())
-{}
+ : state(detail::global_state::create())
+{
+#ifdef SVNXX_POOL_DEBUG
+ SVN_DBG(("svn++ created init object %pp", static_cast<void*>(this)));
+#endif
+}
+
+init::~init() noexcept
+{
+#ifdef SVNXX_POOL_DEBUG
+ SVN_DBG(("svn++ destroyed init object %pp", static_cast<void*>(this)));
+#endif
+}
namespace detail {
@@ -52,6 +64,15 @@ int handle_failed_allocation(int)
throw allocation_failed_builder("svn::allocation_failed");
}
+#ifdef SVNXX_POOL_DEBUG
+apr_status_t notify_root_pool_cleanup(void* key)
+{
+ if (key == impl::root_pool_key)
+ SVN_DBG(("svn++ destroyed root pool"));
+ return APR_SUCCESS;
+}
+#endif
+
apr_pool_t* create_root_pool()
{
// Create the root pool's allocator.
@@ -68,42 +89,56 @@ apr_pool_t* create_root_pool()
throw allocation_failed_builder("svn++ creating root pool");
#if APR_POOL_DEBUG
- apr_pool_tag(root_pool, "svn++ root pool");
+ apr_pool_tag(root_pool, impl::root_pool_tag);
#endif
#if APR_HAS_THREADS
// SVN++ pools are always as thread safe as APR can make them.
apr_thread_mutex_t *mutex = nullptr;
status = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, root_pool);
- if (status || !mutex)
- throw allocation_failed_builder("svn++ creating allocator mutex");
- apr_allocator_mutex_set(allocator, mutex);
+ if (mutex && !status)
+ apr_allocator_mutex_set(allocator, mutex);
+ else
+ {
+#ifdef SVNXX_POOL_DEBUG
+ SVN_DBG(("svn++ could not create allocator mutex, apr_err=%d", status));
+#endif
+ apr_pool_destroy(root_pool); // Don't leak the global pool.
+ throw allocation_failed_builder("svn++ creating allocator mutex");
+ }
+#endif
+
+#ifdef SVNXX_POOL_DEBUG
+ apr_pool_cleanup_register(root_pool, impl::root_pool_key,
+ notify_root_pool_cleanup,
+ apr_pool_cleanup_null);
+ SVN_DBG(("svn++ created root pool"));
#endif
return root_pool;
}
} // anonymous namespace
-std::mutex context::guard;
-context::weak_ptr context::self;
+std::mutex global_state::guard;
+global_state::weak_ptr global_state::self;
-context::ptr context::create()
+global_state::ptr global_state::create()
{
std::unique_lock<std::mutex> lock(guard);
- auto ctx = self.lock();
- if (!ctx)
+ auto state = self.lock();
+ if (!state)
{
// Work around the private constructor: since this struct is
// defined within a class member, the the private constructor
// is accessible and std::make_shared won't complain about it.
- struct make_shared_hack : public context {};
- ctx = std::make_shared<make_shared_hack>();
- self = ctx;
+ struct global_state_builder final : public global_state {};
+ state = std::make_shared<global_state_builder>();
+ self = state;
}
- return ctx;
+ return state;
}
-context::context()
+global_state::global_state()
{
const auto status = apr_initialize();
if (status)
@@ -114,11 +149,18 @@ context::context()
<< apr_strerror(status, errbuf, sizeof(errbuf) - 1);
throw std::runtime_error(message.str());
}
+
root_pool = create_root_pool();
+#ifdef SVNXX_POOL_DEBUG
+ SVN_DBG(("svn++ created global state"));
+#endif
}
-context::~context()
+global_state::~global_state()
{
+#ifdef SVNXX_POOL_DEBUG
+ SVN_DBG(("svn++ destroyed global state"));
+#endif
std::unique_lock<std::mutex> lock(guard);
apr_terminate();
root_pool = nullptr;
Modified: subversion/trunk/subversion/bindings/cxx/src/private/client_context_private.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/private/client_context_private.hpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/private/client_context_private.hpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/private/client_context_private.hpp Tue Jan 8 14:29:31 2019
@@ -26,6 +26,7 @@
#include "svnxx/client/context.hpp"
+#include "../private/init_private.hpp"
#include "../aprwrap.hpp"
#include "svn_client.h"
@@ -39,15 +40,21 @@ namespace detail {
// TODO: document this
class context
{
+ using global_state = svnxx::detail::global_state;
+
public:
context()
- : ctx(create_ctx(ctx_pool))
+ : state(global_state::get()),
+ ctx_pool(state),
+ ctx(create_ctx(ctx_pool))
{}
- svn_client_ctx_t* get() const noexcept { return ctx; };
+ const global_state::ptr& get_state() const noexcept { return state; }
const apr::pool& get_pool() const noexcept { return ctx_pool; }
+ svn_client_ctx_t* get_ctx() const noexcept { return ctx; };
private:
+ const global_state::ptr state;
apr::pool ctx_pool;
svn_client_ctx_t* const ctx;
@@ -61,7 +68,7 @@ namespace impl {
// TODO: document this
inline client::detail::context& unwrap(client::context& ctx)
{
- struct context_wrapper : public client::context
+ struct context_wrapper final : public client::context
{
using inherited::get;
};
Added: subversion/trunk/subversion/bindings/cxx/src/private/debug_private.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/private/debug_private.hpp?rev=1850753&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/private/debug_private.hpp (added)
+++ subversion/trunk/subversion/bindings/cxx/src/private/debug_private.hpp Tue Jan 8 14:29:31 2019
@@ -0,0 +1,49 @@
+/**
+ * @copyright
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#ifndef SVNXX_PRIVATE_DEBUG_HPP
+#define SVNXX_PRIVATE_DEBUG_HPP
+
+// We can only write pool debug logs with SVN_DEBUG enabled.
+#if defined(SVNXX_POOL_DEBUG) && !defined(SVN_DEBUG)
+# undef SVNXX_POOL_DEBUG
+#endif
+
+#ifdef SVNXX_POOL_DEBUG
+#include "private/svn_debug.h"
+#endif
+
+namespace apache {
+namespace subversion {
+namespace svnxx {
+namespace impl {
+
+extern const char root_pool_tag[];
+extern const char root_pool_key[];
+
+} // namespace impl
+} // namespace svnxx
+} // namespace subversion
+} // namespace apache
+
+#endif // SVNXX_PRIVATE_DEBUG_HPP
Propchange: subversion/trunk/subversion/bindings/cxx/src/private/debug_private.hpp
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/trunk/subversion/bindings/cxx/src/private/init_private.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/private/init_private.hpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/private/init_private.hpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/private/init_private.hpp Tue Jan 8 14:29:31 2019
@@ -33,33 +33,31 @@
#include "svnxx/init.hpp"
#include "svnxx/detail/noncopyable.hpp"
-#include "svn_private_config.h"
-
namespace apache {
namespace subversion {
namespace svnxx {
namespace detail {
-class context : noncopyable
+class global_state : noncopyable
{
public:
- using ptr = std::shared_ptr<context>;
- using weak_ptr = std::weak_ptr<context>;
+ using ptr = std::shared_ptr<global_state>;
+ using weak_ptr = std::weak_ptr<global_state>;
- ~context();
+ ~global_state();
static ptr create();
static ptr get()
{
- auto ctx = self.lock();
- if (!ctx)
+ auto state = self.lock();
+ if (!state)
{
throw std::logic_error(
- _("The SVN++ library is not initialized."
- " Did you forget to create an instance of "
- " the apache::subversion::svnxx::init class?"));
+ "The SVN++ library is not initialized."
+ " Did you forget to create an instance of "
+ " the apache::subversion::svnxx::init class?");
}
- return ctx;
+ return state;
}
apr_pool_t* get_root_pool() const noexcept
@@ -68,8 +66,8 @@ public:
}
private:
- // Thou shalt not create contexts other than through the factory.
- context();
+ // Thou shalt not create global_states other than through the factory.
+ global_state();
apr_pool_t* root_pool{nullptr};
Modified: subversion/trunk/subversion/bindings/cxx/tests/test_init.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/tests/test_init.cpp?rev=1850753&r1=1850752&r2=1850753&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/tests/test_init.cpp (original)
+++ subversion/trunk/subversion/bindings/cxx/tests/test_init.cpp Tue Jan 8 14:29:31 2019
@@ -27,38 +27,38 @@ namespace detail = ::apache::subversion:
BOOST_AUTO_TEST_SUITE(init);
-BOOST_AUTO_TEST_CASE(context_with_init)
+BOOST_AUTO_TEST_CASE(state_with_init)
{
svn::init svnxx_initialized;
- BOOST_TEST(detail::context::get());
+ BOOST_TEST(detail::global_state::get());
}
-BOOST_AUTO_TEST_CASE(context_without_init)
+BOOST_AUTO_TEST_CASE(state_without_init)
{
- BOOST_CHECK_THROW(detail::context::get(), std::logic_error);
+ BOOST_CHECK_THROW(detail::global_state::get(), std::logic_error);
}
BOOST_AUTO_TEST_CASE(init_scope)
{
{
svn::init svnxx_initialized;
- BOOST_TEST(detail::context::get());
+ BOOST_TEST(detail::global_state::get());
}
- BOOST_CHECK_THROW(detail::context::get(), std::logic_error);
+ BOOST_CHECK_THROW(detail::global_state::get(), std::logic_error);
}
-BOOST_AUTO_TEST_CASE(multi_init_same_context)
+BOOST_AUTO_TEST_CASE(multi_init_same_state)
{
svn::init svnxx_initialized_first;
- const auto ctx = detail::context::get();
- BOOST_REQUIRE(ctx);
+ const auto state = detail::global_state::get();
+ BOOST_REQUIRE(state);
{
svn::init svnxx_initialized_second;
- BOOST_TEST(ctx == detail::context::get());
+ BOOST_TEST(state == detail::global_state::get());
}
- BOOST_TEST(ctx == detail::context::get());
+ BOOST_TEST(state == detail::global_state::get());
}
BOOST_AUTO_TEST_SUITE_END();