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 InitializeCriticalSectionEx(lpCriticalSection, 0, 0);
52BOOL InitializeCriticalSectionEx(
LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount,
55 WINPR_ASSERT(lpCriticalSection);
68 WLog_WARN(TAG,
"Flags unimplemented");
71 lpCriticalSection->DebugInfo = NULL;
72 lpCriticalSection->LockCount = -1;
73 lpCriticalSection->SpinCount = 0;
74 lpCriticalSection->RecursionCount = 0;
75 lpCriticalSection->OwningThread = NULL;
76 lpCriticalSection->LockSemaphore = (winpr_sem_t*)malloc(
sizeof(winpr_sem_t));
78 if (!lpCriticalSection->LockSemaphore)
83 if (semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 0) !=
89 if (sem_init(lpCriticalSection->LockSemaphore, 0, 0) != 0)
93 SetCriticalSectionSpinCount(lpCriticalSection, dwSpinCount);
96 free(lpCriticalSection->LockSemaphore);
100BOOL InitializeCriticalSectionAndSpinCount(
LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount)
102 return InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0);
105DWORD SetCriticalSectionSpinCount(WINPR_ATTR_UNUSED
LPCRITICAL_SECTION lpCriticalSection,
106 WINPR_ATTR_UNUSED DWORD dwSpinCount)
108 WINPR_ASSERT(lpCriticalSection);
109#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT)
111 DWORD dwPreviousSpinCount = lpCriticalSection->SpinCount;
116 GetNativeSystemInfo(&sysinfo);
118 if (sysinfo.dwNumberOfProcessors < 2)
122 lpCriticalSection->SpinCount = dwSpinCount;
123 return dwPreviousSpinCount;
132 WINPR_ASSERT(lpCriticalSection);
133 WINPR_ASSERT(lpCriticalSection->LockSemaphore);
135#if defined(__APPLE__)
136 semaphore_wait(*((winpr_sem_t*)lpCriticalSection->LockSemaphore));
138 sem_wait((winpr_sem_t*)lpCriticalSection->LockSemaphore);
144 WINPR_ASSERT(lpCriticalSection);
145 WINPR_ASSERT(lpCriticalSection->LockSemaphore);
147 semaphore_signal(*((winpr_sem_t*)lpCriticalSection->LockSemaphore));
149 sem_post((winpr_sem_t*)lpCriticalSection->LockSemaphore);
155 WINPR_ASSERT(lpCriticalSection);
156#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT)
157 ULONG SpinCount = lpCriticalSection->SpinCount;
160 if (SpinCount && TryEnterCriticalSection(lpCriticalSection))
164 while (SpinCount-- && lpCriticalSection->LockCount < 1)
167 if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1)
169 lpCriticalSection->RecursionCount = 1;
170 lpCriticalSection->OwningThread = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
175 if (sched_yield() != 0)
189 if (InterlockedIncrement(&lpCriticalSection->LockCount))
192 if (lpCriticalSection->OwningThread == (HANDLE)(ULONG_PTR)GetCurrentThreadId())
195 lpCriticalSection->RecursionCount++;
200 WaitForCriticalSection(lpCriticalSection);
204 lpCriticalSection->RecursionCount = 1;
205 lpCriticalSection->OwningThread = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
210 HANDLE current_thread = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
212 WINPR_ASSERT(lpCriticalSection);
215 if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1)
217 lpCriticalSection->RecursionCount = 1;
218 lpCriticalSection->OwningThread = current_thread;
223 if (lpCriticalSection->OwningThread == current_thread)
226 lpCriticalSection->RecursionCount++;
227 InterlockedIncrement(&lpCriticalSection->LockCount);
236 WINPR_ASSERT(lpCriticalSection);
239 if (--lpCriticalSection->RecursionCount < 1)
242 lpCriticalSection->OwningThread = NULL;
244 if (InterlockedDecrement(&lpCriticalSection->LockCount) >= 0)
247 UnWaitCriticalSection(lpCriticalSection);
252 (void)InterlockedDecrement(&lpCriticalSection->LockCount);
258 WINPR_ASSERT(lpCriticalSection);
260 lpCriticalSection->LockCount = -1;
261 lpCriticalSection->SpinCount = 0;
262 lpCriticalSection->RecursionCount = 0;
263 lpCriticalSection->OwningThread = NULL;
265 if (lpCriticalSection->LockSemaphore != NULL)
268 semaphore_destroy(mach_task_self(), *((winpr_sem_t*)lpCriticalSection->LockSemaphore));
270 sem_destroy((winpr_sem_t*)lpCriticalSection->LockSemaphore);
272 free(lpCriticalSection->LockSemaphore);
273 lpCriticalSection->LockSemaphore = NULL;