===========================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
/*****************************************************************/
/* A very simple task scheduler which does cooperative */
/* multitasking between two tasks only */
/*****************************************************************/
jmp_buf OTask;
int IsOtherTask = 0;
void SwitchToNextTask(void)
{
if ( IsOtherTask )
{
jmp_buf ThisTask;
if ( setjmp( ThisTask ) == 0 )
{
jmp_buf OtherTask;
memcpy( OtherTask, OTask, sizeof(OtherTask) );
memcpy( OTask, ThisTask, sizeof(OTask) );
longjmp( OtherTask, 1 );
}
}
}
void EndThisTask(void)
{
if ( IsOtherTask )
{ /* Switch to other task */
jmp_buf ThisTask;
IsOtherTask = 0; /* Remove this task */
if ( setjmp( ThisTask ) == 0 )
{
jmp_buf OtherTask;
memcpy( OtherTask, OTask, sizeof(OtherTask) );
memcpy( OTask, ThisTask, sizeof(OTask) );
longjmp( OtherTask, 1 );
}
}
else /* no other task to switch to -- terminate program */
exit(0);
}
void CallNewTask( void (*f)(void) )
{
char stack_placeholder[256];
f();
EndThisTask();
}
int StartNewTask( void (*f)(void) )
{
if ( IsOtherTask )
return -1; /* Other task already started */
IsOtherTask = 1;
if ( setjmp( OTask ) == 0 )
{
CallNewTask(f);
}
return 0;
}
/*****************************************************************/
/* Test application for multitasker */
/*****************************************************************/
int nmax = 10;
void task1(void)
{
int n;
for( n=1; n<=nmax; n++ )
{
printf( "Task 1 loop %d\n", n );
SwitchToNextTask();
}
}
void task2(void)
{
int n;
for( n=1; n<=nmax; n++ )
{
printf( "Task 2 loop %d\n", n );
SwitchToNextTask();
}
}
int main(void)
{
StartNewTask( task1 );
task2();
return 0;
}
===========================================================
The program produces this output:
Task 1 loop 1
Task 2 loop 1
Task 1 loop 2
Task 2 loop 2
Task 1 loop 3
Task 2 loop 3
Task 1 loop 4
Task 2 loop 4
Task 1 loop 5
Task 2 loop 5
Task 1 loop 6
Task 2 loop 6
Task 1 loop 7
Task 2 loop 7
Task 1 loop 8
Task 2 loop 8
Task 1 loop 9
Task 2 loop 9
Task 1 loop 10
Task 2 loop 10
--
----------------------------------------------------------------
Paul Schlyter, Swedish Amateur Astronomer's Society (SAAF)
Grev Turegatan 40, S-114 38 Stockholm, SWEDEN
e-mail: pausch at saaf dot se
WWW: http://hem.passagen.se/pausch/index.html
http://home.tiscali.se/~pausch/
But is there any point to this ? What does this do that a simple state
machine cannot do ?
Using the OS to manage the task switching does actually allow such
mechanisms as interrupt driven.
Using C on Concurrent-CPM-86 (and thus being on-topic) I set up two
processes in one memory area (separate stacks, shared code, shared data)
with each blocking on i-o. Essentially this was a serial printer buffer
accepting data from one serial port and outputting it to another with a
30kb buffer in between. Whichever i-o came free ran its task unless the
buffer was full or empty. The shared buffer was cyclic.
While this too _could_ have been done with a state machine or
co-operative multi-tasking it would have used all available CPU cycles
in doing so. My program never used more that 1% of CPU time and mostly
< 0.001%.
The C was all entirely standard except it needed 'volatile' (and also
used BDOS() function).
The other advantage of using OS processes is that the OS scheduler will
give each task its own timeslice in the scheduling instead of giving
only one timeslice to the program and then having that divided up
internally.
> > The C was all entirely standard except it needed 'volatile'
>
> 'volatile' is part of Standard C.
You won't find it in K&R edition 1 so it isn't 'Standard C'. It may
well be in ANSI C but how many ANSI C's do you get for CP/M or CP/M-86 ?
> > (and also used BDOS() function).
>
> That made your program non-standard C.
It is interesting that you think that having a function with a name that
is not listed in the standard makes the program 'non-standard'. Must a
'standard' program only have a main() ?