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 Win32 implementation of thread management.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deThread.h"
25
26 #if (DE_OS == DE_OS_WIN32 || DE_OS == DE_OS_WINCE)
27
28 #include "deMemory.h"
29 #include "deInt32.h"
30
31 #define VC_EXTRALEAN
32 #define WIN32_LEAN_AND_MEAN
33 #include <windows.h>
34
35 /* Thread handle equals deThread in this implementation. */
36 DE_STATIC_ASSERT(sizeof(deThread) >= sizeof(HANDLE));
37
38 typedef struct ThreadEntry_s
39 {
40 deThreadFunc func;
41 void* arg;
42 } ThreadEntry;
43
mapPriority(deThreadPriority priority)44 static int mapPriority (deThreadPriority priority)
45 {
46 switch (priority)
47 {
48 case DE_THREADPRIORITY_LOWEST: return THREAD_PRIORITY_IDLE;
49 case DE_THREADPRIORITY_LOW: return THREAD_PRIORITY_LOWEST;
50 case DE_THREADPRIORITY_NORMAL: return THREAD_PRIORITY_NORMAL;
51 case DE_THREADPRIORITY_HIGH: return THREAD_PRIORITY_ABOVE_NORMAL;
52 case DE_THREADPRIORITY_HIGHEST: return THREAD_PRIORITY_HIGHEST;
53 default: DE_ASSERT(DE_FALSE);
54 }
55 return 0;
56 }
57
startThread(LPVOID entryPtr)58 static DWORD __stdcall startThread (LPVOID entryPtr)
59 {
60 ThreadEntry* entry = (ThreadEntry*)entryPtr;
61 deThreadFunc func = entry->func;
62 void* arg = entry->arg;
63
64 deFree(entry);
65
66 func(arg);
67
68 return 0;
69 }
70
deThread_create(deThreadFunc func,void * arg,const deThreadAttributes * attributes)71 deThread deThread_create (deThreadFunc func, void* arg, const deThreadAttributes* attributes)
72 {
73 ThreadEntry* entry = (ThreadEntry*)deMalloc(sizeof(ThreadEntry));
74 HANDLE thread = 0;
75
76 if (!entry)
77 return 0;
78
79 entry->func = func;
80 entry->arg = arg;
81
82 thread = CreateThread(DE_NULL, 0, startThread, entry, 0, DE_NULL);
83 if (!thread)
84 {
85 deFree(entry);
86 return 0;
87 }
88
89 if (attributes)
90 SetThreadPriority(thread, mapPriority(attributes->priority));
91
92 return (deThread)thread;
93 }
94
deThread_join(deThread thread)95 deBool deThread_join (deThread thread)
96 {
97 HANDLE handle = (HANDLE)thread;
98 WaitForSingleObject(handle, INFINITE);
99
100 return DE_TRUE;
101 }
102
deThread_destroy(deThread thread)103 void deThread_destroy (deThread thread)
104 {
105 HANDLE handle = (HANDLE)thread;
106 CloseHandle(handle);
107 }
108
deSleep(deUint32 milliseconds)109 void deSleep (deUint32 milliseconds)
110 {
111 Sleep((DWORD)milliseconds);
112 }
113
deYield(void)114 void deYield (void)
115 {
116 SwitchToThread();
117 }
118
getWin32ProcessorInfo(deUint32 * numBytes)119 static SYSTEM_LOGICAL_PROCESSOR_INFORMATION* getWin32ProcessorInfo (deUint32* numBytes)
120 {
121 deUint32 curSize = (deUint32)sizeof(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)*8;
122 SYSTEM_LOGICAL_PROCESSOR_INFORMATION* info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION*)deMalloc(curSize);
123
124 for (;;)
125 {
126 DWORD inOutLen = curSize;
127 DWORD err;
128
129 if (GetLogicalProcessorInformation(info, &inOutLen))
130 {
131 *numBytes = inOutLen;
132 return info;
133 }
134 else
135 {
136 err = GetLastError();
137
138 if (err == ERROR_INSUFFICIENT_BUFFER)
139 {
140 curSize <<= 1;
141 info = deRealloc(info, curSize);
142 }
143 else
144 {
145 deFree(info);
146 return DE_NULL;
147 }
148 }
149 }
150 }
151
152 typedef struct ProcessorInfo_s
153 {
154 deUint32 numPhysicalCores;
155 deUint32 numLogicalCores;
156 } ProcessorInfo;
157
parseWin32ProcessorInfo(ProcessorInfo * dst,const SYSTEM_LOGICAL_PROCESSOR_INFORMATION * src,deUint32 numBytes)158 void parseWin32ProcessorInfo (ProcessorInfo* dst, const SYSTEM_LOGICAL_PROCESSOR_INFORMATION* src, deUint32 numBytes)
159 {
160 const SYSTEM_LOGICAL_PROCESSOR_INFORMATION* cur = src;
161
162 deMemset(dst, 0, sizeof(ProcessorInfo));
163
164 while (((const deUint8*)cur - (const deUint8*)src) + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= numBytes)
165 {
166 if (cur->Relationship == RelationProcessorCore)
167 {
168 dst->numPhysicalCores += 1;
169 #if (DE_PTR_SIZE == 8)
170 dst->numLogicalCores += dePop64(cur->ProcessorMask);
171 #else
172 dst->numLogicalCores += dePop32(cur->ProcessorMask);
173 #endif
174 }
175
176 cur++;
177 }
178 }
179
getProcessorInfo(ProcessorInfo * info)180 deBool getProcessorInfo (ProcessorInfo* info)
181 {
182 deUint32 numBytes = 0;
183 SYSTEM_LOGICAL_PROCESSOR_INFORMATION* rawInfo = getWin32ProcessorInfo(&numBytes);
184
185 if (!numBytes)
186 return DE_FALSE;
187
188 parseWin32ProcessorInfo(info, rawInfo, numBytes);
189 deFree(rawInfo);
190
191 return DE_TRUE;
192 }
193
deGetNumTotalPhysicalCores(void)194 deUint32 deGetNumTotalPhysicalCores (void)
195 {
196 ProcessorInfo info;
197
198 if (!getProcessorInfo(&info))
199 return 1u;
200
201 return info.numPhysicalCores;
202 }
203
deGetNumTotalLogicalCores(void)204 deUint32 deGetNumTotalLogicalCores (void)
205 {
206 ProcessorInfo info;
207
208 if (!getProcessorInfo(&info))
209 return 1u;
210
211 return info.numLogicalCores;
212 }
213
deGetNumAvailableLogicalCores(void)214 deUint32 deGetNumAvailableLogicalCores (void)
215 {
216 return deGetNumTotalLogicalCores();
217 }
218
219 #endif /* DE_OS */
220