How to start other threads in my application?
Pages: 1 2
Reg (3412) 21 posts |
How to start other threads in my application? I want to have a thread to monitor screen touches. |
Bill Antonia (2466) 120 posts |
Threads in RISC OS would be nice but the closest I can think of are event handlers. A bit round about but I have used a pollword event to listen for network connections but that required me to write a couple of modules, one to listen for asynchronous network connections and another to store pollword locations and flags etc. Used this in a inetd equivalent. |
Reg (3412) 21 posts |
Does that means RISC OS doesn’t support threads? If I set-up events can I wait for them, or can I only poll them? |
Steve Fryatt (216) 2046 posts |
Yes. There are hacks in UnixLib, for porting Unixy software, but you don’t really want to be using them in native stuff.
In what context? If we’re talking Wimp applications and a language like C, then – to all intents and purposes – yes. Wimp applications are effectively event-driven, but based around the application polling the Wimp to ask for the next event to process. A decent event handling library will mostly hide that from you, and simply allow you to register functions as event handlers for different actions. Network messages will probably require more work from your end, but it should still be possible to work them into the same scheme. |
Reg (3412) 21 posts |
I’m not sure what context I mean, but something like this:
|
Martin Avison (27) 1418 posts |
May be worthwhile pointing out is that a Wimp_Poll under RISC OS does not return until the condition for a reason code is met. With the exception of a Null_Poll it does not return if there is no event the program has asked to see. |
Reg (3412) 21 posts |
Okay, I see my error that events in RISC OS are different than events in Windows. So if I enable an event I can process the data inside the handler code and return. I can do that for network data and screen touches, but it would probably take too long to redraw the screen within the vsync event handler so I have offload that to the main app. How can I trigger the main application to redraw from the vsync event? Can I use a blocking call to poll the vsync event and have the OS go idle until the next event(s)? |
Steve Fryatt (216) 2046 posts |
You redraw your windows when the Wimp tells you to do it, not on a VSync or when you feel like it. The nearest that you can get to redraw on demand1 is to inform the Wimp that a given area of a window is invalid and then wait for it to get back to you. 1 Aside from immediate redraws, which are rarely required for anything but the most complex of applications. |
Reg (3412) 21 posts |
I’m okay with waiting for the WIMP before redraw, but for my purpose I must update on every frame. Actually I want to use VSync to do two things.
So I guess the question becomes: How to use a VSync event to trigger WIMP to tell my app that it is time to redraw the next frame? So far I think it means something like register a VSync event to switch frame buffers and set some flag or call some SWI to signal to WIMP that the app should start drawing the next frame. I’m not sure if this is a good approach, maybe RISC OS provide a better method? |
Rick Murray (539) 13405 posts |
CONSTRUCTION: You create a small helper module that looks for the VSync event and sets a word in memory, which is linked to the PollWord in your application’s polling loop. Why all the fuss? Simple. The general event vector (EventV) is called when a specified event happens, but when this happens it is extremely likely that your task will not be paged in, therefore you cannot create an event handler in application space. It must be done as a module (always visible, never paged). When your EventV handler is entered, you must first check that it is the VSync event (#4) that you are interested in, as EventV has 28 different event types, some 10-12 of them will be liable to occur on modern machines, such as “key is pressed/released”. You need to use OS_Byte 14 to “enable” an event before use, and OS_Byte 13 to disable it once you are done, along with OS_Claim to hook yourself into the event mechanism, and the corresponding OS_Release to remove yourself when you are done. Your module then sets an internal word of memory to zero when it initialises, and sets that word to anything non-zero when the VSync happens. You should provide two SWIs. The first is to read the address of your word of memory, the second is a way to clear that word (once your application has responded). Then, in Wimp_Poll (or PollIdle), you ensure the poll mask bit 13 is not set, and bit 22 is set. Do not use the “scan PollWord at high priority”, there is/was a nasty bug with that (bottom of the page). The polling loop will run as normal with the usual events, until your PollWord becomes non-zero (as a result of your helper module responding to a VSync), at which the Wimp will return reason code 13 to your application. DECONSTRUCTION: Asides from the obvious complications of having an assistant module kicking around, plus the issue of tidying up after yourself (you can’t blindly call OS_ExitAndDie to quit yourself and kill a module unless you are absolutely certain you’re the only incarnation), you are still going to run into the severe issue which is that there is not necessarily any correlation between the VSync happening and your task being called. RISC OS on a >700MHz processor is pretty slick, but even so, a VSync event does not equate to your application running immediately. Then, once you know that a VSync has happened at some point since you last looked, you can call Wimp_UpdateWindow to fall directly into a redraw loop to bang the data directly to the window. You must use a legitimate call such as Wimp_UpdateWindow as the Wimp does some clever stuff with masking out rectangles so you update your window and don’t end up spewing rubbish all around the screen. Another possibility: Given there is no relationship between VSync and polling, and that sync speeds may differ (or indeed be completely fake), there is another way to do things that may be simpler. And no, I don’t mean to issue an OS_Byte 19 to stall the entire system until the next VSync, such antisocial behaviour has no place in a multitasking application. No, instead you permit Null events to be returned from a poll, and you use Wimp_PollIdle with an earliest time (in R2) being advanced by 1 centisecond (100Hz), 2 centiseconds (50Hz), 4 centiseconds (25Hz), etc, and note this part of the SWI description well: but will return control to this task as soon as possible after the time stated in R2. RISC OS is not an RTOS, it’ll get around to running your application when it gets around to it. You don’t get to jump the queue. Each task runs in turn. When this happens depends pretty much entirely upon when the other running tasks are doing (or, even, if the user has dropped to the command line)… |
Rick Murray (539) 13405 posts |
BTW, I have a Wimp program that uses sockets. It runs a PollIdle to get itself called about five times a second (with variations described just below). At that time, it will call Then a slight fiddle to the PollIdle logic in that it will return sooner than the 1/5th second idling default whilst data is being received. If there was no data received from the socket, the PollIdle time reverts back to 1/5th second. This is done to minimise system loading with pointless checking, but to keep the socket handling responsive. |
Reg (3412) 21 posts |
Thanks Rick for the detailed response. That feels mighty complicated and the fact that there is no guarantee that every frame will be caught makes using the poll method unsuitable for me. Perhaps I can catch the VSync event (or interrupt?) and do the frame update within the handler directly? I’d need to re-enable interrupts I imagine to ensure other things can be processed. And in fact I realise that for my application I don’t need or want the desktop manager, should I remove it? Or maybe replace it with just my application? |
Jon Abbott (1421) 2599 posts |
I use RTSupport on the Pi for threads. ADFFS has three threads, a 50Hz thread that regulates game speed (it actually just unlocks the third thread), a thread that fakes the raster flyback pin and the third that blits the game’s screen to the GPU at VSync. VSync you can get from watching for event 4 when claiming EventV via OS_Claim as Rick has pointed out. What are you trying to code? A game or video decoder possibly? And is it running in a window, or full screen? These will determine what you can do and how you’d go about it. |
Reg (3412) 21 posts |
The application runs full screen 100% of the time. It is a single purpose portal. A legal requirement is that every frame is watermarked, time stamped, and cryptographically tagged. Anyone that tries to insert frames, delete frames or alter the order will invalidate the tag sequencing. So I can’t afford to miss any frames, or update any frame twice. |
Reg (3412) 21 posts |
@Jon Abbott: You mention that you are using threads. Does that mean that RISC OS does support threading? That was in fact my original question but the answers suggested that it wasn’t possible. How is VSync triggered? Is it an interrupt or is it polled by the OS? |
Rick Murray (539) 13405 posts |
The best thing would be a small desktop front end that kicks you into full screen mode for viewing.
Hmm, the more processing you have to do…
It’s an interrupt. The OS has better things to do than repeatedly ask are we there yet? are we there yet? are we there yet? like a five year old. ;-)
No, but it can be faked, more or less, once you understand that a processor can only actually do one thing at a time, so by clever use of TickerV (100Hz) you can manage your own threads by switching them yourself; though on RISC OS it is often simpler to write a routine that will process “an amount” and yield, to let the higher level caller just cycle through the functions repeatedly. Not quite the same as threads, but less hassle to implement than forcibly context switching bits of code. |
Reg (3412) 21 posts |
The watermarking and tagging part doesn’t need the GPU. It is already optimised and takes ~5ms to complete in our prototype. So that part is okay. It is not doing video decoding, the frames are generated internally. But our prototype doesn’t yet have an OS. We are just running the code bare-metal at the moment. Anyhow, I’m glad to see the VSync is an interrupt. I just need to synchronise the interrupt with the frame updates. If I do the drawing inside the interrupt handler (by hooking it or something) can I re-enable the interrupts during that time to allow other things to happen, for example to continue to receive UDP packets, and log screen touches etc.? I sorry if my questions appear to be dumb and obvious. I’m coming from Windows where things are quite different. |
David Feugey (2125) 2687 posts |
Wimp2 could help. Wimp2 should compile and work. ‘Wimp2 patch’ is another story. Since the source code of RISC OS is now available, ‘Wimp2 patch’ could be replaced by something more native. If you ask gently, perhaps the author will accept to relicense the whole Wimp2 package from GPL to BSD, for an inclusion by default in RISC OS. That would be fantastic. |
Rick Murray (539) 13405 posts |
Wimp2 should build (it is BASIC assembler, no compilation) and not work. It makes various assumptions regarding how the Wimp behaves which may or may not be valid a quarter century later, and certain parts are heavily tied into how the IOC/IOMD works, plus it would need messing around with to cater for the separation of PC+PSR, plus Wimp2 messes with OS_File so this will need checked, and finally one of the biggest bugbears of the lot – when Niall wrote this he very much despised RISC OS 3’s proliferation of C code which was going against the purity of the pretty-much-entirely-written-in-assembler RISC OS 2. As such, you will find a comment in the Wimp2 source stating that the message list is more or less useless right beside the instruction that pushes #200 as the version number to pass to the Wimp when initialising the task. Now, between you and me, I think it is utterly stupid to have Wimp “features” decided by some sort of magic version number, instead of a flags word or something sensible. All of this isn’t to say that Wimp2 cannot be made into something that can interact with the HAL on a modern machine, however nobody has been inclined to try…
That would be the best option all around, to be honest. Consider Wimp2 an experiment in how with a bit of lateral thought, it is possible to run a task with pre-emption. What did Wimp2 actually do? It used the IOC/IOMD Timer1 to have a high-speed interrupt that, after a sufficient time period, Wimp2 would stash the state of the currently executing task, and forcibly get the Wimp to switch to a different task. As this was being done by Wimp2 and not regular polling loop, Wimp2 would save state prior and restore state afterwards so the task would be completely unaware that such a thing had actually happened. There is scope for the Wimp to be able to pre-empt. I have outlined on the forum (a few years back) a method where by you can instruct the Wimp that your program is entering a long processing job and it is “okay” to pre-empt. The Wimp will then just set up a timer (a couple of centiseconds, perhaps?) and switch itself when the timer expires. This shouldn’t be too hard to organise. The only sticking point may be specific poll events (Redraw, CloseWindow, UserMessageRecorded, …) that may happen while the task is in the non-polling pre-emption part. This can be dealt with in C by registering a function that can be called into by the Wimp if there is an important message that cannot be missed. BASIC? Will have to miss events or have an assembler veneer of some sort. It isn’t perfect, but then neither was Wimp2 yet it worked pretty good nonetheless… |
Bryan Hogan (339) 563 posts |
Arrgh, please don’t add to Reg’s confusion by bringing Wimp2 into the discussion! He really doesn’t want to be dealing with a 20 year old attempt to hack pre-emption into the OS that never worked that well in the first place. Also:
It definitely sounds like you want a fullscreen, single tasking application, so you can fiddle with interrupts and screen sync to your heart’s content. You don’t need to do anything special for this on RISC OS as all applications are single tasking by default, and only become multi-tasking if you specifically call the WIMP to make them so. The WIMP goes to sleep when your app starts and springs back to life when it quits. So you get an environment like bare metal but with the benefit of an OS to do all that nasty hardware setup, network stack, etc, for you :-) |
David Feugey (2125) 2687 posts |
Don’t confuse Wimp2 and Wimp2 patch. Two very different products.
The same: Wimp2 patch is hacky. Wimp2 (the PMT framework for compatible applications), is more clean.
I did suggest that too. A ‘time limit’ for tasks. But only for compatible applications (would need a specific flag for each task, ot workarounds). Could be better than real PMT, as you’ll be able to extend (desktop PMT) or shrink (RTOS) the time slice on the fly. Like a metronome. |
Steve Fryatt (216) 2046 posts |
However you try to dress it up, Wimp2 is a 20 year old hack. I think that it’s also unnecessary in this context. Reg originally implied (by omission, maybe) that he was writing a standard Wimp application. Now that we know he isn’t, the best advice simply has to be to sidestep the Wimp completely (perhaps with a Wimp front-end for entry and exit), just as a game would do. |
David Feugey (2125) 2687 posts |
And RISC OS a 30 year old one :) |
Steve Pampling (1551) 7932 posts |
However you try to dress it up, Wimp2 is a 20 year old hack. To be more accurate Wimp2 hasn’t been worked on or amended toward a full working setup in 20 years. RO5 hasn’t been updated for about 23… …hours |
Rick Murray (539) 13405 posts |
… What is this? My daddy is better than your daddy? Wimp2 was an interesting experiment that sort of worked in the right conditions. It suggested that there were more options available for developing the Wimp, but that never happened. Aside from ROLtd, there was fairly little such development. 3.1x to 3.5 (etc) was nothing like the scale of 2 to 3. It was an idea, a proof of concept. Not something we should be thinking of plugging into a modern system to overcome deficiencies of application design… |
Pages: 1 2