llvm-project/libcxx/include/thread

409 lines
9.1 KiB
C++

// -*- C++ -*-
//===--------------------------- thread -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_THREAD
#define _LIBCPP_THREAD
/*
thread synopsis
#define __STDCPP_THREADS__ __cplusplus
namespace std
{
class thread
{
public:
class id;
typedef pthread_t native_handle_type;
thread();
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
~thread();
thread(const thread&) = delete;
thread(thread&& t);
thread& operator=(const thread&) = delete;
thread& operator=(thread&& t);
void swap(thread& t);
bool joinable() const;
void join();
void detach();
id get_id() const;
native_handle_type native_handle();
static unsigned hardware_concurrency();
};
void swap(thread& x, thread& y);
class thread::id
{
public:
id();
};
bool operator==(thread::id x, thread::id y);
bool operator!=(thread::id x, thread::id y);
bool operator< (thread::id x, thread::id y);
bool operator<=(thread::id x, thread::id y);
bool operator> (thread::id x, thread::id y);
bool operator>=(thread::id x, thread::id y);
template<class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& out, thread::id id);
namespace this_thread
{
thread::id get_id();
void yield();
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
} // this_thread
} // std
*/
#include <__config>
#include <iosfwd>
#include <__functional_base>
#include <type_traits>
#include <cstddef>
#include <functional>
#include <memory>
#include <system_error>
#include <chrono>
#include <__mutex_base>
#include <pthread.h>
#pragma GCC system_header
#define __STDCPP_THREADS__ __cplusplus
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp>
class __thread_specific_ptr
{
pthread_key_t __key_;
__thread_specific_ptr(const __thread_specific_ptr&);
__thread_specific_ptr& operator=(const __thread_specific_ptr&);
static void __at_thread_exit(void*);
public:
typedef _Tp* pointer;
__thread_specific_ptr();
~__thread_specific_ptr();
pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));}
pointer operator*() const {return *get();}
pointer operator->() const {return get();}
pointer release();
void reset(pointer __p = nullptr);
};
template <class _Tp>
void
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
{
delete static_cast<pointer>(__p);
}
template <class _Tp>
__thread_specific_ptr<_Tp>::__thread_specific_ptr()
{
int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
if (__ec)
throw system_error(error_code(__ec, system_category()),
"__thread_specific_ptr construction failed");
}
template <class _Tp>
__thread_specific_ptr<_Tp>::~__thread_specific_ptr()
{
pthread_key_delete(__key_);
}
template <class _Tp>
typename __thread_specific_ptr<_Tp>::pointer
__thread_specific_ptr<_Tp>::release()
{
pointer __p = get();
pthread_setspecific(__key_, 0);
return __p;
}
template <class _Tp>
void
__thread_specific_ptr<_Tp>::reset(pointer __p)
{
pointer __p_old = get();
pthread_setspecific(__key_, __p);
delete __p_old;
}
class thread;
class __thread_id;
namespace this_thread
{
__thread_id get_id();
} // this_thread
class __thread_id
{
// FIXME: pthread_t is a pointer on Darwin but a long on Linux.
// NULL is the no-thread value on Darwin. Someone needs to check
// on other platforms. We assume 0 works everywhere for now.
pthread_t __id_;
public:
__thread_id() : __id_(0) {}
friend bool operator==(__thread_id __x, __thread_id __y)
{return __x.__id_ == __y.__id_;}
friend bool operator!=(__thread_id __x, __thread_id __y)
{return !(__x == __y);}
friend bool operator< (__thread_id __x, __thread_id __y)
{return __x.__id_ < __y.__id_;}
friend bool operator<=(__thread_id __x, __thread_id __y)
{return !(__y < __x);}
friend bool operator> (__thread_id __x, __thread_id __y)
{return __y < __x ;}
friend bool operator>=(__thread_id __x, __thread_id __y)
{return !(__x < __y);}
template<class _CharT, class _Traits>
friend
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id)
{return __os << __id.__id_;}
private:
__thread_id(pthread_t __id) : __id_(__id) {}
friend __thread_id this_thread::get_id();
friend class thread;
};
template<class _Tp> struct hash;
template<>
struct hash<__thread_id>
: public unary_function<__thread_id, size_t>
{
size_t operator()(__thread_id __v) const
{
const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
return *__p;
}
};
namespace this_thread
{
inline
__thread_id
get_id()
{
return pthread_self();
}
} // this_thread
class thread
{
pthread_t __t_;
#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
thread(const thread&) = delete;
thread& operator=(const thread&) = delete;
#else // _LIBCPP_HAS_NO_DELETED_FUNCTIONS
thread(const thread&);
thread& operator=(const thread&);
#endif // _LIBCPP_HAS_NO_DELETED_FUNCTIONS
public:
typedef __thread_id id;
typedef pthread_t native_handle_type;
thread() : __t_(0) {}
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _F, class ..._Args,
class = typename enable_if
<
!is_same<typename decay<_F>::type, thread>::value
>::type
>
explicit thread(_F&& __f, _Args&&... __args);
#else // _LIBCPP_HAS_NO_VARIADICS
template <class _F> explicit thread(_F __f);
#endif
~thread();
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
thread(thread&& __t) : __t_(__t.__t_) {__t.__t_ = 0;}
thread& operator=(thread&& __t);
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
void swap(thread& __t) {_STD::swap(__t_, __t.__t_);}
bool joinable() const {return __t_ != 0;}
void join();
void detach();
id get_id() const {return __t_;}
native_handle_type native_handle() {return __t_;}
static unsigned hardware_concurrency();
};
class __assoc_sub_state;
class __thread_struct_imp;
class __thread_struct
{
__thread_struct_imp* __p_;
__thread_struct(const __thread_struct&);
__thread_struct& operator=(const __thread_struct&);
public:
__thread_struct();
~__thread_struct();
void notify_all_at_thread_exit(condition_variable*, mutex*);
void __make_ready_at_thread_exit(__assoc_sub_state*);
};
extern __thread_specific_ptr<__thread_struct> __thread_local_data;
template <class _F>
void*
__thread_proxy(void* __vp)
{
__thread_local_data.reset(new __thread_struct);
std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
(*__p)();
return nullptr;
}
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _F, class ..._Args,
class
>
thread::thread(_F&& __f, _Args&&... __args)
{
typedef decltype(bind(std::forward<_F>(__f), std::forward<_Args>(__args)...)) _G;
std::unique_ptr<_G> __p(new _G(bind(std::forward<_F>(__f),
std::forward<_Args>(__args)...)));
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_G>, __p.get());
if (__ec == 0)
__p.release();
else
__throw_system_error(__ec, "thread constructor failed");
}
#else // _LIBCPP_HAS_NO_VARIADICS
template <class _F>
thread::thread(_F __f)
{
std::unique_ptr<_F> __p(new _F(__f));
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_F>, __p.get());
if (__ec == 0)
__p.release();
else
__throw_system_error(__ec, "thread constructor failed");
}
#endif // _LIBCPP_HAS_NO_VARIADICS
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
inline
thread&
thread::operator=(thread&& __t)
{
if (__t_ != 0)
terminate();
__t_ = __t.__t_;
__t.__t_ = 0;
return *this;
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
inline
void swap(thread& __x, thread& __y) {__x.swap(__y);}
namespace this_thread
{
void sleep_for(const chrono::nanoseconds& ns);
template <class _Rep, class _Period>
void
sleep_for(const chrono::duration<_Rep, _Period>& __d)
{
using namespace chrono;
nanoseconds __ns = duration_cast<nanoseconds>(__d);
if (__ns < __d)
++__ns;
sleep_for(__ns);
}
template <class _Clock, class _Duration>
void
sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
{
using namespace chrono;
mutex __mut;
condition_variable __cv;
unique_lock<mutex> __lk(__mut);
while (_Clock::now() < __t)
__cv.wait_until(__lk, __t);
}
template <class _Duration>
inline
void
sleep_until(const chrono::time_point<chrono::monotonic_clock, _Duration>& __t)
{
using namespace chrono;
sleep_for(__t - monotonic_clock::now());
}
inline
void yield() {sched_yield();}
} // this_thread
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_THREAD