

@AT
Members-
Content Count
15 -
Joined
-
Last visited
Everything posted by @AT
-
Recently I was looked into the `assembler` code generated with Delphi 12.3 for the snipped below: ... var [volatile] Src, Dst: TObject; ... begin ... Src:=TObject.Create; Dst:=TInterlocked.Exchange(Src, nil); FreeAndNil(Dst); ... end; And I see this code (Win32 Target): TestInterlocked.dpr.31: Src:=TObject.Create; 003823FD B201 mov dl,$01 003823FF A1EC162B00 mov eax,[$002b16ec] 00382404 E85B66F3FF call $002b8a64 00382409 8945FC mov [ebp-$04],eax TestInterlocked.dpr.32: Dst:=TInterlocked.Exchange(Src, nil); 0038240C 33C0 xor eax,eax 0038240E 8945F0 mov [ebp-$10],eax 00382411 8B45F0 mov eax,[ebp-$10] 00382414 8945EC mov [ebp-$14],eax 00382417 8D45FC lea eax,[ebp-$04] 0038241A 8B55EC mov edx,[ebp-$14] 0038241D E886F5FFFF call $003819a8 00382422 8945E8 mov [ebp-$18],eax 00382425 8B45E8 mov eax,[ebp-$18] 00382428 8945F8 mov [ebp-$08],eax TestInterlocked.dpr.33: FreeAndNil(Dst); 0038242B 8B45F8 mov eax,[ebp-$08] 0038242E 8945E4 mov [ebp-$1c],eax 00382431 33C0 xor eax,eax 00382433 8945F8 mov [ebp-$08],eax 00382436 8B45E4 mov eax,[ebp-$1c] 00382439 E85666F3FF call $002b8a94 I do not think the code generated for the Dst:=TInterlocked.Exchange(Src, nil); call is atomic and thread safe. I have compared what compiler does for the next snippet: ... var [volatile] Src, Dst: TObject; ... begin ... Src:=TObject.Create; Dst:=AtomicExchange(Src, nil); FreeAndNil(Dst); ... end; and see the big difference: TestInterlocked.dpr.27: Src:=TObject.Create; 003823D2 B201 mov dl,$01 003823D4 A1EC162B00 mov eax,[$002b16ec] 003823D9 E88666F3FF call $002b8a64 003823DE 8945FC mov [ebp-$04],eax TestInterlocked.dpr.28: Dst:=AtomicExchange(pointer(Src), nil); 003823E1 33C0 xor eax,eax 003823E3 F08745FC lock xchg [ebp-$04],eax 003823E7 8945F8 mov [ebp-$08],eax TestInterlocked.dpr.29: FreeAndNil(Dst); 003823EA 8B45F8 mov eax,[ebp-$08] 003823ED 8945F4 mov [ebp-$0c],eax 003823F0 33C0 xor eax,eax 003823F2 8945F8 mov [ebp-$08],eax 003823F5 8B45F4 mov eax,[ebp-$0c] 003823F8 E89766F3FF call $002b8a94 The AtomicExchange instrict function generate an atomic code. I suspect that the reason of it is type conversions used in TInterlocked.Exchange, TInterlocked.CompareExchange for the floating point types, TObject, and class generic types. I haven't check what the assembler code generated for the example above by pre-12.x compilers. I would appreciate it if someone can check it with 10.x and 11.x. P.S. TInterlocked.Exchange generate correct code for simple types (integers, pointers, boolean), but adds additional code to Class types and floating point types makes them vulnerable to multithread race condition errors.
-
Are TInterlocked.Exchange and CompareExchange implementation really Atomic with class types??
@AT replied to @AT's topic in RTL and Delphi Object Pascal
Thank you Stefan! You run ahead of me . In my point of view it's not an compiler inlining issue, but the source code issue. If you look at the Embarcadero sources, they use explicit type cast like ...Exchange(pointer(InstanceVar)... much often than ...Exchange<classtype>(... in their own code. However, it might a result of late implementation generic method. Absolutely. I so appreciated for correcting my wording and providing additional information which could be useful for the community. However, it does not mean I have luck of understanding difference of atomic operations and locking primitives and use-cases where they should be used. This topic is closed for me, I have a clear answer on my question already. -
Regression - Delphi 12 - Unable to debug dynamically loaded packages
@AT posted a topic in Delphi IDE and APIs
I'm facing regression in Delphi 12 which blocks me in debugging EMS Server packages. Debugger does not stop at any breakpoints in source code; debugger does not display any symbols in CPU Debug View when execution is stopped in the package, After short investigation I found that local debuggers (Win32, Win64) do not load debug symbols for dynamically loaded packages via LoadPackage function. Issue is reproduced with Delphi 12 SP1 and is not reproduced in Delphi 11.3. -
Are TInterlocked.Exchange and CompareExchange implementation really Atomic with class types??
@AT replied to @AT's topic in RTL and Delphi Object Pascal
Ok, type-casting is correct wording. Thanks again for correcting me. However, there is a big difference between: pointer(someVar) and T((@someVar)^) type-casting when someVar is a class instance variable. First variant does not adds extra code, but second one enforces compiler to get the pointer and then dereference it. This was a source of original question. -
Are TInterlocked.Exchange and CompareExchange implementation really Atomic with class types??
@AT replied to @AT's topic in RTL and Delphi Object Pascal
Thank you for pointing it out. I corrected the example above. I do not confuse atomic operation with locking primitives. I'm refactoring some legacy code which use a lot of locking primitives mostly for updating a single "global" variable of simple type, class or pointer inside a protected code section. So I'm planning to replace some of them with an atomic functions. As I wrote above, I was worried with assembler code generated for a specific methods: TInterlocked.Exchange<T: class> and TInterlocked.CompareExhchange<T: class>... This was a reason why I raised this question. -
Are TInterlocked.Exchange and CompareExchange implementation really Atomic with class types??
@AT replied to @AT's topic in RTL and Delphi Object Pascal
I meant unsuccessful Interlocked.CompareExchange calls returns False. for example, how many collisions (unsuccessful exchanges) this code may generate in heavy loaded multithreading environment: var lSW: TSpinWatch; var lObj: TObject:=CreateNewObject; // CreateNewObject: TObject; var lOldObj: TObject:=nil; var lSucc: boolean; lSW.Reset repeat // FFIeld is a "global" variable TObject type var lCmp:=FField; lOldObj:=TInterlocked.CompareExchange(FField, lObj, lCmp, lSucc); if lSucc then break; lSW.SpinWaitl until True; // do something with lOldObj below // ... in comparison to: var lOldObj: TObject:=nil; FCriticalSection.Enter; // FCriticalSection: TCriticalSection; "global" variable. try lOldObj:=FField; FField:=CreateNewObj; finally FCriticalSection.Leave; end // do something with lOldObj below // ... It's clear, using AtomicExchange functions can generate faster code (where is possible) than the code using locking mechanism. But my worry was that multiprocessor concurrent environment may generate a lot of "collisions" in attempts to update shared variable with Interlocked.CompareExchange<T: class>... method due to additional explicit type conversion code. -
Are TInterlocked.Exchange and CompareExchange implementation really Atomic with class types??
@AT replied to @AT's topic in RTL and Delphi Object Pascal
Thank you folks for your comments. I have to agree with your comments. My original example was simple, but did not show my concern. The Interlocked.CompareExchange methods uses the same semantics and the same explicit conversion for the Generic class types. I expected that explicit conversion increases unsuccessful atomic exchange attempts in the Generic variant in comparison to Pointer variant due to increased CPU command instructions in the Generic variant method. However, my experiments displays that they are close to each other. -
Are TInterlocked.Exchange and CompareExchange implementation really Atomic with class types??
@AT replied to @AT's topic in RTL and Delphi Object Pascal
I showed the example above. AtomicExchange primitive generate correct thread-safe code. Variable value exchanges with the register value in atomic operation which can not be interrupted in the middle of execution. TestInterlocked.dpr.28: Dst:=AtomicExchange(pointer(Src), nil); 003823E1 33C0 xor eax,eax 003823E3 F08745FC lock xchg [ebp-$04],eax 003823E7 8945F8 mov [ebp-$08],eax It you look to the TInterlocked class source code you can find bunch of type conversions: class function TInterlocked.Exchange(var Target: Pointer; Value: Pointer): Pointer; begin Result := AtomicExchange(Target, Value); end; ... class function TInterlocked.Exchange<T>(var Target: T; Value: T): T; begin TObject((@Result)^) := Exchange(TObject((@Target)^), TObject((@Value)^)); end; So, Compiler inlines the only TInterlocked.Exchange<T>(var Target: T; Value: T): T function with explicit underlaid call to TInterlocked.Exchange(var Target: Pointer; Value: Pointer): Pointer; Assembler code displays explicit conversions defined in the Pascal code like TObject((@Value)^), TObject((@Value)^) and TObject((@Result)^) As this assembler code generates multiple set of instructions (tossing register to variables and) vice versa before and after the real exchange, this actual result may be overwritten in the middle by other thread. So my concern is that the TInterlocked.Exchange is called as and atomic primitive, which is not correct in some of declared cases. -
Remote Debugging "Attach To Process" on non-Windows platforms
@AT posted a topic in Delphi IDE and APIs
I'm trying to debug shared library loaded by Linux application. I need to attach debugging session to existing process on remote machine. However, ""Run"->"Attach To Process" configuration form is empty for any debuggers except Windows debuggers. Delphi documentation refers that I should select Connection Profile for remote debugger; however, this field is not available I choose Linux 64-Bit debugger, or any other non-Windows debugger in "Attach To Process" configuration form. I use Delphi 11.4 and 12 IDEs both of them have the same behavior. "Attach To Process" configuration from looks like at attached screenshot. Does anyone have experience with experience with attaching to the Linux process debugging in Delphi/RAD Studio IDE? -
Remote Debugging "Attach To Process" on non-Windows platforms
@AT replied to @AT's topic in Delphi IDE and APIs
Hello Lars, I'm absolutely unsure that gdb.exe must be installed on the development host. Starting 11.3 Delphi support only LLDB: https://docwiki.embarcadero.com/RADStudio/Athens/en/11_Alexandria_-_Release_3#Debuggers -
Remote Debugging "Attach To Process" on non-Windows platforms
@AT replied to @AT's topic in Delphi IDE and APIs
Hello Lars, Of course, I have read that; however it works well for local and remote Windows Debugging only. Ok, let me explain the issue in more details. II have environments developing Delphi applications for Windows, MacOS and Linux for long time. They are more or less stable for normal application development and debugging. However, I can use remote debugging for Linux and MacOS only using "Run Debug" option. "Launch Process" and "Attach to Process" do not work with with MacOS and Linux debuggers. I just found that RAD Studio documentation in this area is unsynchronized and confused: Two documents below describe how to set-up remote debugging including "Attach to Process" and "Load Process" with remote Linux and MacOS. https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Attach_to_Process https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Attaching_to_a_Running_Process However, the https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Debugging_Multi-Device_Applications says "Attachment to a running process is not supported for the Embarcadero Linux 64-bit Debugger, Embarcadero iOS Device 64-bit Debugger, Embarcadero Android 32-bit Debugger, Embarcadero Android 64-bit Debugger, Embarcadero macOS 64-bit Debugger, and Embarcadero macOS ARM 64-bit Debugger.". This document also confirm that "Load Process" debugging functionality works on Linux and MacOS. However, in my environment the "Launch Process" displays error message Unable to start LLDB kernel: "Unable to find program, gdb.exe", which does look weird for me. -
Remote Debugging "Attach To Process" on non-Windows platforms
@AT replied to @AT's topic in Delphi IDE and APIs
Thank you havrlisan for you comment. However, my original question is a first post in this thread. I'm wondering if anyone uses "Attach to the process" debugger functionality with non-Windows applications and does anyone have the similar issue as I described in that post. -
Remote Debugging "Attach To Process" on non-Windows platforms
@AT replied to @AT's topic in Delphi IDE and APIs
I'm wondering if anyone debugs non-windows application 🙂 -
What new features would you like to see in Delphi 13?
@AT replied to PeterPanettone's topic in Delphi IDE and APIs
My list of preferences: arm64 compiler for Linux Enable Generic functions (pure functions/procedures, but not members of classes) Ability to declare external functions without pointing library names (to simplify writing libraries for Linux applications (both, shared and statically linked) Static Code Analysis build-in Improve "Refactor" functionality [Need to think more...] -
Remote Debugging "Attach To Process" on non-Windows platforms
@AT replied to @AT's topic in Delphi IDE and APIs
Hello Remy,, Of course, I have configured Connection profile already. Regular debugging with "Run", "Run with parameters...", "Load Process..." work well with Linux. The problem is only with "Attach To Process" debugging.