| /* |
| * Win32 kernel functions |
| * |
| * Copyright 1995 Martin von Loewis |
| * Copyright 1997 Onno Hovers |
| */ |
| |
| #include <unistd.h> |
| #include <string.h> |
| #include "windef.h" |
| #include "winerror.h" |
| #include "debug.h" |
| |
| |
| /* |
| * FIXME: |
| * The c functions do not protect from non-interlocked accesses |
| * This is no problem as long as we do not have multiple Win32 threads |
| * or processes. |
| * The assembly macro's do protect from non-interlocked access, |
| * but they will only work for i386 systems with GCC. |
| */ |
| |
| /************************************************************************ |
| * InterlockedIncrement [KERNEL32] * |
| * * |
| * InterlockedIncrement adds 1 to a long variable and returns * |
| * - a negative number if the result < 0 * |
| * - zero if the result == 0 * |
| * - a positive number if the result > 0 * |
| * * |
| * The returned number need not be equal to the result!!!! * |
| ************************************************************************/ |
| |
| LONG WINAPI InterlockedIncrement(LPLONG lpAddend) |
| { |
| #if defined(__i386__)&&defined(__GNUC__) |
| long ret; |
| __asm__ |
| ( |
| "\tlock\n" /* for SMP systems */ |
| "\tincl (%1)\n" |
| "\tje 2f\n" |
| "\tjl 1f\n" |
| "\tincl %0\n" |
| "\tjmp 2f\n" |
| "1:\tdec %0\n" |
| "2:\n" |
| :"=r" (ret):"r" (lpAddend), "0" (0): "memory" |
| ); |
| return ret; |
| #else |
| LONG ret; |
| /* StopAllThreadsAndProcesses() */ |
| |
| (*lpAddend)++; |
| ret=*lpAddend; |
| |
| /* ResumeAllThreadsAndProcesses() */ |
| return ret; |
| #endif |
| } |
| |
| /************************************************************************ |
| * InterlockedDecrement [KERNEL32] * |
| * * |
| * InterlockedIncrement adds 1 to a long variable and returns * |
| * - a negative number if the result < 0 * |
| * - zero if the result == 0 * |
| * - a positive number if the result > 0 * |
| * * |
| * The returned number need not be equal to the result!!!! * |
| ************************************************************************/ |
| |
| LONG WINAPI InterlockedDecrement(LPLONG lpAddend) |
| { |
| #if defined(__i386__)&&defined(__GNUC__) |
| LONG ret; |
| __asm__ |
| ( |
| "\tlock\n" /* for SMP systems */ |
| "\tdecl (%1)\n" |
| "\tje 2f\n" |
| "\tjl 1f\n" |
| "\tincl %0\n" |
| "\tjmp 2f\n" |
| "1:\tdec %0\n" |
| "2:\n" |
| :"=r" (ret):"r" (lpAddend), "0" (0): "memory" |
| ); |
| return ret; |
| #else |
| LONG ret; |
| /* StopAllThreadsAndProcesses() */ |
| |
| (*lpAddend)--; |
| ret=*lpAddend; |
| |
| /* ResumeAllThreadsAndProcesses() */ |
| return ret; |
| #endif |
| } |
| |
| /************************************************************************ |
| * InterlockedExchange [KERNEL32.???] |
| * |
| * Atomically exchanges a pair of values. |
| * |
| * RETURNS |
| * Prior value of value pointed to by Target |
| */ |
| LONG WINAPI InterlockedExchange( |
| LPLONG target, /* Address of 32-bit value to exchange */ |
| LONG value /* New value for the value pointed to by target */ |
| ) { |
| #if defined(__i386__)&&defined(__GNUC__) |
| LONG ret; |
| __asm__ ( /* lock for SMP systems */ |
| "lock\n\txchgl %0,(%1)" |
| :"=r" (ret):"r" (target), "0" (value):"memory" ); |
| return ret; |
| #else |
| LONG ret; |
| /* StopAllThreadsAndProcesses() */ |
| |
| ret=*target; |
| *target=value; |
| |
| /* ResumeAllThreadsAndProcesses() */ |
| return ret; |
| #endif |
| } |
| |
| /************************************************************************ |
| * InterlockedCompareExchange [KERNEL32.879] |
| * |
| * Atomically compares Destination and Comperand, and if found equal exchanges |
| * the value of Destination with Exchange |
| * |
| * RETURNS |
| * Prior value of value pointed to by Destination |
| */ |
| PVOID WINAPI InterlockedCompareExchange( |
| PVOID *Destination, /* Address of 32-bit value to exchange */ |
| PVOID Exchange, /* change value, 32 bits */ |
| PVOID Comperand /* value to compare, 32 bits */ |
| ) { |
| #if defined(__i386__)&&defined(__GNUC__) |
| PVOID ret; |
| __asm__ ( /* lock for SMP systems */ |
| "lock\n\t" |
| "cmpxchgl %2,(%1)" |
| :"=r" (ret) |
| :"r" (Destination),"r" (Exchange), "0" (Comperand) |
| :"memory" ); |
| return ret; |
| #else |
| PVOID ret; |
| /* StopAllThreadsAndProcesses() */ |
| |
| ret=*Destination; |
| if(*Destination==Comperand) *Destination=Exchange; |
| |
| /* ResumeAllThreadsAndProcesses() */ |
| return ret; |
| #endif |
| } |
| |
| /************************************************************************ |
| * InterlockedExchangeAdd [KERNEL32.880] |
| * |
| * Atomically adds Increment to Addend and returns the previous value of |
| * Addend |
| * |
| * RETURNS |
| * Prior value of value pointed to by cwAddendTarget |
| */ |
| LONG WINAPI InterlockedExchangeAdd( |
| PLONG Addend, /* Address of 32-bit value to exchange */ |
| LONG Increment /* Value to add */ |
| ) { |
| #if defined(__i386__)&&defined(__GNUC__) |
| LONG ret; |
| __asm__ ( /* lock for SMP systems */ |
| "lock\n\t" |
| "xaddl %0,(%1)" |
| :"=r" (ret) |
| :"r" (Addend), "0" (Increment) |
| :"memory" ); |
| return ret; |
| #else |
| LONG ret; |
| /* StopAllThreadsAndProcesses() */ |
| |
| ret = *Addend; |
| *Addend += Increment; |
| |
| /* ResumeAllThreadsAndProcesses() */ |
| return ret; |
| #endif |
| } |