1// thread -*- C++ -*-
2
3// Copyright (C) 2008-2015 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25
26#include <thread>
27#include <system_error>
28#include <cerrno>
29#include <cxxabi_forced.h>
30
31#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
32
33#if defined(_GLIBCXX_USE_GET_NPROCS)
34# include <sys/sysinfo.h>
35# define _GLIBCXX_NPROCS get_nprocs()
36#elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP)
37# define _GLIBCXX_NPROCS pthread_num_processors_np()
38#elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU)
39# include <stddef.h>
40# include <sys/sysctl.h>
41static inline int get_nprocs()
42{
43 int count;
44 size_t size = sizeof(count);
45 int mib[] = { CTL_HW, HW_NCPU };
46 if (!sysctl(mib, 2, &count, &size, NULL, 0))
47   return count;
48 return 0;
49}
50# define _GLIBCXX_NPROCS get_nprocs()
51#elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN)
52# include <unistd.h>
53# define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
54#elif defined(_GLIBCXX_USE_SC_NPROC_ONLN)
55# include <unistd.h>
56# define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN)
57#else
58# define _GLIBCXX_NPROCS 0
59#endif
60
61#ifndef _GLIBCXX_USE_NANOSLEEP
62# ifdef _GLIBCXX_HAVE_SLEEP
63#  include <unistd.h>
64# elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
65#  include <windows.h>
66# else
67#  error "No sleep function known for this target"
68# endif
69#endif
70
71namespace std _GLIBCXX_VISIBILITY(default)
72{
73  extern "C"
74  {
75    static void*
76    execute_native_thread_routine(void* __p)
77    {
78      thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
79      thread::__shared_base_type __local;
80      __local.swap(__t->_M_this_ptr);
81
82      __try
83	{
84	  __t->_M_run();
85	}
86      __catch(const __cxxabiv1::__forced_unwind&)
87	{
88	  __throw_exception_again;
89	}
90      __catch(...)
91	{
92	  std::terminate();
93	}
94
95      return nullptr;
96    }
97  } // extern "C"
98
99_GLIBCXX_BEGIN_NAMESPACE_VERSION
100
101  void
102  thread::join()
103  {
104    int __e = EINVAL;
105
106    if (_M_id != id())
107      __e = __gthread_join(_M_id._M_thread, 0);
108
109    if (__e)
110      __throw_system_error(__e);
111
112    _M_id = id();
113  }
114
115  void
116  thread::detach()
117  {
118    int __e = EINVAL;
119
120    if (_M_id != id())
121      __e = __gthread_detach(_M_id._M_thread);
122
123    if (__e)
124      __throw_system_error(__e);
125
126    _M_id = id();
127  }
128
129  void
130  thread::_M_start_thread(__shared_base_type __b)
131  {
132    if (!__gthread_active_p())
133#if __cpp_exceptions
134      throw system_error(make_error_code(errc::operation_not_permitted),
135			 "Enable multithreading to use std::thread");
136#else
137      __throw_system_error(int(errc::operation_not_permitted));
138#endif
139
140    _M_start_thread(std::move(__b), nullptr);
141  }
142
143  void
144  thread::_M_start_thread(__shared_base_type __b, void (*)())
145  {
146    auto ptr = __b.get();
147    ptr->_M_this_ptr = std::move(__b);
148    int __e = __gthread_create(&_M_id._M_thread,
149			       &execute_native_thread_routine, ptr);
150    if (__e)
151    {
152      ptr->_M_this_ptr.reset();
153      __throw_system_error(__e);
154    }
155  }
156
157  unsigned int
158  thread::hardware_concurrency() noexcept
159  {
160    int __n = _GLIBCXX_NPROCS;
161    if (__n < 0)
162      __n = 0;
163    return __n;
164  }
165
166_GLIBCXX_END_NAMESPACE_VERSION
167
168namespace this_thread
169{
170_GLIBCXX_BEGIN_NAMESPACE_VERSION
171
172  void
173  __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
174  {
175#ifdef _GLIBCXX_USE_NANOSLEEP
176    __gthread_time_t __ts =
177      {
178	static_cast<std::time_t>(__s.count()),
179	static_cast<long>(__ns.count())
180      };
181    ::nanosleep(&__ts, 0);
182#elif defined(_GLIBCXX_HAVE_SLEEP)
183# ifdef _GLIBCXX_HAVE_USLEEP
184    ::sleep(__s.count());
185    if (__ns.count() > 0)
186      {
187        long __us = __ns.count() / 1000;
188        if (__us == 0)
189          __us = 1;
190        ::usleep(__us);
191      }
192# else
193    ::sleep(__s.count() + (__ns.count() >= 1000000));
194# endif
195#elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
196    unsigned long ms = __ns.count() / 1000000;
197    if (__ns.count() > 0 && ms == 0)
198      ms = 1;
199    ::Sleep(chrono::milliseconds(__s).count() + ms);
200#endif
201  }
202
203_GLIBCXX_END_NAMESPACE_VERSION
204}
205
206} // namespace std
207
208#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
209