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