1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 //                        Kokkos v. 3.0
6 //       Copyright (2020) National Technology & Engineering
7 //               Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 #include <Kokkos_Macros.hpp>
46 #if defined(KOKKOS_ENABLE_THREADS)
47 
48 #include <Kokkos_Core_fwd.hpp>
49 /* Standard 'C' Linux libraries */
50 
51 #include <pthread.h>
52 #include <sched.h>
53 #include <errno.h>
54 
55 /* Standard C++ libraries */
56 
57 #include <cstdlib>
58 #include <string>
59 #include <iostream>
60 #include <stdexcept>
61 
62 #include <Kokkos_Threads.hpp>
63 
64 //----------------------------------------------------------------------------
65 
66 namespace Kokkos {
67 namespace Impl {
68 namespace {
69 
70 pthread_mutex_t host_internal_pthread_mutex = PTHREAD_MUTEX_INITIALIZER;
71 
72 // Pthreads compatible driver.
73 // Recovery from an exception would require constant intra-thread health
74 // verification; which would negatively impact runtime.  As such simply
75 // abort the process.
76 
internal_pthread_driver(void *)77 void* internal_pthread_driver(void*) {
78   try {
79     ThreadsExec::driver();
80   } catch (const std::exception& x) {
81     std::cerr << "Exception thrown from worker thread: " << x.what()
82               << std::endl;
83     std::cerr.flush();
84     std::abort();
85   } catch (...) {
86     std::cerr << "Exception thrown from worker thread" << std::endl;
87     std::cerr.flush();
88     std::abort();
89   }
90   return nullptr;
91 }
92 
93 }  // namespace
94 
95 //----------------------------------------------------------------------------
96 // Spawn a thread
97 
spawn()98 bool ThreadsExec::spawn() {
99   bool result = false;
100 
101   pthread_attr_t attr;
102 
103   if (0 == pthread_attr_init(&attr) ||
104       0 == pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ||
105       0 == pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
106     pthread_t pt;
107 
108     result = 0 == pthread_create(&pt, &attr, internal_pthread_driver, nullptr);
109   }
110 
111   pthread_attr_destroy(&attr);
112 
113   return result;
114 }
115 
116 //----------------------------------------------------------------------------
117 
is_process()118 bool ThreadsExec::is_process() {
119   static const pthread_t master_pid = pthread_self();
120 
121   return pthread_equal(master_pid, pthread_self());
122 }
123 
global_lock()124 void ThreadsExec::global_lock() {
125   pthread_mutex_lock(&host_internal_pthread_mutex);
126 }
127 
global_unlock()128 void ThreadsExec::global_unlock() {
129   pthread_mutex_unlock(&host_internal_pthread_mutex);
130 }
131 
132 //----------------------------------------------------------------------------
133 
wait_yield(volatile int & flag,const int value)134 void ThreadsExec::wait_yield(volatile int& flag, const int value) {
135   while (value == flag) {
136     sched_yield();
137   }
138 }
139 
140 }  // namespace Impl
141 }  // namespace Kokkos
142 
143 /* end #if defined( KOKKOS_ENABLE_THREADS ) */
144 //----------------------------------------------------------------------------
145 //----------------------------------------------------------------------------
146 
147 #elif defined(KOKKOS_ENABLE_WINTHREAD)
148 
149 #include <Kokkos_Core_fwd.hpp>
150 
151 /* Windows libraries */
152 #include <winsock2.h>
153 #include <windows.h>
154 #include <process.h>
155 
156 /* Standard C++ libraries */
157 
158 #include <cstdlib>
159 #include <string>
160 #include <iostream>
161 #include <stdexcept>
162 
163 #include <Kokkos_Threads.hpp>
164 
165 //----------------------------------------------------------------------------
166 // Driver for each created pthread
167 
168 namespace Kokkos {
169 namespace Impl {
170 namespace {
171 
internal_winthread_driver(void * arg)172 unsigned WINAPI internal_winthread_driver(void* arg) {
173   ThreadsExec::driver();
174 
175   return 0;
176 }
177 
178 class ThreadLockWindows {
179  private:
180   CRITICAL_SECTION m_handle;
181 
~ThreadLockWindows()182   ~ThreadLockWindows() { DeleteCriticalSection(&m_handle); }
183 
184   ThreadLockWindows();
185   { InitializeCriticalSection(&m_handle); }
186 
187   ThreadLockWindows(const ThreadLockWindows&);
188   ThreadLockWindows& operator=(const ThreadLockWindows&);
189 
190  public:
191   static ThreadLockWindows& singleton();
192 
lock()193   void lock() { EnterCriticalSection(&m_handle); }
194 
unlock()195   void unlock() { LeaveCriticalSection(&m_handle); }
196 };
197 
singleton()198 ThreadLockWindows& ThreadLockWindows::singleton() {
199   static ThreadLockWindows self;
200   return self;
201 }
202 
203 }  // namespace
204 }  // namespace Impl
205 }  // namespace Kokkos
206 
207 //----------------------------------------------------------------------------
208 //----------------------------------------------------------------------------
209 
210 namespace Kokkos {
211 namespace Impl {
212 
213 // Spawn this thread
214 
spawn()215 bool ThreadsExec::spawn() {
216   unsigned Win32ThreadID = 0;
217 
218   HANDLE handle =
219       _beginthreadex(0, 0, internal_winthread_driver, 0, 0, &Win32ThreadID);
220 
221   return !handle;
222 }
223 
is_process()224 bool ThreadsExec::is_process() { return true; }
225 
global_lock()226 void ThreadsExec::global_lock() { ThreadLockWindows::singleton().lock(); }
227 
global_unlock()228 void ThreadsExec::global_unlock() { ThreadLockWindows::singleton().unlock(); }
229 
wait_yield(volatile int & flag,const int value)230 void ThreadsExec::wait_yield(volatile int& flag, const int value){} {
231   while (value == flag) {
232     Sleep(0);
233   }
234 }
235 
236 }  // namespace Impl
237 }  // namespace Kokkos
238 
239 #else
KOKKOS_CORE_SRC_THREADS_EXEC_BASE_PREVENT_LINK_ERROR()240 void KOKKOS_CORE_SRC_THREADS_EXEC_BASE_PREVENT_LINK_ERROR() {}
241 #endif /* end #elif defined( KOKKOS_ENABLE_WINTHREAD ) */
242