|  | /* | 
|  | * Win32 critical sections | 
|  | * | 
|  | * Copyright 1998 Alexandre Julliard | 
|  | */ | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <errno.h> | 
|  | #include <stdio.h> | 
|  | #include <sys/types.h> | 
|  |  | 
|  | #include "config.h" | 
|  | #include "winerror.h" | 
|  | #include "winbase.h" | 
|  | #include "ntddk.h" | 
|  | #include "heap.h" | 
|  | #include "debugtools.h" | 
|  | #include "thread.h" | 
|  |  | 
|  | DEFAULT_DEBUG_CHANNEL(win32); | 
|  | DECLARE_DEBUG_CHANNEL(relay); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           InitializeCriticalSection   (KERNEL32.472) | 
|  | */ | 
|  | void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit ) | 
|  | { | 
|  | NTSTATUS ret = RtlInitializeCriticalSection( crit ); | 
|  | if (ret) RtlRaiseStatus( ret ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           InitializeCriticalSectionAndSpinCount   (KERNEL32) | 
|  | */ | 
|  | BOOL WINAPI InitializeCriticalSectionAndSpinCount( CRITICAL_SECTION *crit, DWORD spincount ) | 
|  | { | 
|  | NTSTATUS ret = RtlInitializeCriticalSectionAndSpinCount( crit, spincount ); | 
|  | if (ret) RtlRaiseStatus( ret ); | 
|  | return !ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           SetCriticalSectionSpinCount   (KERNEL32) | 
|  | * This function is available on NT4SP3 or later, but not Win98 | 
|  | * It is SMP related | 
|  | */ | 
|  | DWORD WINAPI SetCriticalSectionSpinCount( CRITICAL_SECTION *crit, DWORD spincount ) | 
|  | { | 
|  | ULONG_PTR oldspincount = crit->SpinCount; | 
|  | if(spincount) FIXME("critsection=%p: spincount=%ld not supported\n", crit, spincount); | 
|  | crit->SpinCount = spincount; | 
|  | return oldspincount; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           MakeCriticalSectionGlobal   (KERNEL32.515) | 
|  | */ | 
|  | void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit ) | 
|  | { | 
|  | /* let's assume that only one thread at a time will try to do this */ | 
|  | HANDLE sem = crit->LockSemaphore; | 
|  | if (!sem) NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 ); | 
|  | crit->LockSemaphore = ConvertToGlobalHandle( sem ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ReinitializeCriticalSection   (KERNEL32.581) | 
|  | */ | 
|  | void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit ) | 
|  | { | 
|  | if ( !crit->LockSemaphore ) | 
|  | RtlInitializeCriticalSection( crit ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           UninitializeCriticalSection   (KERNEL32.703) | 
|  | */ | 
|  | void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit ) | 
|  | { | 
|  | RtlDeleteCriticalSection( crit ); | 
|  | } | 
|  |  | 
|  | #ifdef __i386__ | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockCompareExchange (KERNEL32.@) | 
|  | */ | 
|  | PVOID WINAPI InterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare ); | 
|  | __ASM_GLOBAL_FUNC(InterlockedCompareExchange, | 
|  | "movl 12(%esp),%eax\n\t" | 
|  | "movl 8(%esp),%ecx\n\t" | 
|  | "movl 4(%esp),%edx\n\t" | 
|  | "lock; cmpxchgl %ecx,(%edx)\n\t" | 
|  | "ret $12"); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedExchange (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedExchange( PLONG dest, LONG val ); | 
|  | __ASM_GLOBAL_FUNC(InterlockedExchange, | 
|  | "movl 8(%esp),%eax\n\t" | 
|  | "movl 4(%esp),%edx\n\t" | 
|  | "lock; xchgl %eax,(%edx)\n\t" | 
|  | "ret $8"); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedExchangeAdd (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr ); | 
|  | __ASM_GLOBAL_FUNC(InterlockedExchangeAdd, | 
|  | "movl 8(%esp),%eax\n\t" | 
|  | "movl 4(%esp),%edx\n\t" | 
|  | "lock; xaddl %eax,(%edx)\n\t" | 
|  | "ret $8"); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedIncrement (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedIncrement( PLONG dest ); | 
|  | __ASM_GLOBAL_FUNC(InterlockedIncrement, | 
|  | "movl 4(%esp),%edx\n\t" | 
|  | "movl $1,%eax\n\t" | 
|  | "lock; xaddl %eax,(%edx)\n\t" | 
|  | "incl %eax\n\t" | 
|  | "ret $4"); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockDecrement (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedDecrement( PLONG dest ); | 
|  | __ASM_GLOBAL_FUNC(InterlockedDecrement, | 
|  | "movl 4(%esp),%edx\n\t" | 
|  | "movl $-1,%eax\n\t" | 
|  | "lock; xaddl %eax,(%edx)\n\t" | 
|  | "decl %eax\n\t" | 
|  | "ret $4"); | 
|  |  | 
|  | #elif defined(__sparc__) && defined(__sun__) | 
|  |  | 
|  | /* | 
|  | * As the earlier Sparc processors lack necessary atomic instructions, | 
|  | * I'm simply falling back to the library-provided _lwp_mutex routines | 
|  | * to ensure mutual exclusion in a way appropriate for the current | 
|  | * architecture. | 
|  | * | 
|  | * FIXME:  If we have the compare-and-swap instruction (Sparc v9 and above) | 
|  | *         we could use this to speed up the Interlocked operations ... | 
|  | */ | 
|  |  | 
|  | #include <synch.h> | 
|  | static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX; | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedCompareExchange (KERNEL32.@) | 
|  | */ | 
|  | PVOID WINAPI InterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare ) | 
|  | { | 
|  | _lwp_mutex_lock( &interlocked_mutex ); | 
|  |  | 
|  | if ( *dest == compare ) | 
|  | *dest = xchg; | 
|  | else | 
|  | compare = *dest; | 
|  |  | 
|  | _lwp_mutex_unlock( &interlocked_mutex ); | 
|  | return compare; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedExchange (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedExchange( PLONG dest, LONG val ) | 
|  | { | 
|  | LONG retv; | 
|  | _lwp_mutex_lock( &interlocked_mutex ); | 
|  |  | 
|  | retv = *dest; | 
|  | *dest = val; | 
|  |  | 
|  | _lwp_mutex_unlock( &interlocked_mutex ); | 
|  | return retv; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedExchangeAdd (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr ) | 
|  | { | 
|  | LONG retv; | 
|  | _lwp_mutex_lock( &interlocked_mutex ); | 
|  |  | 
|  | retv = *dest; | 
|  | *dest += incr; | 
|  |  | 
|  | _lwp_mutex_unlock( &interlocked_mutex ); | 
|  | return retv; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedIncrement (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedIncrement( PLONG dest ) | 
|  | { | 
|  | LONG retv; | 
|  | _lwp_mutex_lock( &interlocked_mutex ); | 
|  |  | 
|  | retv = ++*dest; | 
|  |  | 
|  | _lwp_mutex_unlock( &interlocked_mutex ); | 
|  | return retv; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		InterlockedDecrement (KERNEL32.@) | 
|  | */ | 
|  | LONG WINAPI InterlockedDecrement( PLONG dest ) | 
|  | { | 
|  | LONG retv; | 
|  | _lwp_mutex_lock( &interlocked_mutex ); | 
|  |  | 
|  | retv = --*dest; | 
|  |  | 
|  | _lwp_mutex_unlock( &interlocked_mutex ); | 
|  | return retv; | 
|  | } | 
|  |  | 
|  | #else | 
|  | #error You must implement the Interlocked* functions for your CPU | 
|  | #endif |