00001 /******************************************************************************* 00002 The content of this file includes portions of the AUDIOKINETIC Wwise Technology 00003 released in source code form as part of the SDK installer package. 00004 00005 Commercial License Usage 00006 00007 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology 00008 may use this file in accordance with the end user license agreement provided 00009 with the software or, alternatively, in accordance with the terms contained in a 00010 written agreement between you and Audiokinetic Inc. 00011 00012 Apache License Usage 00013 00014 Alternatively, this file may be used under the Apache License, Version 2.0 (the 00015 "Apache License"); you may not use this file except in compliance with the 00016 Apache License. You may obtain a copy of the Apache License at 00017 http://www.apache.org/licenses/LICENSE-2.0. 00018 00019 Unless required by applicable law or agreed to in writing, software distributed 00020 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 00021 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for 00022 the specific language governing permissions and limitations under the License. 00023 00024 Version: <VERSION> Build: <BUILDNUMBER> 00025 Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc. 00026 *******************************************************************************/ 00027 00028 /* 00029 * Emulates a subset of the Win32 threading API as a layer on top of WinRT threadpools. 00030 * 00031 * Supported features: 00032 * 00033 * - CreateThread (returns a standard Win32 handle which can be waited on, then closed) 00034 * - CREATE_SUSPENDED and ResumeThread 00035 * - Partial support for SetThreadPriority (see below) 00036 * - Sleep 00037 * - Thread local storage (TlsAlloc, TlsFree, TlsGetValue, TlsSetValue) 00038 * 00039 * Differences from Win32: 00040 * 00041 * - No ExitThread or TerminateThread (just return from the thread function to exit) 00042 * - No SuspendThread, so ResumeThread is only useful in combination with CREATE_SUSPENDED 00043 * - SetThreadPriority is only available while a thread is in CREATE_SUSPENDED state 00044 * - SetThreadPriority only supports three priority levels (negative, zero, or positive) 00045 * - TLS requires use of this CreateThread (leaks memory if called from other threadpool tasks) 00046 * - No thread identifier APIs (GetThreadId, GetCurrentThreadId, OpenThread) 00047 * - No affinity APIs 00048 * - No GetExitCodeThread 00049 * - Failure cases return error codes but do not always call SetLastError 00050 */ 00051 00052 #pragma once 00053 00054 namespace AK 00055 { 00056 namespace ThreadEmulation 00057 { 00058 HANDLE WINAPI CreateThread(__in LPTHREAD_START_ROUTINE lpStartAddress, __in_opt LPVOID lpParameter, __in DWORD dwCreationFlags); 00059 DWORD WINAPI ResumeThread(__in HANDLE hThread); 00060 BOOL WINAPI SetThreadPriority(__in HANDLE hThread, __in int nPriority); 00061 00062 VOID WINAPI Sleep(__in DWORD dwMilliseconds); 00063 VOID WINAPI SleepEx(__in DWORD dwMilliseconds, BOOL in_bAlertable ); 00064 } 00065 } 00066 00067 #ifdef AK_IMPLEMENT_THREAD_EMULATION 00068 00069 #include <assert.h> 00070 #include <vector> 00071 #include <set> 00072 #include <map> 00073 #include <mutex> 00074 00075 namespace AK 00076 { 00077 namespace ThreadEmulation 00078 { 00079 // Stored data for CREATE_SUSPENDED and ResumeThread. 00080 struct PendingThreadInfo 00081 { 00082 LPTHREAD_START_ROUTINE lpStartAddress; 00083 LPVOID lpParameter; 00084 HANDLE completionEvent; 00085 int nPriority; 00086 }; 00087 00088 static std::map<HANDLE, PendingThreadInfo> pendingThreads; 00089 static std::mutex pendingThreadsLock; 00090 00091 00092 // Converts a Win32 thread priority to WinRT format. 00093 static Windows::System::Threading::WorkItemPriority GetWorkItemPriority(int nPriority) 00094 { 00095 if (nPriority < 0) 00096 return Windows::System::Threading::WorkItemPriority::Low; 00097 else if (nPriority > 0) 00098 return Windows::System::Threading::WorkItemPriority::High; 00099 else 00100 return Windows::System::Threading::WorkItemPriority::Normal; 00101 } 00102 00103 00104 // Helper shared between CreateThread and ResumeThread. 00105 static void StartThread(LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, HANDLE completionEvent, int nPriority) 00106 { 00107 auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([=](Windows::Foundation::IAsyncAction^) 00108 { 00109 // Run the user callback. 00110 lpStartAddress(lpParameter); 00111 00112 // Signal that the thread has completed. 00113 SetEvent(completionEvent); 00114 CloseHandle(completionEvent); 00115 00116 }, Platform::CallbackContext::Any); 00117 00118 // Start the threadpool task. 00119 auto workItem = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, GetWorkItemPriority(nPriority), Windows::System::Threading::WorkItemOptions::TimeSliced ); 00120 00121 // workItem->Start(); 00122 } 00123 00124 00125 HANDLE WINAPI CreateThread(__in LPTHREAD_START_ROUTINE lpStartAddress, __in_opt LPVOID lpParameter, __in DWORD dwCreationFlags) 00126 { 00127 // Validate parameters. 00128 assert((dwCreationFlags & ~CREATE_SUSPENDED) == 0); 00129 00130 // Create a handle that will be signalled when the thread has completed. 00131 HANDLE threadHandle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE); 00132 00133 if (!threadHandle) 00134 return nullptr; 00135 00136 // Make a copy of the handle for internal use. This is necessary because 00137 // the caller is responsible for closing the handle returned by CreateThread, 00138 // and they may do that before or after the thread has finished running. 00139 HANDLE completionEvent; 00140 00141 if (!DuplicateHandle(GetCurrentProcess(), threadHandle, GetCurrentProcess(), &completionEvent, 0, false, DUPLICATE_SAME_ACCESS)) 00142 { 00143 CloseHandle(threadHandle); 00144 return nullptr; 00145 } 00146 00147 try 00148 { 00149 if (dwCreationFlags & CREATE_SUSPENDED) 00150 { 00151 // Store info about a suspended thread. 00152 PendingThreadInfo info; 00153 00154 info.lpStartAddress = lpStartAddress; 00155 info.lpParameter = lpParameter; 00156 info.completionEvent = completionEvent; 00157 info.nPriority = 0; 00158 00159 std::lock_guard<std::mutex> lock(pendingThreadsLock); 00160 00161 pendingThreads[threadHandle] = info; 00162 } 00163 else 00164 { 00165 // Start the thread immediately. 00166 StartThread(lpStartAddress, lpParameter, completionEvent, 0); 00167 } 00168 00169 return threadHandle; 00170 } 00171 catch (...) 00172 { 00173 // Clean up if thread creation fails. 00174 CloseHandle(threadHandle); 00175 CloseHandle(completionEvent); 00176 00177 return nullptr; 00178 } 00179 } 00180 00181 00182 DWORD WINAPI ResumeThread(__in HANDLE hThread) 00183 { 00184 std::lock_guard<std::mutex> lock(pendingThreadsLock); 00185 00186 // Look up the requested thread. 00187 auto threadInfo = pendingThreads.find(hThread); 00188 00189 if (threadInfo == pendingThreads.end()) 00190 { 00191 // Can only resume threads while they are in CREATE_SUSPENDED state. 00192 assert(false); 00193 return (DWORD)-1; 00194 } 00195 00196 PendingThreadInfo& info = threadInfo->second; 00197 00198 // Start the thread. 00199 try 00200 { 00201 StartThread(info.lpStartAddress, info.lpParameter, info.completionEvent, info.nPriority); 00202 } 00203 catch (...) 00204 { 00205 return (DWORD)-1; 00206 } 00207 00208 // Remove this thread from the pending list. 00209 pendingThreads.erase(threadInfo); 00210 00211 return 0; 00212 } 00213 00214 00215 BOOL WINAPI SetThreadPriority(__in HANDLE hThread, __in int nPriority) 00216 { 00217 std::lock_guard<std::mutex> lock(pendingThreadsLock); 00218 00219 // Look up the requested thread. 00220 auto threadInfo = pendingThreads.find(hThread); 00221 00222 if (threadInfo == pendingThreads.end()) 00223 { 00224 // Can only set priority on threads while they are in CREATE_SUSPENDED state. 00225 assert(false); 00226 return false; 00227 } 00228 00229 // Store the new priority. 00230 threadInfo->second.nPriority = nPriority; 00231 00232 return true; 00233 } 00234 00235 VOID WINAPI Sleep(__in DWORD dwMilliseconds ) 00236 { 00237 SleepEx( dwMilliseconds, FALSE ); 00238 } 00239 00240 VOID WINAPI SleepEx(__in DWORD dwMilliseconds, BOOL in_bAlertable) 00241 { 00242 static HANDLE singletonEvent = nullptr; 00243 00244 HANDLE sleepEvent = singletonEvent; 00245 00246 // Demand create the event. 00247 if (!sleepEvent) 00248 { 00249 sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE); 00250 00251 if (!sleepEvent) 00252 return; 00253 00254 HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr); 00255 00256 if (previousEvent) 00257 { 00258 // Back out if multiple threads try to demand create at the same time. 00259 CloseHandle(sleepEvent); 00260 sleepEvent = previousEvent; 00261 } 00262 } 00263 00264 // Emulate sleep by waiting with timeout on an event that is never signalled. 00265 DWORD dwResult = WaitForSingleObjectEx(sleepEvent, dwMilliseconds, in_bAlertable); 00266 assert( dwResult != -1 ); 00267 } 00268 } 00269 } 00270 00271 #endif
Des questions ? Des problèmes ? Besoin de plus d'informations ? Contactez-nous, nous pouvons vous aider !
Visitez notre page d'AideEnregistrez votre projet et nous vous aiderons à démarrer sans aucune obligation !
Partir du bon pied avec Wwise