Spending a Million on RISC OS
David Feugey (2125) 2709 posts |
Would not this be simpler with a timed null event?
Ah, yes :)
A very good application, but not compatible with some new modes and not so easy (licence, use) to integrate in an existing Basic application. For newcomers, there is a big difference between a Wimp application, a CLI application and a CLI application that works inside GraphTask.
I was thinking of something older, more similar to RealBasic.
??? |
Steve Fryatt (216) 2105 posts |
If you need to do some processing that takes time, you have to use Wimp_Poll so that you get null events, and can time-slice your processing so as not to hog the CPU. No, because a null event returned by Wimp_PollIdle is a timed null event. When calling Wimp_PollIdle the program gives the earliest time that it wants the call to return a null event. It’s not too difficult (in C1) to package up a callback scheduler from this: NetSurf has one, and the idea might easily form part of a more general event handling library. 1 It’s less fun in BASIC, of course – but then most things after Hello World are. |
David Feugey (2125) 2709 posts |
I know, but he was talking if a classic Wimp_Poll, and I ask “why not a Wimp_PollIdle?” To give more time to other tasks, it seems to be better, no? |
Steve Drain (222) 1620 posts |
Cruel. ;-) When I mentioned my Call module earlier last year in c.s.a.programming, Justin Fletcher berated me for using OS_CallAfter and OS_CallEvery inappropriately. At the time I was not completely convinced, but having re-read his (long) explanation, I think he is right. This should not be surprising, and he suggested that any programmer worth their salt shoud be able to produce scheduling routines for Wimp_PollIdle. So, I thought I would have look at this again. It is not pretty in BASIC and it does not come simply, but I now have a small scheduling library, and it was fun to write. Perhaps the trickiest thing to manage in BASIC is memory allocation. DIM is a blunt weapon, because blocks cannot be reclaimed. I have a routine for using memory above HIMEM the same way that Basalt does, but that is a bit clunky in pure BASIC. So, for this I have eventually employed a method I thought up many moons ago, to use the string allocation table. The result is at: http://kappa.me.uk/Miscellaneous/swPollIdle.zip I welcome comments. |
GavinWraith (26) 1563 posts |
OK, here is a small self-contained RiscLua program that, I hope, does what the BASIC program does.
The schedule object is a table – its list part consists of events which are tables with keys:
I don’t claim this is anything more than a sketch. It does show how a list of scheduled actions can be written using RiscLua’s current wimp.task library without any further explicit memory-handling. |
Steve Drain (222) 1620 posts |
Thanks Gavin. I cannot say I fully follow the Lua, but I do have some questions, based on what I had to consider for the BASIC. First, does this call Wimp_PollIdle? I can only see one mention of a mask and that seems to be set to allow all NULL events. Also, the schedule object seems to take action on those events by searching for the earliest actionable event in the table every time. This seems excessive. Second, once an event is added to the table, is it ever removed? You only have every type events, not after, although I like the delay. If a program repeatedly adds events, does this not constitute a memory leek? One thing I missed in my library is a Schedule_Remove, but that is straightforward and I will do it later. After events are removed when they have been actioned. |
Steve Pampling (1551) 8170 posts |
Look at it in the round and it’s an onion :) Sorry, some typo’s just do that for me. |
GavinWraith (26) 1563 posts |
Yes. If the second argument of
I agree. The code is only acceptable for small lists of scheduled events. I had been thinking a bit about this. My first idea, which was probably too clever or not clever enough, was to work out the highest common factor of the delay times and to set this as a polling interval. Another idea was to order the list using a method: in schedule . But it was not clear to me which method was least expensive. You can remove events by adding within schedule the line: Then removes the i-th event. I just had every events to keep things simple.
|
Vince M Hudd (116) 534 posts |
perhaps we really need a Wimp version of BBC Basic :) I wouldn’t call WimpBasic “A Wimp version of BBC Basic”. I’d call it a Wimp version of Basic, with a dialect familiar to users of BBC Basic. |
Steve Drain (222) 1620 posts |
I thought it worthwhile to mask NULL when there are no timed events. Then it is equivalent to Wimp_Poll. However, there is no provision for untimed NULLs, so I will have to think on this.
But that requires a sort each time you add an event, doesn’t it? That is not much of a problem, but the ordered linked list I used allows events to be inserted without disturbing anything else. Can Lua do such structures? If I read correctly, Lua does garbage collection, so there is no penalty when removing items, which has to be much more considered with BASIC. |
Steve Drain (222) 1620 posts |
I have thought. ;-) AFAICS using timed events (with PollIdle) and returning all NULL events (with Poll) for a long processing job are incompatible. The answer is to use a very short interval timed every event, I think.
If anyone is interested, I have updated the files at: |
David Feugey (2125) 2709 posts |
No problem. “PWP – 404 Error :)
Exactly! Just to make input, print, plot, mode, the same way you do without Wimp (and without the help of an external module/application).
Or to have a system that can generate timed callbacks, to call your code (or opcode for Basic) exactly and only when needed… IMHO, it would use less resources than to check if it’s time to make something. But that’s a completely different approach. |
GavinWraith (26) 1563 posts |
I get a 404 error at http://kappa.me.uk/Miscellaneous/swPollIdle.zip.
Yes – linked lists of various flavours can be constructed using tables, though very often it is not necessary. A doubly-linked list would be constructed out of tables with three fields, previous, next, value, for example. In fact anything you can do with pointers is possible, so long as you realize that you may not be dealing with arrays of consecutive bytes. A propos removing items from lists: if you are iterating over a list you have to be careful not to alter the list during the iteration. Instead you must collect a list of actions to be done to the list and then execute them when the iteration has completed.
Yes. If you have a table I guess the following problem must be a computer science classic: and a number t, what is the most efficient algorithm and data structure for holding the list to determine the index i for which ?
|
Steve Drain (222) 1620 posts |
Sorry, finger trouble when copying the replacement zip. Should be ok now. |
Steve Drain (222) 1620 posts |
That looks quite similar to the scheduling PollIdle problem. ;-) I have self-studied some computer science, but I could not give an answer. What is it? |
GavinWraith (26) 1563 posts |
I am guilty of oversimplifying the problem because the list is varying in time. The earlier members disappear and newer members are being created. Otherwise I would say that we need a binary tree – compare |
Steve Drain (222) 1620 posts |
Thanks for the lesson. I am holding on to my rubber duck. ;-)
It would be exceptional to have very many events on the go at once, so the cost of traversing the list is likely to be small and is only borne when the event is first created. Anyway, in pure BASIC linked lists are relatively easy, and also in assembly – the BASIC module is full of them. |
Rick Murray (539) 13840 posts |
Uhh… … … … Do you have a version with cartoon pictures? |
GavinWraith (26) 1563 posts |
A happy thought. Somebody must have made a nice animated lecture to demonstrate the virtues of binary trees. Unless I dreamed it, I think there was a BASIC demo program on the BBC B to illustrate their speedier lookup properties. |
Steve Drain (222) 1620 posts |
But I still do not understand what you think can be done. A program cannot respond to an OS timer call unless it is paged in. The Wimp has control of that, so let the Wimp do the timing. As for calling BASIC (‘opcode’ what is that?), apart from the technical problem of executing a routine from outside a BASIC environment there is the problem of program flow. On the other hand, BASIC can easily respond to the Wimp through polling. My best guess at what you are after is a single-tasking BASIC program that can respond to some form of timer interrupt, but nevertherless displays its output in a window. If GraphTask does not do it for you, then “Dream On”. ;-) By the way, ‘WimpBasic’ is an existing commercial product, and Vince is quite right about its relationship to BBC BASIC. |
David Feugey (2125) 2709 posts |
I did many time this kind of thing. You put a callback on some part of you C code and fire a timer event. When the time is over, the timer call your C code at the right place. It’s much better – IMHO – than polling many time from you C code to see if it’s the right time to make an action. With opcode, I suggest the same for Basic opcodes. Locomotive Basic on Amstrad worked like this with external timers able to call a specific Basic function after some time. Perhaps that the glue was inside the Basic interpreter and not AMSDOS, but who care? It worked like this: On Timer or Every, and let’s go. That’s not a ‘dream’. I saw it, I used it, and still use it. The only closed equivalent in ROS seems to be WimpCallIdle. You still need to manage the events, but it’s better than nothing (even if it’s not as cool as a true Timer event… since it’s more a delay than a precise timer). Under the CLI, there is nothing.
No. Two different subjects here (even 3). The timer/every problem is one. Wimp is another. I was answering to Vince about the possibility to have a wimped Basic, just for classic commands, and without GraphTask (just wimped by itself). Not at all a clone of WimpBasic. I did not talk of WimpBasic anyway. For true wimp application, it’s another subject. I would talk here of a clone of RealBasic, as the tool made for the Archimedes a long time ago (can’t remember the name). |
GavinWraith (26) 1563 posts |
Here are my thoughts on scheduling with computed time intervals. Let us call an event a pair consisting of a number (a time)
A schedule is a linked list of events. Thus
is a linked list of three events, ev1, ev2, ev3. So p is the key A schedule is ordered if ordering in the linked list coincides with
Ordered insertion (oinsert) of an event preserves the
Triggering an ordered schedule means evaluating the function
I have not tested this code yet. But it is so much more concise than my previous attempts that it has to be right. Fingers crossed. :) |
Jeffrey Lee (213) 6048 posts |
I’m confused. Are people proposing that an ordered linked list is an efficient data structure to use for representing the schedule, or are these just examples of how schedulers should work? There are much better data structures to use, e.g. a binary heap is a popular way of implementing priority queues – example here (although they’re not without their own fair share of flaws). FWIW OS_CallAfter/OS_CallEvery is implemented using a sorted linked list. So popping the front item off the queue takes O(1), but insertion and deletion of arbitrary entries (including re-inserting CallEvery events) takes O(N) time. Luckily Acorn weren’t foolish enough to publish the details of the internal structure (unlike with OS_Heap), so it shouldn’t be too hard to swap it out for a better algorithm if we felt so inclined. |
GavinWraith (26) 1563 posts |
Not this person, exactly. See my earlier remarks about binary trees. I was thinking about a more general notion of event, which computes the next time it is to be triggered, rather than being repeated at a set interval. One will always want a pointer to the earliest event. But if the events are to be held in a binary tree, where is the root to be? Somewhere between the first and last, evidently, but the most efficient point will depend on the statistics of the repetition times that each event computes. This is where my brain starts to go fuzzy. Thanks for the example, which looks interesting. |
Jeffrey Lee (213) 6048 posts |
Are people proposing that an ordered linked list is an efficient data structure to use for representing the schedule, Ah, I managed to miss that bit when skimming over the thread. From my point of view the discussion went straight from “what is the most efficient algorithm and data structure for storing an ordered sequence of events” to “here’s an implementation using a linked list” :-)
The most efficient place for the root of the tree is for it to be at the start, as with the binary heap example. The fun part is:
|