-
Content Count
2771 -
Joined
-
Last visited
-
Days Won
147
Everything posted by Anders Melander
-
Which the TPicture.Graphic help also clearly state: ...and the TPicture.Assign help is also pretty clear:
-
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.
-
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.
-
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
- 2 replies
-
- camera
- tcameracomponent
-
(and 1 more)
Tagged with:
-
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Error creating form: Ancestor for 'TMyDataModule' not found
Anders Melander replied to Sonjli's topic in VCL
Is something preventing you from posting a minimal project that reproduces the problem, so we can avoid this pointless guesswork? -
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;
-
Destroying TList with Managed Types
Anders Melander replied to Trevor S's topic in RTL and Delphi Object Pascal
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. -
Error creating form: Ancestor for 'TMyDataModule' not found
Anders Melander replied to Sonjli's topic in VCL
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. -
Error creating form: Ancestor for 'TMyDataModule' not found
Anders Melander replied to Sonjli's topic in VCL
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}, -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
No access. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
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 -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
There's RSP-23333 which is about this problem. I've already posted a link to the original article and this thread to the report. Beyond that it would be nice if someone on the 10.4 field test could bring it to the attention of those that can do something about it. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
I'm aware that it's a noop in this case and I was leaving that detail to the compiler... ...but that's a good point. I get your point but I always start with registers and then refactor the code to use symbols to make it readable. I guess I should keep the register names in a comment. -
Revisiting TThreadedQueue and TMonitor
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
As far as I can tell that's a coincidence. RDX needs a value: https://www.felixcloutier.com/x86/cmpxchg8b:cmpxchg16b