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
49typedef struct Thread_s
50{
51	pthread_t		thread;
52	deThreadFunc	func;
53	void*			arg;
54} Thread;
55
56DE_STATIC_ASSERT(sizeof(deThread) >= sizeof(Thread*));
57
58static 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
70deThread 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
110deBool 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
128void 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
143void 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
156void deYield (void)
157{
158	sched_yield();
159}
160
161#if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
162
163deUint32 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
194deUint32 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
210deUint32 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
224deUint32 deGetNumTotalPhysicalCores (void)
225{
226	/* \todo [2015-04-09 pyry] Parse /proc/cpuinfo perhaps? */
227	return deGetNumTotalLogicalCores();
228}
229
230#endif /* DE_OS */
231