• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2011, The Android Open Source Project
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 
17 #include "egl_tls.h"
18 
19 #include <android-base/properties.h>
20 #include <log/log.h>
21 #include <stdlib.h>
22 
23 #include "CallStack.h"
24 #include "egl_platform_entries.h"
25 
26 namespace android {
27 
28 pthread_key_t egl_tls_t::sKey = TLS_KEY_NOT_INITIALIZED;
29 pthread_once_t egl_tls_t::sOnceKey = PTHREAD_ONCE_INIT;
30 
egl_tls_t()31 egl_tls_t::egl_tls_t() : error(EGL_SUCCESS), ctx(nullptr), logCallWithNoContext(true) {}
32 
egl_strerror(EGLint err)33 const char* egl_tls_t::egl_strerror(EGLint err) {
34     switch (err) {
35         case EGL_SUCCESS:
36             return "EGL_SUCCESS";
37         case EGL_NOT_INITIALIZED:
38             return "EGL_NOT_INITIALIZED";
39         case EGL_BAD_ACCESS:
40             return "EGL_BAD_ACCESS";
41         case EGL_BAD_ALLOC:
42             return "EGL_BAD_ALLOC";
43         case EGL_BAD_ATTRIBUTE:
44             return "EGL_BAD_ATTRIBUTE";
45         case EGL_BAD_CONFIG:
46             return "EGL_BAD_CONFIG";
47         case EGL_BAD_CONTEXT:
48             return "EGL_BAD_CONTEXT";
49         case EGL_BAD_CURRENT_SURFACE:
50             return "EGL_BAD_CURRENT_SURFACE";
51         case EGL_BAD_DISPLAY:
52             return "EGL_BAD_DISPLAY";
53         case EGL_BAD_MATCH:
54             return "EGL_BAD_MATCH";
55         case EGL_BAD_NATIVE_PIXMAP:
56             return "EGL_BAD_NATIVE_PIXMAP";
57         case EGL_BAD_NATIVE_WINDOW:
58             return "EGL_BAD_NATIVE_WINDOW";
59         case EGL_BAD_PARAMETER:
60             return "EGL_BAD_PARAMETER";
61         case EGL_BAD_SURFACE:
62             return "EGL_BAD_SURFACE";
63         case EGL_CONTEXT_LOST:
64             return "EGL_CONTEXT_LOST";
65         default:
66             return "UNKNOWN";
67     }
68 }
69 
validateTLSKey()70 void egl_tls_t::validateTLSKey() {
71     struct TlsKeyInitializer {
72         static void create() { pthread_key_create(&sKey, destructTLSData); }
73     };
74     pthread_once(&sOnceKey, TlsKeyInitializer::create);
75 }
76 
destructTLSData(void * data)77 void egl_tls_t::destructTLSData(void* data) {
78     egl_tls_t* tls = static_cast<egl_tls_t*>(data);
79     if (!tls) return;
80 
81     // Several things in the call tree of eglReleaseThread expect to be able to get the current
82     // thread state directly from TLS. That's a problem because Bionic has already cleared our
83     // TLS pointer before calling this function (pthread_getspecific(sKey) will return nullptr).
84     // Instead the data is passed as our parameter.
85     //
86     // Ideally we'd refactor this so we have thin wrappers that retrieve thread state from TLS and
87     // then pass it as a parameter (or 'this' pointer) to functions that do the real work without
88     // touching TLS. Then from here we could just call those implementation functions with the the
89     // TLS data we just received as a parameter.
90     //
91     // But that's a fairly invasive refactoring, so to do this robustly in the short term we just
92     // put the data *back* in TLS and call the top-level eglReleaseThread. It and it's call tree
93     // will retrieve the value from TLS, and then finally clear the TLS data. Bionic explicitly
94     // tolerates re-setting the value that it's currently trying to destruct (see
95     // pthread_key_clean_all()). Even if we forgot to clear the restored TLS data, bionic would
96     // call the destructor again, but eventually gives up and just leaks the data rather than
97     // enter an infinite loop.
98     pthread_setspecific(sKey, tls);
99     eglReleaseThread();
100     ALOGE_IF(pthread_getspecific(sKey) != nullptr,
101              "EGL TLS data still exists after eglReleaseThread");
102 }
103 
setErrorEtcImpl(const char * caller,int line,EGLint error,bool quiet)104 void egl_tls_t::setErrorEtcImpl(const char* caller, int line, EGLint error, bool quiet) {
105     validateTLSKey();
106     egl_tls_t* tls = getTLS();
107     if (tls->error != error) {
108         if (!quiet) {
109             ALOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
110             if (base::GetBoolProperty("debug.egl.callstack", false)) {
111                 CallStack::log(LOG_TAG);
112             }
113         }
114         tls->error = error;
115     }
116 }
117 
logNoContextCall()118 bool egl_tls_t::logNoContextCall() {
119     egl_tls_t* tls = getTLS();
120     if (tls->logCallWithNoContext) {
121         tls->logCallWithNoContext = false;
122         return true;
123     }
124     return false;
125 }
126 
getTLS()127 egl_tls_t* egl_tls_t::getTLS() {
128     egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
129     if (tls == nullptr) {
130         tls = new egl_tls_t;
131         pthread_setspecific(sKey, tls);
132     }
133     return tls;
134 }
135 
clearTLS()136 void egl_tls_t::clearTLS() {
137     if (sKey != TLS_KEY_NOT_INITIALIZED) {
138         egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
139         if (tls) {
140             pthread_setspecific(sKey, nullptr);
141             delete tls;
142         }
143     }
144 }
145 
clearError()146 void egl_tls_t::clearError() {
147     // This must clear the error from all the underlying EGL implementations as
148     // well as the EGL wrapper layer.
149     android::eglGetErrorImpl();
150 }
151 
getError()152 EGLint egl_tls_t::getError() {
153     if (sKey == TLS_KEY_NOT_INITIALIZED) {
154         return EGL_SUCCESS;
155     }
156     egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
157     if (!tls) {
158         return EGL_SUCCESS;
159     }
160     EGLint error = tls->error;
161     tls->error = EGL_SUCCESS;
162     return error;
163 }
164 
setContext(EGLContext ctx)165 void egl_tls_t::setContext(EGLContext ctx) {
166     validateTLSKey();
167     getTLS()->ctx = ctx;
168 }
169 
getContext()170 EGLContext egl_tls_t::getContext() {
171     if (sKey == TLS_KEY_NOT_INITIALIZED) {
172         return EGL_NO_CONTEXT;
173     }
174     egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
175     if (!tls) return EGL_NO_CONTEXT;
176     return tls->ctx;
177 }
178 
179 } // namespace android
180