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