1// LAF Base Library
2// Copyright (C) 2019-2021 Igara Studio S.A.
3// Copyright (C) 2001-2016 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "base/thread.h"
13
14#if LAF_WINDOWS
15 #include <windows.h>
16 #include <process.h>
17#else
18 #include <pthread.h> // Use pthread library in Unix-like systems
19
20 #include <unistd.h>
21 #include <sys/time.h>
22#endif
23
24namespace {
25
26#if LAF_WINDOWS
27
28 DWORD WINAPI win32_thread_proxy(LPVOID data)
29 {
30 base::thread::details::thread_proxy(data);
31 return 0;
32 }
33
34#else
35
36 void* pthread_thread_proxy(void* data)
37 {
38 base::thread::details::thread_proxy(data);
39 return NULL;
40 }
41
42#endif
43
44}
45
46namespace base {
47
48thread::thread()
49 : m_native_handle((native_handle_type)0)
50#if LAF_WINDOWS
51 , m_native_id((native_id_type)0)
52#endif
53{
54}
55
56thread::~thread()
57{
58 if (joinable())
59 detach();
60}
61
62bool thread::joinable() const
63{
64 return m_native_handle != (native_handle_type)0;
65}
66
67void thread::join()
68{
69 if (joinable()) {
70#if LAF_WINDOWS
71 ::WaitForSingleObject(m_native_handle, INFINITE);
72#else
73 ::pthread_join((pthread_t)m_native_handle, NULL);
74#endif
75 detach();
76 }
77}
78
79void thread::detach()
80{
81 if (joinable()) {
82#if LAF_WINDOWS
83 ::CloseHandle(m_native_handle);
84 m_native_handle = (native_handle_type)0;
85#else
86 ::pthread_detach((pthread_t)m_native_handle);
87#endif
88 }
89}
90
91thread::native_id_type thread::native_id() const
92{
93#if LAF_WINDOWS
94
95 return m_native_id;
96
97#else
98
99 return (thread::native_id_type)m_native_handle;
100
101#endif
102}
103
104void thread::launch_thread(func_wrapper* f)
105{
106 m_native_handle = (native_handle_type)0;
107
108#if LAF_WINDOWS
109
110 static_assert(sizeof(DWORD) == sizeof(native_id_type),
111 "native_id_type must match DWORD size on Windows");
112
113 m_native_handle = ::CreateThread(NULL, 0, win32_thread_proxy, (LPVOID)f,
114 CREATE_SUSPENDED, (LPDWORD)&m_native_id);
115 ResumeThread(m_native_handle);
116
117#else
118
119 pthread_t thread;
120 if (::pthread_create(&thread, NULL, pthread_thread_proxy, f) == 0)
121 m_native_handle = (void*)thread;
122
123#endif
124}
125
126void thread::details::thread_proxy(void* data)
127{
128 func_wrapper* f = reinterpret_cast<func_wrapper*>(data);
129
130 // Call operator() of func_wrapper class (this is a virtual method).
131 (*f)();
132
133 // Delete the data (it was created in the thread() ctor).
134 delete f;
135}
136
137void this_thread::yield()
138{
139#if LAF_WINDOWS
140
141 ::Sleep(0);
142
143#elif defined(HAVE_SCHED_YIELD) && defined(_POSIX_PRIORITY_SCHEDULING)
144
145 sched_yield();
146
147#else
148
149 timeval timeout;
150 timeout.tv_sec = 0;
151 timeout.tv_usec = 0;
152 select(0, nullptr, nullptr, nullptr, &timeout);
153
154#endif
155}
156
157void this_thread::sleep_for(double seconds)
158{
159#if LAF_WINDOWS
160
161 ::Sleep(DWORD(seconds * 1000.0));
162
163#else
164
165 usleep(seconds * 1000000.0);
166
167#endif
168}
169
170thread::native_id_type this_thread::native_id()
171{
172#if LAF_WINDOWS
173
174 return (thread::native_id_type)GetCurrentThreadId();
175
176#else
177
178 return (thread::native_id_type)pthread_self();
179
180#endif
181}
182
183} // namespace base
184