1 /*-------------------------------------------------------------------------
2 * drawElements Thread Library
3 * ---------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Unix implementation of thread management.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deThread.h"
25
26 #if (DE_OS == DE_OS_UNIX || DE_OS == DE_OS_OSX || DE_OS == DE_OS_ANDROID || DE_OS == DE_OS_SYMBIAN || \
27 DE_OS == DE_OS_IOS || DE_OS == DE_OS_QNX || DE_OS == DE_OS_FUCHSIA)
28
29 #include "deMemory.h"
30 #include "deInt32.h"
31
32 #if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 500)
33 #error "You are using too old posix API!"
34 #endif
35
36 #include <unistd.h>
37 #include <pthread.h>
38 #include <sched.h>
39 #if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
40 #include <sys/syscall.h>
41 #endif
42
43 #if (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
44 #if !defined(_SC_NPROCESSORS_CONF)
45 #define _SC_NPROCESSORS_CONF 57
46 #endif
47 #if !defined(_SC_NPROCESSORS_ONLN)
48 #define _SC_NPROCESSORS_ONLN 58
49 #endif
50 #endif
51
52 typedef struct Thread_s
53 {
54 pthread_t thread;
55 deThreadFunc func;
56 void *arg;
57 } Thread;
58
59 DE_STATIC_ASSERT(sizeof(deThread) >= sizeof(Thread *));
60
startThread(void * entryPtr)61 static void *startThread(void *entryPtr)
62 {
63 Thread *thread = (Thread *)entryPtr;
64 deThreadFunc func = thread->func;
65 void *arg = thread->arg;
66
67 /* Start actual thread. */
68 func(arg);
69
70 return DE_NULL;
71 }
72
deThread_create(deThreadFunc func,void * arg,const deThreadAttributes * attributes)73 deThread deThread_create(deThreadFunc func, void *arg, const deThreadAttributes *attributes)
74 {
75 pthread_attr_t attr;
76 Thread *thread = (Thread *)deCalloc(sizeof(Thread));
77
78 if (!thread)
79 return 0;
80
81 thread->func = func;
82 thread->arg = arg;
83
84 if (pthread_attr_init(&attr) != 0)
85 {
86 deFree(thread);
87 return 0;
88 }
89
90 /* \todo [2009-11-12 pyry] Map attributes. */
91 DE_UNREF(attributes);
92
93 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) != 0)
94 {
95 pthread_attr_destroy(&attr);
96 deFree(thread);
97 return 0;
98 }
99
100 if (pthread_create(&thread->thread, &attr, startThread, thread) != 0)
101 {
102 pthread_attr_destroy(&attr);
103 deFree(thread);
104 return 0;
105 }
106 DE_ASSERT(thread->thread);
107
108 pthread_attr_destroy(&attr);
109
110 return (deThread)thread;
111 }
112
deThread_join(deThread threadptr)113 bool deThread_join(deThread threadptr)
114 {
115 Thread *thread = (Thread *)threadptr;
116 int ret;
117
118 DE_ASSERT(thread->thread);
119 ret = pthread_join(thread->thread, DE_NULL);
120
121 /* If join fails for some reason, at least mark as detached. */
122 if (ret != 0)
123 pthread_detach(thread->thread);
124
125 /* Thread is no longer valid as far as we are concerned. */
126 thread->thread = 0;
127
128 return (ret == 0);
129 }
130
deThread_destroy(deThread threadptr)131 void deThread_destroy(deThread threadptr)
132 {
133 Thread *thread = (Thread *)threadptr;
134
135 if (thread->thread)
136 {
137 /* Not joined, detach. */
138 int ret = pthread_detach(thread->thread);
139 DE_ASSERT(ret == 0);
140 DE_UNREF(ret);
141 }
142
143 deFree(thread);
144 }
145
deSleep(uint32_t milliseconds)146 void deSleep(uint32_t milliseconds)
147 {
148 /* Maximum value for usleep is 10^6. */
149 uint32_t seconds = milliseconds / 1000;
150
151 milliseconds = milliseconds - seconds * 1000;
152
153 if (seconds > 0)
154 sleep(seconds);
155
156 usleep((useconds_t)milliseconds * (useconds_t)1000);
157 }
158
deYield(void)159 void deYield(void)
160 {
161 sched_yield();
162 }
163
164 #if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
165
deGetNumAvailableLogicalCores(void)166 uint32_t deGetNumAvailableLogicalCores(void)
167 {
168 #if !defined(__FreeBSD__)
169 unsigned long mask = 0;
170 const unsigned int maskSize = sizeof(mask);
171 long ret;
172
173 deMemset(&mask, 0, sizeof(mask));
174
175 ret = syscall(__NR_sched_getaffinity, 0, maskSize, &mask);
176
177 if (ret > 0)
178 {
179 return (uint32_t)dePop64(mask);
180 }
181 else
182 {
183 #endif
184 #if defined(_SC_NPROCESSORS_ONLN)
185 const long count = sysconf(_SC_NPROCESSORS_ONLN);
186
187 if (count <= 0)
188 return 1;
189 else
190 return (uint32_t)count;
191 #else
192 return 1;
193 #endif
194
195 #if !defined(__FreeBSD__)
196 }
197 #endif
198 }
199
200 #else
201
deGetNumAvailableLogicalCores(void)202 uint32_t deGetNumAvailableLogicalCores(void)
203 {
204 #if defined(_SC_NPROCESSORS_ONLN)
205 const long count = sysconf(_SC_NPROCESSORS_ONLN);
206
207 if (count <= 0)
208 return 1;
209 else
210 return (uint32_t)count;
211 #else
212 return 1;
213 #endif
214 }
215
216 #endif
217
deGetNumTotalLogicalCores(void)218 uint32_t deGetNumTotalLogicalCores(void)
219 {
220 #if defined(_SC_NPROCESSORS_CONF)
221 const long count = sysconf(_SC_NPROCESSORS_CONF);
222
223 if (count <= 0)
224 return 1;
225 else
226 return (uint32_t)count;
227 #else
228 return 1;
229 #endif
230 }
231
deGetNumTotalPhysicalCores(void)232 uint32_t deGetNumTotalPhysicalCores(void)
233 {
234 /* \todo [2015-04-09 pyry] Parse /proc/cpuinfo perhaps? */
235 return deGetNumTotalLogicalCores();
236 }
237
238 #endif /* DE_OS */
239