GSRead has never been threadsafe
Pages: 1 2
nemo (145) 2546 posts |
gerph wrote
Yeah, you’ll be needing to do more than that. And sadly your approach of effectively “repeatedly GS_Trans then read a byte” simply cannot be compatible with RISC OS. Consider the string This is the problem with writing a new implementation from poor documentation of the actual code that has existed for 35 years, and why I keep trying to inject some sanity when anyone – in good faith of course – suggests rewriting stuff in C because “it will be easier to maintain”. If you can’t maintain the MC then you certainly aren’t going to be able to match its implementation. Pyro AIUI isn’t trying to be RISC OS compatible per se, but your GS_Read is very different. Termination in particular doesn’t work the way you think – explore the result of GS_Trans on |
nemo (145) 2546 posts |
This may help clarify that GSRead is more complicated (and powerful) than documented: And I don’t know whether I’ve mentioned this before, but The documentation is rubbish.
|
Simon Willcocks (1499) 513 posts |
Isn’t there a Service that’s called when the application completes? The only use case I can think of that would really screw things up would be an application calling GSInit, optionally some GSReads, then telling another program where to call some GSReads to get the rest of the string. It is a terrible API, which is why I’d read the whole thing in one go in GSInit, then allow the GSRead interface to read through the resulting string. I’m not sure how that could fail.
Oh, yes. Or the implementation doesn’t match it. Code variables are interesting as well, especially if their size changes over reads. “|!” → 384 (&180)? Strange. |
nemo (145) 2546 posts |
Indeed! I’ve extended the character constant syntax to support Unicode, e.g. <U+1EF00> produces a UTF-8 sequence, so
This is legal:
You don’t know when the program will have finished with the state in S% (and hence the internal context). You might hope that GSInit invalidates the previous, but that’s not true as it has always supported nested invocations. You might hope to associate contexts with DomainID, but as you say it’s not impossible that state be passed around – it has never been illegal so one must assume that if it can be done, it has been done. The absence of GSFinished is a design flaw.
As I wish some other people would remember, if the only thing you can think of which disproves the theory “x+y=5 means x=3” is when y=4, then that’s the end of the theory, however attractive it may have been. |
Charles Ferguson (8243) 427 posts |
The point is that it doesn’t need to be (shouldn’t be) completely identical to what RISC OS Classic does. It just needs to be meeting the requirements of the documentation and expected use. And the expected use of OS_GSInit/OS_GSRead is DON’T. Really no future implementation should attempt to be bug compatible, because there are too many bugs and misfeatures. As you’ve stated, OS_GSInit/OS_GSRead cannot be made to work safely. So don’t try beyond the basics. There is no point in carrying ancient RISC OS problems through into Aarch64 or x64. Life’s too short and unexpected behaviour is clearly bad. Part of the purpose of Pyromaniac is to make it clear what you’re doing and what you’re not doing. Those FIXMEs are there for exactly that reason – to state that there is a deviance in behaviour and that it should be fixed. OR that it can be ignored because it’s not important. There are a lot of interfaces in RISC OS that really need to work – and OS_GSInit/OS_GSRead is not one of them. |
Simon Willcocks (1499) 513 posts |
You can also write REPEAT:DIM B% 1000:U. 0 But when the application runs out of resources, it gets an error and the memory is tidied up. Which I know doesn’t happen with the current implementation of GSInit/GSRead, but will if the implementation always gets the result of a GSTrans (once, in GSInit) and GSRead simply returns each of the characters in the string sequentially (R0 or R2 simply pointing to the next character). What I’m after is not having the output change as a result of another independent program’s execution. What happens if you do: DIM B% 100 $B%="<MyVar>" OSCLI "Set MyVar Hello" SYS"OS_GSInit",B% TO G%,C%,S%:VDU C% SYS"OS_GSRead",G%,,S% TO G%,C%,S%:VDU C% SYS"OS_GSRead",G%,,S% TO G%,C%,S%:VDU C% SYS"OS_GSRead",G%,,S% TO G%,C%,S%:VDU C% OSCLI "Set MyVar World": REM As if another program pre-empted this one and set the variable SYS"OS_GSRead",G%,,S% TO G%,C%,S%:VDU C% SYS"OS_GSRead",G%,,S% TO G%,C%,S%:VDU C%
|
nemo (145) 2546 posts |
Not after thirty five years, no. That’s fantasy.
It can, for some tighter definition of the word “safely”.
And you do not get to be the arbiter of that, with the greatest of respect, or what you end up with is not an Operating System but an exclusive Club by invitation only. The ridiculous thing is that compatibility is not hard… unless you don’t know what to be compatible with. Ignorance is not a virtue, and the PRMs are certainly not a Holy Book. They’re a very flawed partial description of the facts, and have rotted over time. They are not a blueprint to a More Perfect RISC OS. Far from it. Simon suggested
Yes but that will always and has always failed. Whereas you were suggesting something that had not previously failed but now would (unless I misunderstood). Having a finite number of contexts with one buffer per context is the best we can do to cope with both dangling contexts (as my example creates) and safe buffering (as your eminent suggestion requires). You’ve changed my mind about buffering BTW, I’ll be switching to copying the SysVars rather than retaining pointers.
Yes, t’was always so. And GSRead’s behaviour with Code Variables is even worse – claiming temporary ownership of SysVar memory is one thing, but when it’s a CodeVar it retains a pointer into its internal buffer. Very nasty. This has been a useful discussion Simon, you’ve changed my mind about the buffering. |
David J. Ruck (33) 1635 posts |
That is not the right way to go. If the PRMs need updating, then so be it, but they are the contract that specify how RISC OS delivers its services, they aren’t there to legitimise bugs, omissions and misbehaviour by certain versions of the operating system. Insisting on bug for bug compatibility, isn’t OS development, it’s maintaining a legacy emulator. |
nemo (145) 2546 posts |
Have the PRMs never changed? It cannot be your position that demonstrable evidence from 35 years’ of OS and software is irrelevant until somebody else (who?) changes a piece of paper. Don’t be daft. Take RemV. Every version of the PRMs has claimed that the byte removed is in R0 but if examined the byte is in R2. Is that what you’re calling “the contract”? Because every version of the Kernel has relied on the byte always being in R0 in some places, and other parts rely on it being in R2. It’s been like that for 35 years1. And 35 years’ of software has been written against an OS that behaves like that. You do not now get to break all that software because of an error in the documentation and a delusional belief in the power of paper. And once you acknowledge as you must the fallibility of the documentation, then writing an implementation against docs known to be wrong is a fool’s errand. 1 I first discovered it 30 years ago when I wrote the keyboard emulation for Prentke Romich talkers. I rediscovered it 25 years ago writing the MMK keyboard handler, and again more than 20 years ago when I made DeepKeys… and decided I needed my own documentation because I was sick of scribbling in the margins of the hopeless PRMs. So to see people venerating these piles of misinformation from either a position of naive ignorance or fervent fundamentalism is dispiriting, and the exact opposite of engineering. Reality is inconvenient. |
David J. Ruck (33) 1635 posts |
There is a big difference between correcting a mistake in the PRMs as in that case, and using the PRMs to document specific misfeature’s of certain implementations which was being discussed before. |
Simon Willcocks (1499) 513 posts |
Just FYI, if anyone gets around to re-implementing this, OS_EvaluateExpression currently sometimes bypasses the GSRead step and makes assumptions about what’s in r0 and r2 (specifically changing r0, which I was using to point to the base of the internal buffer). The side-effects are interesting, to say the least. |
Pages: 1 2