Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Multitasking with setjmp/longjmp in C

680 views
Skip to first unread message

Paul Schlyter

unread,
Jan 8, 2002, 1:34:59 PM1/8/02
to
Below is a simple ANSI C program which switches between two tasks
using setjmp/longjmp:

===========================================================

#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/

Richard Plinston

unread,
Jan 9, 2002, 5:02:12 AM1/9/02
to
Paul Schlyter wrote:
>
> Below is a simple ANSI C program which switches between two tasks
> using setjmp/longjmp:

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.

Paul Schlyter

unread,
Jan 9, 2002, 3:31:42 AM1/9/02
to
In article <3C3C1524...@Azonic.co.nz>,

Richard Plinston <rip...@Azonic.co.nz> wrote:

> Paul Schlyter wrote:
>
>> Below is a simple ANSI C program which switches between two tasks
>> using setjmp/longjmp:
>
> But is there any point to this ?

The point was to demonstrate that even in C you can have some stack
control.


> What does this do that a simple state machine cannot do ?

Nothing I suppose. Did I ever claim it did something a state machine
cannot do?


> Using the OS to manage the task switching does actually allow such
> mechanisms as interrupt driven.

:-)))) ...yes, we do know that already, thank you!


...................................................................


> The C was all entirely standard except it needed 'volatile'

'volatile' is part of Standard C.


> (and also used BDOS() function).

That made your program non-standard C.


> 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.

Of course! Anything else that's new?

Richard Plinston

unread,
Jan 10, 2002, 2:37:04 AM1/10/02
to
Paul Schlyter wrote:

> > 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() ?

Paul Schlyter

unread,
Jan 9, 2002, 7:09:14 PM1/9/02
to
In article <3C3D44A0...@Azonic.co.nz>,

Richard Plinston <rip...@Azonic.co.nz> wrote:

> Paul Schlyter wrote:
>
>>> 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

FYI: Standard C _is_ ANSI-C. K&R edition 1 is pre-standard C.
ANSI-C is the only C standard we have -- K&R C edition 1 was too
unclearly defined to be considered a standard.

Yes, 'volatile' is indeed part of Standard C.


> but how many ANSI C's do you get for CP/M or CP/M-86 ?

Not many, since CP/M predated Standard C.


>>> (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() ?

Of course not! So do you want to claim that this BDOS() function
also was implemented in Standard C, calling only Standard C library
functions or only other functions who eventually ended up calling
only Standard C library functions ?

My guess is that this BDOS() function was implemented in some
language other than C, or called an interface which isn't part of
Standard C....
0 new messages