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 #include <sys/resource.h>
49
50 namespace glslang {
51
52 //
53 // Thread cleanup
54 //
55
56 //
57 // Wrapper for Linux call to DetachThread. This is required as pthread_cleanup_push() expects
58 // the cleanup routine to return void.
59 //
DetachThreadLinux(void *)60 static void DetachThreadLinux(void *)
61 {
62 DetachThread();
63 }
64
65 //
66 // Registers cleanup handler, sets cancel type and state, and executes the thread specific
67 // cleanup handler. This function will be called in the Standalone.cpp for regression
68 // testing. When OpenGL applications are run with the driver code, Linux OS does the
69 // thread cleanup.
70 //
OS_CleanupThreadData(void)71 void OS_CleanupThreadData(void)
72 {
73 #ifdef __ANDROID__
74 DetachThreadLinux(NULL);
75 #else
76 int old_cancel_state, old_cancel_type;
77 void *cleanupArg = NULL;
78
79 //
80 // Set thread cancel state and push cleanup handler.
81 //
82 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
83 pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg);
84
85 //
86 // Put the thread in deferred cancellation mode.
87 //
88 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type);
89
90 //
91 // Pop cleanup handler and execute it prior to unregistering the cleanup handler.
92 //
93 pthread_cleanup_pop(1);
94
95 //
96 // Restore the thread's previous cancellation mode.
97 //
98 pthread_setcanceltype(old_cancel_state, NULL);
99 #endif
100 }
101
102 //
103 // Thread Local Storage Operations
104 //
PthreadKeyToTLSIndex(pthread_key_t key)105 inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key)
106 {
107 return (OS_TLSIndex)((uintptr_t)key + 1);
108 }
109
TLSIndexToPthreadKey(OS_TLSIndex nIndex)110 inline pthread_key_t TLSIndexToPthreadKey(OS_TLSIndex nIndex)
111 {
112 return (pthread_key_t)((uintptr_t)nIndex - 1);
113 }
114
OS_AllocTLSIndex()115 OS_TLSIndex OS_AllocTLSIndex()
116 {
117 pthread_key_t pPoolIndex;
118
119 //
120 // Create global pool key.
121 //
122 if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
123 assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
124 return OS_INVALID_TLS_INDEX;
125 }
126 else
127 return PthreadKeyToTLSIndex(pPoolIndex);
128 }
129
OS_SetTLSValue(OS_TLSIndex nIndex,void * lpvValue)130 bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
131 {
132 if (nIndex == OS_INVALID_TLS_INDEX) {
133 assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
134 return false;
135 }
136
137 if (pthread_setspecific(TLSIndexToPthreadKey(nIndex), lpvValue) == 0)
138 return true;
139 else
140 return false;
141 }
142
OS_GetTLSValue(OS_TLSIndex nIndex)143 void* OS_GetTLSValue(OS_TLSIndex nIndex)
144 {
145 //
146 // This function should return 0 if nIndex is invalid.
147 //
148 assert(nIndex != OS_INVALID_TLS_INDEX);
149 return pthread_getspecific(TLSIndexToPthreadKey(nIndex));
150 }
151
OS_FreeTLSIndex(OS_TLSIndex nIndex)152 bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
153 {
154 if (nIndex == OS_INVALID_TLS_INDEX) {
155 assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
156 return false;
157 }
158
159 //
160 // Delete the global pool key.
161 //
162 if (pthread_key_delete(TLSIndexToPthreadKey(nIndex)) == 0)
163 return true;
164 else
165 return false;
166 }
167
168 namespace {
169 pthread_mutex_t gMutex;
170 }
171
InitGlobalLock()172 void InitGlobalLock()
173 {
174 pthread_mutexattr_t mutexattr;
175 pthread_mutexattr_init(&mutexattr);
176 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
177 pthread_mutex_init(&gMutex, &mutexattr);
178 }
179
GetGlobalLock()180 void GetGlobalLock()
181 {
182 pthread_mutex_lock(&gMutex);
183 }
184
ReleaseGlobalLock()185 void ReleaseGlobalLock()
186 {
187 pthread_mutex_unlock(&gMutex);
188 }
189
190 // #define DUMP_COUNTERS
191
OS_DumpMemoryCounters()192 void OS_DumpMemoryCounters()
193 {
194 #ifdef DUMP_COUNTERS
195 struct rusage usage;
196
197 if (getrusage(RUSAGE_SELF, &usage) == 0)
198 printf("Working set size: %ld\n", usage.ru_maxrss * 1024);
199 #else
200 printf("Recompile with DUMP_COUNTERS defined to see counters.\n");
201 #endif
202 }
203
204 } // end namespace glslang
205