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