hello
h0bby1 (2567) 480 posts |
aaaaa |
Rick Murray (539) 13840 posts |
This depends upon how “real” you want your multitasking. I find Android is a lot better at performing multiple operations than iOS. For example, my first phone (Moto DEFY), I could choose to open half a dozen web pages in the browser, then switch to read email, while listening to an MP3. By the time I read the email, I could switch back to the browser and the pages should have loaded. This is no longer possible on my Sony phones, leave the browser for anything (even change MP3), going back will trigger a refresh. Most bl**dy annoying behaviour.
Sort of. Generally there is only one polling loop per application, although for special cases I write special loops with their own handler code. An example here is a multitasking error box so the application can be ‘frozen’ (it will “bing” and push the error message to the front) while polling continues so everything else works.
It can start a new Wimp application, but if you are thinking of threads, then no. RISC OS has a concept of applications, it doesn’t have a concept of threads.
If you want to repeatedly check to see if there has been any activity, this should work. If you want to use any events to be notified upon activity, this absolutely will not work. The difference is that you cannot pass addresses to things within your application space to OS routines that call you (ClaimEvent, Callback, CallAfter, etc). This is because the addresses in your application space will only be valid while your application is paged in, and at all other times, those addresses will point at something else entirely.
I have written a telnet server and it works more or less like this:
All the way through this, the server is capable of responding to incoming requests and spawning new tasks to handle them. I tried a while back with the server on a Pi and connections from my PC (via WiFi LAN) and I think I had around 14 connections running concurrently before I got bored. ;-)
The problem there is in having the buffer and the task accessing it being separate. If you are implementing the server in a module, it might be doable. If you are implementing the server as a regular task, it is not. Sure, you can do it using the Wimp_TransferBlock (IIRC) SWI, but how that works is basically to page out part of your task, page in part of the task with the data required, copy stuff around, then page in/out as necessary to restore sanity. It would be better to just maintain your own block.
If you send a “register” Wimp_Message to your server, you can extract the task handle from that. Then just keep an eye on what tasks are closing down. If the handle matches…
Can’t GCC do this? With the DDE, you can pass a stub (created by CMHG) to OS_CallEvery which will set up the environment correctly to call the handler of your choice. Note that you are limited in what you can do (probably no file operations, FileCore is not re-entrant) so your CallEvery handler will need to schedule a Callback which is when it is safe to do stuff. But you will need an interlock to not schedule if one is currently pending (things get upset otherwise).
Sort of. What you say is correct, but if the address passed to CallEvery / Callback is within the application that will be polling, you must remove all traces of this prior to executing the poll. Think of what would happen if the event fires and the OS branches to the address given which is some random place in some random application… That said, as Steve points out, if any of your tasks are not polling, then yes, the timed events will still fire but everything will appear to have ground to a halt. Multitasking will stop. No if, but, or maybe. This is why I said above that RISC OS is not Linux. You cannot think of the Linux paradigm of writing some code and letting the OS decide how best to execute it. Applications for RISC OS that are to work in a multitasking world need to be written with that in mind from the ground up. You will come astray if you think of linear application code and then try to bolt on some multitasking behaviour later. Also, be careful of David’s suggestion:
Yes, this is correct. The TaskWindow provides a pre-empted environment to run non-Wimp tasks within the Wimp (most of us use it as a quick and easy command line, but it also holds true for compilers and assemblers!); however it submits you to the same restrictions as a normal polled app on the use of addresses passed to OS routines that will call you back at unknown times. Namely, if you have a CallEvery running and the TaskWindow module polls (thus you’ll get paged out), BANG! |
h0bby1 (2567) 480 posts |
aaaaa |
Rick Murray (539) 13840 posts |
Yes. In two ways. The common way is a module that starts itself as a standard Wimp task. Runs at &8000. The more complicated way (and not directly possible with DDE) is to run as a module task. The difference here is that it runs in module space, not &8000, so when it is paged out, the addresses are still valid.
How do you mean? I don’t recall the exact SWI that I use in my task, Socket_Select I think. Anyway, given a handle reference, it will inform me if there is data pending. So I don’t need events, I don’t need to fart around with CallAfter, I just do this:
Because of the nature of what I am doing, I need to spawn a new task to uniquely handle each connection. This is not necessary, it makes a lot of the internals of my code easier – the internal state of the task relates to the user that is connected without worrying about anything else. It is possible to handle multiple connections in a server in a single task. I suggest that you look at the source code of WebJames, the RISC OS http server. That might provide some instruction on how all these parts fit together.
Wimp_SendMessage from the sender, to the Message event of the receiver’s polling loop. You can even have it with registered-must-be-signed-for delivery if you like. ;-)
The Wimp’s task management interacts with the kernel’s paging and memory handling code. Best not interfere with that. RISC OS (which is not Linux…) doesn’t really have stuff like “framework”. There is a basic eighties style single tasking single user operating system. On top of that sits a clever task switcher and windowing system. There is no in-between. This isn’t Linux where you have loads of layers between the bare metal and the UI the user sees.
For this plan, you have three possibilities, in decreasing order of baldness-inducing:
Does it? Can you not just hand over the socket handle and let the subtask talk directly to the socket for the duration of its work? |
Rick Murray (539) 13840 posts |
What about:
Your complication is in wanting to run PHP → is there a PHP available that fits in with the RISC OS way of doing things? I only have a dim memory of the RISC OS PHP (last used it over a decade ago) but I think it was a single-tasking application that ran as a single tasking program. I’m not sure how the data from PHP got to the server – you’ll need to look at WebJames, it might even have linked into the TaskWindow I/O like how Edit does… |
h0bby1 (2567) 480 posts |
aaaaa |
David Feugey (2125) 2709 posts |
Time to make some announcement I planned… Wimp2 implement CMP multitasking via time limit on task. It’s more complex than this, but basically: 1/ set a timer 2/ when interrupted, check if you were running application code, from an application that does not crash in Wimp2 mode 3/ if OK, simulate a Wimp_Poll call to go to next task. It’s what Wimp2 did, but with the need to implement a microtimer and to redirect some system calls (with a lot of problems). With microtimers now in HAL and source code of RISC OS available, it should be much much more easy to (re)write Wimp2 today, since it will be only an ‘interrupt and switch’ module (to be more precise “set new timer if next task is PMT compliant (Ok, it’s not really PMT… much more a time limit on CMT), and switch”). Unfortunately, you can’t rely on Wimp2 for this part, since this software is a GPL one. A new, BSD, version would be better. Nota: with timers in HAL, it would be easy to change timer delay on the fly, to make a system more or less responsive (less for calculation, more for servers, 60 fps for games or multimedia). Or even not to fix timers (CMT mode). The author of Wimp2 confirmed me that it’s more or less the way Wimp2 worked, and a way to recreate it. Bounty of 500 euros from my eBay account to the one that will make it again. |
David Feugey (2125) 2709 posts |
Nota: I have also other bounties to announce, with the same amount (or less) money. Port of RPCEmu, image file support for FilecoreFS (IMHO, should be here: https://www.riscosopen.org/bounty/polls/10) , HardFP support in FPEmulator (https://www.riscosopen.org/bounty/polls/6 ?), and a few others. |
h0bby1 (2567) 480 posts |
aaaaa |
GavinWraith (26) 1563 posts |
@huebby: I hope you do not mind me saying this. I am finding your prose very hard to read. The sentences tend to be too long for my eyes to follow. How about a few more full stops? The secret of simple English is to use parataxis. Avoid phrasal conjunctions and relative clauses. ;)
Not so. The answer is to use coroutines, with plenty of yield points in the cgi code. After all, the wimp and applications see each other as mutual coroutines. See section 9.4, Non-Preemptive Multithreading, of the third edition of PiL (Programming in Lua, by Roberto Ierusalimschy, ISBN 978-85-903798-5-0). |
h0bby1 (2567) 480 posts |
aaaaa |
Rick Murray (539) 13840 posts |
[I wrote this last night and got sidetracked, never clicked on Save Reply… duh!]
That is why I said: Your complication is in wanting to run PHP → is there a PHP available that fits in with the RISC OS way of doing things? If we were writing a script processor, we could poll every X lines of input, or after X centiseconds had elapsed. But taking something written for another system and another methodology… that’s more complicated.
Not quite. The cgi should do a little bit and then return, doing a bit more on the next call. You can understand why PHP could be ‘difficult’.
…on Linux, perhaps. Does our Internet stack even do that? |
Rick Murray (539) 13840 posts |
David:
I see I’m not the only one thinking about this possibility.
We don’t need Wimp2 at all. What we have in mind is the basic premise of what Wimp2 was trying to achieve. Now that the source of RISC OS is now available, the cleanest method would be to fold this functionality into the Wimp itself. Consider, if you like, two new SWIs. Being called something like The EnterPMT call should take an options word for setting various parameters (like “this is a low priority job” and “this needs FP/VFP/Neon registers preserved” and “this runs in SVC mode”, etc). Preferably flags and not the yucky version numbers and magic words rubbish that has blighted the API since Arthur… Envisaged problems:
Mostly just thinking out aloud… |
h0bby1 (2567) 480 posts |
aaaaa |
h0bby1 (2567) 480 posts |
aaaaa |
Rick Murray (539) 13840 posts |
;-) You’re sort of comparing apples and oranges here. Android 5.0.2 (24 days ago) → evolution of Android (2008) → built upon Linux (1991ish but that incarnation is too basic for something like Android) → ideas derived from commercial Unix and MINIX but code is related to neither. On the other hand: RISC OS 5.20 (2014) → evolution of RISC OS (1989) → derived from Arthur (1987) → which has a lot in common with the BBC Master MOS (1986) → derived from the BBC MOS (1981). Seriously. If you have some free time and nothing to read, go grab yourself a copy of the BBC Advanced User Guide (PDF here) and browse it. Look at, for example, Vectors (p253) and also Events (p287). Seem familiar? :-) We can but wonder at what might have been; however RISC OS, for all of its simplicity, is what we have here and now, and indeed if you compare Android starting up on any mobile phone (takes about a minute at its fastest on my phones) with RISC OS starting on a slower less capable device such as a Pi (takes maybe fifteen seconds from power up to desktop (beta versions are slower thanks to the list of module inits)), you can see that something simpler and less complicated wins in the speed stakes. So there’s your choice. A nice feature laden system that will struggle on anything “last year”, or a simple system with a basic multitasking environment (the core OS doesn’t) that runs fast enough to make you gasp. |
h0bby1 (2567) 480 posts |
aaaaa |
David Feugey (2125) 2709 posts |
If it’s possible to apply this on old code (with or without success), why not… The Wimp2 approach was simple: interrupt applications (that’s always possible), see if we are in a safe part of execution, then switch. If not working, blacklist the application. And of course a framework to be sure that an application is “time limit” compliant. Catch me if you can :) Nota: this is not PMT. Much more CMT with interruptions. So it’s not compatible with SMP. Anyway I prefer AMP with a simple interface (connect to other cores via CLI, send data, send commands, get data). The same interface could be used for clusters. CMT and SMP in RISC OS could be better, but if old software cannot work any more, it’s in fact a new OS.
My opcode engine has a very simple execution loop that could be used for this. Self modifying opcodes are also an idea to share CPU time between scripts. Of course, it’s not PHP any more :) Code available on request. |
Steve Pampling (1551) 8170 posts |
Not complicated? Note: This isn’t dissing the ideas, it is just pointing out how often in looking at what can be done you hit the “well things are simple in Java, but we don’t have Java” or “my PC browser is just fine on this or that site that uses Flash on the front page, but RISC OS browsers won’t display anything because there isn’t a flash enabled browser”. |
h0bby1 (2567) 480 posts |
aaaaa |
Rick Murray (539) 13840 posts |
David:
The Wimp2 approach looks simple, but is in fact horrendously complicated. Yes, you can always interrupt an application – and that is what Wimp2 did – but in order to task switch outside of the Wimp, you effectively need to call Wimp_Poll. Which is what Wimp2 did. This is why I suggest that this really needs to be done by the Wimp itself. It is the one place in the entire scheme where the task switching can be performed without a polling loop behaviour. In essence, the Wimp will know that the task is unable to receive events so it will just let it run for a length of time before switching it out. An external module cannot do this without making a hell of a lot of assumptions (and we all know that “assume” makes an ASS out of U and ME (sorry, lame, really lame…)).
Indeed, this is the important point; and why my proposal is for elective task switching (namely, the app “asks”). It needs to work alongside and co-exist with existing software.
Ah. That old chestnut. Otherwise known as “how to mess up the pipeline and the cache in one easy lesson”. h0bby1:
Sounds like you wrote the crux of the multitasker from the ground up. Here, you either have to co-exist with the current Wimp; or you will need to write your own. Note that yours will need to be compatible with the Wimp (quirks and all) or people will be like “Oh no, this doesn’t run XYZZY!”. Having said that, I think you might be better to downsize your plans a tad, see how you get on with something a little less radical than reinventing the task switching methodology. |
David Feugey (2125) 2709 posts |
I know. But most people don’t want CMT. They just want a more fluid UI. In a way, we need the two solutions. My idea is to get first part 1, ie more speed to switch between some Wimp tasks. A ‘better than nothing solution’ or a CMT accelerator, if you want :) Without the timer & vectors part, source code of Wimp2 is not very big. Problem: it’s GPL, so no way to integrate this CMT accelerator in the ROM. There is no other solution than to write another one from scratch. For me, plan is clear. I just want something that can switch Wimp task by simulating a Wimp_Poll. Some applications will work, some will not (example, the Filer). To ease the work of the accelerator, some applications could say ’I’m compliant’ when starting. Simply by using a Wimp2_Run command in their !Run file. A list of compatible software could also be loaded in memory with the module. I think the 2 solutions are good and could coexist. Then, if there is a way to make the second part, that’s OK for me too, but later. The problem is that everyone wants something powerful, complex and perfect. So we are waiting. A short term solution would be cool too (example, the Midi module: not perfect, but good enough to use Midi and make new applications). |
David Feugey (2125) 2709 posts |
You don’t get the point: self modifying opcodes in my opcode engine. I talk of an interpreter engine. Here, all is possible. Of course, a lot of people will say: self modifying code is not good for developers. Not so true, if it becomes a facility (to implement threading or debugging for example). The same with reverse code (ability to play the code in the other direction): precious for debugging. A long time ago, processors became too complex for these techniques. So we throw them from compilers. But why did we forget them on interpreters? |
h0bby1 (2567) 480 posts |
aaaaa |
h0bby1 (2567) 480 posts |
aaaaa |