21#include <winpr/config.h>
23#include <winpr/assert.h>
24#include <winpr/tchar.h>
25#include <winpr/synch.h>
26#include <winpr/sysinfo.h>
27#include <winpr/interlocked.h>
28#include <winpr/thread.h>
32#ifdef WINPR_HAVE_UNISTD_H
39#include <mach/semaphore.h>
45#define TAG WINPR_TAG("synch.critical")
49 if (!InitializeCriticalSectionEx(lpCriticalSection, 0, 0))
50 WLog_ERR(TAG,
"InitializeCriticalSectionEx failed");
53BOOL InitializeCriticalSectionEx(
LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount,
56 WINPR_ASSERT(lpCriticalSection);
69 WLog_WARN(TAG,
"Flags unimplemented");
72 lpCriticalSection->DebugInfo =
nullptr;
73 lpCriticalSection->LockCount = -1;
74 lpCriticalSection->SpinCount = 0;
75 lpCriticalSection->RecursionCount = 0;
76 lpCriticalSection->OwningThread =
nullptr;
77 lpCriticalSection->LockSemaphore = (winpr_sem_t*)malloc(
sizeof(winpr_sem_t));
79 if (!lpCriticalSection->LockSemaphore)
84 if (semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 0) !=
90 if (sem_init(lpCriticalSection->LockSemaphore, 0, 0) != 0)
94 SetCriticalSectionSpinCount(lpCriticalSection, dwSpinCount);
97 free(lpCriticalSection->LockSemaphore);
101BOOL InitializeCriticalSectionAndSpinCount(
LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount)
103 return InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0);
106DWORD SetCriticalSectionSpinCount(WINPR_ATTR_UNUSED
LPCRITICAL_SECTION lpCriticalSection,
107 WINPR_ATTR_UNUSED DWORD dwSpinCount)
109 WINPR_ASSERT(lpCriticalSection);
110#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT)
112 DWORD dwPreviousSpinCount = lpCriticalSection->SpinCount;
117 GetNativeSystemInfo(&sysinfo);
119 if (sysinfo.dwNumberOfProcessors < 2)
123 lpCriticalSection->SpinCount = dwSpinCount;
124 return dwPreviousSpinCount;
133 WINPR_ASSERT(lpCriticalSection);
134 WINPR_ASSERT(lpCriticalSection->LockSemaphore);
136#if defined(__APPLE__)
137 semaphore_wait(*((winpr_sem_t*)lpCriticalSection->LockSemaphore));
139 sem_wait((winpr_sem_t*)lpCriticalSection->LockSemaphore);
145 WINPR_ASSERT(lpCriticalSection);
146 WINPR_ASSERT(lpCriticalSection->LockSemaphore);
148 semaphore_signal(*((winpr_sem_t*)lpCriticalSection->LockSemaphore));
150 sem_post((winpr_sem_t*)lpCriticalSection->LockSemaphore);
156 WINPR_ASSERT(lpCriticalSection);
157#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT)
158 ULONG SpinCount = lpCriticalSection->SpinCount;
161 if (SpinCount && TryEnterCriticalSection(lpCriticalSection))
165 while (SpinCount-- && lpCriticalSection->LockCount < 1)
168 if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1)
170 lpCriticalSection->RecursionCount = 1;
171 lpCriticalSection->OwningThread = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
176 if (sched_yield() != 0)
190 if (InterlockedIncrement(&lpCriticalSection->LockCount))
193 if (lpCriticalSection->OwningThread == (HANDLE)(ULONG_PTR)GetCurrentThreadId())
196 lpCriticalSection->RecursionCount++;
201 WaitForCriticalSection(lpCriticalSection);
205 lpCriticalSection->RecursionCount = 1;
206 lpCriticalSection->OwningThread = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
211 HANDLE current_thread = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
213 WINPR_ASSERT(lpCriticalSection);
216 if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1)
218 lpCriticalSection->RecursionCount = 1;
219 lpCriticalSection->OwningThread = current_thread;
224 if (lpCriticalSection->OwningThread == current_thread)
227 lpCriticalSection->RecursionCount++;
228 InterlockedIncrement(&lpCriticalSection->LockCount);
237 WINPR_ASSERT(lpCriticalSection);
240 if (--lpCriticalSection->RecursionCount < 1)
243 lpCriticalSection->OwningThread =
nullptr;
245 if (InterlockedDecrement(&lpCriticalSection->LockCount) >= 0)
248 UnWaitCriticalSection(lpCriticalSection);
253 (void)InterlockedDecrement(&lpCriticalSection->LockCount);
259 WINPR_ASSERT(lpCriticalSection);
261 lpCriticalSection->LockCount = -1;
262 lpCriticalSection->SpinCount = 0;
263 lpCriticalSection->RecursionCount = 0;
264 lpCriticalSection->OwningThread =
nullptr;
266 if (lpCriticalSection->LockSemaphore !=
nullptr)
269 semaphore_destroy(mach_task_self(), *((winpr_sem_t*)lpCriticalSection->LockSemaphore));
271 sem_destroy((winpr_sem_t*)lpCriticalSection->LockSemaphore);
273 free(lpCriticalSection->LockSemaphore);
274 lpCriticalSection->LockSemaphore =
nullptr;