diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index b80bfd8b..4e3f402b 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -1,6 +1,11 @@ #ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP #define BOOST_THREAD_CONFIG_WEK01032003_HPP +#include +#ifndef BOOST_HAS_THREADS +# error Thread support is unavailable! +#endif + #if defined(BOOST_HAS_WINTHREADS) # if defined(BOOST_THREAD_BUILD_DLL) # define BOOST_THREAD_DECL __declspec(dllexport) @@ -11,4 +16,21 @@ # define BOOST_THREAD_DECL #endif // BOOST_THREAD_SHARED_LIB +#if defined(BOOST_HAS_WINTHREADS) +# define BOOST_THREAD_ATTRIBUTES_STACKSIZE +# define BOOST_THREAD_STACK_MIN 0 +# define BOOST_THREAD_PRIORITY_SCHEDULING +#elif defined(BOOST_HAS_PTHREADS) +# if defined(_POSIX_THREAD_ATTR_STACKSIZE) +# define BOOST_THREAD_ATTRIBUTES_STACKSIZE +# define BOOST_THREAD_STACK_MIN PTHREAD_STACK_MIN +# endif +# if defined(_POSIX_THREAD_ATTR_STACKADDR) +# define BOOST_THREAD_ATTRIBUTES_STACKADDR +# endif +# if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +# define BOOST_THREAD_PRIORITY_SCHEDULING +# endif +#endif + #endif // BOOST_THREAD_CONFIG_WEK1032003_HPP diff --git a/include/boost/thread/thread.hpp b/include/boost/thread/thread.hpp index 65486b2a..88e56cb1 100644 --- a/include/boost/thread/thread.hpp +++ b/include/boost/thread/thread.hpp @@ -12,10 +12,6 @@ #ifndef BOOST_THREAD_WEK070601_HPP #define BOOST_THREAD_WEK070601_HPP -#include -#ifndef BOOST_HAS_THREADS -# error Thread support is unavailable! -#endif #include #include @@ -48,6 +44,37 @@ public: ~thread_cancel(); }; +#if defined(BOOST_THREAD_PRIORITY_SCHEDULING) +# if defined(BOOST_HAS_WINTHREADS) + +struct sched_param +{ + int priority; +}; + +enum { sched_fifo, sched_rr, sched_other }; +enum { scope_process, scope_system }; + +# elif defined(BOOST_HAS_PTHREADS) + +using ::sched_param; + +enum +{ + sched_fifo = SCHED_FIFO, + sched_rr = SCHED_RR, + sched_other = SCHED_OTHER +}; + +enum +{ + scope_process = PTHREAD_SCOPE_PROCESS, + scope_system = PTHREAD_SCOPE_SYSTEM +}; + +# endif +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + class BOOST_THREAD_DECL thread : private noncopyable { public: @@ -60,16 +87,14 @@ public: #if defined(BOOST_THREAD_ATTRIBUTES_STACKSIZE) attributes& stack_size(size_t size); size_t stack_size() const; -#endif +#endif // BOOST_THREAD_ATTRIBUTES_STACKSIZE #if defined(BOOST_THREAD_ATTRIBUTES_STACKADDR) attributes& stack_address(void* addr); void* stack_address() const; -#endif +#endif // BOOST_THREAD_ATTRIBUTES_STACKADDR #if defined(BOOST_THREAD_PRIORITY_SCHEDULING) - struct sched_param { int priority; } - attributes& inherit_scheduling(bool inherit); bool inherit_scheduling() const; attributes& scheduling_parameter(const sched_param& param); @@ -78,6 +103,17 @@ public: int scheduling_policy() const; attributes& scope(int scope); int scope() const; +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + + private: + friend class thread; + +#if defined(BOOST_HAS_WINTHREADS) + size_t m_stacksize; + bool m_schedinherit; + sched_param m_schedparam; +#elif defined(BOOST_HAS_PTHREADS) + pthread_attr_t m_attr; #endif }; @@ -91,6 +127,14 @@ public: void join(); void cancel(); +#if defined(BOOST_THREAD_PRIORITY_SCHEDULING) + void set_scheduling_parameter(int policy, const sched_param& param); + void get_scheduling_parameter(int& policy, sched_param& param) const; + + static int max_priority(int policy); + static int min_priority(int policy); +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + static void test_cancel(); static void sleep(const xtime& xt); static void yield(); diff --git a/src/thread.cpp b/src/thread.cpp index 4365da5d..8c73ac73 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #if defined(BOOST_HAS_WINTHREADS) # include @@ -52,8 +53,13 @@ public: void test_cancel(); void run(); +#if defined(BOOST_THREAD_PRIORITY_SCHEDULING) + void set_scheduling_parameter(int policy, const sched_param& param); + void get_scheduling_parameter(int& policy, sched_param& param) const; +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + private: - boost::mutex m_mutex; + mutable boost::mutex m_mutex; boost::condition m_cond; boost::function0 m_threadfunc; unsigned int m_refcount; @@ -239,6 +245,46 @@ void thread::data::run() m_threadfunc(); } +#if defined(BOOST_THREAD_PRIORITY_SCHEDULING) + +void thread::data::set_scheduling_parameter(int policy, const sched_param& param) +{ +#if defined(BOOST_HAS_WINTHREADS) + if (policy != sched_other) + throw std::invalid_argument("policy"); + if (param.priority < THREAD_PRIORITY_LOWEST || param.priority > THREAD_PRIORITY_HIGHEST) + throw std::invalid_argument("param"); + boost::mutex::scoped_lock lock(m_mutex); + BOOL res = FALSE; + res = SetThreadPriority(m_thread, param.priority); + assert(res); +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_setschedparam(m_thread, policy, ¶m); + if (res == EINVAL || res == ENOTSUP) + throw std::invalid_argument("policy/param"); + if (res == EPERM) + throw std::runtime_error("permission denied"); + assert(res == 0); +#endif +} + +void thread::data::get_scheduling_parameter(int& policy, sched_param& param) const +{ +#if defined(BOOST_HAS_WINTHREADS) + policy = sched_other; + boost::mutex::scoped_lock lock(m_mutex); + param.priority = GetThreadPriority(m_thread); +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + boost::mutex::scoped_lock lock(m_mutex); + res = pthread_getschedparam(m_thread, &policy, ¶m); + assert(res == 0); +#endif +} + +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + thread_cancel::thread_cancel() { } @@ -249,12 +295,193 @@ thread_cancel::~thread_cancel() thread::attributes::attributes() { +#if defined(BOOST_HAS_WINTHREADS) + m_stacksize = 0; + m_schedinherit = true; + m_schedparam.priority = THREAD_PRIORITY_NORMAL; +#elif defined(BOOST_HAS_PTHREADS) + int res = pthread_attr_init(&m_attr); + if (res == ENOMEM) + throw thread_resource_error(); + assert(res == 0); +#endif } thread::attributes::~attributes() { +#if defined(BOOST_HAS_PTHREADS) + pthread_attr_destroy(&m_attr); +#endif } +#if defined(BOOST_THREAD_ATTRIBUTES_STACKSIZE) + +thread::attributes& thread::attributes::stack_size(size_t size) +{ +#if defined(BOOST_HAS_WINTHREADS) + m_stacksize = size; +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_attr_setstacksize(&m_attr, size); + if (res == EINVAL) + throw std::invalid_argument("size"); + assert(res == 0); +#endif + return *this; +} + +size_t thread::attributes::stack_size() const +{ +#if defined(BOOST_HAS_WINTHREADS) + return m_stacksize; +#elif defined(BOOST_HAS_PTHREADS) + size_t size; + int res = 0; + res = pthread_attr_getstacksize(&m_attr, &size); + assert(res == 0); + return size; +#endif +} + +#endif // BOOST_THREAD_ATTRIBUTES_STACKSIZE + +#if defined(BOOST_THREAD_ATTRIBUTES_STACKADDR) + +thread::attributes& thread::attributes::stack_address(void* addr) +{ +#if defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_attr_setstackaddr(&m_attr, addr); + assert(res == 0); +#endif + return *this; +} + +void* thread::attributes::stack_address() const +{ +#if defined(BOOST_HAS_PTHREADS) + void* addr; + int res = 0; + res = pthread_attr_getstackaddr(&m_attr, &addr); + assert(res == 0); + return addr; +#endif +} + +#endif // BOOST_THREAD_ATTRIBUTES_STACKADDR + +#if defined(BOOST_THREAD_PRIORITY_SCHEDULING) + +thread::attributes& thread::attributes::inherit_scheduling(bool inherit) +{ +#if defined(BOOST_HAS_WINTHREADS) + m_schedinherit = inherit; +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_attr_setinheritsched(&m_attr, inherit ? PTHREAD_INHERIT_SCHED : PTHREAD_EXPLICIT_SCHED); + if (res == ENOTSUP) + throw std::invalid_argument("inherit"); + assert(res == 0); +#endif + return *this; +} + +bool thread::attributes::inherit_scheduling() const +{ +#if defined(BOOST_HAS_WINTHREADS) + return m_schedinherit; +#elif defined (BOOST_HAS_PTHREADS) + int inherit = 0; + int res = 0; + res = pthread_attr_getinheritsched(&m_attr, &inherit); + assert(res == 0); + return inherit == PTHREAD_INHERIT_SCHED; +#endif +} + +thread::attributes& thread::attributes::scheduling_parameter(const sched_param& param) +{ +#if defined(BOOST_HAS_WINTHREADS) + m_schedparam = param; +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_attr_setschedparam(&m_attr, ¶m); + if (res == EINVAL || res == ENOTSUP) + throw std::invalid_argument("param"); +#endif + return *this; +} + +sched_param thread::attributes::scheduling_parameter() const +{ +#if defined(BOOST_HAS_WINTHREADS) + return m_schedparam; +#elif defined(BOOST_HAS_PTHREADS) + sched_param param; + int res = 0; + res = pthread_attr_getschedparam(&m_attr, ¶m); + assert(res == 0); + return param; +#endif +} + +thread::attributes& thread::attributes::scheduling_policy(int policy) +{ +#if defined(BOOST_HAS_WINTHREADS) + if (policy != sched_other) + throw std::invalid_argument("policy"); +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_attr_setschedpolicy(&m_attr, policy); + if (res == ENOTSUP) + throw std::invalid_argument("policy"); + assert(res); +#endif + return *this; +} + +int thread::attributes::scheduling_policy() const +{ +#if defined(BOOST_HAS_WINTHREADS) + return sched_other; +#elif defined(BOOST_HAS_PTHREADS) + int policy = 0; + int res = 0; + res = pthread_attr_getschedpolicy(&m_attr, &policy); + assert(res == 0); + return policy; +#endif +} + +thread::attributes& thread::attributes::scope(int scope) +{ +#if defined(BOOST_HAS_WINTHREADS) + if (scope != scope_system) + throw std::invalid_argument("scope"); +#elif defined(BOOST_HAS_PTHREADS) + int res = 0; + res = pthread_attr_setscope(&m_attr, scope); + if (res == EINVAL || res == ENOTSUP) + throw std::invalid_argument("scope"); + assert(res == 0); +#endif + return *this; +} + +int thread::attributes::scope() const +{ +#if defined(BOOST_HAS_WINTHREADS) + return scope_system; +#elif defined(BOOST_HAS_PTHREADS) + int scope = 0; + int res = 0; + res = pthread_attr_getscope(&m_attr, &scope); + return scope; +#endif +} + +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + thread::thread() : m_handle(0) { @@ -285,13 +512,16 @@ thread::thread(const function0& threadfunc, attributes attr) throw thread_resource_error(); #if defined(BOOST_HAS_WINTHREADS) unsigned int id; - HANDLE h = (HANDLE)_beginthreadex(0, 0, &thread_proxy, param.get(), 0, &id); + HANDLE h = (HANDLE)_beginthreadex(0, attr.m_stacksize, &thread_proxy, param.get(), CREATE_SUSPENDED, &id); if (!h) throw thread_resource_error(); + if (!attr.m_schedinherit) + SetThreadPriority(h, attr.m_schedparam.priority); + ResumeThread(h); #elif defined(BOOST_HAS_PTHREADS) int res = 0; pthread_t t; - res = pthread_create(&t, 0, &thread_proxy, param.get()); + res = pthread_create(&t, &attr.m_attr, &thread_proxy, param.get()); if (res != 0) throw thread_resource_error(); #elif defined(BOOST_HAS_MPTASKS) @@ -349,6 +579,42 @@ void thread::test_cancel() self.m_handle->test_cancel(); } +#if defined(BOOST_THREAD_PRIORITY_SCHEDULING) + +void thread::set_scheduling_parameter(int policy, const sched_param& param) +{ + m_handle->set_scheduling_parameter(policy, param); +} + +void thread::get_scheduling_parameter(int& policy, sched_param& param) const +{ + m_handle->get_scheduling_parameter(policy, param); +} + +int thread::max_priority(int policy) +{ +#if defined(BOOST_HAS_WINTHREADS) + if (policy != sched_other) + throw std::invalid_argument("policy"); + return THREAD_PRIORITY_HIGHEST; +#elif defined(BOOST_HAS_PTHREADS) +#endif + return 0; +} + +int thread::min_priority(int policy) +{ +#if defined(BOOST_HAS_WINTHREADS) + if (policy != sched_other) + throw std::invalid_argument("policy"); + return THREAD_PRIORITY_LOWEST; +#elif defined(BOOST_HAS_PTHREADS) +#endif + return 0; +} + +#endif // BOOST_THREAD_PRIORITY_SCHEDULING + void thread::sleep(const xtime& xt) { for (;;)