Jump to content

Anders Melander

Members
  • Content Count

    2312
  • Joined

  • Last visited

  • Days Won

    119

Everything posted by Anders Melander

  1. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    You are right about that but they can fix TMonitor (the ABA problem) by using a private, correct implementation of InterlockedCompareExchange128 without breaking DCU compatibility. They could also just implement a temporary fix for InterlockedCompareExchange128 that maintains the incorrect return type (bool) but returns the correct value.
  2. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Not fixed in 10.4: InterlockedCompareExchange128 EventCache Push and Pop ABA problem I guess we were too late 😞
  3. Anders Melander

    Front-end vs Back-end question

    It depends. Next question.
  4. Anders Melander

    TDBImage descendant

    Which the TPicture.Graphic help also clearly state: ...and the TPicture.Assign help is also pretty clear:
  5. I think you are. You are not presenting the subject in a neutral way and your arguments are all over the place. I'm not biting.
  6. Anders Melander

    app logins

    One important thing to keep in mind is that once a customer (i.e. a subscriber) becomes a non-customer, then you have to get rid of any identifying data. Anonymizing the data is Okay. Basically you must not store any personal data that is not vital to servicing the customer. Even if the data is "nice to have", might come in handy or whatever. Exactly. GDPR is not something you ask to have explained in some forum. You need to read up on and understand the issues involved because it's your responsibility to make your software compliant.
  7. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Yes, so you can revert your change in RSP-28272. They copy the result back to the ComparandResult parameter (or rather the 128 bit value it points to). See the InterlockedCompareExchange128 documentation: Because the stress test does not use return value in the ComparandResult parameter. My test code (see an earlier post) includes a test of InterlockedCompareExchange128 which does validate that ComparandResult is set correctly.
  8. Anders Melander

    How to flip image taken from front camera

  9. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Thanks for the update. Note that more threads does not necessarily result in a higher likelihood of failure. More threads means more overhead (context switching and so on) and less time spent actually exercising the code we want to test. I think the the goal should be to loop as fast as possible (i.e. perform as many operations as possible), utilizing all available CPUs, with as few context switches and as little kernel mode as possible.
  10. Anders Melander

    Error creating form: Ancestor for 'TMyDataModule' not found

    Is something preventing you from posting a minimal project that reproduces the problem, so we can avoid this pointless guesswork?
  11. Anders Melander

    Detect Windows shutdown?

    That's not how you do it. You need to let the message handler return with the status you've set, and then call SaveData. You also seem to be confused about the meaning of the WM_QUERYENDSESSION result value. False means you wish to postpone the shutdown. Something like this: const MSG_SAVEDATA = WM_USER; type TForm3 = class(TForm) ... protected procedure MsgSaveData(var Msg: TMessage); message MSG_SAVEDATA; ... end; procedure TForm3.WMQueryEndSession(var Msg: TWMQueryEndSession); begin Msg.Result := lResult(not DataToBeSaved); if (DataToBeSaved) then PostMessage(Handle, MSG_SAVEDATA, 0, 0); end; procedure TForm3.MsgSaveData(var Msg: TMessage); begin SaveData; end;
  12. Anders Melander

    Destroying TList with Managed Types

    Isn't that supposed to be a no-no. I seem to recall there's a problem with premature release when creating an instance as a parameter if the parameter is declared const. Edit: Never mind. The as takes care of that problem.
  13. Anders Melander

    Error creating form: Ancestor for 'TMyDataModule' not found

    Then I'm afraid I can't reproduce the problem. Can you attach a minimal project (just the dpr, dproj and two datamodule units) which reproduces the problem. And please state what version of Delphi you're using.
  14. Anders Melander

    Error creating form: Ancestor for 'TMyDataModule' not found

    https://stackoverflow.com/questions/4518521/delphi-how-to-get-rid-of-ancestor-of-tmyform-not-found-error TL;DR Make sure all data modules (and forms) are declared in the DPR uses list on the form: <unit name> in '<file name>' {<instance variable name>: <base type>}, e.g. ModuleFoo in 'datamodules\ModuleFoo.pas' {DataModuleFoo: TDataModule}, I'm guessing this should work too: ModuleFoo in 'datamodules\ModuleFoo.pas' {TDataModule},
  15. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Yes. You are right. As I read it .NOFRAME tells the compiler that I'm not calling anything and don't need a stack frame. Of course that means I'm relying on the existing stack frame having room for the single register we're pushing. I guess removing .NOFRAME would be the safe thing to do.
  16. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Aaaaand there's an additional problem with InterlockedCompareExchange128: It doesn't return any value in the ComparandResult parameter. It's supposed to return the new value on success and the current value on failure. Anyway, here's my final (hopefully) fixed version of InterlockedCompareExchange128 which conforms to the Win32 API documentation: {$IFDEF Win64} function InterlockedCompareExchange128(Destination: Pointer; ExchangeHigh, ExchangeLow: Int64; ComparandResult: Pointer): boolean; // The parameters are in the RCX, RDX, R8 and R9 registers per the MS x64 calling convention: // RCX Destination // RDX ExchangeHigh // R8 ExchangeLow // R9 ComparandResult // // CMPXCHG16B requires the following register setup: // RDX:RAX ComparandResult.High:ComparandResult.Low // RCX:RBX ExchangeHigh:ExchangeLow // See: https://www.felixcloutier.com/x86/cmpxchg8b:cmpxchg16b asm .NOFRAME .PUSHNV RBX MOV R10,Destination // RCX MOV RBX,ExchangeLow // R8 MOV RCX,ExchangeHigh // RDX MOV RDX,[ComparandResult+8] // R9 MOV RAX,[ComparandResult] // R9 LOCK CMPXCHG16B [R10] MOV [ComparandResult+8],RDX // R9 MOV [ComparandResult],RAX // R9 SETZ BL XOR EAX, EAX MOV AL,BL end; {$ENDIF Win64} and here's the test I used against it: type T128 = record Low: pointer; High: pointer; end; procedure TestInterlockedCompareExchange128; const Value: T128 = (low: pointer($0010203040506070); high: pointer($8090A0B0C0D0E0F)); var Dest, OldValue, NewValue: T128; begin (* ** Test success *) Dest := Value; OldValue := Value; NewValue.Low := pointer($ABABABABABABABAB); NewValue.High := pointer($1212121212121212); // InterlockedCompareExchange128 should return True Assert(InterlockedCompareExchange128(@Dest, Int64(NewValue.High), Int64(NewValue.Low), @OldValue), 'Success expected'); // Dest contains new value Assert(Dest.Low = NewValue.Low); Assert(Dest.High = NewValue.High); // Comparand contains new value = old value Assert(OldValue.Low = Value.Low); Assert(OldValue.High = Value.High); (* ** Test failure *) Dest := Value; OldValue.Low := pointer($ABABABABABABABAB); OldValue.High := pointer($1212121212121212); NewValue.Low := nil; NewValue.High := nil; // InterlockedCompareExchange128 should return False Assert(not InterlockedCompareExchange128(@Dest, Int64(NewValue.High), Int64(NewValue.Low), @OldValue), 'Failure expected'); // Dest contains original value Assert(Dest.Low = Value.Low); Assert(Dest.High = Value.High); // Comparand contains original value Assert(OldValue.Low = Value.Low); Assert(OldValue.High = Value.High); end; With this fix my event stack test passes no matter how hard I hit it.
  17. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    There's one thing that bothers me with both InterlockedCompareExchange128 and CAS. They both return a boolean indicating if the swap was performed or not. They correctly do so by examining ZF after calling CMPXCHG16B. If the flag is set they set AL to 1, otherwise clear it to zero: CMPXCHG16B [...] SETZ AL The problem is that the caller examines the value of AX to get the boolean result: call InterlockedCompareExchange128 test eax,eax jnz ... Now what about the value that just happens to be in AH? I would think that we'd need to clear AX before calling SETZ: CMPXCHG16B [...] XOR EAX, EAX SETZ AL Edit: Whoops. XOR EAX,EAX sets ZF.
  18. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    I've looked at several but they just wrap CMPXCHG16B like CAS does. I think I have an old version of msvc installed somewhere but I think it predates InterlockedCompareExchange128.
  19. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Thanks but that can't be the only problem with it. My tests fail even with that detail fixed but passes with the OmniThreadLibrary CAS. I can't spot what the problem is.
  20. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Ah, that was why I couldn't get the alignment working. The "packed" wasn't there from the start but at some point I think I must have copied your changes back into my own.
  21. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Well, I just tried it anyway. With the CAS version my test passes with 100 threads each doing 10 million operations. I'll have to compare the assembler of the calling code - but first I have some large quantities of pizza to prepare and eat and then I'm watching Astralis anihilate G2.
  22. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    Probably. It's not a problem but of course it would be nice it we had access now that we're hacking at the problem.
  23. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    That function is too obscure; I'm not using it. The oldReference parameter is unused and as I said it's not setting the RDX register.
  24. Anders Melander

    Revisiting TThreadedQueue and TMonitor

    I got rid of the AV in CMPXCHG16B by allocating the stack head on the heap thus ensuring correct alignment, but I'm still experiencing problems with 64-bit. At some point, when freeing a block returned by Pop, I get an EInvalidPointer exception from FastMM. Other times I end up with a negative count of items on the stack. I can reproduce with just two threads! Occasionally the error occurs after less than 20 operations. Test source attached. UnitEventStackTest.pas UnitEventStackTest.dfm
×