diff --git a/build/Jamfile.v2 b/build/Jamfile.v2
index 3ca6eac8..4040cc13 100644
--- a/build/Jamfile.v2
+++ b/build/Jamfile.v2
@@ -30,6 +30,7 @@ lib boost_fiber
: context.cpp
detail/spinlock.cpp
fiber.cpp
+ mutex.cpp
scheduler.cpp
: shared:../../context/build//boost_context
;
diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp
index 56e9bb3f..7b0c9490 100644
--- a/include/boost/fiber/all.hpp
+++ b/include/boost/fiber/all.hpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp
index b1504941..87cbffd0 100644
--- a/include/boost/fiber/context.hpp
+++ b/include/boost/fiber/context.hpp
@@ -134,8 +134,6 @@ private:
void set_terminated_() noexcept;
- void suspend_() noexcept;
-
protected:
virtual void deallocate() {
}
@@ -231,7 +229,7 @@ public:
// notify waiting (joining) fibers
release();
// switch to another fiber
- suspend_();
+ suspend();
BOOST_ASSERT_MSG( false, "fiber already terminated");
}),
wait_queue_() {
@@ -247,6 +245,8 @@ public:
void resume();
+ void suspend() noexcept;
+
void release() noexcept;
void join() noexcept;
diff --git a/include/boost/fiber/mutex.hpp b/include/boost/fiber/mutex.hpp
new file mode 100644
index 00000000..293e5009
--- /dev/null
+++ b/include/boost/fiber/mutex.hpp
@@ -0,0 +1,62 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_FIBERS_MUTEX_H
+#define BOOST_FIBERS_MUTEX_H
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace fibers {
+
+class BOOST_FIBERS_DECL mutex {
+private:
+ enum class mutex_status {
+ locked = 0,
+ unlocked
+ };
+
+ typedef context::wait_queue_t wait_queue_t;
+
+ std::atomic< mutex_status > state_;
+ context::id owner_;
+ wait_queue_t wait_queue_;
+ detail::spinlock wait_queue_splk_;
+
+ bool lock_if_unlocked_();
+
+public:
+ mutex();
+
+ ~mutex();
+
+ mutex( mutex const&) = delete;
+ mutex & operator=( mutex const&) = delete;
+
+ void lock();
+
+ bool try_lock();
+
+ void unlock();
+};
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_FIBERS_MUTEX_H
diff --git a/src/context.cpp b/src/context.cpp
index 29bf954c..1492464f 100644
--- a/src/context.cpp
+++ b/src/context.cpp
@@ -50,11 +50,6 @@ context::set_terminated_() noexcept {
scheduler_->set_terminated( this);
}
-void
-context::suspend_() noexcept {
- scheduler_->re_schedule( this);
-}
-
// main fiber context
context::context( main_context_t) :
ready_hook_(),
@@ -117,6 +112,11 @@ context::resume() {
ctx_();
}
+void
+context::suspend() noexcept {
+ scheduler_->re_schedule( this);
+}
+
void
context::release() noexcept {
BOOST_ASSERT( is_terminated() );
@@ -183,7 +183,7 @@ context::set_ready( context * ctx) noexcept {
scheduler_->set_ready( ctx);
} else {
// remote
- scheduler_->set_remote_ready( ctx);
+ ctx->scheduler_->set_remote_ready( ctx);
}
}
diff --git a/src/mutex.cpp b/src/mutex.cpp
new file mode 100644
index 00000000..cf632e7a
--- /dev/null
+++ b/src/mutex.cpp
@@ -0,0 +1,116 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "boost/fiber/mutex.hpp"
+
+#include
+
+#include
+
+#include "boost/fiber/scheduler.hpp"
+#include "boost/fiber/interruption.hpp"
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace fibers {
+
+bool
+mutex::lock_if_unlocked_() {
+ if ( mutex_status::locked == state_.load( std::memory_order_relaxed) ) {
+ return false;
+ }
+
+ if ( mutex_status::unlocked != state_.exchange( mutex_status::locked, std::memory_order_acquire) ) {
+ return false;
+ }
+
+ BOOST_ASSERT( ! owner_);
+ owner_ = context::active()->get_id();
+ return true;
+}
+
+mutex::mutex() :
+ state_( mutex_status::unlocked),
+ owner_(),
+ wait_queue_(),
+ wait_queue_splk_() {
+}
+
+mutex::~mutex() {
+ BOOST_ASSERT( ! owner_);
+ BOOST_ASSERT( wait_queue_.empty() );
+}
+
+void
+mutex::lock() {
+ context * ctx = context::active();
+ for (;;) {
+ try {
+ if ( lock_if_unlocked_() ) {
+ return;
+ }
+
+ // store this fiber in order to be notified later
+ detail::spinlock_lock lk( wait_queue_splk_);
+ BOOST_ASSERT( ! ctx->wait_is_linked() );
+ wait_queue_.push_back( * ctx);
+ lk.unlock();
+
+ // suspend this fiber
+ ctx->suspend();
+
+ // remove fiber from wait-queue
+ lk.lock();
+ ctx->wait_unlink();
+ } catch (...) {
+ // remove fiber from wait-queue
+ detail::spinlock_lock lk( wait_queue_splk_);
+ ctx->wait_unlink();
+ throw;
+ }
+ }
+}
+
+bool
+mutex::try_lock() {
+ if ( lock_if_unlocked_() ) {
+ return true;
+ }
+
+ // let other fiber release the lock
+ context::active()->yield();
+ return false;
+}
+
+void
+mutex::unlock() {
+ BOOST_ASSERT( mutex_status::locked == state_);
+ BOOST_ASSERT( context::active()->get_id() == owner_);
+
+ detail::spinlock_lock lk( wait_queue_splk_);
+ context * ctx( nullptr);
+ if ( ! wait_queue_.empty() ) {
+ ctx = & wait_queue_.front();
+ wait_queue_.pop_front();
+ BOOST_ASSERT( nullptr != ctx);
+ }
+ lk.unlock();
+ owner_ = context::id();
+ state_ = mutex_status::unlocked;
+
+ if ( nullptr != ctx) {
+ context::active()->set_ready( ctx);
+ }
+}
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 4b919d5d..f3504ae9 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -41,3 +41,33 @@ run test_fiber.cpp :
cxx11_variadic_macros
cxx11_variadic_templates
cxx14_initialized_lambda_captures ] ;
+
+run test_mutex.cpp :
+ : :
+ [ requires cxx11_constexpr
+ cxx11_decltype
+ cxx11_deleted_functions
+ cxx11_explicit_conversion_operators
+ cxx11_hdr_tuple cxx11_lambdas
+ cxx11_noexcept
+ cxx11_nullptr
+ cxx11_template_aliases
+ cxx11_rvalue_references
+ cxx11_variadic_macros
+ cxx11_variadic_templates
+ cxx14_initialized_lambda_captures ] ;
+
+run test_mutex_mt.cpp :
+ : :
+ [ requires cxx11_constexpr
+ cxx11_decltype
+ cxx11_deleted_functions
+ cxx11_explicit_conversion_operators
+ cxx11_hdr_tuple cxx11_lambdas
+ cxx11_noexcept
+ cxx11_nullptr
+ cxx11_template_aliases
+ cxx11_rvalue_references
+ cxx11_variadic_macros
+ cxx11_variadic_templates
+ cxx14_initialized_lambda_captures ] ;
diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp
new file mode 100644
index 00000000..b6b17fe0
--- /dev/null
+++ b/test/test_mutex.cpp
@@ -0,0 +1,472 @@
+
+// Copyright Oliver Kowalke 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// This test is based on the tests of Boost.Thread
+
+#include
+#include
+#include
+#include