home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-08-13 | 46.3 KB | 1,280 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- C S W I T C H
- -----------------
-
-
-
-
-
- Multitasking Functions for DOS Programs
-
- Copyright 1990 by Herb Rose
- All Rights Reserved
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Version 1.0 release date : Aug 10, 1990
-
-
- This file is an introduction to the Cswitch functions. These
- functions provide limited multitasking capabilities for programs
- running under MS-DOS or PC-DOS.
-
- The term 'limited multitasking' is used because these routines do not
- provide a multitasking user interface like DESQVIEW or WINDOWS. These
- routines are programming tools that will enable a C programmer to
- write applications that consist of independent, simultaneously executing
- programs.
-
- Using Cswitch, you can execute functions as independent tasks, which
- execute concurrently in a time-slicing environment. You may also load
- and execute programs separately. Cswitch provides you with a priority
- driven scheduler and dispatcher, DOS interface, and task control
- functions to implement true multitasking under your program's control.
-
- Before I continue the explanation of Cswitch, please bear with me as
- I detail the legalities of using these routines.
-
-
- WARRANTY
- --------
-
- This software is distributed as is, with no warranty of any kind,
- either expressed or implied. No warranty or guarantee is made that
- the software is complete or error free. All liability and risk
- associated with the use of this software is assumed by the user.
- Under no circumstances will ADEPT Software, its owners, or its
- agents be responsible for any damages arising from the use, or the
- inability to use this product. This applies to all damages and
- remedies including, but not limited to, loss of or damage to property,
- and loss of profits.
-
- This software has been tested in many configurations, under various
- conditions, and has consistently performed acceptably. To the best
- of my knowledge, there are no errors or omissions in the software
- that will pose a problem to the user.
-
- The user must be aware, however, that this is a programmer's tool,
- and by it's very nature will affect the software that controls the
- user's computer. All reasonable precautions should be taken to
- protect your computer from the affects of an errant operating system.
-
- In short -
- BACK UP YOUR DISKS, AND BE CAREFUL WHEN TESTING NEW PROGRAMS THAT
- USE CSWITCH!!!!!
-
-
-
- Shareware Distribution
- ----------------------
-
- CSWITCH is distributed as shareware. You may freely use and distribute
- these routines under the following conditions :
-
- 1. All files on this diskette must be distributed as a set, and no
- modifications or additions may be distributed as part of the
- set unless specifically approved in writing by Herb Rose.
-
- 2. All copyright and legal notices must remain intact and unaltered.
-
- 3. Copying and distribution fees may not exceed $6, and must be
- clearly specified as such.
-
- 4. You must register Cswitch if you want a copy of the source code,
- or if you wish to distribute a software product that makes use
- of any of the Cswitch functions.
-
- Note that registration is not required if you simply want to use Cswitch
- in the privacy of your own home, or just to see what it can do. As an
- incentive to registration, I include C and assembly source code when you
- register. The source code is easy to read and well documented. Make
- files are included for Microsoft C and Microsoft Assembler.
-
- Registered users are informed of new releases of the software, and may
- download new releases (including source code) from the INFO*SHARE BBS.
-
- If you plan to distribute any software product that makes use of Cswitch
- functions, then registration is mandatory. Registration provides you
- with an unlimited, nonexclusive binary distribution license, with no
- royalties. This is only fair, I think. If you distribute a program,
- you should pay for the tools you used to create that program.
-
- Registration is for use on a single computer. Contact ADEPT Software
- for site licensing, or for multiple copy discounts.
-
- Due to practical constraints, I cannot provide telephone assistance
- except to registered users. I operate a 24-hour Bulletin Board System
- to handle technical assistance. Telephone support is available for
- registered users, but I prefer to handle non-emergency questions via
- the BBS. The number is (703) 803-8000.
-
-
-
- Registration Form
- -----------------
-
- Please use the following form, or a reasonable facsimile, when
- registering Cswitch.
-
-
- Mail to : ADEPT Software
- P.O. Box 2181
- Woodbridge, Va. 22193
-
-
- CSWITCH Registration ..................... ______ @ $30 = ______
-
- Virginia Residents add 4.5% sales tax ................. = ______
-
- Overseas Air Delivery ...............................$5 = ______
- (U.S. delivery and Overseas Surface delivery is free)
-
- TOTAL ................................................. = ______
-
- Please send check or money order, in U.S. funds.
-
-
- Your Name : _____________________________________
-
- Company Name : _____________________________________
-
- Address : _____________________________________
-
- City, State, Zip : _____________________________________
- (or country)
-
-
-
-
-
-
- Introduction to Multitasking
- ----------------------------
-
- Multitasking is not a new concept. Computers have been programmed to
- execute multiple tasks concurrently for many years. It was observed
- a long time ago that most programs spent the majority of their time
- waiting for data input or output. Since users and most peripheral devices
- are notoriously slow compared to the execution speeds of modern computers,
- most programs simply sit there 'twiddling their thumbs' waiting for data.
- It was observed that the computer's computational capabilities could be
- used more efficiently if another program were allowed to use the processor
- while a program that was just waiting was put into a dormant state.
- Carrying this observation one step farther, we find true multitasking.
- Multitasking is the ability to have several programs loaded into the
- computers memory, and apparently executing simultaneously. In reality,
- there is a controlling program, called the Kernel, or Scheduler, that
- causes the computer to execute some of each programs instructions in
- a round-robin fashion. Programs that are waiting for something to
- happen, such as waiting for a keystroke, or for a disk transfer to
- complete, are normally placed into a 'waiting' state, and do not get
- placed back into execution until the event they are waiting for has
- actually happened.
-
- Notice that I said programs were 'apparently' running simultaneously.
- It is impossible for a microcomputer, such as the PC, to execute more
- that one program simultaneously. Other computers may have several micro-
- processors, and can actually execute more than one task simultaneously.
- When there is only one microprocessor, the tasks must be executed one
- at a time. The term 'time-slicing' is used to describe the operation
- of a multi-tasking operating system, meaning that the processor will
- execute each task's instructions for a short time, then will execute
- another task's instructions for a while, eventually allowing all the
- tasks to get some of their work done in a round-robin fashion. If the
- amount of time given to each task is very large, say one or two seconds,
- there could be a significant amount of time for each task to remain
- idle while it awaited it's turn to execute. If the amount of time
- given to each task (called the 'time slice') is too short, then too
- much of the computer's time will be spent saving and restoring task
- context information, diminishing the efficiency of the system. A
- good time slice setting is one that allows many different tasks to
- execute in a short period of time, without noticably affecting the
- efficiency of the system. Cswitch uses the timer interrupt for the
- PC to trigger a task switch. This occurs approximately 18 times per
- second, or once every 55 milliseconds. Since a normal time slice on
- a real multitasking operating system is usually around 50 microseconds,
- our time slice is actually very large. In fact, 55 milliseconds is
- way too big for a real-time operating system, which has to react to
- external stimulus as quickly as possible. With 18 tasks loaded into
- Cswitch, each task will only get to run once per second, for about
- 1/18 second. If some of the tasks are higher priority than others,
- the lower priority tasks may not run at all for several seconds. This
- is clearly not acceptable for programs that must react to external
- stimulus.
-
- The 55 millisecond time slice, however, is fine for running one or
- two tasks at a high priority, and allowing several other tasks to
- run at a lower priority. This gives the effect of 'background'
- processes running.
-
- If you find the 55 millisecond time slice inadequate, you should
- consider altering the timer chip's programming so that it provides
- a timer interrupt more often. Your interrupt handler will have to
- count the number of interrupts, and activate the DOS time-of-day
- routine (the normal destination of interrupt vector 8) once every
- 55 milliseconds, otherwise the computer's internal date and time
- settings will not be accurate.
-
- Now we will focus on how you get multiple tasks to cooperate so that a
- given job will get done. Basically, there are only 2 areas that we are
- concerned with -
-
- 1. Passing information from one task to another, and
- 2. Preventing another task from interfering with a resource you are using.
-
-
- Moving Data Between Tasks
- -------------------------
-
- The first area is handled in Cswitch via Message Queues. A queue is
- simply a list of messages. In this case, Cswitch has 64 queues, numbered
- 0-63. Any task may place a message onto any of the queues, and any
- task may fetch a message from any of the queues. If there is more than
- one message waiting on a queue, they will be fetched sequentially, on a
- first-in, first-out basis.
-
- A message may be any format, containing any information that may be needed
- by another task. When placing a message on a queue, you must tell Cswitch
- which queue to put it on, how long the message is (in bytes), and the
- address of the first byte of the message. Cswitch will copy as many
- bytes as you have told it into a temporary buffer, and will place a
- pointer to that buffer into the message list for that queue.
-
- When you fetch a message from a queue, you must tell Cswitch which queue
- to read a message from, the maximum number of bytes you are willing to
- receive, and where to put the message. After Cswitch has copied the
- message (or as much of the message as you will allow) into your memory,
- the temp buffer is released, and the message pointer is deleted from
- the queue's list. Note : if the message contained more bytes than
- you received (by specifying a maximum byte count lower than the actual
- size of the message), the message will still be removed from the
- queue. You should make certain you allow enough room to receive any
- message your task is likely to receive.
-
- It is up to the individual tasks to coordinate which queue numbers will
- be used to pass messages back and forth. In the Falken BBS, a multi-
- line Bulletin Board System program written with Cswitch, the main
- BBS program assigns input and output queues to each task when it is
- started. Queue number 1 is reserved, and is used to send the queue
- assignments to the tasks. In other words, when a task first runs
- under control of Falken, it must read a message from queue number 1.
- That message will tell it which queue it must read messages from, and
- which queue it can write messages to, for the rest of the time it is
- running.
-
-
- Semaphores
- ----------
-
- The second area of concern is to prevent another task from interfering
- with a resource that you are using. A resource may be almost anything,
- from a disk file to a memory buffer, to a peripheral device. Cswitch
- uses a semaphore system to control access to these resources.
-
- You must know in advance which resources must be controlled with
- semaphores. If you are going to allow several tasks to access a
- memory area simultaneously, it may be a good idea to control it, since
- one task may try to write new information to the memory while another
- task is trying to read the old information.
-
- Semaphores work like this -
- A semaphore has an owner and a waiting list. If your task attempts to
- 'attach' to the semaphore, but another task already 'owns' the semaphore,
- your task gets placed onto the 'waiting list', and does not get to run
- anymore (it is taken out of the ready queue). Your task will remain
- dormant until it is the 'owner' of the semaphore.
-
- When the owner of the semaphore 'releases' it, the first task in the
- 'waiting list' is made the new owner, and is allowed to run again.
-
- Note : When you 'attach' to a semaphore, you will become the owner of
- the semaphore before you are allowed to continue. Your
- program remains dormant until it is the owner, and you must release the
- semaphore when you are done with it, to allow other programs to run,
- which may be waiting for the semaphore.
-
- If you attempt to 'attach' to a semaphore, and it is unowned, your
- task becomes the owner and is allowed to continue running immediately.
- You must still release the semaphore when you are done.
-
-
- Cswitch Functions
- -----------------
-
- Cswitch allows tasks to perform the following functions :
-
- - All normal DOS and BIOS functions
- - Send information between tasks with Message Queues
- - Control system resources with Semaphores
- - Alter task priority
- - Suspend / Resume task execution
- - Delay for a time period (sleep)
- - Start new tasks, either sharing existing code, or loading a new
- program file from disk.
- - Load small programs into expanded memory to allow more programs
- to execute simultaneously.
-
- To use Cswitch, you must link your main program with the CSWITCH1.OBJ,
- CSWITCH2.OBJ and LMTC.OBJ files. These files provide interrupt level
- control for task switching, and the operating system functions, such as
- message passing and semaphore control. In addition, programs which
- will be loaded and executed under control of Cswitch must be linked
- with LMTC.OBJ or SMTC.OBJ (for large or small model, respectively).
- These files contain interface routines for calling system services.
-
- Your main program must call the function START_MT().
-
- START_MT() initializes the Cswitch data areas and enables multitasking.
- It intercepts several interrupt vectors, and builds Task Control
- Blocks for your main program and for an 'idle task'. The idle task
- runs at a low priority, and checks the delay and termination queues
- regularly to service tasks waiting for those functions.
- After the call to START_MT(), multitasking is fully operational,
- and you may spawn tasks and load programs. Note that your main
- program has a Task Control Block (TCB) and gets scheduled for time-
- slicing just as every other task does. Your main program runs at a
- priority of 1 (the highest priority allowed).
-
- Before terminating, your main program MUST call the function END_MT().
- END_MT restores the interrupt vectors, releases all unnecessary
- memory, and halts all multitasking. Essentially, it restores the
- computer to the same state it was in prior to the START_MT() call.
-
- ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING **
-
- If you allow your program to terminate without calling END_MT, almost
- anything can happen, since the interrupt vectors are still pointing
- to Cswitch code which may or may not be overwritten by DOS. At a
- minimum, your system will lock up. A worst-case scenario could
- involve unrecoverable damage to disk files.
-
- It is highly recommended that you test all your programs that use
- multitasking on a 'test' computer, a separate machine that does not
- contain any critical files or programs, to prevent loss of valuable
- data or programs. At a minimum, make sure all your important files
- are backed up before testing new programs that use Cswitch routines.
-
-
- Executing Tasks
- ---------------
-
- There are 2 methods of starting new tasks under Cswitch. The first
- method is to SPAWN a new task that will execute a portion of your code
- independently. Normally, this facility will be used to execute a
- function as a separate task. The new task will be given it's own
- stack and TCB, and will be scheduled for time-slicing normally. It
- will begin executing code at the address you specify (normally a
- function name). It may call other functions, and may manipulate
- global data normally. Any automatic (local) variables will reside
- on the new tasks stack, so there will not be any interference when
- a function is called by 2 different tasks. In fact, you can spawn
- several new tasks which execute the same function if you like.
-
- When the function being executed returns to the caller, the task will
- be terminated. Any functions that are called by the spawned task will
- return normally, of course. Only when the function being spawned
- returns will the task terminate.
-
- The second method of starting new tasks is to load a program from
- disk and execute it. The function LOADTASK() is used to load an EXE
- or COM file from disk and execute it. You must supply 3 parameters
- to the LOADTASK function - the command line to run the program and
- the priority to be assigned to the task, and a flag indicating whether
- the task may be loaded into expanded memory or not.
-
- For instance, to load and run the program MYPROG.EXE with the parameter
- 'myfile.dat', you would normally enter a DOS command line like this :
-
- C:>myprog myfile.dat
-
- To load and run the program under Cswitch, you would call the LOADTASK
- function like this :
-
- loadtask("myprog myfile.dat",4,1);
-
- This loads and runs 'myprog.exe', gives it the command line parameter
- 'myfile.dat', and allows it to run at priority 4, and allows it to be
- loaded into expanded memory, if possible.
-
- The .EXE extension is assumed if no extension is provided. You can
- load and execute .COM files by specifying the .COM extension. You
- must specify the full path of the program to be executed, if it is not
- in the current default directory. Cswitch will not search your PATH
- for the program.
-
-
- Scheduling
- ----------
-
- The Cswitch scheduler maintains a list of tasks that are waiting to
- execute, called the 'ready queue'. When a task switch occurs, the
- TCB at the head of the ready queue is fetched, and allowed to run.
- Normally, the TCB that was just executing is inserted back into the
- ready queue. In some cases, such as waiting for semaphore, delaying,
- etc. the task will not be re-inserted into the ready queue.
-
- Tasks are inserted into the ready queue according to their relative
- priority. Each task is assigned a 'base priority' from 1 to 10.
- 1 is the highest priority, and 10 is the lowest. Each task also has
- a 'current priority', which is used to insert TCBs into the ready
- queue. Each time a task is fetched from the ready queue, the 'current
- priority' of all the other TCBs on the ready queue is decremented
- by 1. When a task is re-inserted into the ready list, it's current
- priority is set equal to it's base priority, then it is inserted
- into the ready queue so that it is in front of all tasks whose current
- priority is lower. In this way, tasks with a higher priority will
- be allowed to execute more often than tasks of lower priority. The
- tasks with lower priority will remain on the ready queue until their
- current priority increases to the point that the other tasks get
- inserted behind them, and they work their way to the head of the queue.
-
-
- Using Expanded Memory
- ---------------------
-
- Cswitch can use expanded memory to load and run tasks that require less
- than 64K. By calling START_SWAPPING(), you tell Cswitch to start using
- expanded memory. Any task that is loaded after calling START_SWAPPING()
- is eligible to be loaded into expanded memory.
-
-
- Cswitch System Services
- -----------------------
-
- Cswitch must replace some of the DOS system services with it's own
- services. In every case, the calling sequence and register setup
- is identical do the DOS call. Return values are also identical
- to DOS return values. In short, if your program ran OK under DOS,
- it should run OK under Cswitch.
-
- Cswitch replaces the following DOS (interrupt 21) services :
-
- 48h : allocate memory
-
- Cswitch controls memory allocation for all tasks. DOS uses
- a 'first fit' algorithm for allocating memory, meaning that
- it allocates a chunk of memory from the first block that
- is large enough to fulfill the request. This leads to memory
- fragmentation, limiting the number of tasks that can run.
- Cswitch uses a 'best fit' algorithm, searching all the
- available memory blocks to find a block that is exactly the
- size needed, or is closest to it. This way, memory fragmentation
- is kept to a minimum.
-
- Note : starting with DOS 3.3, you can alter the memory
- allocation strategy that DOS uses, but 'first fit' is still
- the default.
-
- 49h : release memory
-
- Cswitch must also handle the memory release function. When a
- block of memory is released, all memory is re-combined as much
- as possible to limit memory fragmentation.
-
- 4ah : set memory block size
-
- This DOS function is used to adjust the size of a memory block.
- Since DOS tasks expect to be the only task running, they assume
- that a memory block can be altered by simply increasing the size
- of the block when they need more memory. Since several tasks
- may occupy memory blocks adjacent to the block to be modified,
- this is not always possible under Cswitch. Cswitch will attempt
- to fulfill the request by looking for a free block adjacent to
- the specified block, and combining them to form a larger block.
- If unsuccessful, it will return an error.
-
- Note that programs that allocate memory dynamically with CALLOC
- or MALLOC calls may run into problems with this limitation.
- The problem is that the library routines for allocating memory
- (MALLOC, et al) use a table of structures to control the memory
- blocks they obtain from DOS. Normally, this table will only
- hold 20 entries (this is true for Microsoft C and QuickC).
- Since Cswitch will return an error on some of the 'set memory
- block' calls, the library routines may execute an 'allocate
- memory' call every time you execute MALLOC. After 20 calls,
- the table is full, and you can't allocate any more memory!
-
- You can avoid problems by using the EXEMOD program to change
- the minimum memory requirement of your task, so that enough
- memory will be reserved when your task is loaded to handle
- dynamic memory allocation demands without having to request
- more memory from DOS.
-
- Or, you can avoid using the MALLOC/CALLOC routines wherever
- possible, and instead call the DOS allocate memory call
- directly. Be careful, though, because Cswitch can only
- control a total of 512 memory blocks.
-
- When a task in expanded memory wants to extend the memory block,
- it is much easier to do, provided the limit of 64K is not exceeded.
- Since each task loaded into expanded memory is allocated the
- entire 64K expanded memory region to work in, it is usually
- possible to extend the memory allocation to the desired size.
-
- 4ch : terminate task
-
- Cswitch handles task termination internally. It will release
- memory held by the task, close all open files, and release the
- Task Control Block.
-
- 1ah : set new DTA area
-
- Cswitch records the address of the tasks new DTA in the TCB, then
- passes this request to DOS normally. This function is normally
- handled by the library routines, and is seldom called explicitly
- by a programmer.
-
- 2fh : get DTA address
-
- Cswitch returns the DTA address from the tasks TCB.
-
-
- Cswitch Functions
- -----------------
-
- The following functions are provided in the file CSWITCH1.C, and may
- only be called by the main program. i.e. these functions may only be
- called by the program that is linked with Cswitch1 and Cswitch2.
-
- START_MT()
-
- Parameters :
- none
-
- Description :
- Starts the multitasking kernel, and enables all system
- functions. This function must be called once, and only
- once, before executing any of the other functions or
- system services.
-
- Return Value :
- none
-
- Notes/Comments :
-
-
- START_SWAPPING()
-
- Parameters :
- none
-
- Description :
- This function sets Cswitch up to swap tasks out to
- expanded memory.
-
- Return Value :
- The amount of expanded memory available is returned,
-
- Notes/Comments :
- All tasks started prior to this call are memory-resident,
- and all spawned tasks are memory resident. This routine
- may only be called once, and there is no way to turn
- off usage of expanded memory once it is started.
-
-
- END_MT()
-
- Parameters :
- none
-
- Description :
- Ends multitasking. The program that called START_MT()
- must call END_MT() before terminating.
-
- Return Value :
- none
-
- Notes/Comments :
- See the warning above concerning the dire consequences
- of terminating without restoring the interrupt vectors
- and turning off multitasking.
-
-
-
-
- LOADPRG(cmd_string,pri,expmemflag)
- char *cmd_string;
- int pri;
- int expmemflag;
-
- Parameters :
- cmd_string is a character pointer to a command string
- to load the program, including command line parameters
- just as you would type in to load the program under
- DOS.
-
- pri is the base priority of the new task
-
- if expmemflag is true, the task is eligible to be loaded
- into expanded memory. if set to 0, the task may not be
- loaded into expanded memory, even if START_SWAPPING()
- has been called previously.
-
- Description :
- Loads and executes an .EXE or .COM file from disk.
- The full path to the program file must be specified,
- and command line parameters may be used.
-
- Return Value :
- 0 = no error
- -1 = not enough memory to create new task stack
- -2 = no free task control blocks
- -3 = no free memory control blocks
-
- Notes/Comments :
- This function performs the same service as LOADTASK()
- below. The difference is that this service is called
- directly as a function. LOADTASK is invoked via the
- INT 62H. Functionally, there is no difference, since
- LOADTASK() eventually calls LOADPRG to do the work.
-
-
- Cswitch Global Variables
- ------------------------
-
- The following variables are available to the main program. These are
- provided for information only.
-
- int dos48, dos49, dos4a, dos4c;
-
- These integers represent a running count of how many DOS calls
- (INT 21H) have been made for these function codes.
-
- unsigned int base_mem_segment;
-
- This is the segment value of the memory segment controlled by
- Cswitch.
-
- int idlecount;
-
- This is a running count of how many times the idle task has
- run. The idle task is spawned when START_MT() is called, and
- handles the tasks that are delaying and terminating.
-
- int swap_count;
-
- This is a running count of how many task switches have taken
- place. When the scheduler is called, this count is incremented
- even if no task switch takes place due to a task locking out
- switching or some other reason.
-
- int extmem_pages;
-
- This is the total number of expanded memory pages available
- for task swapping. This variable is loaded after a successful
- call to START_SWAPPING().
-
- int exmemfree;
-
- This is the number of free pages of expanded memory
- left in the system. Pages are allocated as needed by memory
- allocation calls, so this number may vary somewhat during
- operation.
-
-
- Cswitch Internal Services
- -------------------------
-
- The following functions are provided in the file LMTC.OBJ and SMTC.OBJ,
- and may be called by any task executing under Cswitch control. These
- functions allow access to the semaphore, messaging, and task control
- functions of Cswitch.
-
- These functions are actually invoked via an INT 62H call. The parameters
- are loaded into registers, and the INT 62H transfers control to an
- assembly language routine. The registers are then pushed onto the stack,
- and the C function for system calls is executed.
-
- Most of the work done by Cswitch is done by C routines, with assembly
- language used only for interrupt control.
-
- All of these functions are of type INT, although some do not have return
- values assigned.
-
-
-
- RELINQ()
-
- Parameters :
- none
-
- Description :
- Gives up the rest of the tasks time slice.
- This is graceful way of not wasting processor time if
- your task has nothing else to do for a short while.
-
- Return Value :
- none
-
- Notes/Comments :
- none
-
-
-
- SPAWN(func_addr,pri)
- int *func_addr();
- int pri;
-
- Parameters :
- func_addr is the address of a function or subroutine
- that is to be executed as a separate task
-
- pri is the base priority for the new task (1-10)
-
- Description :
- Causes the specified function or subroutine to be
- executed as a separate task. A new stack is allocated
- for the task, allowing it to have exclusive access to
- local variables. It will still share global variables
- with the calling task.
-
- STDIN, STDOUT, and STDERR are inherited from the caller.
-
- The function can be spawned more than once, allowing
- multiple tasks to execute the same code thread.
-
- Return Value :
- >0 = the tcb number of the new task, indicating no error
- -1 = not enough memory to create new task stack
- -2 = no free task control blocks
- -3 = no free memory control blocks
-
- Notes/Comments :
- A task that is swappable to expanded memory (i.e. one
- that was loaded after a call to START_SWAPPING() )
- cannot spawn new tasks.
-
-
-
- LOADTASK(cmd_string,pri,expmemflag)
- char *cmd_string;
- int pri;
- int expmemflag;
-
- Parameters :
- cmd_string is a character pointer to a command string
- to load the program, including command line parameters
- just as you would type in to load the program under
- DOS.
-
- pri is the base priority of the new task
-
- if expmemflag is non-zero, the task may be loaded into
- expanded memory, if it is enabled. If exmemflag is
- 0, the task will not be loaded into expanded memory.
-
- Description :
- Loads and executes an .EXE or .COM file from disk.
- The full path to the program file must be specified,
- and command line parameters may be used.
-
- STDIN, STDOUT, and STDERR are inherited from the caller.
-
- Return Value :
- 0 = task loader queue is full
- 1 = no error
-
- Notes/Comments :
- This call actually places a load request onto a queue
- to be executed by the 'idle' task. The status of the
- load may be checked with the TEST_LOAD() call.
-
- .COM files are given exactly 64K memory. .EXE files
- are sized according to the information in the file
- header. The MINALLOC parameter is used to determine
- how much memory, in addition to the task size and
- data space, is needed for the program.
-
-
-
- SLEEP(seconds)
- int sleep;
-
- Parameters :
- seconds is the number of seconds the task is to remain
- alseep.
-
- Description :
- puts the calling task into a sleeping state, where it
- will not execute at all, for a specified number of
- seconds.
-
- Return Value :
- none
-
- Notes/Comments :
-
-
-
-
- SEND_MD_MSG(queue,message_addr,count)
- int queue;
- char *message_addr;
- int count;
-
- Parameters :
- queue is the message queue to place a message on
- message_addr is a pointer to the data to be placed on queue
- count is the number of bytes to place on the queue
-
- Description :
- places the specified number of bytes onto a message
- queue. queues are numbered 0-63.
-
- Return Value :
- -1 = bad queue number
- other wise, returns number of bytes transferred
-
- Notes/Comments :
-
-
-
-
- TESTMSG(queue)
- int queue;
-
- Parameters :
- queue is the queue number to test
-
- Description :
- tests whether there are any messages waiting on the
- specified queue.
-
- Return Value :
- -1 = bad queue number
- 0 = nothing on queue
- else, returns the number of bytes contained in the
- first message on the queue
-
- Notes/Comments :
-
-
-
-
- RECVMSG(queue,message_addr,count)
- int queue;
- char *message_addr;
- int count;
-
- Parameters :
- queue is the message queue to place a message on
- message_addr is a pointer a data area to receive the data
- count is the maximum number of bytes to transfer
-
- Description :
- reads the first message from the specified queue
- into the data area pointed to by message_addr. only
- the first 'count' bytes of the message are transferred.
- if more than 'count' bytes are in the message, the
- extra is lost.
-
- If there are no messages on the specified queue, the
- task is placed into a dormant state until a message is
- put on the queue. If you do not want your task to remain
- dormant if the queue is empty, you should call TESTMSG()
- to make sure something is available before calling this
- function.
-
- Return Value :
- -1 = bad queue number
- 0 = no message was on queue
- else, returns the number of bytes transferred
-
- Notes/Comments :
-
-
-
-
- SEM_ATTACH(semaphore_number)
- int semaphore_number;
-
- Parameters :
- semaphore number is the number of the semaphore to
- attach (0-63)
-
- Description :
- attaches to the semaphore. see semaphore description
- elsewhere in documentation
-
- Return Value :
- -1 = invalid semaphore number
- all other values = success
-
- Notes/Comments :
-
-
-
-
- SEM_RELEASE(semaphore_number)
- int semaphore_number;
-
- Parameters :
- semaphore number is the number of the semaphore to
- be released (0-63)
-
- Description :
- releases the semaphore. see semaphore description
- elsewhere in documentation
-
- Return Value :
- -1 = invalid semaphore number
- all other values = success
-
-
-
-
-
- SEM_TEST(semaphore_number)
- int semaphore_number;
-
- Parameters :
- semaphore number is the number of the semaphore to
- test (0-63)
-
- Description :
- tests to see if the semaphore is already owned by
- another task. see semaphore description
- elsewhere in documentation
-
- Return Value :
- -1 = semaphore is unowned
- all other values = semaphore is owned
-
-
-
-
-
- SETPRI(new_priority)
- int new_priority;
-
- Parameters :
- new_priority is the new base priority of the calling
- task.
-
- Description :
- allows a task to change its priority, affecting how
- often the task gets to execute.
-
- Return Value :
- none
-
- Notes/Comments :
- only values 1-10 are legal. the lower the number, the
- more often a task will run. the main program is assigned
- a prioroty of 1, and usually should be the only task with
- such a low priority.
-
-
-
-
- SUSPEND()
-
- Parameters :
- none
-
- Description :
- suspends the task until it is awakened by a WAKEUP()
- call.
-
- Return Value :
- none
-
- Notes/Comments :
-
-
-
-
- WAKEUP(tcb_number)
- int tcb_number;
-
- Parameters :
- tcb_number is the tcb identifier for the task that is
- to be awakened.
-
- Description :
- allows a task that was suspended with a SUSPEND() call
- to continue processing.
-
- Return Value :
- none
-
- Notes/Comments :
- This is the ONLY way to wake up a SUSPENDed task.
- This call will also wake up a task that is in a
- SLEEP state (see SLEEP() above). In this way, a task
- may go into a sleep state, and another task can cause
- it to start executing again before the sleep delay is
- over.
-
-
-
-
- HOG()
-
- Parameters :
- none
-
- Description :
- prevents this task from being swapped out until a
- corresponding NOHOG() is issued. In effect, this
- halts multitasking, allowing the caller to run
- forever, if desired.
-
- Return Value :
- none
-
- Notes/Comments :
- Use this function when your task must not be interrupted.
- DOS functions like I/O and other critical functions are
- already protected, so this function should not be used
- too often.
-
-
-
-
- NOHOG()
-
- Parameters :
- none
-
- Description :
- allows multitasking to continue after being halted by
- a HOG() call.
-
- Return Value :
- none
-
- Notes/Comments :
-
-
-
-
- SPAWN_EXIT()
-
- Parameters :
- none
-
- Description :
- halts execution of a SPAWNed task.
-
- Return Value :
- none
-
- Notes/Comments :
- this is the preferred method of halting execution of a
- spawned task. When the spawned task is finished, it
- should call this function to terminate.
-
-
-
-
-
- GET_TCB_INFO(pointer_address)
- struct tcb_rec far **pointer_address;
-
- Parameters :
- pointer_address is the address of a pointer into
- which the address of the calling tasks TCB will be placed.
-
- Description :
- this function is used to access your Task Control Block
- you pass in the address of a pointer, and the address
- of your TCB is placed into the pointer. The pointer
- must be a LONG pointer, as supported in the LARGE
- memory model.
-
- Return Value :
- the TCB identifier (an index into the TCB array) is
- returned.
-
-
- Notes/Comments :
- Normally, tasks do not need access to their TCB. Since
- TCBs contain critical task control information, great
- care must be taken when accessing the TCB.
-
-
- GET_TCB_ADDRESS(pointer_address)
- struct tcb_rec far **pointer_address;
-
- Parameters :
- pointer_address is the address of a pointer into
- which the address of the TCB array will be placed.
-
- Description :
- similar to 'GET_TCB_INFO()' above, but this call
- returns the address of the TCB array in memory, to
- allow your task to access any given TCB, based on
- the task number.
-
- Return Value :
- the TCB identifier (an index into the TCB array) of
- the calling task returned.
-
-
- Notes/Comments :
- Normally, tasks do not need access to their TCB. Since
- TCBs contain critical task control information, great
- care must be taken when accessing the TCB.
-
-
-
-
- GET_LOAD_STATUS()
-
- Parameters :
- none
-
- Description :
- returns the status of the last 'LOAD_TASK()' call
- made by your program.
-
- Return Value :
- 0 = load in progress (not done yet)
- -1 = cannot open file
- -2 = insufficient memory
- -3 = no TCBs available
- -4 = no Memory Control Blocks available
-
- otherwise, the TCB number (index into the TCB array)
- of the new task is returned.
-
- Notes/Comments :
-
-
-
-
- Sample Programs
- ---------------
-
- 2 sample program are included, with full source code.
- MTTEST.C will load and execute the programs TEST1.EXE, TEST2.EXE,
- TEST3.EXE, TEST4.EXE and TEST5.EXE. These 5 programs read
- and write a disk file. Each time they finish reading and writing
- the file, they send a message to MTTEST. MTTEST receives and
- displays the messages. It's not particularly impressive to
- watch, but it does illustrate that several programs can perform
- concurrent I/O, and that programs can easily be loaded and executed
- from disk.
-
- MT.C is another sample program. It demonstrates one use of the
- semaphores, and the sleep() function.
-
- The source files for these programs, and a make file for Microsoft
- C is included.
-
-
- Writing Programs With CSWITCH
- -----------------------------
-
- When you write your multitasking program, there are several things
- to remember :
-
- 1. You must use the LARGE memory model. Programs that are linked with
- SMTC, or that are simply loaded and run, may be small model. But
- your main program must be LARGE model.
-
- 2. You must compile your main program, and any program that will SPAWN
- tasks, with the /Gs option to turn off stack checking. This is
- imperative, and without it, your program will not run.
-
- 3. C library routines are not re-entrant. Therefore, you cannot
- do a PRINTF() from your main program, and one from a SPAWNED task
- at the same time. In general, if a spawned task needs to do I/O,
- do it with DOS interrupts rather than with the library calls. If
- this is impractical or impossible, then make the spawned function
- a separate program and execute it with LOADTASK().
-
- If several different programs perform simultaneous I/O there is no
- problem. It is only when the same PRINTF or FOPEN routines are
- called from 2 different places in the same program at the same time
- that there is a problem.
-
- This probably applies to other languages as well.
-
- Also, most library routines perform stack checking upon entry. Since
- a SPAWNED task is assigned a stack from free memory, the stack check
- will often fail, causing SPAWNED tasks to abort with a false stack
- overflow error. If SPAWNed tasks are going to be performing complex
- functions and making a lot of library calls, they probably should
- be made into separate programs and executed with LOADTASK().
-
-
- Language Support
- ----------------
-
- Currently, the only language directly supported is C. Most languages
- can be made to mimic C's function calls, so there should not be a
- problem with linking these routines to other languages.
-
- Soon, I will be adding interface modules for Turbo Pascal and QuickBasic.
-
- Identifiers are prefixed with an underscore ( _ ) by the C compiler, so
- if your compiler does not automatically add the underscore, you will have
- to use it explicitly in the module names, and in the global data names.
-
-
- Cswitch Limitations
- -------------------
-
- Cswitch routines will not be appropriate in every situation requiring
- multitasking. In some cases, products like Desqview, Omniview, Windows,
- OS/2, and Unix are more appropriate. Cswitch does give a programmer
- an option, however. Writing programs that multitask in the DOS
- environment is a clean solution to many problems. In general, if your
- application must somehow do several things all at once, then writing
- your application as a set of cooperating tasks is a lot easier than
- trying to build every function into a single task. Let your
- imagination take it from there.
-
- As stated previously, Cswitch does not attempt to provide a multi-
- tasking user interface. You must prevent tasks from writing to the
- monitor or reading the keyboard simultaneously. This can easily be
- done with semaphores or I/O redirection.
-
- Tasks that are created using the SPAWN call inherit their owners STDIN,
- STDOUT and STDERR, as do tasks loaded from disk. Normally these handles
- refer to the CON device - the keyboard and monitor. No other file
- handles are inherited.
-
-