Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.

Public Report
Report From: Delphi-BCB/RTL/Delphi/WinAPI    [ Add a report in this area ]  
Report #:  6212   Status: Open
Lack of InterlockedXxx Windows API definitions in Windows.pas
Project:  Delphi Build #:  ALL
Version:    15.1 Submitted By:   Will DeWitt Jr.
Report Type:  Basic functionality failure Date Reported:  10/16/2003 7:33:56 AM
Severity:    Commonly encountered problem Last Updated: 3/20/2012 2:24:39 AM
Platform:    All platforms Internal Tracking #:   283775
Resolution: None (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: (6 Total Ratings)
5.00 out of 5
Total Votes: None
Description
Added by Sysop
<<<<<<<<<<<<<
See comments of QC for more details.
>>>>>>>>>>>>>

Windows Server 2003 includes a number of new Interlocked functions that would be very useful across all platforms.  What this report asks is that the specified functions be included in Delphi's RTL.  This would remove the version requirements for using the Win32 functions (as well as provide the functionality to LINUX users).  Below is a listing of the functions I'd like to see included in the RTL--

InterlockedIncrement64
InterlockedDecrement64
InterlockedExchange64
InterlockedExchangeAdd64
InterlockedCompareExchange64

SysUtils.pas (as of Delphi 6) implements a subset of Interlocked functions and defines them for LINUX compiles of that unit.  Because those functions use the register calling convention they are inherently faster than the Win32 API's implementation (which uses stdcall).  It would be nice if these functions were not limited to LINUX compiles, but were always included so developers could leverage their slightly faster performance.

NOTE: Implementing these would require changing the minimum processor to execute Delphi applications from 486 to Pentium (CMPXCHG8B is only available on Pentium and later processors, and AFAIK this is the only way to implement 64-bit atomic operations).  The Pentium requirement would *only* exist if a developer used one of these functions in their code, otherwise the code would still run fine on a 486.
Steps to Reproduce:

Added by Sysop
<<<<<<<<<<<<
This is the complete list of Interlocked functions that are defined in the Windows API but not in Delphi:

InterlockedAdd64
InterlockedAnd
InterlockedAnd16
InterlockedAnd64
InterlockedAnd8
InterlockedBitTestAndReset
InterlockedBitTestAndReset64
InterlockedBitTestAndSet
InterlockedBitTestAndSet64
InterlockedCompare64Exchange128
InterlockedDecrement64
InterlockedExchange64
InterlockedExchangeAdd64
InterlockedIncrement64
InterlockedOr
InterlockedOr16
InterlockedOr64
InterlockedOr8
InterlockedXor
InterlockedXor16
InterlockedXor64
InterlockedXor8
>>>>>>>>>>>>
Workarounds
{ From my limited testing, these functions all seem to work.  These implement all the requested functions listed in the report.  I've prefixed them with 'Quick' because they use the register calling convention (and are (presumably) quicker as a result.  =)).  Note that the code below requires at least a Pentium (classic) to execute!

- Will }

function  QuickInterlockedDecrement64(var Addend: Int64): Int64; register;
asm
{     ->          EAX     Addend }
{     <-          EDX:EAX Result }
          PUSH    EDI
          PUSH    EBX

          MOV     EDI, EAX

          MOV     EAX, [EDI]    // Fetch original Int64 at memory location
          MOV     EDX, [EDI+4]
@@1:
          MOV     ECX, EDX
          MOV     EBX, EAX

          SUB     EBX, 1
          SBB     ECX, 0

LOCK      CMPXCHG8B [EDI]
          JNZ     @@1

          { Returns updated value of Addend }
          MOV     EAX, EBX
          MOV     EDX, ECX

          POP     EBX
          POP     EDI
end;

function  QuickInterlockedIncrement64(var Addend: Int64): Int64; register;
asm
{     ->          EAX     Addend }
{     <-          EDX:EAX Result }
          PUSH    EDI
          PUSH    EBX

          MOV     EDI, EAX

          MOV     EAX, [EDI]    // Fetch original Int64 at memory location
          MOV     EDX, [EDI+4]
@@1:
          MOV     ECX, EDX
          MOV     EBX, EAX

          ADD     EBX, 1
          ADC     ECX, 0

LOCK      CMPXCHG8B [EDI]
          JNZ     @@1

          { Returns updated value of Addend }
          MOV     EAX, EBX
          MOV     EDX, ECX

          POP     EBX
          POP     EDI
end;

function  QuickInterlockedExchangeAdd64(var Addend: Int64; Value: Int64): Int64; register;
asm
{     ->          EAX     Addend }
{                 ESP+4   Value  }
{     <-          EDX:EAX Result }

          PUSH    EDI
          PUSH    ESI
          PUSH    EBP
          PUSH    EBX

          MOV     ESI, DWORD PTR [Value]    // EDI:ESI = Value
          MOV     EDI, DWORD PTR [Value+4]
          MOV     EBP, EAX

          MOV     EAX, [EBP]    // EDX:EAX = Addend (fetch original Int64 value)
          MOV     EDX, [EBP+4]
@@1:
          MOV     ECX, EDX      // ECX:EBX = Addend
          MOV     EBX, EAX

          ADD     EBX, ESI
          ADC     ECX, EDI

LOCK      CMPXCHG8B [EBP]
          JNZ     @@1
          // Returns initial value in Addend

          POP     EBX
          POP     EBP
          POP     ESI
          POP     EDI
end;

function  QuickInterlockedExchange64(var Target: Int64; Value: Int64): Int64; register;
asm
{     ->          EAX     Target }
{                 ESP+4   Value  }
{     <-          EDX:EAX Result }
          PUSH    EDI
          PUSH    EBX

          MOV     EDI, EAX

          MOV     EAX, [EDI]
          MOV     EDX, [EDI+4]

          MOV     EBX, DWORD PTR [Value]
          MOV     ECX, DWORD PTR [Value+4]
@@1:
LOCK      CMPXCHG8B [EDI]
          JNZ     @@1
          // Returns initial value in Target

          POP     EBX
          POP     EDI
end;

function  QuickInterlockedCompareExchange64(var Destination: Int64; Exchange, Comperand: Int64): Int64; register;
asm
{     ->          EAX     Destination }
{                 ESP+4   Exchange    }
{                 ESP+12  Comperand   }
{     <-          EDX:EAX Result      }
          PUSH    EBX
          PUSH    EDI

          MOV     EDI, EAX

          MOV     EAX, DWORD PTR [Comperand]
          MOV     EDX, DWORD PTR [Comperand+4]

          MOV     EBX, DWORD PTR [Exchange]
          MOV     ECX, DWORD PTR [Exchange+4]

LOCK      CMPXCHG8B [EDI]

          POP     EDI
          POP     EBX
end;
Attachment
None
Comments

Ritsaert Hornstra at 10/20/2003 11:17:48 AM -
Why rely on the Win32 implementation?

If SyncObjs is extended with these functions and interlocked functions for 32bit it can also run under Linux with Kylix. You already give a give default implementation ;-)

Will DeWitt Jr. at 10/20/2003 12:20:06 PM -
> Why rely on the Win32 implementation?

I should probably re-word the report-- I'm asking for Borland to include implementations of the functions as defined in Windows Server 2003 (this is mostly for consistancy, so developers can quickly see that these functions are identical in their parameters as their Win32 cousins and just drop them in and go).  The code would be in SyncObjs or maybe even in System (I personally prefer System, I know they're generally categorized with synchronization functions but they also provide a very low level interface to almost universally available CPU capabilities).  

> If SyncObjs is extended with these functions and interlocked functions for 32bit it can also run under Linux with Kylix. You already give a give default implementation ;-)

=)  Yeah, this is what I'd like to see, the actual functions implemented in Delphi's RTL so that we can a) avoid the version issues of Windows (in the case of 64-bit interlocked functions, you need Windows Server 2003, lower versions of Windows such as XP and 2000 won't have these functions) and b) gain some additional performance by avoiding the stdcall calling convention.

I'll see about re-wording the report a bit so it's easier to understand.  =)

Gorazd Jernejc at 5/8/2008 2:39:50 PM -
Posible thread dead lock..
Look: http://qc.borland.com/wc/qcmain.aspx?d=61914

Jan Goyvaerts at 6/12/2011 6:30:46 PM -
This is the complete list of Interlocked functions that are defined in the Windows API but not in Delphi:

InterlockedAdd64
InterlockedAnd
InterlockedAnd16
InterlockedAnd64
InterlockedAnd8
InterlockedBitTestAndReset
InterlockedBitTestAndReset64
InterlockedBitTestAndSet
InterlockedBitTestAndSet64
InterlockedCompare64Exchange128
InterlockedDecrement64
InterlockedExchange64
InterlockedExchangeAdd64
InterlockedIncrement64
InterlockedOr
InterlockedOr16
InterlockedOr64
InterlockedOr8
InterlockedXor
InterlockedXor16
InterlockedXor64
InterlockedXor8

Tomohiro Takahashi at 6/12/2011 6:53:48 PM -
Thanks for the notificaton.
I refreshed status of this report as Sysop.

Jan Goyvaerts at 6/13/2011 2:08:09 AM -
Delphi XE (and possibly earlier verisons) has a TInterlocked class in the SyncObjs unit that implements 64-bit interlocked operations.  But it does not implement the full set of interlocked operations supported by the Windows API.  Adding those may still be useful.

Server Response from: ETNACODE01