resnicks@netcom.COM (Steve Resnick) (04/03/91)
There seems to have been a bit of discussion about multi-threaded C.
Having written some code for this as an experiment, I find I have no
real need for it :) (But give me a preemptive scheduler and I am happy =])
If anyone is interested, here it is. This seems to work both with Turbo C,
and MSC 6.0 (under OS/2). The OS/2 part seems utterly useless, but what
the heck ....
Have fun :)
-----------------------------------------------------------------------------
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 04/02/1991 21:22 UTC by resnicks@netcom
# Source directory /u9/resnicks/foo
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 2749 -rw-r--r-- ct.c
# 435 -rw-r--r-- ct.h
# 0 -rw-r--r-- ct.shar
# 733 -rw-r--r-- main.c
# 200 -rw-r--r-- makefile
# 501 -rw-r--r-- readme
# 946 -rw-r--r-- stack.asm
# 581 -rw-r--r-- task1.c
#
# ============= ct.c ==============
if test -f 'ct.c' -a X"$1" != X"-c"; then
echo 'x - skipping ct.c (File already exists)'
else
echo 'x - extracting ct.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ct.c' &&
/*
X * This set of routines implements a simple, cooperative multi-tasking
X * scheduler. scheduling is done on a round-robin basis, running each task
X * one after another for each runnable task. Each running task must decide
X * when to give up it's "slice" to enable other tasks to run.
*/
#include <stdio.h>
#include <setjmp.h>
#include <time.h>
#include <mem.h>
#include <dos.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "ct.h"
X
#define DEAD 0
#define RUN 1
#define START 2
#define BLOCK 3
#define NUMTSKS 10
X
typedef struct _tss
{
X void (*EntryPt)(void); /* Task Entry point */
X int Valid;
X int NewStack;
X char *Stack;
X char Save[sizeof(jmp_buf)];
} Tss;
Tss Tasks[NUMTSKS+2];
X
jmp_buf tsstmp;
jmp_buf _init_senv;
unsigned _stklen = 10240;
int CurPID = -1;
X
Switcher()
{
static int OldTI, NewTI =-1, i, j;
static jmp_buf tmp;
X
X for (j = i = 0; i < NUMTSKS; i++)
X {
X if (Tasks[i].Stack != NULL && Tasks[i].Valid == DEAD)
X {
X free(Tasks[i].Stack);
X Tasks[i].Stack = NULL;
X }
X if (Tasks[i].Valid != DEAD)
X j ++ ;
X }
X if (j == 0)
X {
X printf("panic: No tasks to run.\n");
X ResolveSystem();
X }
X OldTI = CurPID;
X while(Tasks[++CurPID].Valid == DEAD || Tasks[CurPID].Valid == BLOCK )
X if (CurPID >= NUMTSKS)
X CurPID = -1;
X
X if (CurPID >= NUMTSKS)
X CurPID = 0;
X
X NewTI = CurPID;
X
X memcpy(Tasks[OldTI].Save,tsstmp,sizeof(jmp_buf));
X memcpy(tmp,Tasks[NewTI].Save,sizeof(jmp_buf));
X if (Tasks[NewTI].Valid == START)
X {
X Tasks[NewTI].Valid = RUN;
X StartTask(Tasks[NewTI].EntryPt, Tasks[NewTI].Stack);
X }
X longjmp(tmp,1);
}
int CreateTask(void(*EntryPt)(void), int StackSize)
{
X int i, Ctask = -1;
X for (i = 0; i < NUMTSKS; i++)
X if (Tasks[i].Valid == DEAD)
X {
X Ctask = i;
X break ;
X }
X if (Ctask == -1)
X return -1;
X Tasks[Ctask].EntryPt = EntryPt;
X Tasks[Ctask].Valid = START;
X if ((Tasks[Ctask].Stack = calloc(StackSize,1)) == NULL)
X return -1;
X Tasks[Ctask].Stack += StackSize;
X Ctask ++ ;
X return 0;
}
void EndTask(void)
{
X Tasks[CurPID].Valid = DEAD;
X TaskSwitch();
}
DumpTss()
{
X int i, Num = 0;
X char *States[] = {"Dead","Running","Loading","Blocked",};
X
X for (i = 0; i <NUMTSKS; i++)
X if (Tasks[i].Valid != DEAD)
X Num ++ ;
X
X printf("Tasks currently executing: %2d Process Table Size: %2d \n",
X Num,NUMTSKS);
X printf("TID\t\tProgram\t\tStack\t\t State\r\n");
X printf("---\t\t---------\t---------\t -------\n");
X for(i = 0; i < NUMTSKS; i++)
X {
X if (Tasks[i].Valid != DEAD)
X {
X printf("%4.4X\t\t",i);
X printf("%p\t",Tasks[i].EntryPt);
X printf("%p\t",Tasks[i].Stack);
X printf(" %-10.10s\n\r",States[Tasks[i].Valid]);
X }
X }
X printf("%70.70s\r","");
}
SHAR_EOF
chmod 0644 ct.c ||
echo 'restore of ct.c failed'
Wc_c="`wc -c < 'ct.c'`"
test 2749 -eq "$Wc_c" ||
echo 'ct.c: original size 2749, current size' "$Wc_c"
fi
# ============= ct.h ==============
if test -f 'ct.h' -a X"$1" != X"-c"; then
echo 'x - skipping ct.h (File already exists)'
else
echo 'x - extracting ct.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ct.h' &&
X
extern jmp_buf tsstmp;
extern jmp_buf _init_senv;
X
#define TaskSwitch() {if (setjmp(tsstmp) == 0) Switcher();}
#define DosExitProgram(Rcode) _AX = 0x4C00 | (Rcode&0xFF); geninterrupt(0x21)
#define EnableTasker() if (setjmp(_init_senv) == 0) Switcher()
#define ResolveSystem() (longjmp(_init_senv,1))
X
int CreateTask(void(*EntryPt)(void), int);
void StartTask(void far (*EntryPt)(void),char far *);
void EndTask(void);
X
X
SHAR_EOF
chmod 0644 ct.h ||
echo 'restore of ct.h failed'
Wc_c="`wc -c < 'ct.h'`"
test 435 -eq "$Wc_c" ||
echo 'ct.h: original size 435, current size' "$Wc_c"
fi
# ============= ct.shar ==============
if test -f 'ct.shar' -a X"$1" != X"-c"; then
echo 'x - skipping ct.shar (File already exists)'
else
echo 'x - extracting ct.shar (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ct.shar' &&
SHAR_EOF
chmod 0644 ct.shar ||
echo 'restore of ct.shar failed'
Wc_c="`wc -c < 'ct.shar'`"
test 0 -eq "$Wc_c" ||
echo 'ct.shar: original size 0, current size' "$Wc_c"
fi
# ============= main.c ==============
if test -f 'main.c' -a X"$1" != X"-c"; then
echo 'x - skipping main.c (File already exists)'
else
echo 'x - extracting main.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
#include <stdio.h>
#include <setjmp.h>
#include <time.h>
#include <mem.h>
#include <dos.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "ct.h"
X
void Task1(void);
void Task2(void);
X
X
X
main()
{
X CreateTask(Task1,4096);
X CreateTask(Task2,4096);
X CreateTask(Task2,4096);
X CreateTask(Task2,4096);
X clrscr();
X EnableTasker();
X printf("\n\nProgram terminated normally.\n");
X return 0;
}
void Task1(void)
{
X int PC = 0;
X while(PC < 0x80)
X {
X printf("\033[9;1H\033[7mTask 1 PC=%4.4X\033[0m",PC);
X printf("\033[10;20HProcess Status Task\r\n");
X DumpTss();
X printf("\r\n\n");
X PC ++ ;
X if (kbhit())
X if (getch() == 27)
X ResolveSystem();
X TaskSwitch();
X }
}
X
X
SHAR_EOF
chmod 0644 main.c ||
echo 'restore of main.c failed'
Wc_c="`wc -c < 'main.c'`"
test 733 -eq "$Wc_c" ||
echo 'main.c: original size 733, current size' "$Wc_c"
fi
# ============= makefile ==============
if test -f 'makefile' -a X"$1" != X"-c"; then
echo 'x - skipping makefile (File already exists)'
else
echo 'x - extracting makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
OBJS=main.obj ct.obj task1.obj stack.obj
CARGS=-ml -v -M -a -d -f- -r -N- -Z
X
ctsk.exe: $(OBJS)
X cc -eCTSK.EXE $(CARGS) $(OBJS)
X
.c.obj:
X cc $(CARGS) -c $<
X
.asm.obj:
X tasm /Zi /Mx stack
X
SHAR_EOF
chmod 0644 makefile ||
echo 'restore of makefile failed'
Wc_c="`wc -c < 'makefile'`"
test 200 -eq "$Wc_c" ||
echo 'makefile: original size 200, current size' "$Wc_c"
fi
# ============= readme ==============
if test -f 'readme' -a X"$1" != X"-c"; then
echo 'x - skipping readme (File already exists)'
else
echo 'x - extracting readme (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readme' &&
This is my multi-threaded C "library". This is public domain, you may
do with it as you will. I wrote this as an experiment, and it seems to
work, but I haven't done anything of great signifigance. This is for
large model Turbo/Borland C. It has also been tested in Protected Mode
under OS/2 using Microsoft C 6.0, but there is little practical use there :)
X
Have fun!
X
X
Steve Resnick
resnicks@netcom.com
steve@camphq
steve.resnick@f105.n143.z1.FIDONET.ORG
(408) 263-8017 12/2400 IFNA node 143/105.0
X
SHAR_EOF
chmod 0644 readme ||
echo 'restore of readme failed'
Wc_c="`wc -c < 'readme'`"
test 501 -eq "$Wc_c" ||
echo 'readme: original size 501, current size' "$Wc_c"
fi
# ============= stack.asm ==============
if test -f 'stack.asm' -a X"$1" != X"-c"; then
echo 'x - skipping stack.asm (File already exists)'
else
echo 'x - extracting stack.asm (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'stack.asm' &&
.model large
EXTRN _EndTask:FAR
.code
PUBLIC _StartTask
;
; Usage: StartTask( void far (*entrypt)(void),char far * Stack)
;
; StartTask sets up a new stack for a particular task, and then calls the
; task entry point. If the newly created task returns, EndTask() is called
; to invalidate the current task, and no more processing occurs.
;
_StartTask PROC
X PUSH BP
X MOV BP,SP ; Save current stack frame
X MOV AX,[BP+12] ; Segment Address of New Stack
X MOV BX,[BP+10] ; Offset Address of New Stack
X MOV CX,[BP+8] ; Segment Address of entry point
X MOV DX,[BP+6] ; Offset Address of entry point
X MOV SS,AX ; Select new stack segment
X MOV SP,BX ; And set new stack pointer
X MOV AX,offset CEtsk ; Get IP Value for dummy return
X PUSH CS ; Make return segment point to here
X PUSH AX ; Make return offset point to CEtsk
X PUSH CX ; Push return CS
X PUSH DX ; Push Return IP
X RET
CEtsk: CALL far ptr _EndTask
_StartTask ENDP
X END
X
X
X
SHAR_EOF
chmod 0644 stack.asm ||
echo 'restore of stack.asm failed'
Wc_c="`wc -c < 'stack.asm'`"
test 946 -eq "$Wc_c" ||
echo 'stack.asm: original size 946, current size' "$Wc_c"
fi
# ============= task1.c ==============
if test -f 'task1.c' -a X"$1" != X"-c"; then
echo 'x - skipping task1.c (File already exists)'
else
echo 'x - extracting task1.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'task1.c' &&
#include <stdio.h>
#include <setjmp.h>
#include <time.h>
#include <mem.h>
#include <dos.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "ct.h"
X
extern int CurPID;
X
void Task2(void)
{
X int Row, Num, EndPoint, PC = 0;
X int EndPoints[] = {0,0x20,0x40,0x60};
X Num = CurPID;
X Row = (Num * 2) + 1;
X EndPoint = EndPoints[CurPID];
X
X Num ++ ;
X while(PC < EndPoint + 1)
X {
X printf("\033[%d;1H\033[7mTask %d PC=%4.4X\033[0m",Row,Num,PC);
X PC ++ ;
X TaskSwitch();
X }
X printf("\033[%d;1HTask %d: Terminating.\n",Row+1,Num,PC);
X return ;
}
SHAR_EOF
chmod 0644 task1.c ||
echo 'restore of task1.c failed'
Wc_c="`wc -c < 'task1.c'`"
test 581 -eq "$Wc_c" ||
echo 'task1.c: original size 581, current size' "$Wc_c"
fi
exit 0
--
-------------------------------------------------------------------------------
resnicks@netcom.com, steve@camphq, IFNA: 1:143/105.0,
USNail: 530 Lawrence Expressway, Suite 374
Sunnyvale, Ca 94086
- In real life: Steve Resnick. Flames, grammar and spelling errors >/dev/null
0x2b |~ 0x2b, THAT is the question.
The Asylum OS/2 BBS - (408)263-8017 12/2400,8,1 - Running Maximus CBCS 1.2
-------------------------------------------------------------------------------tabu6@CCVAX.IASTATE.EDU (Adam Goldberg) (04/03/91)
In article <1991Apr2.212636.14024@netcom.COM>, resnicks@netcom.COM (Steve Resnick) writes: > >There seems to have been a bit of discussion about multi-threaded C. >Having written some code for this as an experiment, I find I have no >real need for it :) (But give me a preemptive scheduler and I am happy =]) > >If anyone is interested, here it is. This seems to work both with Turbo C, >and MSC 6.0 (under OS/2). The OS/2 part seems utterly useless, but what >the heck .... >Have fun :) > The April issue of Dr. Dobb's has an article regarding run-until-block multitasking using C, including source code and an explaination thereof. +----------------------------------------------------------------------------+ + Adam Goldberg Bitnet: tabu6@ISUVAX.BITNET + + Iowa State University Internet: tabu6@CCVAX.IASTATE.EDU + + "It's simple! Even a Pascal programmer could do it!" + + "Remember: The sooner you fall behind, the more time you have to catch up" + +----------------------------------------------------------------------------+
resnicks@netcom.COM (Steve Resnick) (04/04/91)
In article <1991Apr3.011816.15419@news.iastate.edu> tabu6@CCVAX.IASTATE.EDU writes: >In article <1991Apr2.212636.14024@netcom.COM>, resnicks@netcom.COM (Steve Resnick) writes: >> >>There seems to have been a bit of discussion about multi-threaded C. >>Having written some code for this as an experiment, I find I have no >>real need for it :) (But give me a preemptive scheduler and I am happy =]) >> >>If anyone is interested, here it is. This seems to work both with Turbo C, >>and MSC 6.0 (under OS/2). The OS/2 part seems utterly useless, but what >>the heck .... >>Have fun :) >> > >The April issue of Dr. Dobb's has an article regarding run-until-block >multitasking using C, including source code and an explaination thereof. I never saw the Dr. Dobbs version, but the one in the C User's Journal doesn't work. (Not under TC 2.0, BC 2.0, or MSC 6.0) Soap Box: On Personally, I have been boycotting Dr. Dobbs because of the way they offer a "no risk" subscription. Get your first issue, and mark "CANCEL" on the bill. Instead of cancelling my subscription, their distribution/ subscription service sent me threatening letters telling me how my credit is going to be damaged. Since this is a service and not the publisher, I am left with no way to contact these people, except through a PO box in Colorado. That's no way to do business, and I for one will not support any business which resorts to such tactics. Soap Box: Off -- ------------------------------------------------------------------------------- resnicks@netcom.com, steve@camphq, IFNA: 1:143/105.0, USNail: 530 Lawrence Expressway, Suite 374 Sunnyvale, Ca 94086 - In real life: Steve Resnick. Flames, grammar and spelling errors >/dev/null 0x2b |~ 0x2b, THAT is the question. The Asylum OS/2 BBS - (408)263-8017 12/2400,8,1 - Running Maximus CBCS 1.2 -------------------------------------------------------------------------------
jwm712@unhd.unh.edu (Jonathan W Miner) (04/04/91)
In article <1991Apr3.011816.15419@news.iastate.edu> tabu6@CCVAX.IASTATE.EDU writes: >In article <1991Apr2.212636.14024@netcom.COM>, resnicks@netcom.COM (Steve Resnick) writes: >> >>There seems to have been a bit of discussion about multi-threaded C. >>Having written some code for this as an experiment, I find I have no >>real need for it :) (But give me a preemptive scheduler and I am happy =]) >> >>If anyone is interested, here it is. This seems to work both with Turbo C, >>and MSC 6.0 (under OS/2). The OS/2 part seems utterly useless, but what >>the heck .... >>Have fun :) >> > >The April issue of Dr. Dobb's has an article regarding run-until-block >multitasking using C, including source code and an explaination thereof. > I have downloaded CTASK22 from wuarchive and that works well. I compiled under Turbo C with no problems. Just my $0.02 -- Jonathan Miner | I don't speak for UNH, and UNH does not jwm712@unhd.unh.edu | speak for me! (603)868-3416 | Hacking to survive......
chetl@sparc23.tamu.EDU (Chet T Laughlin) (04/04/91)
Xcuse me, but why are you writing your own task handler under OS/2? Seems redundant to me when you already have OS support for processes and threads. Its not like you HAVE to write one, as one would have to under DOS. -- +-----------------------------------------------------+ | Chet Laughlin chetl@sparc21.tamu.edu | | I have no opinions, my lawyers told me so. My | | existance is currently under debate. | +-----------------------------------------------------+