/src/openh264/codec/common/src/WelsThreadLib.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /*! |
2 | | * \copy |
3 | | * Copyright (c) 2009-2013, Cisco Systems |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * * Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * * Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in |
15 | | * the documentation and/or other materials provided with the |
16 | | * distribution. |
17 | | * |
18 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
21 | | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
22 | | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
23 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
24 | | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
26 | | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
28 | | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | | * POSSIBILITY OF SUCH DAMAGE. |
30 | | * |
31 | | * |
32 | | * \file WelsThreadLib.c |
33 | | * |
34 | | * \brief Interfaces introduced in thread programming |
35 | | * |
36 | | * \date 11/17/2009 Created |
37 | | * |
38 | | ************************************************************************************* |
39 | | */ |
40 | | |
41 | | |
42 | | #if defined(__linux__) || defined(__GNU__) |
43 | | #ifndef _GNU_SOURCE |
44 | | #define _GNU_SOURCE |
45 | | #endif |
46 | | #include <sched.h> |
47 | | #elif !defined(_WIN32) && !defined(__CYGWIN__) |
48 | | #include <sys/types.h> |
49 | | #include <sys/param.h> |
50 | | #include <unistd.h> |
51 | | #ifdef __EMSCRIPTEN__ |
52 | | #include <emscripten/threading.h> |
53 | | #elif !defined(__Fuchsia__) |
54 | | #include <sys/sysctl.h> |
55 | | #endif |
56 | | #ifdef __APPLE__ |
57 | | #define HW_NCPU_NAME "hw.logicalcpu" |
58 | | #elif defined(HW_NCPUONLINE) |
59 | | #define HW_NCPU_NAME "hw.ncpuonline" |
60 | | #else |
61 | | #define HW_NCPU_NAME "hw.ncpu" |
62 | | #endif |
63 | | #endif |
64 | | #ifdef ANDROID_NDK |
65 | | #include <cpu-features.h> |
66 | | #endif |
67 | | #ifdef __ANDROID__ |
68 | | #include <android/api-level.h> |
69 | | #endif |
70 | | |
71 | | #include "WelsThreadLib.h" |
72 | | #include <stdio.h> |
73 | | #include <stdlib.h> |
74 | | |
75 | | |
76 | | #if defined(_WIN32) || defined(__CYGWIN__) |
77 | | |
78 | | WELS_THREAD_ERROR_CODE WelsMutexInit (WELS_MUTEX* mutex) { |
79 | | InitializeCriticalSection (mutex); |
80 | | |
81 | | return WELS_THREAD_ERROR_OK; |
82 | | } |
83 | | |
84 | | WELS_THREAD_ERROR_CODE WelsMutexLock (WELS_MUTEX* mutex) { |
85 | | EnterCriticalSection (mutex); |
86 | | |
87 | | return WELS_THREAD_ERROR_OK; |
88 | | } |
89 | | |
90 | | WELS_THREAD_ERROR_CODE WelsMutexUnlock (WELS_MUTEX* mutex) { |
91 | | LeaveCriticalSection (mutex); |
92 | | |
93 | | return WELS_THREAD_ERROR_OK; |
94 | | } |
95 | | |
96 | | WELS_THREAD_ERROR_CODE WelsMutexDestroy (WELS_MUTEX* mutex) { |
97 | | DeleteCriticalSection (mutex); |
98 | | |
99 | | return WELS_THREAD_ERROR_OK; |
100 | | } |
101 | | |
102 | | #else /* _WIN32 */ |
103 | | |
104 | 0 | WELS_THREAD_ERROR_CODE WelsMutexInit (WELS_MUTEX* mutex) { |
105 | 0 | return pthread_mutex_init (mutex, NULL); |
106 | 0 | } |
107 | | |
108 | 0 | WELS_THREAD_ERROR_CODE WelsMutexLock (WELS_MUTEX* mutex) { |
109 | 0 | return pthread_mutex_lock (mutex); |
110 | 0 | } |
111 | | |
112 | 0 | WELS_THREAD_ERROR_CODE WelsMutexUnlock (WELS_MUTEX* mutex) { |
113 | 0 | return pthread_mutex_unlock (mutex); |
114 | 0 | } |
115 | | |
116 | 0 | WELS_THREAD_ERROR_CODE WelsMutexDestroy (WELS_MUTEX* mutex) { |
117 | 0 | return pthread_mutex_destroy (mutex); |
118 | 0 | } |
119 | | |
120 | | #endif /* !_WIN32 */ |
121 | | |
122 | | #if defined(_WIN32) || defined(__CYGWIN__) |
123 | | |
124 | | WELS_THREAD_ERROR_CODE WelsEventOpen (WELS_EVENT* event, const char* event_name) { |
125 | | WELS_EVENT h = CreateEvent (NULL, FALSE, FALSE, NULL); |
126 | | *event = h; |
127 | | if (h == NULL) { |
128 | | return WELS_THREAD_ERROR_GENERAL; |
129 | | } |
130 | | return WELS_THREAD_ERROR_OK; |
131 | | } |
132 | | |
133 | | WELS_THREAD_ERROR_CODE WelsEventSignal (WELS_EVENT* event, WELS_MUTEX *pMutex, int* iCondition) { |
134 | | (*iCondition) --; |
135 | | if ((*iCondition) <= 0) { |
136 | | if (SetEvent (*event)) { |
137 | | return WELS_THREAD_ERROR_OK; |
138 | | } |
139 | | } |
140 | | return WELS_THREAD_ERROR_GENERAL; |
141 | | } |
142 | | |
143 | | WELS_THREAD_ERROR_CODE WelsEventWait (WELS_EVENT* event, WELS_MUTEX* pMutex, int& iCondition) { |
144 | | return WaitForSingleObject (*event, INFINITE); |
145 | | } |
146 | | |
147 | | WELS_THREAD_ERROR_CODE WelsEventWaitWithTimeOut (WELS_EVENT* event, uint32_t dwMilliseconds, WELS_MUTEX* pMutex) { |
148 | | return WaitForSingleObject (*event, dwMilliseconds); |
149 | | } |
150 | | |
151 | | WELS_THREAD_ERROR_CODE WelsMultipleEventsWaitSingleBlocking (uint32_t nCount, |
152 | | WELS_EVENT* event_list, WELS_EVENT* master_even, WELS_MUTEX* pMutext) { |
153 | | // Don't need/use the master event for anything, since windows has got WaitForMultipleObjects |
154 | | return WaitForMultipleObjects (nCount, event_list, FALSE, INFINITE); |
155 | | } |
156 | | |
157 | | WELS_THREAD_ERROR_CODE WelsEventClose (WELS_EVENT* event, const char* event_name) { |
158 | | CloseHandle (*event); |
159 | | |
160 | | *event = NULL; |
161 | | return WELS_THREAD_ERROR_OK; |
162 | | } |
163 | | |
164 | | #ifndef WP80 |
165 | | void WelsSleep (uint32_t dwMilliSecond) { |
166 | | ::Sleep (dwMilliSecond); |
167 | | } |
168 | | #else |
169 | | void WelsSleep (uint32_t dwMilliSecond) { |
170 | | static WELS_EVENT hSleepEvent = NULL; |
171 | | if (!hSleepEvent) { |
172 | | WELS_EVENT hLocalSleepEvent = NULL; |
173 | | WELS_THREAD_ERROR_CODE ret = WelsEventOpen (&hLocalSleepEvent); |
174 | | if (WELS_THREAD_ERROR_OK != ret) { |
175 | | return; |
176 | | } |
177 | | WELS_EVENT hPreviousEvent = InterlockedCompareExchangePointerRelease (&hSleepEvent, hLocalSleepEvent, NULL); |
178 | | if (hPreviousEvent) { |
179 | | WelsEventClose (&hLocalSleepEvent); |
180 | | } |
181 | | //On this singleton usage idea of using InterlockedCompareExchangePointerRelease: |
182 | | // similar idea of can be found at msdn blog when introducing InterlockedCompareExchangePointerRelease |
183 | | } |
184 | | |
185 | | WaitForSingleObject (hSleepEvent, dwMilliSecond); |
186 | | } |
187 | | #endif |
188 | | |
189 | | WELS_THREAD_ERROR_CODE WelsThreadCreate (WELS_THREAD_HANDLE* thread, LPWELS_THREAD_ROUTINE routine, |
190 | | void* arg, WELS_THREAD_ATTR attr) { |
191 | | WELS_THREAD_HANDLE h = CreateThread (NULL, 0, routine, arg, 0, NULL); |
192 | | |
193 | | if (h == NULL) { |
194 | | return WELS_THREAD_ERROR_GENERAL; |
195 | | } |
196 | | * thread = h; |
197 | | |
198 | | return WELS_THREAD_ERROR_OK; |
199 | | } |
200 | | |
201 | | WELS_THREAD_ERROR_CODE WelsThreadSetName (const char* thread_name) { |
202 | | // do nothing |
203 | | return WELS_THREAD_ERROR_OK; |
204 | | } |
205 | | |
206 | | |
207 | | WELS_THREAD_ERROR_CODE WelsThreadJoin (WELS_THREAD_HANDLE thread) { |
208 | | WaitForSingleObject (thread, INFINITE); |
209 | | CloseHandle (thread); |
210 | | |
211 | | return WELS_THREAD_ERROR_OK; |
212 | | } |
213 | | |
214 | | |
215 | | WELS_THREAD_HANDLE WelsThreadSelf() { |
216 | | return GetCurrentThread(); |
217 | | } |
218 | | |
219 | | WELS_THREAD_ERROR_CODE WelsQueryLogicalProcessInfo (WelsLogicalProcessInfo* pInfo) { |
220 | | SYSTEM_INFO si; |
221 | | |
222 | | GetSystemInfo (&si); |
223 | | |
224 | | pInfo->ProcessorCount = si.dwNumberOfProcessors; |
225 | | |
226 | | return WELS_THREAD_ERROR_OK; |
227 | | } |
228 | | |
229 | | #else //platform: #ifdef _WIN32 |
230 | | |
231 | | WELS_THREAD_ERROR_CODE WelsThreadCreate (WELS_THREAD_HANDLE* thread, LPWELS_THREAD_ROUTINE routine, |
232 | 0 | void* arg, WELS_THREAD_ATTR attr) { |
233 | 0 | WELS_THREAD_ERROR_CODE err = 0; |
234 | |
|
235 | 0 | pthread_attr_t at; |
236 | 0 | err = pthread_attr_init (&at); |
237 | 0 | if (err) |
238 | 0 | return err; |
239 | 0 | #if !defined(__ANDROID__) && !defined(__Fuchsia__) |
240 | 0 | err = pthread_attr_setscope (&at, PTHREAD_SCOPE_SYSTEM); |
241 | 0 | if (err) |
242 | 0 | return err; |
243 | 0 | err = pthread_attr_setschedpolicy (&at, SCHED_FIFO); |
244 | 0 | if (err) |
245 | 0 | return err; |
246 | 0 | #endif |
247 | 0 | err = pthread_create (thread, &at, routine, arg); |
248 | |
|
249 | 0 | pthread_attr_destroy (&at); |
250 | |
|
251 | 0 | return err; |
252 | 0 | } |
253 | | |
254 | 0 | WELS_THREAD_ERROR_CODE WelsThreadSetName (const char* thread_name) { |
255 | | #ifdef APPLE_IOS |
256 | | pthread_setname_np (thread_name); |
257 | | #endif |
258 | | #if defined(__ANDROID__) && __ANDROID_API__ >= 9 |
259 | | pthread_setname_np (pthread_self(), thread_name); |
260 | | #endif |
261 | | // do nothing |
262 | 0 | return WELS_THREAD_ERROR_OK; |
263 | 0 | } |
264 | | |
265 | 0 | WELS_THREAD_ERROR_CODE WelsThreadJoin (WELS_THREAD_HANDLE thread) { |
266 | 0 | return pthread_join (thread, NULL); |
267 | 0 | } |
268 | | |
269 | 0 | WELS_THREAD_HANDLE WelsThreadSelf() { |
270 | 0 | return pthread_self(); |
271 | 0 | } |
272 | | |
273 | | // unnamed semaphores aren't supported on OS X |
274 | | |
275 | 0 | WELS_THREAD_ERROR_CODE WelsEventOpen (WELS_EVENT* p_event, const char* event_name) { |
276 | | #ifdef __APPLE__ |
277 | | WELS_THREAD_ERROR_CODE err= pthread_cond_init (p_event, NULL); |
278 | | return err; |
279 | | #else |
280 | 0 | WELS_EVENT event = (WELS_EVENT) malloc (sizeof (*event)); |
281 | 0 | if (event == NULL){ |
282 | 0 | *p_event = NULL; |
283 | 0 | return WELS_THREAD_ERROR_GENERAL; |
284 | 0 | } |
285 | 0 | WELS_THREAD_ERROR_CODE err = sem_init (event, 0, 0); |
286 | 0 | if (!err) { |
287 | 0 | *p_event = event; |
288 | 0 | return err; |
289 | 0 | } |
290 | 0 | free (event); |
291 | 0 | *p_event = NULL; |
292 | 0 | return err; |
293 | 0 | #endif |
294 | 0 | } |
295 | 0 | WELS_THREAD_ERROR_CODE WelsEventClose (WELS_EVENT* event, const char* event_name) { |
296 | | //printf("event_close:%x, %s\n", event, event_name); |
297 | | #ifdef __APPLE__ |
298 | | WELS_THREAD_ERROR_CODE err = pthread_cond_destroy (event); |
299 | | return err; |
300 | | #else |
301 | 0 | WELS_THREAD_ERROR_CODE err = sem_destroy (*event); // match with sem_init |
302 | 0 | free (*event); |
303 | 0 | *event = NULL; |
304 | 0 | return err; |
305 | 0 | #endif |
306 | 0 | } |
307 | | |
308 | 0 | void WelsSleep (uint32_t dwMilliSecond) { |
309 | 0 | usleep (dwMilliSecond * 1000); |
310 | 0 | } |
311 | | |
312 | 0 | WELS_THREAD_ERROR_CODE WelsEventSignal (WELS_EVENT* event, WELS_MUTEX *pMutex, int* iCondition) { |
313 | 0 | WELS_THREAD_ERROR_CODE err = 0; |
314 | | //fprintf( stderr, "before signal it, event=%x iCondition= %d..\n", event, *iCondition ); |
315 | | #ifdef __APPLE__ |
316 | | WelsMutexLock (pMutex); |
317 | | (*iCondition) --; |
318 | | WelsMutexUnlock (pMutex); |
319 | | if ((*iCondition) <= 0) { |
320 | | err = pthread_cond_signal (event); |
321 | | //fprintf( stderr, "signal it, event=%x iCondition= %d..\n",event, *iCondition ); |
322 | | |
323 | | } |
324 | | #else |
325 | 0 | (*iCondition) --; |
326 | 0 | if ((*iCondition) <= 0) { |
327 | | // int32_t val = 0; |
328 | | // sem_getvalue(event, &val); |
329 | | // fprintf( stderr, "before signal it, val= %d..\n",val ); |
330 | 0 | if (event != NULL) |
331 | 0 | err = sem_post (*event); |
332 | | // sem_getvalue(event, &val); |
333 | | //fprintf( stderr, "signal it, event=%x iCondition= %d..\n",event, *iCondition ); |
334 | 0 | } |
335 | 0 | #endif |
336 | | //fprintf( stderr, "after signal it, event=%x iCondition= %d..\n",event, *iCondition ); |
337 | 0 | return err; |
338 | 0 | } |
339 | | |
340 | 0 | WELS_THREAD_ERROR_CODE WelsEventWait (WELS_EVENT* event, WELS_MUTEX* pMutex, int& iCondition) { |
341 | | #ifdef __APPLE__ |
342 | | int err = 0; |
343 | | WelsMutexLock(pMutex); |
344 | | //fprintf( stderr, "WelsEventWait event %x %d..\n", event, iCondition ); |
345 | | while (iCondition>0) { |
346 | | err = pthread_cond_wait (event, pMutex); |
347 | | } |
348 | | WelsMutexUnlock(pMutex); |
349 | | return err; |
350 | | #else |
351 | 0 | return sem_wait (*event); // blocking until signaled |
352 | 0 | #endif |
353 | 0 | } |
354 | | |
355 | 0 | WELS_THREAD_ERROR_CODE WelsEventWaitWithTimeOut (WELS_EVENT* event, uint32_t dwMilliseconds, WELS_MUTEX* pMutex) { |
356 | |
|
357 | 0 | if (dwMilliseconds != (uint32_t) - 1) { |
358 | | #if defined(__APPLE__) |
359 | | return pthread_cond_wait (event, pMutex); |
360 | | #else |
361 | 0 | return sem_wait (*event); |
362 | 0 | #endif |
363 | 0 | } else { |
364 | 0 | struct timespec ts; |
365 | 0 | struct timeval tv; |
366 | |
|
367 | 0 | gettimeofday (&tv, 0); |
368 | |
|
369 | 0 | ts.tv_nsec = tv.tv_usec * 1000 + dwMilliseconds * 1000000; |
370 | 0 | ts.tv_sec = tv.tv_sec + ts.tv_nsec / 1000000000; |
371 | 0 | ts.tv_nsec %= 1000000000; |
372 | |
|
373 | | #if defined(__APPLE__) |
374 | | return pthread_cond_timedwait (event, pMutex, &ts); |
375 | | #else |
376 | 0 | return sem_timedwait (*event, &ts); |
377 | 0 | #endif |
378 | 0 | } |
379 | |
|
380 | 0 | } |
381 | | |
382 | | WELS_THREAD_ERROR_CODE WelsMultipleEventsWaitSingleBlocking (uint32_t nCount, |
383 | 0 | WELS_EVENT* event_list, WELS_EVENT* master_event, WELS_MUTEX* pMutex) { |
384 | 0 | uint32_t nIdx = 0; |
385 | 0 | uint32_t uiAccessTime = 2; // 2 us once |
386 | |
|
387 | 0 | if (nCount == 0) |
388 | 0 | return WELS_THREAD_ERROR_WAIT_FAILED; |
389 | | #if defined(__APPLE__) |
390 | | if (master_event != NULL) { |
391 | | // This design relies on the events actually being semaphores; |
392 | | // if multiple events in the list have been signalled, the master |
393 | | // event should have a similar count (events in windows can't keep |
394 | | // track of the actual count, but the master event isn't needed there |
395 | | // since it uses WaitForMultipleObjects). |
396 | | int32_t err = pthread_cond_wait (master_event, pMutex); |
397 | | if (err != WELS_THREAD_ERROR_OK) |
398 | | return err; |
399 | | uiAccessTime = 0; // no blocking, just quickly loop through all to find the one that was signalled |
400 | | } |
401 | | |
402 | | while (1) { |
403 | | nIdx = 0; // access each event by order |
404 | | while (nIdx < nCount) { |
405 | | int32_t err = 0; |
406 | | int32_t wait_count = 0; |
407 | | |
408 | | /* |
409 | | * although such interface is not used in __GNUC__ like platform, to use |
410 | | * pthread_cond_timedwait() might be better choice if need |
411 | | */ |
412 | | do { |
413 | | err = pthread_cond_wait (&event_list[nIdx], pMutex); |
414 | | if (WELS_THREAD_ERROR_OK == err) |
415 | | return WELS_THREAD_ERROR_WAIT_OBJECT_0 + nIdx; |
416 | | else if (wait_count > 0 || uiAccessTime == 0) |
417 | | break; |
418 | | usleep (uiAccessTime); |
419 | | ++ wait_count; |
420 | | } while (1); |
421 | | // we do need access next event next time |
422 | | ++ nIdx; |
423 | | } |
424 | | usleep (1); // switch to working threads |
425 | | if (master_event != NULL) { |
426 | | // A master event was used and was signalled, but none of the events in the |
427 | | // list was found to be signalled, thus wait a little more when rechecking |
428 | | // the list to avoid busylooping here. |
429 | | // If we ever hit this codepath it's mostly a bug in the code that signals |
430 | | // the events. |
431 | | uiAccessTime = 2; |
432 | | } |
433 | | } |
434 | | #else |
435 | 0 | if (master_event != NULL) { |
436 | | // This design relies on the events actually being semaphores; |
437 | | // if multiple events in the list have been signalled, the master |
438 | | // event should have a similar count (events in windows can't keep |
439 | | // track of the actual count, but the master event isn't needed there |
440 | | // since it uses WaitForMultipleObjects). |
441 | 0 | int32_t err = sem_wait (*master_event); |
442 | 0 | if (err != WELS_THREAD_ERROR_OK) |
443 | 0 | return err; |
444 | 0 | uiAccessTime = 0; // no blocking, just quickly loop through all to find the one that was signalled |
445 | 0 | } |
446 | | |
447 | 0 | while (1) { |
448 | 0 | nIdx = 0; // access each event by order |
449 | 0 | while (nIdx < nCount) { |
450 | 0 | int32_t err = 0; |
451 | 0 | int32_t wait_count = 0; |
452 | | |
453 | | /* |
454 | | * although such interface is not used in __GNUC__ like platform, to use |
455 | | * pthread_cond_timedwait() might be better choice if need |
456 | | */ |
457 | 0 | do { |
458 | 0 | err = sem_trywait (event_list[nIdx]); |
459 | 0 | if (WELS_THREAD_ERROR_OK == err) |
460 | 0 | return WELS_THREAD_ERROR_WAIT_OBJECT_0 + nIdx; |
461 | 0 | else if (wait_count > 0 || uiAccessTime == 0) |
462 | 0 | break; |
463 | 0 | usleep (uiAccessTime); |
464 | 0 | ++ wait_count; |
465 | 0 | } while (1); |
466 | | // we do need access next event next time |
467 | 0 | ++ nIdx; |
468 | 0 | } |
469 | 0 | usleep (1); // switch to working threads |
470 | 0 | if (master_event != NULL) { |
471 | | // A master event was used and was signalled, but none of the events in the |
472 | | // list was found to be signalled, thus wait a little more when rechecking |
473 | | // the list to avoid busylooping here. |
474 | | // If we ever hit this codepath it's mostly a bug in the code that signals |
475 | | // the events. |
476 | 0 | uiAccessTime = 2; |
477 | 0 | } |
478 | 0 | } |
479 | | |
480 | 0 | #endif |
481 | 0 | return WELS_THREAD_ERROR_WAIT_FAILED; |
482 | 0 | } |
483 | | |
484 | 0 | WELS_THREAD_ERROR_CODE WelsQueryLogicalProcessInfo (WelsLogicalProcessInfo* pInfo) { |
485 | | #ifdef ANDROID_NDK |
486 | | pInfo->ProcessorCount = android_getCpuCount(); |
487 | | return WELS_THREAD_ERROR_OK; |
488 | | #elif defined(__linux__) || defined(__GNU__) |
489 | |
|
490 | 0 | cpu_set_t cpuset; |
491 | |
|
492 | 0 | CPU_ZERO (&cpuset); |
493 | |
|
494 | 0 | if (!sched_getaffinity (0, sizeof (cpuset), &cpuset)) { |
495 | 0 | #ifdef CPU_COUNT |
496 | 0 | pInfo->ProcessorCount = CPU_COUNT (&cpuset); |
497 | | #else |
498 | | int32_t count = 0; |
499 | | for (int i = 0; i < CPU_SETSIZE; i++) { |
500 | | if (CPU_ISSET (i, &cpuset)) { |
501 | | count++; |
502 | | } |
503 | | } |
504 | | pInfo->ProcessorCount = count; |
505 | | #endif |
506 | 0 | } else { |
507 | 0 | pInfo->ProcessorCount = 1; |
508 | 0 | } |
509 | |
|
510 | 0 | return WELS_THREAD_ERROR_OK; |
511 | |
|
512 | | #elif defined(__EMSCRIPTEN__) |
513 | | |
514 | | // There is not yet a way to determine CPU count in emscripten JS environment. |
515 | | pInfo->ProcessorCount = emscripten_num_logical_cores(); |
516 | | return WELS_THREAD_ERROR_OK; |
517 | | |
518 | | #elif defined(__Fuchsia__) |
519 | | |
520 | | pInfo->ProcessorCount = sysconf(_SC_NPROCESSORS_ONLN); |
521 | | return WELS_THREAD_ERROR_OK; |
522 | | #else |
523 | | |
524 | | size_t len = sizeof (pInfo->ProcessorCount); |
525 | | |
526 | | #if defined(__OpenBSD__) |
527 | | int scname[] = { CTL_HW, HW_NCPUONLINE }; |
528 | | if (sysctl (scname, 2, &pInfo->ProcessorCount, &len, NULL, 0) == -1) |
529 | | #else |
530 | | if (sysctlbyname (HW_NCPU_NAME, &pInfo->ProcessorCount, &len, NULL, 0) == -1) |
531 | | #endif |
532 | | pInfo->ProcessorCount = 1; |
533 | | |
534 | | return WELS_THREAD_ERROR_OK; |
535 | | |
536 | | #endif//__linux__ |
537 | 0 | } |
538 | | |
539 | | #endif |