123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- /*
- Copyright (C) 1994-1995 Apogee Software, Ltd.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /**********************************************************************
- module: TASK_MAN.C
- author: James R. Dose
- date: July 25, 1994
- Low level timer task scheduler.
- (c) Copyright 1994 James R. Dose. All Rights Reserved.
- **********************************************************************/
- #define TRUE ( 1 == 1 )
- #define FALSE ( !TRUE )
- //#define USESTACK
- #define LOCKMEMORY
- #define NOINTS
- #define USE_USRHOOKS
- #include <stdlib.h>
- #include <dos.h>
- #include <conio.h>
- #include <string.h>
- #include "interrup.h"
- #include "linklist.h"
- #include "task_man.h"
- #ifdef USESTACK
- #include "dpmi.h"
- #endif
- #ifdef LOCKMEMORY
- #include "dpmi.h"
- #endif
- #ifdef USE_USRHOOKS
- #include "usrhooks.h"
- #define FreeMem( ptr ) USRHOOKS_FreeMem( ( ptr ) )
- #else
- #define FreeMem( ptr ) free( ( ptr ) )
- #endif
- typedef struct
- {
- task *start;
- task *end;
- } tasklist;
- /*---------------------------------------------------------------------
- Global variables
- ---------------------------------------------------------------------*/
- #ifdef USESTACK
- // adequate stack size
- #define kStackSize 2048
- static unsigned short StackSelector = NULL;
- static unsigned long StackPointer;
- static unsigned short oldStackSelector;
- static unsigned long oldStackPointer;
- #endif
- static task HeadTask;
- static task *TaskList = &HeadTask;
- static void ( __interrupt __far *OldInt8 )( void );
- static volatile long TaskServiceRate = 0x10000L;
- static volatile long TaskServiceCount = 0;
- #ifndef NOINTS
- static volatile int TS_TimesInInterrupt;
- #endif
- static char TS_Installed = FALSE;
- volatile int TS_InInterrupt = FALSE;
- /*---------------------------------------------------------------------
- Function prototypes
- ---------------------------------------------------------------------*/
- static void TS_FreeTaskList( void );
- static void TS_SetClockSpeed( long speed );
- static long TS_SetTimer( long TickBase );
- static void TS_SetTimerToMaxTaskRate( void );
- static void __interrupt __far TS_ServiceSchedule( void );
- static void __interrupt __far TS_ServiceScheduleIntEnabled( void );
- static void TS_AddTask( task *ptr );
- static int TS_Startup( void );
- static void RestoreRealTimeClock( void );
- // These declarations are necessary to use the inline assembly pragmas.
- extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
- extern void SetStack(unsigned short selector,unsigned long stackptr);
- // This function will get the current stack selector and pointer and save
- // them off.
- #pragma aux GetStack = \
- "mov [edi],esp" \
- "mov ax,ss" \
- "mov [esi],ax" \
- parm [esi] [edi] \
- modify [eax esi edi];
- // This function will set the stack selector and pointer to the specified
- // values.
- #pragma aux SetStack = \
- "mov ss,ax" \
- "mov esp,edx" \
- parm [ax] [edx] \
- modify [eax edx];
- /**********************************************************************
- Memory locked functions:
- **********************************************************************/
- #define TS_LockStart TS_FreeTaskList
- /*---------------------------------------------------------------------
- Function: TS_FreeTaskList
- Terminates all tasks and releases any memory used for control
- structures.
- ---------------------------------------------------------------------*/
- static void TS_FreeTaskList
- (
- void
- )
- {
- task *node;
- task *next;
- unsigned flags;
- flags = DisableInterrupts();
- node = TaskList->next;
- while( node != TaskList )
- {
- next = node->next;
- FreeMem( node );
- node = next;
- }
- TaskList->next = TaskList;
- TaskList->prev = TaskList;
- RestoreInterrupts( flags );
- }
- /*---------------------------------------------------------------------
- Function: TS_SetClockSpeed
- Sets the rate of the 8253 timer.
- ---------------------------------------------------------------------*/
- static void TS_SetClockSpeed
- (
- long speed
- )
- {
- unsigned flags;
- flags = DisableInterrupts();
- if ( ( speed > 0 ) && ( speed < 0x10000L ) )
- {
- TaskServiceRate = speed;
- }
- else
- {
- TaskServiceRate = 0x10000L;
- }
- outp( 0x43, 0x36 );
- outp( 0x40, TaskServiceRate );
- outp( 0x40, TaskServiceRate >> 8 );
- RestoreInterrupts( flags );
- }
- /*---------------------------------------------------------------------
- Function: TS_SetTimer
- Calculates the rate at which a task will occur and sets the clock
- speed if necessary.
- ---------------------------------------------------------------------*/
- static long TS_SetTimer
- (
- long TickBase
- )
- {
- long speed;
- speed = 1192030L / TickBase;
- if ( speed < TaskServiceRate )
- {
- TS_SetClockSpeed( speed );
- }
- return( speed );
- }
- /*---------------------------------------------------------------------
- Function: TS_SetTimerToMaxTaskRate
- Finds the fastest running task and sets the clock to operate at
- that speed.
- ---------------------------------------------------------------------*/
- static void TS_SetTimerToMaxTaskRate
- (
- void
- )
- {
- task *ptr;
- long MaxServiceRate;
- unsigned flags;
- flags = DisableInterrupts();
- MaxServiceRate = 0x10000L;
- ptr = TaskList->next;
- while( ptr != TaskList )
- {
- if ( ptr->rate < MaxServiceRate )
- {
- MaxServiceRate = ptr->rate;
- }
- ptr = ptr->next;
- }
- if ( TaskServiceRate != MaxServiceRate )
- {
- TS_SetClockSpeed( MaxServiceRate );
- }
- RestoreInterrupts( flags );
- }
- #ifdef NOINTS
- /*---------------------------------------------------------------------
- Function: TS_ServiceSchedule
- Interrupt service routine
- ---------------------------------------------------------------------*/
- static void __interrupt __far TS_ServiceSchedule
- (
- void
- )
- {
- task *ptr;
- task *next;
- TS_InInterrupt = TRUE;
- #ifdef USESTACK
- // save stack
- GetStack( &oldStackSelector, &oldStackPointer );
- // set our stack
- SetStack( StackSelector, StackPointer );
- #endif
- ptr = TaskList->next;
- while( ptr != TaskList )
- {
- next = ptr->next;
- if ( ptr->active )
- {
- ptr->count += TaskServiceRate;
- //JIM
- // if ( ptr->count >= ptr->rate )
- while( ptr->count >= ptr->rate )
- {
- ptr->count -= ptr->rate;
- ptr->TaskService( ptr );
- }
- }
- ptr = next;
- }
- #ifdef USESTACK
- // restore stack
- SetStack( oldStackSelector, oldStackPointer );
- #endif
- TaskServiceCount += TaskServiceRate;
- if ( TaskServiceCount > 0xffffL )
- {
- TaskServiceCount &= 0xffff;
- _chain_intr( OldInt8 );
- }
- outp( 0x20,0x20 );
- TS_InInterrupt = FALSE;
- }
- #else
- /*---------------------------------------------------------------------
- Function: TS_ServiceScheduleIntEnabled
- Interrupt service routine with interrupts enabled.
- ---------------------------------------------------------------------*/
- static void __interrupt __far TS_ServiceScheduleIntEnabled
- (
- void
- )
- {
- task *ptr;
- task *next;
- TS_TimesInInterrupt++;
- TaskServiceCount += TaskServiceRate;
- if ( TaskServiceCount > 0xffffL )
- {
- TaskServiceCount &= 0xffff;
- _chain_intr( OldInt8 );
- }
- outp( 0x20,0x20 );
- if ( TS_InInterrupt )
- {
- return;
- }
- TS_InInterrupt = TRUE;
- _enable();
- #ifdef USESTACK
- // save stack
- GetStack( &oldStackSelector, &oldStackPointer );
- // set our stack
- SetStack( StackSelector, StackPointer );
- #endif
- while( TS_TimesInInterrupt )
- {
- ptr = TaskList->next ;
- while( ptr != TaskList )
- {
- next = ptr->next;
- if ( ptr->active )
- {
- ptr->count += TaskServiceRate;
- if ( ptr->count >= ptr->rate )
- {
- ptr->count -= ptr->rate;
- ptr->TaskService( ptr );
- }
- }
- ptr = next;
- }
- TS_TimesInInterrupt--;
- }
- _disable();
- #ifdef USESTACK
- // restore stack
- SetStack( oldStackSelector, oldStackPointer );
- #endif
- TS_InInterrupt = FALSE;
- }
- #endif
- #ifdef USESTACK
- /*---------------------------------------------------------------------
- Function: allocateTimerStack
- Allocate a block of memory from conventional (low) memory and return
- the selector (which can go directly into a segment register) of the
- memory block or 0 if an error occured.
- ---------------------------------------------------------------------*/
- static unsigned short allocateTimerStack
- (
- unsigned short size
- )
- {
- union REGS regs;
- // clear all registers
- memset( ®s, 0, sizeof( regs ) );
- // DPMI allocate conventional memory
- regs.w.ax = 0x100;
- // size in paragraphs
- regs.w.bx = ( size + 15 ) / 16;
- int386( 0x31, ®s, ®s );
- if (!regs.w.cflag)
- {
- // DPMI call returns selector in dx
- // (ax contains real mode segment
- // which is ignored here)
- return( regs.w.dx );
- }
- // Couldn't allocate memory.
- return( NULL );
- }
- /*---------------------------------------------------------------------
- Function: deallocateTimerStack
- Deallocate a block of conventional (low) memory given a selector to
- it. Assumes the block was allocated with DPMI function 0x100.
- ---------------------------------------------------------------------*/
- static void deallocateTimerStack
- (
- unsigned short selector
- )
- {
- union REGS regs;
- if ( selector != NULL )
- {
- // clear all registers
- memset( ®s, 0, sizeof( regs ) );
- regs.w.ax = 0x101;
- regs.w.dx = selector;
- int386( 0x31, ®s, ®s );
- }
- }
- #endif
- /*---------------------------------------------------------------------
- Function: TS_Startup
- Sets up the task service routine.
- ---------------------------------------------------------------------*/
- static int TS_Startup
- (
- void
- )
- {
- if ( !TS_Installed )
- {
- #ifdef LOCKMEMORY
- int status;
- status = TS_LockMemory();
- if ( status != TASK_Ok )
- {
- TS_UnlockMemory();
- return( status );
- }
- #endif
- #ifdef USESTACK
- StackSelector = allocateTimerStack( kStackSize );
- if ( StackSelector == NULL )
- {
- #ifdef LOCKMEMORY
- TS_UnlockMemory();
- #endif
- return( TASK_Error );
- }
- // Leave a little room at top of stack just for the hell of it...
- StackPointer = kStackSize - sizeof( long );
- #endif
- //static const task *TaskList = &HeadTask;
- TaskList->next = TaskList;
- TaskList->prev = TaskList;
- TaskServiceRate = 0x10000L;
- TaskServiceCount = 0;
- #ifndef NOINTS
- TS_TimesInInterrupt = 0;
- #endif
- OldInt8 = _dos_getvect( 0x08 );
- #ifdef NOINTS
- _dos_setvect( 0x08, TS_ServiceSchedule );
- #else
- _dos_setvect( 0x08, TS_ServiceScheduleIntEnabled );
- #endif
- TS_Installed = TRUE;
- }
- return( TASK_Ok );
- }
- /*---------------------------------------------------------------------
- Function: TS_Shutdown
- Ends processing of all tasks.
- ---------------------------------------------------------------------*/
- void TS_Shutdown
- (
- void
- )
- {
- if ( TS_Installed )
- {
- TS_FreeTaskList();
- TS_SetClockSpeed( 0 );
- _dos_setvect( 0x08, OldInt8 );
- #ifdef USESTACK
- deallocateTimerStack( StackSelector );
- StackSelector = NULL;
- #endif
- // Set Date and Time from CMOS
- // RestoreRealTimeClock();
- #ifdef LOCKMEMORY
- TS_UnlockMemory();
- #endif
- TS_Installed = FALSE;
- }
- }
- /*---------------------------------------------------------------------
- Function: TS_ScheduleTask
- Schedules a new task for processing.
- ---------------------------------------------------------------------*/
- task *TS_ScheduleTask
- (
- void ( *Function )( task * ),
- int rate,
- int priority,
- void *data
- )
- {
- task *ptr;
- #ifdef USE_USRHOOKS
- int status;
- ptr = NULL;
- status = USRHOOKS_GetMem( &ptr, sizeof( task ) );
- if ( status == USRHOOKS_Ok )
- #else
- ptr = malloc( sizeof( task ) );
- if ( ptr != NULL )
- #endif
- {
- if ( !TS_Installed )
- {
- status = TS_Startup();
- if ( status != TASK_Ok )
- {
- FreeMem( ptr );
- return( NULL );
- }
- }
- ptr->TaskService = Function;
- ptr->data = data;
- ptr->rate = TS_SetTimer( rate );
- ptr->count = 0;
- ptr->priority = priority;
- ptr->active = FALSE;
- TS_AddTask( ptr );
- }
- return( ptr );
- }
- /*---------------------------------------------------------------------
- Function: TS_AddTask
- Adds a new task to our list of tasks.
- ---------------------------------------------------------------------*/
- static void TS_AddTask
- (
- task *node
- )
- {
- LL_SortedInsertion( TaskList, node, next, prev, task, priority );
- }
- /*---------------------------------------------------------------------
- Function: TS_Terminate
- Ends processing of a specific task.
- ---------------------------------------------------------------------*/
- int TS_Terminate
- (
- task *NodeToRemove
- )
- {
- task *ptr;
- task *next;
- unsigned flags;
- flags = DisableInterrupts();
- ptr = TaskList->next;
- while( ptr != TaskList )
- {
- next = ptr->next;
- if ( ptr == NodeToRemove )
- {
- LL_RemoveNode( NodeToRemove, next, prev );
- NodeToRemove->next = NULL;
- NodeToRemove->prev = NULL;
- FreeMem( NodeToRemove );
- TS_SetTimerToMaxTaskRate();
- RestoreInterrupts( flags );
- return( TASK_Ok );
- }
- ptr = next;
- }
- RestoreInterrupts( flags );
- return( TASK_Warning );
- }
- /*---------------------------------------------------------------------
- Function: TS_Dispatch
- Begins processing of all inactive tasks.
- ---------------------------------------------------------------------*/
- void TS_Dispatch
- (
- void
- )
- {
- task *ptr;
- unsigned flags;
- flags = DisableInterrupts();
- ptr = TaskList->next;
- while( ptr != TaskList )
- {
- ptr->active = TRUE;
- ptr = ptr->next;
- }
- RestoreInterrupts( flags );
- }
- /*---------------------------------------------------------------------
- Function: TS_SetTaskRate
- Sets the rate at which the specified task is serviced.
- ---------------------------------------------------------------------*/
- void TS_SetTaskRate
- (
- task *Task,
- int rate
- )
- {
- unsigned flags;
- flags = DisableInterrupts();
- Task->rate = TS_SetTimer( rate );
- TS_SetTimerToMaxTaskRate();
- RestoreInterrupts( flags );
- }
- #ifdef LOCKMEMORY
- /*---------------------------------------------------------------------
- Function: TS_LockEnd
- Used for determining the length of the functions to lock in memory.
- ---------------------------------------------------------------------*/
- static void TS_LockEnd
- (
- void
- )
- {
- }
- /*---------------------------------------------------------------------
- Function: TS_UnlockMemory
- Unlocks all neccessary data.
- ---------------------------------------------------------------------*/
- void TS_UnlockMemory
- (
- void
- )
- {
- DPMI_UnlockMemoryRegion( TS_LockStart, TS_LockEnd );
- DPMI_Unlock( TaskList );
- DPMI_Unlock( OldInt8 );
- DPMI_Unlock( TaskServiceRate );
- DPMI_Unlock( TaskServiceCount );
- DPMI_Unlock( TS_Installed );
- #ifndef NOINTS
- DPMI_Unlock( TS_TimesInInterrupt );
- #endif
- #ifdef USESTACK
- DPMI_Unlock( StackSelector );
- DPMI_Unlock( StackPointer );
- DPMI_Unlock( oldStackSelector );
- DPMI_Unlock( oldStackPointer );
- #endif
- }
- /*---------------------------------------------------------------------
- Function: TS_LockMemory
- Locks all neccessary data.
- ---------------------------------------------------------------------*/
- int TS_LockMemory
- (
- void
- )
- {
- int status;
- status = DPMI_LockMemoryRegion( TS_LockStart, TS_LockEnd );
- status |= DPMI_Lock( TaskList );
- status |= DPMI_Lock( OldInt8 );
- status |= DPMI_Lock( TaskServiceRate );
- status |= DPMI_Lock( TaskServiceCount );
- status |= DPMI_Lock( TS_Installed );
- #ifndef NOINTS
- status |= DPMI_Lock( TS_TimesInInterrupt );
- #endif
- #ifdef USESTACK
- status |= DPMI_Lock( StackSelector );
- status |= DPMI_Lock( StackPointer );
- status |= DPMI_Lock( oldStackSelector );
- status |= DPMI_Lock( oldStackPointer );
- #endif
- if ( status != DPMI_Ok )
- {
- TS_UnlockMemory();
- return( TASK_Error );
- }
- return( TASK_Ok );
- }
- #endif
- /*
- // Converts a hex byte to an integer
- static int btoi
- (
- unsigned char bcd
- )
- {
- unsigned b;
- unsigned c;
- unsigned d;
- b = bcd / 16;
- c = bcd - b * 16;
- d = b * 10 + c;
- return( d );
- }
- static void RestoreRealTimeClock
- (
- void
- )
- {
- int read;
- int i;
- int hr;
- int min;
- int sec;
- int cent;
- int yr;
- int mo;
- int day;
- int year;
- union REGS inregs;
- // Read Real Time Clock Time.
- read = FALSE;
- inregs.h.ah = 0x02;
- for( i = 1; i <= 3; i++ )
- {
- int386( 0x1A, &inregs, &inregs );
- if ( inregs.x.cflag == 0 )
- {
- read = TRUE;
- }
- }
- if ( read )
- {
- //and convert BCD to integer format
- hr = btoi( inregs.h.ch );
- min = btoi( inregs.h.cl );
- sec = btoi( inregs.h.dh );
- // Read Real Time Clock Date.
- inregs.h.ah = 0x04;
- int386( 0x1A, &inregs, &inregs );
- if ( inregs.x.cflag == 0 )
- {
- //and convert BCD to integer format
- cent = btoi( inregs.h.ch );
- yr = btoi( inregs.h.cl );
- mo = btoi( inregs.h.dh );
- day = btoi( inregs.h.dl );
- year = cent * 100 + yr;
- // Set System Time.
- inregs.h.ch = hr;
- inregs.h.cl = min;
- inregs.h.dh = sec;
- inregs.h.dl = 0;
- inregs.h.ah = 0x2D;
- int386( 0x21, &inregs, &inregs );
- // Set System Date.
- inregs.w.cx = year;
- inregs.h.dh = mo;
- inregs.h.dl = day;
- inregs.h.ah = 0x2B;
- int386( 0x21, &inregs, &inregs );
- }
- }
- }
- */
- /*
- struct dostime_t time;
- struct dosdate_t date;
- outp(0x70,0);
- time.second=inp(0x71);
- outp(0x70,2);
- time.minute=inp(0x71);
- outp(0x70,4);
- time.hour=inp(0x71);
- outp(0x70,7);
- date.day=inp(0x71);
- outp(0x70,8);
- date.month=inp(0x71);
- outp(0x70,9);
- date.year=inp(0x71);
- time.second=(time.second&0x0f)+((time.second>>4)*10);
- time.minute=(time.minute&0x0f)+((time.minute>>4)*10);
- time.hour=(time.hour&0x0f)+((time.hour>>4)*10);
- date.day=(date.day&0x0f)+((date.day>>4)*10);
- date.month=(date.month&0x0f)+((date.month>>4)*10);
- date.year=(date.year&0x0f)+((date.year>>4)*10);
- _dos_settime(&time);
- _dos_setdate(&date);
- */
|