desktop-src/Win7AppQual/preventing-hangs-in-windows-applications.md:111:Worse yet, the operating system has its own internal process-specific lock that sometimes is held while your code executes. This lock is acquired when DLLs are loaded into the process, and is therefore called the 'loader lock.' The DllMain function always executes under the loader lock; if you acquire any locks in DllMain (and you should not), you need to make the loader lock part of your lock order. Calling certain Win32 APIs might also acquire the loader lock on your behalf - functions like LoadLibraryEx, GetModuleHandle, and especially CoCreateInstance.
desktop-src/Win7AppQual/preventing-hangs-in-windows-applications.md:113:To tie all of this together, look at the sample code below. This function acquires multiple synchronization objects and implicitly defines a lock order, something that is not necessarily obvious on cursory inspection. On function entry, the code acquires a Critical Section and does not release it until function exit, thereby making it the top node in our lock hierarchy. The code then calls the Win32 function LoadIcon(), which under the covers might call into the Operating System Loader to load this binary. This operation would acquire the loader lock, which now also becomes part of this lock hierarchy (make sure the DllMain function does not acquire the g\_cs lock). Next the code calls SendMessage(), a blocking cross-thread operation, which will not return unless the UI thread responds. Again, make sure that the UI thread never acquires g\_cs.
desktop-src/Win7AppQual/preventing-hangs-in-windows-applications.md:132:-   Design a lock hierarchy and obey it. Add all the necessary locks. There are many more synchronization primitives than just Mutex and CriticalSections; they all need to be included. Include the loader lock in your hierarchy if you take any locks in DllMain()
desktop-src/Win7AppQual/preventing-hangs-in-windows-applications.md:137:-   Be careful when waiting on a thread handle from a DLL. Always assume that your code could be called under the loader lock. It's better to reference-count your resources and let the worker thread do its own cleanup (and then use FreeLibraryAndExitThread to terminate cleanly)
desktop-src/Win7AppQual/preventing-hangs-in-windows-applications.md:144:-   Do any work in the constructors and destructors for global variables, they are executed under the loader lock
desktop-src/DevNotes/ldrfastfailinloadercallout.md:43:This routine does not catch all potential deadlock cases; it is possible for a thread inside a loader callout to acquire a lock while some thread outside a loader callout holds the same lock and makes a call into the loader. In other words, there can be a lock order inversion between the loader lock and a client lock.
desktop-src/shell/ctf.md:55:| <span id="CTF_NOADDREFLIB"></span><span id="ctf_noaddreflib"></span><dl> <dt>**CTF\_NOADDREFLIB**</dt> <dt>0x00002000</dt> </dl>                        | 0x00002000. **Windows 7 or later.** This flag is essentially the opposite of CTF\_FREELIBANDEXIT. This avoids [**LoadLibrary**](/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya)/[**FreeLibraryAndExitThread**](/windows/win32/api/libloaderapi/nf-libloaderapi-freelibraryandexitthread) calls that can result in contention for the loader lock. Use CTF\_NOADDREFLIB only when the new thread has means to ensure that the code of the original thread procedure will remain loaded. This value should not be used in the context of COM objects, because COM objects must ensure that the DLL stays loaded (normally, COM unloads the DLLs).<br/>                                                                                                                                                                                                                                                                                                                    |
desktop-src/ProcThread/user-mode-scheduling.md:89:-   To help prevent deadlocks, the UMS scheduler thread should not share locks with UMS worker threads. This includes both application-created locks and system locks that are acquired indirectly by operations such as allocating from the heap or loading DLLs. For example, suppose the scheduler runs a UMS worker thread that loads a DLL. The worker thread acquires the loader lock and blocks. The system calls the scheduler entry point function, which then loads a DLL. This causes a deadlock, because the loader lock is already held and cannot be released until the first thread unblocks. To help avoid this problem, delegate work that might share locks with UMS worker threads to a dedicated UMS worker thread or a non-UMS thread.
desktop-src/Dlls/dllmain.md:131:During initial process startup or after a call to [**LoadLibrary**](/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya), the system scans the list of loaded DLLs for the process. For each DLL that has not already been called with the **DLL\_PROCESS\_ATTACH** value, the system calls the DLL's entry-point function. This call is made in the context of the thread that caused the process address space to change, such as the primary thread of the process or the thread that called **LoadLibrary**. Access to the entry point is serialized by the system on a process-wide basis. Threads in *DllMain* hold the loader lock so no additional DLLs can be dynamically loaded or initialized.
desktop-src/Dlls/dynamic-link-library-best-practices.md:29:[**DllMain**](dllmain.md) is called while the loader-lock is held. Therefore, significant restrictions are imposed on the functions that can be called within **DllMain**. As such, **DllMain** is designed to perform minimal initialization tasks, by using a small subset of the Microsoft® Windows® API. You cannot call any function in **DllMain** that directly or indirectly tries to acquire the loader lock. Otherwise, you will introduce the possibility that your application deadlocks or crashes. An error in a **DllMain** implementation can jeopardize the entire process and all of its threads.
desktop-src/Dlls/dynamic-link-library-best-practices.md:31:The ideal [**DllMain**](dllmain.md) would be just an empty stub. However, given the complexity of many applications, this is generally too restrictive. A good rule of thumb for **DllMain** is to postpone as much initialization as possible. Lazy initialization increases robustness of the application because this initialization is not performed while the loader lock is held. Also, lazy initialization enables you to safely use much more of the Windows API.
desktop-src/Dlls/dynamic-link-library-best-practices.md:40:-   Acquire a synchronization object that is owned by code that is waiting to acquire the loader lock. This can cause a deadlock.
desktop-src/Dlls/dynamic-link-library-best-practices.md:44:-   Call [**ExitThread**](/windows/win32/api/libloaderapi/nf-libloaderapi-freelibraryandexitthread). Exiting a thread during DLL detach can cause the loader lock to be acquired again, causing a deadlock or a crash.
desktop-src/Dlls/dynamic-link-library-best-practices.md:66:It is important to note that the loader calls [**DllMain**](dllmain.md) with the loader lock already acquired, so the loader lock should have the highest precedence in the locking hierarchy. Also note that code only has to acquire the locks it requires for proper synchronization; it does not have to acquire every single lock that is defined in the hierarchy. For example, if a section of code requires only locks A and C for proper synchronization, then the code should acquire lock A before it acquires lock C; it is not necessary for the code to also acquire lock B. Furthermore, DLL code cannot explicitly acquire the loader lock. If the code must call an API such as [**GetModuleFileName**](/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea) that can indirectly acquire the loader lock and the code must also acquire a private lock, then the code should call **GetModuleFileName** before it acquires lock P, thus ensuring that load order is respected.
desktop-src/Dlls/dynamic-link-library-best-practices.md:68:Figure 2 is an example that illustrates lock order inversion. Consider a DLL whose main thread contains [**DllMain**](dllmain.md). The library loader acquires the loader lock L and then calls into **DllMain**. The main thread creates synchronization objects A, B, and G to serialize access to its data structures and then tries to acquire lock G. A worker thread that has already successfully acquired lock G then calls a function such as GetModuleHandle that attempts to acquire the loader lock L. Thus, the worker thread is blocked on L and the main thread is blocked on G, resulting in a deadlock.
desktop-src/Dlls/dynamic-link-library-best-practices.md:87:-   Thread synchronization is tricky because waiting on threads to exit in [**DllMain**](dllmain.md) can cause a deadlock. For example, DLL A holds the loader lock. It signals thread T to exit and waits for the thread to exit. Thread T exits and the loader tries to acquire the loader lock to call into DLL A’s **DllMain** with DLL\_THREAD\_DETACH. This causes a deadlock. To minimize the risk of a deadlock:
desktop-src/Dlls/dynamic-link-library-best-practices.md:92:If a DLL is unloaded after all its threads have been created, but before they begin executing, the threads may crash. If the DLL created threads in its **DllMain** as part of its initialization, some threads may not have finished initialization and their DLL\_THREAD\_ATTACH message is still waiting to be delivered to the DLL. In this situation, if the DLL is unloaded, it will begin terminating threads. However, some threads may be blocked behind the loader lock. Their DLL\_THREAD\_ATTACH messages are processed after the DLL has been unmapped, causing the process to crash.
desktop-src/Dlls/dynamic-link-library-best-practices.md:99:-   If using a private lock inside [**DllMain**](dllmain.md), define a locking hierarchy and use it consistently. The loader lock must be at the bottom of this hierarchy.
