eglcurrent.c revision cdc920a0
1#include <stdlib.h> 2#include <string.h> 3#include "eglglobals.h" 4#include "egllog.h" 5#include "eglmutex.h" 6#include "eglcurrent.h" 7 8 9/* This should be kept in sync with _eglInitThreadInfo() */ 10#define _EGL_THREAD_INFO_INITIALIZER \ 11 { EGL_SUCCESS, { NULL }, 0 } 12 13/* a fallback thread info to guarantee that every thread always has one */ 14static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER; 15 16 17#ifdef GLX_USE_TLS 18static __thread const _EGLThreadInfo *_egl_TSD 19 __attribute__ ((tls_model("initial-exec"))); 20 21static INLINE void _eglSetTSD(const _EGLThreadInfo *t) 22{ 23 _egl_TSD = t; 24} 25 26static INLINE _EGLThreadInfo *_eglGetTSD(void) 27{ 28 return (_EGLThreadInfo *) _egl_TSD; 29} 30 31static INLINE void _eglFiniTSD(void) 32{ 33} 34 35static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *)) 36{ 37 /* TODO destroy TSD */ 38 (void) dtor; 39 (void) _eglFiniTSD; 40 return EGL_TRUE; 41} 42 43#elif PTHREADS 44#include <pthread.h> 45 46static _EGL_DECLARE_MUTEX(_egl_TSDMutex); 47static EGLBoolean _egl_TSDInitialized; 48static pthread_key_t _egl_TSD; 49static void (*_egl_FreeTSD)(_EGLThreadInfo *); 50 51static INLINE void _eglSetTSD(const _EGLThreadInfo *t) 52{ 53 pthread_setspecific(_egl_TSD, (const void *) t); 54} 55 56static INLINE _EGLThreadInfo *_eglGetTSD(void) 57{ 58 return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD); 59} 60 61static INLINE void _eglFiniTSD(void) 62{ 63 _eglLockMutex(&_egl_TSDMutex); 64 if (_egl_TSDInitialized) { 65 _EGLThreadInfo *t = _eglGetTSD(); 66 67 _egl_TSDInitialized = EGL_FALSE; 68 if (t && _egl_FreeTSD) 69 _egl_FreeTSD((void *) t); 70 pthread_key_delete(_egl_TSD); 71 } 72 _eglUnlockMutex(&_egl_TSDMutex); 73} 74 75static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *)) 76{ 77 if (!_egl_TSDInitialized) { 78 _eglLockMutex(&_egl_TSDMutex); 79 80 /* check again after acquiring lock */ 81 if (!_egl_TSDInitialized) { 82 if (pthread_key_create(&_egl_TSD, (void (*)(void *)) dtor) != 0) { 83 _eglUnlockMutex(&_egl_TSDMutex); 84 return EGL_FALSE; 85 } 86 _egl_FreeTSD = dtor; 87 _eglAddAtExitCall(_eglFiniTSD); 88 _egl_TSDInitialized = EGL_TRUE; 89 } 90 91 _eglUnlockMutex(&_egl_TSDMutex); 92 } 93 94 return EGL_TRUE; 95} 96 97#else /* PTHREADS */ 98static const _EGLThreadInfo *_egl_TSD; 99static void (*_egl_FreeTSD)(_EGLThreadInfo *); 100 101static INLINE void _eglSetTSD(const _EGLThreadInfo *t) 102{ 103 _egl_TSD = t; 104} 105 106static INLINE _EGLThreadInfo *_eglGetTSD(void) 107{ 108 return (_EGLThreadInfo *) _egl_TSD; 109} 110 111static INLINE void _eglFiniTSD(void) 112{ 113 if (_egl_FreeTSD && _egl_TSD) 114 _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD); 115} 116 117static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *)) 118{ 119 if (!_egl_FreeTSD && dtor) { 120 _egl_FreeTSD = dtor; 121 _eglAddAtExitCall(_eglFiniTSD); 122 } 123 return EGL_TRUE; 124} 125 126#endif /* !PTHREADS */ 127 128 129static void 130_eglInitThreadInfo(_EGLThreadInfo *t) 131{ 132 memset(t, 0, sizeof(*t)); 133 t->LastError = EGL_SUCCESS; 134 /* default, per EGL spec */ 135 t->CurrentAPIIndex = _eglConvertApiToIndex(EGL_OPENGL_ES_API); 136} 137 138 139/** 140 * Allocate and init a new _EGLThreadInfo object. 141 */ 142static _EGLThreadInfo * 143_eglCreateThreadInfo(void) 144{ 145 _EGLThreadInfo *t = (_EGLThreadInfo *) calloc(1, sizeof(_EGLThreadInfo)); 146 if (t) 147 _eglInitThreadInfo(t); 148 else 149 t = &dummy_thread; 150 return t; 151} 152 153 154/** 155 * Delete/free a _EGLThreadInfo object. 156 */ 157static void 158_eglDestroyThreadInfo(_EGLThreadInfo *t) 159{ 160 if (t != &dummy_thread) 161 free(t); 162} 163 164 165/** 166 * Make sure TSD is initialized and return current value. 167 */ 168static INLINE _EGLThreadInfo * 169_eglCheckedGetTSD(void) 170{ 171 if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) { 172 _eglLog(_EGL_FATAL, "failed to initialize \"current\" system"); 173 return NULL; 174 } 175 176 return _eglGetTSD(); 177} 178 179 180/** 181 * Return the calling thread's thread info. 182 * If the calling thread nevers calls this function before, or if its thread 183 * info was destroyed, a new one is created. This function never returns NULL. 184 * In the case allocation fails, a dummy one is returned. See also 185 * _eglIsCurrentThreadDummy. 186 */ 187_EGLThreadInfo * 188_eglGetCurrentThread(void) 189{ 190 _EGLThreadInfo *t = _eglCheckedGetTSD(); 191 if (!t) { 192 t = _eglCreateThreadInfo(); 193 _eglSetTSD(t); 194 } 195 196 return t; 197} 198 199 200/** 201 * Destroy the calling thread's thread info. 202 */ 203void 204_eglDestroyCurrentThread(void) 205{ 206 _EGLThreadInfo *t = _eglCheckedGetTSD(); 207 if (t) { 208 _eglDestroyThreadInfo(t); 209 _eglSetTSD(NULL); 210 } 211} 212 213 214/** 215 * Return true if the calling thread's thread info is dummy. 216 * A dummy thread info is shared by all threads and should not be modified. 217 * Functions like eglBindAPI or eglMakeCurrent should check for dummy-ness 218 * before updating the thread info. 219 */ 220EGLBoolean 221_eglIsCurrentThreadDummy(void) 222{ 223 _EGLThreadInfo *t = _eglCheckedGetTSD(); 224 return (!t || t == &dummy_thread); 225} 226 227 228/** 229 * Return the currently bound context of the given API, or NULL. 230 */ 231PUBLIC _EGLContext * 232_eglGetAPIContext(EGLenum api) 233{ 234 _EGLThreadInfo *t = _eglGetCurrentThread(); 235 return t->CurrentContexts[_eglConvertApiToIndex(api)]; 236} 237 238 239/** 240 * Return the currently bound context of the current API, or NULL. 241 */ 242_EGLContext * 243_eglGetCurrentContext(void) 244{ 245 _EGLThreadInfo *t = _eglGetCurrentThread(); 246 return t->CurrentContexts[t->CurrentAPIIndex]; 247} 248 249 250/** 251 * Record EGL error code and return EGL_FALSE. 252 */ 253EGLBoolean 254_eglError(EGLint errCode, const char *msg) 255{ 256 _EGLThreadInfo *t = _eglGetCurrentThread(); 257 258 if (t == &dummy_thread) 259 return EGL_FALSE; 260 261 t->LastError = errCode; 262 263 if (errCode != EGL_SUCCESS) { 264 const char *s; 265 266 switch (errCode) { 267 case EGL_BAD_ACCESS: 268 s = "EGL_BAD_ACCESS"; 269 break; 270 case EGL_BAD_ALLOC: 271 s = "EGL_BAD_ALLOC"; 272 break; 273 case EGL_BAD_ATTRIBUTE: 274 s = "EGL_BAD_ATTRIBUTE"; 275 break; 276 case EGL_BAD_CONFIG: 277 s = "EGL_BAD_CONFIG"; 278 break; 279 case EGL_BAD_CONTEXT: 280 s = "EGL_BAD_CONTEXT"; 281 break; 282 case EGL_BAD_CURRENT_SURFACE: 283 s = "EGL_BAD_CURRENT_SURFACE"; 284 break; 285 case EGL_BAD_DISPLAY: 286 s = "EGL_BAD_DISPLAY"; 287 break; 288 case EGL_BAD_MATCH: 289 s = "EGL_BAD_MATCH"; 290 break; 291 case EGL_BAD_NATIVE_PIXMAP: 292 s = "EGL_BAD_NATIVE_PIXMAP"; 293 break; 294 case EGL_BAD_NATIVE_WINDOW: 295 s = "EGL_BAD_NATIVE_WINDOW"; 296 break; 297 case EGL_BAD_PARAMETER: 298 s = "EGL_BAD_PARAMETER"; 299 break; 300 case EGL_BAD_SURFACE: 301 s = "EGL_BAD_SURFACE"; 302 break; 303 case EGL_BAD_SCREEN_MESA: 304 s = "EGL_BAD_SCREEN_MESA"; 305 break; 306 case EGL_BAD_MODE_MESA: 307 s = "EGL_BAD_MODE_MESA"; 308 break; 309 default: 310 s = "other"; 311 } 312 _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); 313 } 314 315 return EGL_FALSE; 316} 317