asjoshi@phoenix.princeton.edu (Amit S. Joshi) (03/06/88)
Submitted-By: "Amit S. Joshi" <asjoshi@phoenix.princeton.edu> Archive-Name: turbo-C-timers Comp.sources.misc: Volume 2, Issue 69 Submitted-By: "Amit S. Joshi" <asjoshi@phoenix.princeton.edu> Archive-Name: turbo-C-timers [*Another* ARCed source?! Egads! ++bsa] Here are a set of four functions to handle timers and ^C breaks slightly more easily from Turbo C. Includes a small 'manual' page to use the functions. Could be ported to MSC (but I don't have that expensive compiler ;-). For some reason the functions cause a stack overflow in the small, tiny and medium models. There is a small test program to excercise the timer functions included. Also included is the makefile and the default rules file. I used NDMAKE. UUdecode and then unarchive. Any old arc program (even tthe UNIX ones) should be able to do it. [Not any more; it's now a shar. ++bsa] ----- cut above this line ----- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -rw-r--r-- 1 allbery System 1622 Feb 27 00:55 MAKE.INI # -rw-r--r-- 1 allbery System 1129 Mar 4 15:01 MAKEFILE # -rw-r--r-- 1 allbery System 1574 Mar 4 15:37 TEST.C # -rw-r--r-- 1 allbery System 5556 Feb 25 12:35 TICK.C # -rw-r--r-- 1 allbery System 2511 Mar 4 14:56 TICK.DOC # -rw-r--r-- 1 allbery System 1442 Feb 25 11:49 TICK.H # echo 'x - MAKE.INI' if test -f MAKE.INI; then echo 'shar: not overwriting MAKE.INI'; else sed 's/^X//' << '________This_Is_The_END________' > MAKE.INI X# rules especially for the Turbo C package. X XCC=tcc XAS=masm XLB=lib XCPP=cpp XLINK=tlink XMODEL=s X XLIB=c:\turboc\lib XINCLUDE=c:\turboc\include X XLIBS= XSTDLIBFILES=$(LIB)\math$(MODEL) $(LIB)\c$(MODEL) $(LIB)\fp87 XSTDOBJFILES=$(LIB)\c0$(MODEL) X X XTCFLAGS=-DTURBOC -m$(MODEL) XASFLAGS=/E XLFLAGS=/d XCFLAGS= X X.SUFFIXES: .i .com .exe .obj .asm .c .for .pas X X# create response files for tlink too. X.RESPONSE_LINK: tlink X X# ASM -> EXE using masm and tlink X.asm.exe: X $(AS) $<; X $(LINK) $(STDOBJFILES) $*,$*,,$(STDLIBFILES) $(LFLAGS) X @rm -f $*.obj X X# ASM -> OBJ using MASM X.asm.obj: X $(AS) $<; X X# C -> ASM using tcc -S option X.c.asm: X $(CC) $(TCFLAGS) -S $(CFLAGS) -I$(INCLUDE) -L$(LIB) $(LIBS) $< X @tcod $* X @mv $*.cod $*.asm X X# C -> COM using tcc and then exe2bin X.c.com: X $(CC) $(TCFLAGS) $(CFLAGS) -I$(INCLUDE) -L$(LIB) $(LIBS) $< X -(@exe2bin $*.exe $*.com) X @rm -f $*.obj $*.exe X X# C -> EXE using tcc ; use this since it is faster than C -> OBJ -> EXE X.c.exe: X $(CC) $(TCFLAGS) $(CFLAGS) -I$(INCLUDE) -L$(LIB) $(LIBS) $< X @rm -fi- $*.obj X X# C -> OBJ using tcc -c option X.c.obj: X $(CC) $(TCFLAGS) -c $(CFLAGS) -I$(INCLUDE) -L$(LIB) $(LIBS) $< X X# OBJ -> EXE using tcc X.obj.exe: X $(CC) $(TCFLAGS) $(CFLAGS) -I$(INCLUDE) -L$(LIB) $(LIBS) $< X X# EXE -> COM using exe2bin X.exe.com: X exe2bin $< $*.com X @rm -f $*.exe X X# C -> I run preprocessor only X.c.i: X $(CPP) $(TCFLAGS) -P $(CFLAGS) -I$(INCLUDE) -L$(LIB) $(LIBS) $< X X# cleans the current directory - always needed Xclean:; @rm -f *.bak *.map *.lst X X# make makefile using mkmf interactively ________This_Is_The_END________ if test `wc -l < MAKE.INI` -ne 75; then echo 'shar: MAKE.INI was damaged during transit (should have been 75 bytes)' fi fi ; : end of overwriting check echo 'x - MAKEFILE' if test -f MAKEFILE; then echo 'shar: not overwriting MAKEFILE'; else sed 's/^X//' << '________This_Is_The_END________' > MAKEFILE X XMODEL = ml X# turn optimization on by default XCFLAGS = -O X XDEST = . X XEXTHDRS = /turboc/include/dos.h \ X /turboc/include/stdarg.h \ X /turboc/include/stdio.h \ X /turboc/include/stdlib.h X XHDRS = TICK.H X XLIBS = X XMAKEFILE = makefile X XOBJS = TEST.OBJ \ X TICK.OBJ X X# Print over the ethernet XPRINT = eprint X XPROGRAM = test.exe X XSRCS = TEST.C \ X TICK.C X Xall: $(PROGRAM) X X$(PROGRAM): $(OBJS) $(LIBS) X $(LINK) $(STDOBJFILES) $(OBJS),$@,,$(LIBS) $(STDLIBFILES) X Xclean:; rm -f *.bak *.lst *.map $(OBJS) X Xdepend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST) X Xinstall: $(PROGRAM) X @mv $(PROGRAM) $(DEST) X Xprint:; $(PRINT) $(HDRS) $(SRCS) X Xprogram: $(PROGRAM) X Xupdate: $(DEST)/$(PROGRAM) X X$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS) X @make -f $(MAKEFILE) DEST=$(DEST) install X### XTEST.OBJ: /turboc/include/stdio.h /turboc/include/stdarg.h tick.h \ X /turboc/include/dos.h XTICK.OBJ: /turboc/include/stdlib.h /turboc/include/stdio.h \ X /turboc/include/stdarg.h tick.h /turboc/include/dos.h ________This_Is_The_END________ if test `wc -l < MAKEFILE` -ne 54; then echo 'shar: MAKEFILE was damaged during transit (should have been 54 bytes)' fi fi ; : end of overwriting check echo 'x - TEST.C' if test -f TEST.C; then echo 'shar: not overwriting TEST.C'; else sed 's/^X//' << '________This_Is_The_END________' > TEST.C X/* test.c - gently excersise the tick.c functions */ X X#include <stdio.h> X#include "tick.h" X X#define NT 300 X#define ND 5 X Xvoid test1(void) { X printf("1"); X} X Xvoid test2(void) { X putc('a',stderr); X} X Xmain() { X int i; X void test1(), test2(); X X for (i = NT; i > 0; i--) { X test1(); test2(); X delay(ND); X } X X if ((i = install_timer(test1)) != 0) { X printf("Install_timer failed: %d\n",i); X exit(1); X } X X printf("\nInstalled timer 1\n"); X X for (i = NT; i > 0; i--) delay(ND); X X if ((i = install_timer(test2)) != 0) { X printf("Install_timer failed: %d\n",i); X exit(1); X } X X printf("\nInstalled timer 2\n"); X X for (i = NT; i > 0; i--) delay(ND); X X if ((i = remove_timer(test2)) != 0) { X printf("Remove timer failed: %d\n",i); X exit(1); X } X printf("\nRemoved timer 2\n"); X for (i = NT; i > 0; i--) delay(ND); X if ((i = install_timer(test2)) != 0) { X printf("Install_timer failed: %d\n",i); X exit(1); X } X X printf("\nInstalled timer 2\n"); X X for (i = NT; i > 0; i--) delay(ND); X if ((i = remove_timer(test1)) != 0) { X printf("Remove timer failed: %d\n",i); X exit(1); X } X printf("\nRemoved timer 1\n"); X for (i = NT; i > 0; i--) delay(ND); X X if ((i = install_timer(test1)) != 0) { X printf("Install_timer failed: %d\n",i); X exit(1); X } X X printf("\nInstalled timer 1\n"); X for (i = NT; i > 0; i--) delay(ND); X X if ((i = remove_timer(NULLVFP)) != 0) { X printf("Remove timer failed: %d\n",i); X exit(1); X } X printf("\nRemoved all timers\n"); X for (i = NT; i < 0; i--) delay(ND); X} X ________This_Is_The_END________ if test `wc -l < TEST.C` -ne 80; then echo 'shar: TEST.C was damaged during transit (should have been 80 bytes)' fi fi ; : end of overwriting check echo 'x - TICK.C' if test -f TICK.C; then echo 'shar: not overwriting TICK.C'; else sed 's/^X//' << '________This_Is_The_END________' > TICK.C X/* tick.c - installs a function which is called every clock tick */ X/* (c) - Amit Joshi, Princeton University X X This code may be used freely for any noncommercial use. It may NOT X be used in any commercial package without written permission from X the author. This clause is to protect me from legal hassles with X the university about code developed here. This code is supplied X "AS IS" i.e. with no warranty. Do not remove this notice. Any X modifications should be clearly noted before redistribution. X**/ X X/** Amit Joshi X MAE Dept., Engg. Quad. X Princeton University X December 1987 X**/ X X/** X The __tick__() and dosbusy() functions have been stolen from the X "rdir.c" code by Dean D. McCrory. The __tick__() has been X rewritten (and renamed from timer_handler()) to be more general. X Amit Joshi X January 1988 X**/ X X#include <stdlib.h> X#include <stdio.h> X#include "tick.h" X X/* Stuff for to handle the ctrl break functions */ Xstatic int __nc_brks = 0; Xstatic char __abort = 1; Xstatic void (* __c_brks[NCBRKS])(); X X/* Stuff to run timers */ Xstatic void interrupt (* __otimer)() = NULLIVFP; Xstatic int __ntimers = 0; Xstatic void (* __timers[NTIMERS])(); Xstatic char far * dosbusy_fl; /* dos maintains this */ X X/* The functions used in this file */ Xstatic int __cbrk(void); Xstatic void __clean_timer(void); Xstatic void interrupt __tick__(void); Xstatic char far * getdosbusy(void); X Xstatic int X__cbrk(void) { X int nf; X X if (!abort) { X for (nf = 0; nf < __nc_brks; ++nf) X (* __c_brks[nf])(); X exit(1); X } else return 1; X} X Xstatic void X__clean_timer(void) { X if (__otimer == NULLIVFP) return; /* nothing set yet */ X setvect(TIMER_INT,__otimer); X} X X/* __tick__ () X * X * This function intercepts the hardware timer interrupt. It checks the X * dosbusy flag and runs through a list of timer driven functions if safe X * to do so. X */ X Xstatic void interrupt X__tick__(void) X{ X static int in_fl = 0; X int timer; X X /* if the following statement is NOT coded, the 8259 blocks all hardware X interrupts including the keyboard interrupt. Since we wait for a key X in list_directory (), this causes the PC to lock up. This one took X a while to figure out */ X outportb (0x20, 0x20); /* send eoi to 8259 */ X (*__otimer) (); /* chain to previous timer handler */ X X if (! in_fl) X { X in_fl = 1; /* we are in our ISR */ X if (! *dosbusy_fl ) X /* run through the list of timers */ X for (timer = 0; timer < __ntimers; ++timer) X if (__timers[timer] != NULLVFP) X (* __timers[timer])(); X in_fl = 0; X } X return; /* return from ISR */ X} X X/* getdosbusy () X * X * Gets the Dos busy flag through interrupt 34h. This Dos function returnes X * the busy flag address in es:bx. This is an UNDOCUMENTED feature of Dos, X * however it has worked in Dos versions 2.11 - 3.30 for me - Dean McCrory. X */ Xstatic char far * Xgetdosbusy (void) X{ X struct SREGS sregs; /* segment registers */ X union REGS regs; /* normal registers */ X X regs.h.ah = 0x34; /* get dos busy flag address (UNDOCUMENTED) */ X intdosx (®s, ®s, &sregs); X return (MK_FP (sregs.es, regs.x.bx)); X} X Xint Xinstall_timer(void (*func)(void)) X{ X int i = 0; X void __clean_timer(); X void interrupt __tick__(); X X /* check if the function is already installed */ X X if (!__ntimers) { X __otimer = getvect(TIMER_INT); X /* Get address of DOS busy flag. */ X dosbusy_fl = getdosbusy(); X if (atexit(__clean_timer)) return 2; X install_cbrk(NULLVFP); X setvect(TIMER_INT,__tick__); X } X /* are we already installed ? */ X for (i=0; i < __ntimers; i++) X if (__timers[i] == func) return 0; X /* enough space for another function ? */ X if (__ntimers >= NTIMERS) return 1; X __timers[__ntimers++] = func; X return 0; X} X Xint Xremove_timer(void (*func)(void)) X{ X int i = 0; X X if (func == NULLVFP) { X __clean_timer(); X __ntimers = 0; X return 0; X } X X if (!__ntimers) return 1; /* No timers return func not there */ X X do { X /* have we found the function ? */ X if (__timers[i] == func) { X /* is it the last one in the chain ? */ X if (i++ == __ntimers) { X __timers[i-1] = NULLVFP; X } else { X /* move the chain backwards */ X do { X __timers[i-1] = __timers[i]; i++; X } while(i <= __ntimers); X } X __ntimers--; X return 0; X } else i++; X } while (i < __ntimers); X return 1; X} X Xint Xinstall_cbrk (void (* func)(void)) X{ X int i = 0; X X X X if (!__nc_brks) { X setcbrk(1); /* ensure that ctrl break is enabled */ X ctrlbrk(__cbrk); X __abort = 1; X } X X if (func == NULLVFP) __abort = 1; X X for (i = 0; i < __nc_brks; i++) X if (__c_brks[i] == func) return 0; X /* enough space for another function ? */ X if (__nc_brks >= NCBRKS) return 1; X __c_brks[__nc_brks++] = func; X return 0; X} X Xint Xremove_cbrk (void (* func)(void)) X{ X int i = 0; X X if (func == NULLVFP) __abort = 0; X X if (!__nc_brks) return 1; /* No timers return func not there */ X X do { X /* have we found the function ? */ X if (__c_brks[i] == func) { X /* is it the last one in the chain ? */ X if (i++ == __nc_brks) { X __c_brks[i-1] = NULLVFP; X } else { X /* move the chain backwards */ X do { X __c_brks[i-1] = __c_brks[i]; i++; X } while(i <= __nc_brks); X } X __nc_brks--; X return 0; X } else i++; X } while (i < __nc_brks); X return 1; ________This_Is_The_END________ if test `wc -l < TICK.C` -ne 220; then echo 'shar: TICK.C was damaged during transit (should have been 220 bytes)' fi fi ; : end of overwriting check echo 'x - TICK.DOC' if test -f TICK.DOC; then echo 'shar: not overwriting TICK.DOC'; else sed 's/^X//' << '________This_Is_The_END________' > TICK.DOC XAll the functions in this file make heavy use of TurboC and PCDOS Xfacilities and are not portable. X XWARNING: X DO NOT compile with tiny, small or medium models. Stack overflow X occurs and if the stack checking option of the compiler is used X then the timers are not unloaded and the system crashes - in fact X you have to setup the entire system from scratch. X XUSAGE: X #include "tick.h" X X int install_timer(vod (*func()); X Installs the function "func()" to be called EVERY tick. X Removes the function on exit from the program - both if X ^C or normal. You MUST NOT use the Turbo C supplied X ctrlbrk() function if you use this one. Use X "install_cbrk()" instead. X X int install_cbrk(void (*func)()); X Installs the function "func()" to be called when ^C is hit. X You can chain a series of functions. If you use this DO NOT X use the Turbo C supplied ctrlbrk(). If argument is NULLVFP X ^C exits from the program. X X int remove_timer(void (*func)()); X Removes "func()" from timer list. If NULLVFP is given as an X argument all timers are cleaned. X X int remove_cbrk(void (*func)()); X Removes "func()" from ctrlbrk list. If argument is NULLVFP X ^C has no action. XRETURN VALUES: X 0 => function was successfully installed or removed. X 1 => Install failed because of lack of space. Compile again with a X larger NTIMER or NCBRK in "tick.h" X Remove failed because function not found. X 2 => Install timer failed because we could not hook timer cleaner X onto atexit(). Try again with fewer atexit() functions. X XNOTES: X * DO NOT use the Turbo C ctrlbrk() function if using these functions X - it can have quite disasterous effects. Use install_cbrk() - it X is more general in any case !. X * Both the install functions try to check if the function is already X present and do not duplicate installations. X * Define HARDTIMER in "tick.h" if you want to use the hardware X interrupt rather than the DOS 'soft' interrupt. This is at your own X peril. I have not used this. X XBUGS: X Notify all bugs to : X Q3696@PUCC.BITNET or X {seismo, rutgers}\!princeton\!phoenix\!asjoshi X XACKNOWLEDGEMENTS: X Dean D. McCrory for two functions which really form the heart of the X timer portion : timer_handler, and dosbusy. The first has been X modified and made more general. It is also renamed to __tick__(). X The rest of the code was written using Turbo C v1.5 entirely by me X Thanks to Borland for the wonderful (and inexpensive) C compiler. X ________This_Is_The_END________ if test `wc -l < TICK.DOC` -ne 62; then echo 'shar: TICK.DOC was damaged during transit (should have been 62 bytes)' fi fi ; : end of overwriting check echo 'x - TICK.H' if test -f TICK.H; then echo 'shar: not overwriting TICK.H'; else sed 's/^X//' << '________This_Is_The_END________' > TICK.H X/* tick.h - the include file for timer and c_brk function installation */ X/* (c) - Amit Joshi, Princeton University X X This code may be used freely for any noncommercial use. It may NOT X be used in any commercial package without written permission from X the author. This clause is to protect me from legal hassles with X the university about code developed here. This code is supplied X "AS IS" i.e. with no warranty. Do not remove this notice. Any X modifications should be clearly noted before redistribution. X**/ X X/** Amit Joshi X MAE Dept., Engg. Quad. X Princeton University X December 1987 X**/ X X/** X Change the values defined for NTIMERS and NCBRKS to increase X number of timer and cbrk functions installed. X X Amit Joshi X January 1988 X**/ X X#ifndef __TICK_H__ X#define __TICK_H__ X X#include <dos.h> X X/* Change the following definitions to increase number of timers and cbrks */ X#define NTIMERS 2 /* number of timers installable */ X#define NCBRKS 2 /* number of cbrks installable */ X X#define NULLIVFP (void interrupt (*)())NULL X#define NULLVFP (void (*)())NULL X#define NULLFP (int (*)())NULL X X#ifdef HARDTIMER X#define TIMER_INT 0x08 X#else X#define TIMER_INT 0x1C X#endif X X/* user callable functions */ Xint _Cdecl install_timer(void (*func)()); Xint _Cdecl install_cbrk(void (*func)()); Xint _Cdecl remove_timer(void (*func)()); Xint _Cdecl remove_cbrk(void (*func)()); X X#endif __TICK_H__ ________This_Is_The_END________ if test `wc -l < TICK.H` -ne 51; then echo 'shar: TICK.H was damaged during transit (should have been 51 bytes)' fi fi ; : end of overwriting check exit 0 ---- cut below this line ----- Amit Joshi BITNET | Q3696@PUCC.BITNET USENET | {seismo, rutgers}\!princeton\!phoenix\!asjoshi "There's a pleasure in being mad... which none but madmen know!" - St.Dryden -- Amit Joshi BITNET | Q3696@PUCC.BITNET USENET | {seismo, rutgers}\!princeton\!phoenix\!asjoshi "There's a pleasure in being mad... which none but madmen know!" - St.Dryden