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 || DE_OS == DE_OS_IOS)
27
28 #include "deMemory.h"
29 #include "deInt32.h"
30
31 #if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 500)
32 # error "You are using too old posix API!"
33 #endif
34
35 #include <unistd.h>
36 #include <pthread.h>
37 #include <sched.h>
38 #include <sys/syscall.h>
39
40 #if (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
41 # if !defined(_SC_NPROCESSORS_CONF)
42 # define _SC_NPROCESSORS_CONF 57
43 # endif
44 # if !defined(_SC_NPROCESSORS_ONLN)
45 # define _SC_NPROCESSORS_ONLN 58
46 # endif
47 #endif
48
49 typedef struct Thread_s
50 {
51 pthread_t thread;
52 deThreadFunc func;
53 void* arg;
54 } Thread;
55
56 DE_STATIC_ASSERT(sizeof(deThread) >= sizeof(Thread*));
57
startThread(void * entryPtr)58 static void* startThread (void* entryPtr)
59 {
60 Thread* thread = (Thread*)entryPtr;
61 deThreadFunc func = thread->func;
62 void* arg = thread->arg;
63
64 /* Start actual thread. */
65 func(arg);
66
67 return DE_NULL;
68 }
69
deThread_create(deThreadFunc func,void * arg,const deThreadAttributes * attributes)70 deThread deThread_create (deThreadFunc func, void* arg, const deThreadAttributes* attributes)
71 {
72 pthread_attr_t attr;
73 Thread* thread = (Thread*)deCalloc(sizeof(Thread));
74
75 if (!thread)
76 return 0;
77
78 thread->func = func;
79 thread->arg = arg;
80
81 if (pthread_attr_init(&attr) != 0)
82 {
83 deFree(thread);
84 return 0;
85 }
86
87 /* \todo [2009-11-12 pyry] Map attributes. */
88 DE_UNREF(attributes);
89
90 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) != 0)
91 {
92 pthread_attr_destroy(&attr);
93 deFree(thread);
94 return 0;
95 }
96
97 if (pthread_create(&thread->thread, &attr, startThread, thread) != 0)
98 {
99 pthread_attr_destroy(&attr);
100 deFree(thread);
101 return 0;
102 }
103 DE_ASSERT(thread->thread);
104
105 pthread_attr_destroy(&attr);
106
107 return (deThread)thread;
108 }
109
deThread_join(deThread threadptr)110 deBool deThread_join (deThread threadptr)
111 {
112 Thread* thread = (Thread*)threadptr;
113 int ret;
114
115 DE_ASSERT(thread->thread);
116 ret = pthread_join(thread->thread, DE_NULL);
117
118 /* If join fails for some reason, at least mark as detached. */
119 if (ret != 0)
120 pthread_detach(thread->thread);
121
122 /* Thread is no longer valid as far as we are concerned. */
123 thread->thread = 0;
124
125 return (ret == 0);
126 }
127
deThread_destroy(deThread threadptr)128 void deThread_destroy (deThread threadptr)
129 {
130 Thread* thread = (Thread*)threadptr;
131
132 if (thread->thread)
133 {
134 /* Not joined, detach. */
135 int ret = pthread_detach(thread->thread);
136 DE_ASSERT(ret == 0);
137 DE_UNREF(ret);
138 }
139
140 deFree(thread);
141 }
142
deSleep(deUint32 milliseconds)143 void deSleep (deUint32 milliseconds)
144 {
145 /* Maximum value for usleep is 10^6. */
146 deUint32 seconds = milliseconds / 1000;
147
148 milliseconds = milliseconds - seconds * 1000;
149
150 if (seconds > 0)
151 sleep(seconds);
152
153 usleep((useconds_t)milliseconds * (useconds_t)1000);
154 }
155
deYield(void)156 void deYield (void)
157 {
158 sched_yield();
159 }
160
161 #if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
162
deGetNumAvailableLogicalCores(void)163 deUint32 deGetNumAvailableLogicalCores (void)
164 {
165 unsigned long mask = 0;
166 const unsigned int maskSize = sizeof(mask);
167 long ret;
168
169 deMemset(&mask, 0, sizeof(mask));
170
171 ret = syscall(__NR_sched_getaffinity, 0, maskSize, &mask);
172
173 if (ret > 0)
174 {
175 return (deUint32)dePop64(mask);
176 }
177 else
178 {
179 #if defined(_SC_NPROCESSORS_ONLN)
180 const long count = sysconf(_SC_NPROCESSORS_ONLN);
181
182 if (count <= 0)
183 return 1;
184 else
185 return (deUint32)count;
186 #else
187 return 1;
188 #endif
189 }
190 }
191
192 #else
193
deGetNumAvailableLogicalCores(void)194 deUint32 deGetNumAvailableLogicalCores (void)
195 {
196 #if defined(_SC_NPROCESSORS_ONLN)
197 const long count = sysconf(_SC_NPROCESSORS_ONLN);
198
199 if (count <= 0)
200 return 1;
201 else
202 return (deUint32)count;
203 #else
204 return 1;
205 #endif
206 }
207
208 #endif
209
deGetNumTotalLogicalCores(void)210 deUint32 deGetNumTotalLogicalCores (void)
211 {
212 #if defined(_SC_NPROCESSORS_CONF)
213 const long count = sysconf(_SC_NPROCESSORS_CONF);
214
215 if (count <= 0)
216 return 1;
217 else
218 return (deUint32)count;
219 #else
220 return 1;
221 #endif
222 }
223
deGetNumTotalPhysicalCores(void)224 deUint32 deGetNumTotalPhysicalCores (void)
225 {
226 /* \todo [2015-04-09 pyry] Parse /proc/cpuinfo perhaps? */
227 return deGetNumTotalLogicalCores();
228 }
229
230 #endif /* DE_OS */
231