bool _M_active;
};
- mutable std::mutex _M_mutex;
+#if defined(_GLIBCXX_HAS_GTHREADS)
+ using mutex_type = std::mutex;
+#else
+ struct mutex_type
+ {
+ void lock() const { }
+ void unlock() const { }
+ };
+#endif
+ mutable mutex_type _M_mutex;
// Sorted in order of beginning of service object lifetime.
std::list<_ServicePtr> _M_services;
static_assert(is_base_of<_Key, _Service>::value,
"a service type must match or derive from its key_type");
auto __key = execution_context::_S_key<_Key>();
- std::lock_guard<std::mutex> __lock(__ctx._M_mutex);
+ lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
auto& __svc = __ctx._M_keys[__key];
if (__svc == nullptr)
{
static_assert(is_base_of<_Key, _Service>::value,
"a service type must match or derive from its key_type");
auto __key = execution_context::_S_key<_Key>();
- std::lock_guard<std::mutex> __lock(__ctx._M_mutex);
+ lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
auto& __svc = __ctx._M_keys[__key];
if (__svc != nullptr)
throw service_already_exists();
"a service type must derive from execution_context::service");
static_assert(is_base_of<_Key, _Service>::value,
"a service type must match or derive from its key_type");
- std::lock_guard<std::mutex> __lock(__ctx._M_mutex);
+ lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
return __ctx._M_keys.count(execution_context::_S_key<_Key>());
}
void stop()
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<mutex_type> __lock(_M_mtx);
_M_stopped = true;
_M_cv.notify_all();
}
bool stopped() const noexcept
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<mutex_type> __lock(_M_mtx);
return _M_stopped;
}
void join()
{
- _M_thread.join();
+ if (_M_thread.joinable())
+ _M_thread.join();
}
private:
struct __tag { explicit __tag() = default; };
system_context(__tag) { }
+#ifndef _GLIBCXX_HAS_GTHREADS
+ struct thread
+ {
+ bool joinable() const { return false; }
+ void join() { }
+ };
+ struct condition_variable
+ {
+ void notify_all() { }
+ };
+#endif
+
thread _M_thread;
- mutable mutex _M_mtx;
+ mutable mutex_type _M_mtx; // XXX can we reuse base's _M_mutex?
condition_variable _M_cv;
queue<function<void()>> _M_tasks;
bool _M_stopped = false;
+#ifdef _GLIBCXX_HAS_GTHREADS
void
_M_run()
{
{
function<void()> __f;
{
- unique_lock<mutex> __lock(_M_mtx);
+ unique_lock<mutex_type> __lock(_M_mtx);
_M_cv.wait(__lock,
[this]{ return _M_stopped || !_M_tasks.empty(); });
if (_M_stopped)
__f();
}
}
+#endif
void
- _M_post(std::function<void()> __f)
+ _M_post(std::function<void()> __f __attribute__((__unused__)))
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<mutex_type> __lock(_M_mtx);
if (_M_stopped)
return;
+#ifdef _GLIBCXX_HAS_GTHREADS
if (!_M_thread.joinable())
_M_thread = std::thread(&system_context::_M_run, this);
_M_tasks.push(std::move(__f)); // XXX allocator not used
_M_cv.notify_one();
+#else
+ __throw_system_error(EOPNOTSUPP);
+#endif
}
static system_context&
bool
running_in_this_thread() const noexcept
- { return std::this_thread::get_id() == _M_state->_M_running_on; }
+ { return _M_state->running_in_this_thread(); }
execution_context&
context() const noexcept
// TODO add synchronised queue
struct _State
{
+#if defined(_GLIBCXX_HAS_GTHREADS)
+ bool
+ running_in_this_thread() const
+ { return std::this_thread::get_id() == _M_state->_M_running_on; }
+
std::thread::id _M_running_on;
+#else
+ bool running_in_this_thread() const { return true; }
+#endif
};
shared_ptr<_State> _M_state;
_Executor _M_inner_ex;
};
-#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
+#if defined(_GLIBCXX_HAS_GTHREADS)
// Completion token for asynchronous operations initiated with use_future.
template<typename _Func, typename _Alloc>
// (probably need to move _Type outside of handler_type so we don't have
// a non-deduced context)
-
#endif
// [async.packaged.task.specializations]
return_type _M_future;
};
-#endif
+#endif // _GLIBCXX_HAS_GTHREADS
/// @}
#include <functional>
#include <system_error>
#include <thread>
+#include <vector>
#include <experimental/netfwd>
#include <experimental/executor>
#if _GLIBCXX_HAVE_UNISTD_H
bool running_in_this_thread() const noexcept
{
- lock_guard<mutex> __lock(_M_ctx->_M_mtx);
+#ifdef _GLIBCXX_HAS_GTHREADS
+ lock_guard<execution_context::mutex_type> __lock(_M_ctx->_M_mtx);
auto __end = _M_ctx->_M_call_stack.end();
return std::find(_M_ctx->_M_call_stack.begin(), __end,
this_thread::get_id()) != __end;
+#else
+ return _M_ctx->_M_run_count != 0;
+#endif
}
io_context& context() const noexcept { return *_M_ctx; }
void
post(_Func&& __f, const _ProtoAllocator& __a) const
{
- lock_guard<mutex> __lock(_M_ctx->_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_ctx->_M_mtx);
// TODO (re-use functionality in system_context)
_M_ctx->_M_reactor._M_notify();
}
void stop()
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_mtx);
_M_stopped = true;
_M_reactor._M_notify();
}
bool stopped() const noexcept
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_mtx);
return _M_stopped;
}
__timer_queue_base(execution_context& __ctx) : service(__ctx)
{
auto& __ioc = static_cast<io_context&>(__ctx);
- lock_guard<mutex> __lock(__ioc._M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(__ioc._M_mtx);
__ioc._M_timers.push_back(this);
}
- mutable mutex _M_qmtx;
+ mutable execution_context::mutex_type _M_qmtx;
};
template<typename _Timer, typename _Key = typename _Timer::_Key>
push(const _Timer& __t, function<void(error_code)> __h)
{
context().get_executor().on_work_started();
- lock_guard<mutex> __lock(_M_qmtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_qmtx);
_M_queue.emplace(__t, _M_next_id++, std::move(__h));
// no need to notify reactor unless this timer went to the front?
}
size_t
cancel(const _Timer& __t)
{
- lock_guard<mutex> __lock(_M_qmtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_qmtx);
size_t __count = 0;
auto __last = _M_queue.end();
for (auto __it = _M_queue.begin(), __end = __last; __it != __end;
bool
cancel_one(const _Timer& __t)
{
- lock_guard<mutex> __lock(_M_qmtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_qmtx);
const auto __end = _M_queue.end();
auto __oldest = __end;
for (auto __it = _M_queue.begin(); __it != __end; ++__it)
{
typename _Timer::time_point __exp;
{
- lock_guard<mutex> __lock(_M_qmtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_qmtx);
if (_M_queue.empty())
return chrono::milliseconds::max(); // no pending timers
if (_M_queue.top()._M_key == nullptr)
function<void(error_code)> __h;
error_code __ec;
{
- lock_guard<mutex> __lock(_M_qmtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_qmtx);
if (_M_queue.top()._M_key == nullptr) // cancelled
{
void
async_wait(int __fd, int __w, _Op&& __op)
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_mtx);
// TODO need push_back, use std::list not std::forward_list
auto __tail = _M_ops.before_begin(), __it = _M_ops.begin();
while (__it != _M_ops.end())
void cancel(int __fd, error_code&)
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_mtx);
const auto __end = _M_ops.end();
auto __it = _M_ops.begin();
auto __prev = _M_ops.before_begin();
};
atomic<count_type> _M_work_count;
- mutable mutex _M_mtx;
+ mutable execution_context::mutex_type _M_mtx;
queue<function<void()>> _M_op;
bool _M_stopped = false;
{
__monitor(io_context& __c) : _M_ctx(__c)
{
- lock_guard<mutex> __lock(_M_ctx._M_mtx);
+#ifdef _GLIBCXX_HAS_GTHREADS
+ lock_guard<execution_context::mutex_type> __lock(_M_ctx._M_mtx);
_M_ctx._M_call_stack.push_back(this_thread::get_id());
+#else
+ _M_ctx._M_run_count++;
+#endif
}
~__monitor()
{
- lock_guard<mutex> __lock(_M_ctx._M_mtx);
+#ifdef _GLIBCXX_HAS_GTHREADS
+ lock_guard<execution_context::mutex_type> __lock(_M_ctx._M_mtx);
_M_ctx._M_call_stack.pop_back();
+#else
+ _M_ctx._M_run_count--;
+#endif
if (_M_ctx._M_outstanding_work() == 0)
{
_M_ctx._M_stopped = true;
chrono::milliseconds __ms{0};
{
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_mtx);
if (_M_stopped)
return false;
if (__fds.empty()) // nothing to do
return false;
- lock_guard<mutex> __lock(_M_mtx);
+ lock_guard<execution_context::mutex_type> __lock(_M_mtx);
for (auto __it = _M_ops.begin(), __end = _M_ops.end(),
__prev = _M_ops.before_begin(); __it != __end; ++__it, ++__prev)
{
vector<__timer_queue_base*> _M_timers;
forward_list<unique_ptr<__async_operation>> _M_ops;
+#ifdef _GLIBCXX_HAS_GTHREADS
vector<thread::id> _M_call_stack;
+#else
+ int _M_run_count = 0;
+#endif
};
inline bool