blob: f3e5b73d2a871e78d9f06b179f5f4ec6af1e5340 [file] [log] [blame]
Pierre Ossman687d52c2015-11-12 12:16:08 +01001/* Copyright 2015 Pierre Ossman for Cendio AB
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#ifdef WIN32
20#include <windows.h>
Steve Kondik2b563712017-06-19 23:14:18 -070021#elif defined(__ANDROID__)
22#include <functional>
23#include <utils/Thread.h>
Pierre Ossman687d52c2015-11-12 12:16:08 +010024#else
25#include <pthread.h>
Pierre Ossmana6b00262016-01-04 14:19:15 +010026#include <signal.h>
Pierre Ossman7b63a7c2015-11-13 14:07:52 +010027#include <unistd.h>
Pierre Ossman687d52c2015-11-12 12:16:08 +010028#endif
29
30#include <rdr/Exception.h>
31
32#include <os/Mutex.h>
33#include <os/Thread.h>
34
35using namespace os;
36
Steve Kondik2b563712017-06-19 23:14:18 -070037#if defined(__ANDROID__)
38namespace os {
39class AndroidThread : public ::android::Thread {
40public:
41 AndroidThread(std::function<void()> worker) : mWorker(worker) {}
42
43 virtual bool threadLoop() {
44 try {
45 mWorker();
46 } catch(...) {
47 }
48 return false;
49 }
50private:
51 std::function<void()> mWorker;
52};
53};
54#endif
55
Pierre Ossman687d52c2015-11-12 12:16:08 +010056Thread::Thread() : running(false), threadId(NULL)
57{
58 mutex = new Mutex;
59
60#ifdef WIN32
61 threadId = new HANDLE;
Steve Kondik2b563712017-06-19 23:14:18 -070062#elif defined(__ANDROID__)
63 threadId = new AndroidThread(std::bind(&Thread::worker, this));
Pierre Ossman687d52c2015-11-12 12:16:08 +010064#else
65 threadId = new pthread_t;
66#endif
67}
68
69Thread::~Thread()
70{
71#ifdef WIN32
72 delete (HANDLE*)threadId;
Steve Kondik2b563712017-06-19 23:14:18 -070073#elif defined(__ANDROID__)
74 ((AndroidThread*)threadId)->requestExit();
75 delete (::android::Thread*)threadId;
Pierre Ossman687d52c2015-11-12 12:16:08 +010076#else
77 if (isRunning())
78 pthread_cancel(*(pthread_t*)threadId);
79 delete (pthread_t*)threadId;
80#endif
81
82 delete mutex;
83}
84
85void Thread::start()
86{
87 AutoMutex a(mutex);
88
89#ifdef WIN32
90 *(HANDLE*)threadId = CreateThread(NULL, 0, startRoutine, this, 0, NULL);
91 if (*(HANDLE*)threadId == NULL)
92 throw rdr::SystemException("Failed to create thread", GetLastError());
Steve Kondik2b563712017-06-19 23:14:18 -070093#elif defined(__ANDROID__)
94 ((AndroidThread*)threadId)->run(NULL);
Pierre Ossman687d52c2015-11-12 12:16:08 +010095#else
96 int ret;
Pierre Ossmana6b00262016-01-04 14:19:15 +010097 sigset_t all, old;
98
99 // Creating threads from libraries is a bit evil, so mitigate the
100 // issue by at least avoiding signals on these threads
101 sigfillset(&all);
102 ret = pthread_sigmask(SIG_SETMASK, &all, &old);
103 if (ret != 0)
104 throw rdr::SystemException("Failed to mask signals", ret);
Pierre Ossman687d52c2015-11-12 12:16:08 +0100105
106 ret = pthread_create((pthread_t*)threadId, NULL, startRoutine, this);
Pierre Ossmana6b00262016-01-04 14:19:15 +0100107
108 pthread_sigmask(SIG_SETMASK, &old, NULL);
109
Pierre Ossman687d52c2015-11-12 12:16:08 +0100110 if (ret != 0)
111 throw rdr::SystemException("Failed to create thread", ret);
112#endif
113
114 running = true;
115}
116
117void Thread::wait()
118{
119 if (!isRunning())
120 return;
121
122#ifdef WIN32
123 DWORD ret;
124
125 ret = WaitForSingleObject(*(HANDLE*)threadId, INFINITE);
126 if (ret != WAIT_OBJECT_0)
127 throw rdr::SystemException("Failed to join thread", GetLastError());
Steve Kondik2b563712017-06-19 23:14:18 -0700128#elif defined(__ANDROID__)
129 ::android::status_t ret;
130
131 ret = ((AndroidThread*)threadId)->join();
132 if (ret != ::android::NO_ERROR)
133 throw rdr::SystemException("Failed to join thread", ret);
Pierre Ossman687d52c2015-11-12 12:16:08 +0100134#else
135 int ret;
136
137 ret = pthread_join(*(pthread_t*)threadId, NULL);
138 if (ret != 0)
139 throw rdr::SystemException("Failed to join thread", ret);
140#endif
141}
142
143bool Thread::isRunning()
144{
Steve Kondik2b563712017-06-19 23:14:18 -0700145#if defined(__ANDROID__)
146 return ((::android::Thread*)threadId)->isRunning();
147#else
Pierre Ossman687d52c2015-11-12 12:16:08 +0100148 AutoMutex a(mutex);
149
150 return running;
Steve Kondik2b563712017-06-19 23:14:18 -0700151#endif
Pierre Ossman687d52c2015-11-12 12:16:08 +0100152}
153
Pierre Ossman7b63a7c2015-11-13 14:07:52 +0100154size_t Thread::getSystemCPUCount()
155{
156#ifdef WIN32
157 SYSTEM_INFO si;
158 size_t count;
159 DWORD mask;
160
161 GetSystemInfo(&si);
162
163 count = 0;
164 for (mask = si.dwActiveProcessorMask;mask != 0;mask >>= 1) {
165 if (mask & 0x1)
166 count++;
167 }
168
169 if (count > si.dwNumberOfProcessors)
170 count = si.dwNumberOfProcessors;
171
172 return count;
173#else
174 long ret;
175
176 ret = sysconf(_SC_NPROCESSORS_ONLN);
177 if (ret == -1)
178 return 0;
179
180 return ret;
181#endif
182}
183
Pierre Ossman687d52c2015-11-12 12:16:08 +0100184#ifdef WIN32
185long unsigned __stdcall Thread::startRoutine(void* data)
186#else
187void* Thread::startRoutine(void* data)
188#endif
189{
190 Thread *self;
191
192 self = (Thread*)data;
193
194 try {
195 self->worker();
196 } catch(...) {
197 }
198
199 self->mutex->lock();
200 self->running = false;
201 self->mutex->unlock();
202
203 return 0;
204}