cooperative multitasking scheme

Goodness, no. Task priority in this case is used only to select a set of runnable tasks that will not introduce stack contention. Task priority is not used to decide how long or often to run anything. There is no preemption or any other attempt at cpu resource management. It is obviously not a realtime system...

It is true that tasks of the same priority cannot wait for each other. This is just as well, as they could then deadlock. However, nothing precludes the use of many tasks at the same priority level, and indeed the application run over this schedule often has hundreds of tasks at the same priority.

Tasks can only wait for a message response. Since messages are addressed with a (priority, number) tuple, it is easy to implement runtime checks for illegal waits; it is also straightforward to inspect the task source code for correctness.

The secondary restriction, implicit in the first, is that no task being waited on may require input from a task with a priority number = to self. This artificial restriction makes static checking less difficult.

Well, he must have missed something. The executive I wrote to do this most certainly works, and it really is possible to develop nontrivial applications atop it. Furthermore it is easy to understand the application in a debugger, which was the whole point :)

--
Grant Taylor
Embedded Linux Consultant
http://www.picante.com/
Reply to
Grant Taylor
Loading thread data ...

"Hans-Bernhard Broeker" schreef in bericht news: snipped-for-privacy@uni-berlin.de...

What's in a name? ;-) Perhaps my choice of the term "priority" wasn't quite what it should be, for lack of a better word. However, the whole purpose of this excercise was to try and mimic the behaviour of an RTOS as close as possible, without having to use interrupts (which are inherently system dependent. Remember that the kernel has to be system independent). The thing I call "priority" does control the sequencing of tasks almost as an RTOS does. Of couse, and in that I fully agree, the kernel can only work properly if tasks give up control of the cpu voluntarily. And that's what they will do, either by waiting for a message from another task, excluding themselves for a given number of times from competng for cpu control, or suspending themselves until resumed by another task.

BCNU

Waldemar

Reply to
Waldemar

You can download the sources of a prototype from

formatting link
as to get an idea of what I'm aiming at.

Waldemar

Reply to
Waldemar

Jon, thanks for your extensive treatise of the matter.

You can download the sources of a prototype from

formatting link
as to get an idea of what I'm aiming at.

Waldemar

Reply to
Waldemar

You can download the sources of a prototype from

formatting link
as to get an idea of what I'm aiming at.

Waldemar

Reply to
Waldemar

You can download the sources of a prototype from

formatting link
as to get an idea of what I'm aiming at.

Waldemar

Reply to
Waldemar

I've only looked at the page, itself. No download. Where is 'AddTask()?'

Jon

Reply to
Jonathan Kirwan

"Jonathan Kirwan" schreef in bericht news: snipped-for-privacy@4ax.com...

Hi

My fault... I forgot to repace the '

Reply to
Waldemar

Why is it necessary to post this four times, without any quotes to indicate what you are aiming at?

--
 "It is not a question of staying the course, but of changing
  the course"                        - John Kerry, 2004-09-20
 "Ask any boat owner the eventual result of continuing the
  present course indefinitely"    - C.B. Falconer, 2004-09-20
Reply to
CBFalconer

I didn't try to download anything -- I decided to simply look at what was present on the web page.

So, you use setjmp/longjmp as a mechanism to get back to the call frame of schedule() and, when running a process again, simply call it. I don't consider this very useful as a process loses it's local context anytime it exits (whether by a longjmp or simply returning) and is always restarted at the top. This isn't my idea of a cooperative switcher.

But perhaps I missed some detail.

Jon

Reply to
Jonathan Kirwan

"Jonathan Kirwan" schreef in bericht news: snipped-for-privacy@4ax.com...

There's no other "clean" way to get back to the scheduler, unless you want to call it recursively and that's exactly *not* what I want to do (especially not on a microcontroller with very limited stack space, apart from the fact that the scheduler needs to know that it was called recursively and instead of keep on looping needs to return, i.e. more overhead.) The idea behind it is that a task should keep track of what state it was in (which is common practice) and once a task gives up control of the cpu from whatever level of function nesting, a complete steck roll up is in order. I agree that loosing the local context may pose a problem, but then again, the size and complexity of the tasks will be limited.

Waldemar

Reply to
Waldemar

"CBFalconer" schreef in bericht news: snipped-for-privacy@yahoo.com...

Forgive my ignorance of news group etiquette. Just trying to be polite, answering to the various directions this discussion takes.

Waldemar

Reply to
Waldemar

I don't think that is common terminology to call that a "task". In most implementations of a "multi-tasking executive", even the cooperative variety, a task is a fairly general thread of execution whose place in the code is preseved through interruptions for CPU-sharing. I'll grant you that most small microcontrollers don't have the facilities to implement separate stacks, but that is no reason to call something a "multi-tasker" when it isn't. I would say that the kind of tasks that you are describing are really state machines. That is the kind of task that always starts at the top of a loop, and whose state is kept in ways other than by the program counter. That certainly doesn't describe most "tasks". So what you have implemented you should call an "executive for the cooperative management of parallel state machines".

-Robert Scott Ypsilanti, Michigan (Reply through this forum, not by direct e-mail to me, as automatic reply address is fake.)

Reply to
Robert Scott

I can't agree with this. In fact, there are much cleaner ways than I saw there. A matter of opinion, perhaps, though.

How would recursion solve anything here? Your saying this makes me think you haven't really experienced a well-designed and clean approach. Sad, as it is very easy to achieve (just a few lines of assembly code.)

I implement a much fuller (and, I imagine, designed cleaner) operating system than you've illustrated and I use very, very few bytes per process as bookkeeping. If you don't enable semaphores, I implement ready and sleep queues with one byte per process (+1 extra.) Semaphore queues do take another byte per queue. The stack space is entirely up to you, so that can be as little or much as you want. Task state depends on the processor and the C compiler, but it's usually quite small as there is no need to save registers that the compiler assumes are scratched across calls (in a cooperative system.) Preemption is supported, if you want it. But it costs some more process state to do it, plus a timer resource.

To me, this is dead wrong. It is **exactly** because I want to write cleaner application code that doesn't have to bend over backwards trying to save... and then somehow restore... both the earlier state and the program counter place that motivates me to use a cooperative (or preemptive, I suppose) operating system in the first place. And with cooperative-only mode, it takes almost no code and can be easily written from the ground up and then added to an existing project in an afternoon. And I'm not kidding about that. It's that easy.

Some years ago, a programmer working at a place I was contracting at needed to untangle code that monitored a manually scanned keyboard, updated a display, operated serial port outputs, etc. It was a ..nasty.. mess because the keyboard, for example, was polled and had to be polled 'often enough' while at the same time many other various polled operations were also competing. The resulting application was a disaster waiting to happen, with all kinds of various calls salted everywhere and... worst of all... lots and lots of weird code added to these routines to save some odd nested condition state so that they could return to the "shift key seen, but no other key yet seen" state to continue the polling process. Since these routines not only had to restore variables but also had to return to the deeply buried nested condition states they were in the last time they saved themselves, it was a nightmare to read and modify.

I suggested adding a cooperative tasker. He'd never done one before and was feeling a little cautious about my recommendation because of that. But I set down with him one morning and explained some details to him and suggested a line of reasoning. I did NOT write any code, except as pseudo code examples. By the next morning he came back over to my office and was ecstatic! It was working! He'd spent an afternoon working on the code and by a few hours into the next morning had a working switcher. Over the next weeks, he and I worked to unravel the nastinesses in the existing application. We never had any troubles with his code.

It's dirt easy and there is no justification I can think of for writing something like what I saw at your site when the clear and distinct advantages of having an operating system in the first place are starkly absent. If all I needed to do was cause various routines to execute at different times, I might just as well simply salt in the calls in various places in the code rather than go to the long trouble of writing an "operating system" which really isn't anything more than an extra complication without a distinguishing purpose.

Saving and restoring state is common practice when you don't have an operating system around to help out. That's why you get a cooperative operating system in the first place -- to allow you to focus on proper design and structure of the application, separated along functional lines, and without having to confound it with weird save/restore rube-goldberg contraptions that grow without bound.

It's why you do an O/S -- to avoid this common practice and produce something that is easily read and modified with a low risk of breaking things.

Nope. Not so. In two ways. One is that if you keep separate stacks (which can be done quite simply with nothing more than a static array that gets divided up, if you want.) In such cases, there is no need for a longjmp stack unwind. Quite the opposite. Which is why you do it. Another is something called a "thunk" which can allow you to do coroutines on a single stack, using a nested stack context that looks almost the same as a local variable on a stack frame but which allows you to ping-pong between two tasks without losing a beat or any context. Very fast, nice, clean.

Two reasons why your comment misses the reality. And there are probably more.

The will be, of course, because anyone trying to add complexity will face daunting hurdles that would give pause to the best of programmers.

I frankly see no real value in how you are approaching this which cannot already be purchased far more cheaply and easily in other ways in an application. But that's just me. You are, of course, entitled to enjoy this process and sharpen your programming claws on it. But it's nothing I'd enjoy seeing or using.

Jon

Reply to
Jonathan Kirwan

Fair enough. In general, thank-yous are considered unnecessary clutter on newsgroups. At any rate a single message, possibly mentioning the respnders, would have been more than enough. You might have responded to one with some further comment and suitable quotations, and mentioned the others in the same response.

Besides which I was grouchy, mean, and cantankerous this morning.

--
Chuck F (cbfalconer@yahoo.com) (cbfalconer@worldnet.att.net)
   Available for consulting/temporary embedded and systems.
     USE worldnet address!
Reply to
CBFalconer

Yeah -- a general "thanks to all" is usually enough and also frequently welcomed.

I *hate* when I take the time to answer a good question and but never hear from the original poster again. I generally decide that if they can't take the time for a quick "thanks" then there's no reason for me to take the time to answer any of their questions in the future.

Ermm.... "this morning"? just kidding...

--
Rich Webb   Norfolk, VA
Reply to
Rich Webb

Pre-emption requires a timer? I understand time-slicing would but surely you can do preemption w/o a timer. Useful yes. Necessary?

Robert

Reply to
R Adsett

plus

I don't see how. However, it need not consume the resource entirely- other stuff could be chained off the same timer interrupt.

Best regards, Spehro Pefhany

--
"it's the network..."                          "The Journey is the reward"
speff@interlog.com             Info for manufacturers: http://www.trexon.com
Embedded software/hardware/analog  Info for designers:  http://www.speff.com
Reply to
Spehro Pefhany

plus

The basic essence of preemption is that there must be some method by which the operating system gains momentary control of the CPU, without cooperation by the current process. I suppose you could use any interrupt event to force a task switch, but I'm just not sure how useful it would be to use a serial port interrupt for such a purpose (for example.) Timers are the traditional (and, I think, sensible) way.

Jon

Reply to
Jonathan Kirwan

Yup. My preference usually is to assign a timer to the exclusive use of the operating system, so that the timer can be adjusted without worrying about the impacts that may imply elsewhere. But it's not a requirement by any stretch.

Jon

Reply to
Jonathan Kirwan

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.