1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 //
9 //    Redistributions of source code must retain the above copyright
10 //    notice, this list of conditions and the following disclaimer.
11 //
12 //    Redistributions in binary form must reproduce the above
13 //    copyright notice, this list of conditions and the following
14 //    disclaimer in the documentation and/or other materials provided
15 //    with the distribution.
16 //
17 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
18 //    contributors may be used to endorse or promote products derived
19 //    from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 // POSSIBILITY OF SUCH DAMAGE.
33 //
34 
35 //
36 // This file contains the Linux-specific functions
37 //
38 #include "../osinclude.h"
39 #include "../../../OGLCompilersDLL/InitializeDll.h"
40 
41 #include <pthread.h>
42 #include <semaphore.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <stdint.h>
46 #include <cstdio>
47 #include <sys/time.h>
48 
49 #if !defined(__Fuchsia__)
50 #include <sys/resource.h>
51 #endif
52 
53 namespace glslang {
54 
55 //
56 // Thread cleanup
57 //
58 
59 //
60 // Wrapper for Linux call to DetachThread.  This is required as pthread_cleanup_push() expects
61 // the cleanup routine to return void.
62 //
DetachThreadLinux(void *)63 static void DetachThreadLinux(void *)
64 {
65     DetachThread();
66 }
67 
68 //
69 // Registers cleanup handler, sets cancel type and state, and executes the thread specific
70 // cleanup handler.  This function will be called in the Standalone.cpp for regression
71 // testing.  When OpenGL applications are run with the driver code, Linux OS does the
72 // thread cleanup.
73 //
OS_CleanupThreadData(void)74 void OS_CleanupThreadData(void)
75 {
76 #if defined(__ANDROID__) || defined(__Fuchsia__)
77     DetachThreadLinux(NULL);
78 #else
79     int old_cancel_state, old_cancel_type;
80     void *cleanupArg = NULL;
81 
82     //
83     // Set thread cancel state and push cleanup handler.
84     //
85     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
86     pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg);
87 
88     //
89     // Put the thread in deferred cancellation mode.
90     //
91     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type);
92 
93     //
94     // Pop cleanup handler and execute it prior to unregistering the cleanup handler.
95     //
96     pthread_cleanup_pop(1);
97 
98     //
99     // Restore the thread's previous cancellation mode.
100     //
101     pthread_setcanceltype(old_cancel_state, NULL);
102 #endif
103 }
104 
105 //
106 // Thread Local Storage Operations
107 //
PthreadKeyToTLSIndex(pthread_key_t key)108 inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key)
109 {
110     return (OS_TLSIndex)((uintptr_t)key + 1);
111 }
112 
TLSIndexToPthreadKey(OS_TLSIndex nIndex)113 inline pthread_key_t TLSIndexToPthreadKey(OS_TLSIndex nIndex)
114 {
115     return (pthread_key_t)((uintptr_t)nIndex - 1);
116 }
117 
OS_AllocTLSIndex()118 OS_TLSIndex OS_AllocTLSIndex()
119 {
120     pthread_key_t pPoolIndex;
121 
122     //
123     // Create global pool key.
124     //
125     if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
126         assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
127         return OS_INVALID_TLS_INDEX;
128     }
129     else
130         return PthreadKeyToTLSIndex(pPoolIndex);
131 }
132 
OS_SetTLSValue(OS_TLSIndex nIndex,void * lpvValue)133 bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
134 {
135     if (nIndex == OS_INVALID_TLS_INDEX) {
136         assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
137         return false;
138     }
139 
140     if (pthread_setspecific(TLSIndexToPthreadKey(nIndex), lpvValue) == 0)
141         return true;
142     else
143         return false;
144 }
145 
OS_GetTLSValue(OS_TLSIndex nIndex)146 void* OS_GetTLSValue(OS_TLSIndex nIndex)
147 {
148     //
149     // This function should return 0 if nIndex is invalid.
150     //
151     assert(nIndex != OS_INVALID_TLS_INDEX);
152     return pthread_getspecific(TLSIndexToPthreadKey(nIndex));
153 }
154 
OS_FreeTLSIndex(OS_TLSIndex nIndex)155 bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
156 {
157     if (nIndex == OS_INVALID_TLS_INDEX) {
158         assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
159         return false;
160     }
161 
162     //
163     // Delete the global pool key.
164     //
165     if (pthread_key_delete(TLSIndexToPthreadKey(nIndex)) == 0)
166         return true;
167     else
168         return false;
169 }
170 
171 namespace {
172     pthread_mutex_t gMutex;
173 }
174 
InitGlobalLock()175 void InitGlobalLock()
176 {
177   pthread_mutexattr_t mutexattr;
178   pthread_mutexattr_init(&mutexattr);
179   pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
180   pthread_mutex_init(&gMutex, &mutexattr);
181 }
182 
GetGlobalLock()183 void GetGlobalLock()
184 {
185   pthread_mutex_lock(&gMutex);
186 }
187 
ReleaseGlobalLock()188 void ReleaseGlobalLock()
189 {
190   pthread_mutex_unlock(&gMutex);
191 }
192 
193 // #define DUMP_COUNTERS
194 
OS_DumpMemoryCounters()195 void OS_DumpMemoryCounters()
196 {
197 #ifdef DUMP_COUNTERS
198     struct rusage usage;
199 
200     if (getrusage(RUSAGE_SELF, &usage) == 0)
201         printf("Working set size: %ld\n", usage.ru_maxrss * 1024);
202 #else
203     printf("Recompile with DUMP_COUNTERS defined to see counters.\n");
204 #endif
205 }
206 
207 } // end namespace glslang
208