xref: /aosp_15_r20/external/deqp/framework/delibs/dethread/unix/deThreadUnix.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
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