1#pragma once
2
3#if __cplusplus < 201103L
4#error "C++ version lower than C++11"
5#endif
6
7//#if defined(RT_USING_PTHREADS)
8
9#include <unistd.h>
10#include <pthread.h>
11#include <sched.h>
12#include <rtthread.h>
13
14#include <cstddef>
15#include <cerrno>
16#include <ostream>
17#include <functional>
18#include <utility>
19#include <chrono>
20#include <memory>
21
22#define rt_cpp_thread_t pthread_t
23#ifndef PTHREAD_NUM_MAX
24#define PTHREAD_NUM_MAX 32
25#endif
26#define CPP_UNJOINABLE_THREAD PTHREAD_NUM_MAX
27
28namespace std
29{
30    #define __STDCPP_THREADS__ __cplusplus
31
32
33
34    class thread
35    {
36    public:
37        typedef rt_cpp_thread_t   native_handle_type;
38
39        struct invoker_base;
40        typedef shared_ptr<invoker_base> invoker_base_ptr;
41
42        class id
43        {
44            // basically a wrapper around native_handle_type
45            native_handle_type __cpp_thread_t;
46
47        public:
48            id() noexcept : __cpp_thread_t(CPP_UNJOINABLE_THREAD) {}
49
50            explicit id(native_handle_type hid)
51                : __cpp_thread_t(hid) {}
52        private:
53            friend class thread;
54            friend class hash<thread::id>;
55
56            friend bool operator==(thread::id x, thread::id y) noexcept;
57
58            friend bool operator<(thread::id x, thread::id y) noexcept;
59
60            template <class charT, class traits>
61            friend basic_ostream<charT, traits>&
62            operator<<(basic_ostream<charT, traits>& out, thread::id id);
63        };
64
65        thread() noexcept = default;
66        thread(const thread&) = delete;
67        thread& operator=(const thread&) = delete;
68        ~thread();
69
70        template <class F, class ...Args>
71        explicit thread(F&& f, Args&&... args)
72        {
73            start_thread(make_invoker_ptr(std::bind(
74                std::forward<F>(f),
75                std::forward<Args>(args)...
76            )));
77        }
78
79        thread(thread&& t) noexcept
80        {
81            swap(t);
82        }
83
84        thread& operator=(thread&& t) noexcept
85        {
86            if (joinable())
87                terminate();
88            swap(t);
89            return *this;
90        }
91
92        // member functions
93        void swap(thread& t) noexcept
94        {
95            std::swap(_m_thr, t._m_thr);
96        }
97
98        bool joinable() const noexcept
99        {
100            return (_m_thr.__cpp_thread_t < PTHREAD_NUM_MAX);
101        }
102
103        void join();
104
105        void detach();
106
107        id get_id() const noexcept { return _m_thr; }
108
109        native_handle_type native_handle() { return _m_thr.__cpp_thread_t; }
110
111        // static members
112        static unsigned hardware_concurrency() noexcept;
113
114    private:
115        id _m_thr;
116
117        void start_thread(invoker_base_ptr b);
118    public:
119        struct invoker_base
120        {
121            invoker_base_ptr this_ptr;
122
123            virtual ~invoker_base() = default;
124
125            virtual void invoke() = 0;
126        };
127
128
129        template<typename Callable>
130        struct invoker : public invoker_base
131        {
132            Callable func;
133
134            invoker(Callable&& F) : func(std::forward<Callable>(F)) { }
135
136            void invoke() { func(); }
137        };
138
139        template <typename Callable>
140        shared_ptr<invoker<Callable>> make_invoker_ptr(Callable&& F)
141        {
142            return std::make_shared<invoker<Callable>>(std::forward<Callable>(F));
143        }
144
145
146    };
147
148    inline void swap(thread& x, thread& y) noexcept
149    {
150        x.swap(y);
151    }
152
153
154    inline bool operator==(thread::id x, thread::id y) noexcept
155    {
156        // From POSIX for pthread_equal:
157        //"If either t1 or t2 are not valid thread IDs,  the behavior is undefined."
158        return x.__cpp_thread_t == y.__cpp_thread_t;
159    }
160
161    inline bool operator!=(thread::id x, thread::id y) noexcept
162    {
163        return !(x == y);
164    }
165
166    inline bool operator<(thread::id x, thread::id y) noexcept
167    {
168        return x.__cpp_thread_t < y.__cpp_thread_t;
169    }
170
171    inline bool operator<=(thread::id x, thread::id y) noexcept
172    {
173        return !(y < x);
174    }
175
176    inline bool operator>(thread::id x, thread::id y) noexcept
177    {
178        return !(x <= y);
179    }
180
181    inline bool operator>=(thread::id x, thread::id y) noexcept
182    {
183        return !(x < y);
184    }
185
186    template <class charT, class traits>
187    inline basic_ostream<charT, traits>&
188    operator<<(basic_ostream<charT, traits>& out, thread::id id)
189    {
190        if (id == thread::id()) // id is invalid, representing no pthread
191            out << "thread::id of a non-executing thread";
192        else
193            out << id.__cpp_thread_t;
194        return out;
195    }
196
197    template <>
198    struct hash<thread::id>
199    {
200        typedef size_t result_type;
201        typedef thread::id argument_type;
202        size_t operator()(const thread::id& id) const noexcept
203        {
204            return hash<rt_cpp_thread_t>()(id.__cpp_thread_t);
205        }
206    };
207
208    namespace this_thread
209    {
210        inline thread::id get_id() noexcept
211        {
212            return thread::id(pthread_self());
213        }
214
215        inline void yield() noexcept
216        {
217            sched_yield();
218        }
219
220        template <class Rep, class Period>
221        inline void sleep_for(const chrono::duration<Rep, Period>& rel_time)
222        {
223            if (rel_time <= rel_time.zero()) // less than zero, no need to sleep
224                return;
225            auto milli_secs = chrono::duration_cast<chrono::milliseconds>(rel_time);
226            // the precision is limited by rt-thread thread API
227            rt_thread_mdelay(milli_secs.count());
228        }
229
230        template <class Clock, class Duration>
231        inline void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)
232        {
233            auto now = Clock::now();
234            if (abs_time > now)
235                sleep_for(abs_time - now);
236        }
237
238    }
239}
240