Multitasking

Reference Section

_exit_overflow
_get_numtasks
_get_tpriority
_get_tspec
_get_tstatus
overflow_addr
_set_tpriority
_task_add
_tasking_init
_task_remove
_task_resume
_task_sleep
_task_sleeptime
_task_suspend
_task_yield
_task_yieldto
_tstack_avail
_tstack_free
_tstack_initc
_tstack_malloc
_tstack_max
_yield_resume
_yield_suspend

_exit_overflow


Descrip
Displays a stack overflow message and exits to DOS with an ERRORLEVEL of 1.

Syntax
#include <mtask.h>
void _exit_overflow(void);
Returns
DOES NOT RETURN (exits to DOS with an ERRORLEVEL of 1).

Notes
This function displays a DOS-like error message ("Stack overflow"), sets the ERRORLEVEL to 1, and terminates the program. This function is the default stack overflow handler. The overflow_addr variable is initialized with the address of this function.

If stack overflow is detected in the multitasking system, the stack overflow handler defined in the overflow_addr variable is called. To specify an alternate stack overflow handler, load the address of the new handler into the overflow_addr function pointer.

Source file TKEXOVFL.ASM ASM equiv EXIT_OVERFLOW
See also
overflow_addr

_get_numtasks


Descrip
Returns the number of tasks currently in the task scheduler list.

Syntax
#include <mtask.h>
int _get_numtasks(void);

Returns
The number of tasks in the multitasking system.

Notes
This function returns the number of tasks in the task scheduler for the multitasking system. The return value includes all tasks, even if they are inactive.

_tasking_init must be called before this function.

C/C++ Example
	{
	   char buffer[20];
	   ...
	   _put_str(_i_to_dec(_get_numtasks(), buffer));
	   	  	 	/* display number of tasks */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   char buffer[20];
	   ...
	   get_numtasks();/* get number of tasks being scheduled */
	   lea   si,buffer    /* SI -> buffer */
	   i_to_dec();	/* int -> "string" */
	   put_str();	/* display number of tasks */
	   ...
	}

Source file _TKGNUMT.ASM ASM equiv.GET_NUMTASKS
See also
_task_add, _task_remove

_get_tpriority


Descrip
Returns the priority and current skip count of a task.

Syntax
#include <mtask.h>
int _get_tpriority(int handle, unsigned char *priority, unsigned char *skips);

Returns
0 if the function was successful.
priority priority of task
skips current skip count

-1 if handle is invalid.

Notes
This function returns the priority and remaining skip count for the task associated with handle. If handle is -1, then the priority and skip count for the active task are returned. If the return value is 0, priority contains the task's priority and skips contains the task's current skip count. -1 is returned if handle is not a valid task handle.

C/C++ Example
	{
	   unsigned char priority, skip;
	   ...
	   if(_get_tpriority(-1, &priority, &skip) != 0)
	      _put_str("Error getting priority/skip of task 1");
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   unsigned char priority, skip;
	...
	mov bx,-1	 /* BX = handle of active task */
	get_tpriority();/* successful? */
	 jc label_010/*   n: invalid handle */
	mov priority,al/* set priority variable */
	mov skip,ah	/* set skip variable */
	... 
	label_010:
	...
	}

Source file _TKGPRTY.ASM ASM equiv GET_TPRIORITY
See also
_get_tspec, _set_tpriority

_get_tspec


Descrip
Returns a copy of a specified task descriptor.

Syntax
#include <mtask.h>
int _get_tspec(int handle, void far * buffer);

Returns
0 if the function was successful.
buffer task descriptor for the task associated with handle

-1 if handle is invalid.

Notes
This function makes a copy of the current task descriptor structure for the task associated with handle. If handle is -1, then the active task descriptor is copied. If the function was successful, the copy is placed in buffer in the form of a satask definition structure and 0 is returned. -1 is returned if handle is invalid.

The satask task descriptor structure is defined in MTASK.H as follows:

typedef struct {
unsigned int t_handle;/* task handle (-1 to return next avail handle) */
void(*t_addr)(void); /* task address */
unsigned int t_stksize;/* size task's stack (default 256 bytes) */
void *t_stkaddr; /* stack address */
unsigned char t_priority;/* priority of task (0-255) */
unsigned char t_numskips;/* skip count (initial priority) (0-255) */
unsigned long t_waketime;/* time to wake up task */
void *t_nextlink; /* address of next task descriptor in task list */
void *t_stksave; /* preserve stack address when task yields */
void near *t_dstack; /* address of task stack relative to heap segment
(small data models only) */
unsigned char t_statbyte;/* status of task */
char reserved; /* (RESERVED) */
} satask;

See the Multitasking technical notes for a detailed explanation of task descriptors.

C/C++ Example
	{
	   char buffer[sizeof(satask)];
	   ...
	   if(_get_tspec(-1, (char *)buffer) != 0)
	      _put_str("Invalid handle.\n\r");
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   char buffer [sizeof(satask)];
	   char *str;
	   ...
	   lea si,buffer/* SI -> buffer */
	   	  
	   mov bx,-1	/* BX = handle of active task */
	   get_tspec()	/* copy current task's specs */
	    jnclabel_010
	   str = "Invalid handle.\n\r";
	   mov si,str	/* SI -> string */
	   put_str();	/* display error message */
	label_010:
	   ...
	}

Source file _TKGSPEC.ASM ASM equiv GET_TSPEC
See also
_task_add

_get_tstatus


Descrip
Determines if any of the specified task status flags are set.

Syntax
#include <mtask.h>
int _get_tstatus(int handle, unsigned char tstat);

Returns
1 if any condition specified in tstat is true.

0 if all conditions specified in tstat are false.

-1 if handle is invalid or the task has been removed.

Notes
This function tests the status of the task associated with handle. If handle is -1, the status of the active task is tested. 1 is returned if any of the conditions specified in tstat are true (i.e., if any of the specified flags are set). 0 is returned if all specified conditions are false. -1 is returned if the specified handle is invalid or the task has been removed. This function is especially useful just prior to calling _task_yieldto, since yielding to a specified task bypasses all conditions (e.g., suspended, sleeping, and number-of-skips).

The following symbolic constants (defined in MTASK.H) identify the task status flags which may be specified in tstat:

T_AUTOREMOVE(0x01) Automatically remove task on return
T_SUSPEND (0x02) Task is suspended
T_SLEEP (0x04) Task is sleeping
T_STACKHEAP(0x10) Task stack is allocated on a stack heap

C/C++ Example
	#include<mtask.h>
	{
	   ...
	   if(_get_tstatus(0, T_SUSPEND+T_SLEEP))
	      _put_str("Unable to yield default task.\n\r");
	   else
	      _task_yieldto(0);
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	...
	mov bx,-1	 /* BX = handle of task to check 
		   	    (default task) */
	mov al,T_SUSPEND+T_SLEEP /* AL = status to check */
	task_tstatus();	/* get status of default task */
	 je label_010/*   y: don't yield to it */
	task_yieldto();	/*   n: yield to it */
	label_010:
	...
	}

Source file _TKGSTAT.ASM ASM equiv GET_TSTATUS
See also
_get_tspec

overflow_addr


Descrip
(Variable) Contains the address of the current stack overflow handler.

Syntax
#include <mtask.h>
extern void *overflow_addr;

Notes
This near/far pointer variable contains the address of the current stack overflow handler. In small code models this variable is near pointer; in large code models, this variable is a far pointer.

This variable is initialized with the address of _exit_overflow, the default stack overflow handler. If stack overflow is detected in the multitasking system, control is passed to the stack overflow handler pointed to by this variable. To specify an alternate stack overflow handler, load the address of the new handler into this variable.

Source file TKOFLOW.ASM ASM equivâ
See also
_exit

_set_tpriority


Descrip
Sets the priority and skip count of a task.

Syntax
#include <mtask.h>
int _set_tpriority(int handle, unsigned char priority, unsigned char skipcount);

Returns
0 if function was successful.

-1 if handle is invalid.

Notes
This function sets the priority and/or the skip count for the task associated with handle. If -1 is specified for handle, the changes are made to the active task. Otherwise, the changes are made to the task associated with handle. Valid values for priority and skipcount are in the range 0 to 254; if -1 is specified, the current value is used. 0 is returned if the function was successful. -1 is returned if handle is invalid.

Each task has a priority and skip count associated with it. The task scheduler uses these two values to determine how often each task will gain control ofthe CPU. The skip count is a "count down to zero" variable, and the priority is a reload value for the skip count. A non-suspended task's skip count is decremented each cycle through the task scheduler. The scheduler only passes control to a task if its skip count is zero when it is polled and if it is not suspended or sleeping. Each time a task is given control, its skip count is reloaded with its priority.

A task's priority and skip count do not need to be identical and may be modified dynamically by any task at any time.

C/C++ Example
	   ...
	   if (_set_tpriority(-1, 10, 0) == -1) /* set priority = 10, */
	   	  	     /* skip count = 0 for active task */
	      _put_str("Invalid handle on set priority\n\r.");
	   ...

Inline Assembly Example
	#include <inline.h>
	{
	   char *str;
	   ...
	   mov bx,-1	/* BX = active task handle */
	   mov al,10	/* AL = priority of 10 */
	   xor ah,ah	/* AH = skip count of zero */
	   set_tpriority();/* set task priority */
	    jnclabel_010
	   str = "Invalid handle on set priority.\n\r";
	   mov si,str	/* SI-> string */
	   put_str();	/* display error message */
	label_010:
	   ...
	}

Source file _TKSPRTY.ASM ASM equiv SET_TPRIORITY
See also
_get_tpriority, _get_tstatus

_task_add


Descrip
Adds a task to the scheduler task list.

Syntax
#include <mtask.h>
int _task_add(satask *tspec);

Returns
The task handle if the task was successfully added.

-1 if the task handle specified in tspec was not available.

Notes
This function adds a task to the multitasking scheduler list. tspec defines the task to be added, the task handle to use, and the initial task settings. If the handle specified in tspec is available, the task is added to the list and the task handle is returned. If the handle is not available, -1 is returned and the task is not added.

tspec must be a task descriptor structure of type satask, which is defined in MTASK.H as follows:

typedef struct {
int t_handle; /* task handle (-1 to use next avail handle) */
void(*t_addr)(void); /* task starting address */
unsigned int t_stksize; /* task stack size (default=256 bytes) */
void *t_stkaddr; /* task stack address (default=inherit) */
unsigned char t_priority; /* priority of task (0-255, default=0) */
unsigned char t_numskips; /* skip count (initial priority) (0-255, def=0) */
unsigned long t_waketime; /* time of day to wake up task */
void *t_nextlink; /* address of next descriptor in task list */
void *t_stksave; /* task stack address when task yields */
void near *t_dstack; /* offset of task stack relative to heap segment
(small data models only) */
unsigned char t_statbyte; /* current status of task */
char reserved; /* (RESERVED) */
} satask;

The t_handle field may be assigned a specific handle number or it may be set to -1 to allow it to default to the next available task handle. Handle values determine the order in which tasks are polled by the multitasking system (tasks are polled in increasing order of their handle values).

The t_addr field must indicate the starting address of the task. This address is also used whenever the multitasking system automatically restarts a task.

The task stack must be allocated and the t_stkaddr and t_stksize fields must indicate the address and size of the stack prior to calling this function. The task stack may be allocated manually (e.g., defined statically or on a heap) or it may be allocated on the stack heap by calling _tstack_malloc. The t_stkaddr and t_stksize fields are automatically initialized by _tstack_malloc if it is used to allocate the task stack.

t_priority and t_numskips specify the priority and initial skip count for the task. See _set_tpriority for an explanation of these fields.

A task has the option of returning when it is finished. The t_statbyte field indicates whether or not the task is automatically removed when this occurs. By default, the task remains in the task list and is automatically restarted at its starting address the next time the task is given control. However, the following symbolic constant (defined in MTASK.H) may be specified in the t_statbyte field to indicate that the task should automatically be removed from the task list when it returns:
T_AUTOREMOV
E (0x01) Automatically remove task on return

See the Multitasking technical notes for further information regarding task descriptors.

_tasking_init must be called before this function may be used.

C/C++ Example
	{
	   static char stack1[250];
	   static satask task0 = TASK_DEFAULT;
	   static satask task1 = TASK_DEFAULT;
	   int handle;
	   ...

	   task0.t_addr = task_0;
	   task1.t_statbyte = T_AUTO_REMOVE;
	   task1.t_stkaddr = stack1;
	   task1.t_addr = task_1;

	   _tasking_init(&task0); /* initialize multitasking */
	   if ((handle = _task_add(&task1)) == -1)
	      _put_str("Error adding task 1.\n\r");
	   else
	      task_0();
	   ...
	}
	void task_0(void)
	{
	   ...
	   _task_yield();/* start multitasking */
	   ...
	}
	void task_1(void)
	{
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   static char stack1[250];
	   static satask task0 = TASK_DEFAULT;
	   static satask task1 = TASK_DEFAULT;
	   task0.t_addr = task_0;
	   task1.t_statbyte = T_AUTO_REMOVE;
	   task1.t_stkaddr = stack1;
	   task1.t_addr = task_1;
	   ...
	   mov si,offset task0
	   	  /* SI = offset of default task descriptor */
	   tasking_init();    /* initialize multitasking */
	   mov si,offset task1/* SI = offset of task 1 desc */
	   task_add();	/* add task 1 to tasking list */
	    jc label_010/* if error, return */
	   task_0();
	label_010:
	    ...
	}
	void task_0(void)
	{
	   ...
	   _task_yield();/* start multitasking */
	   ...
	}
	void task_1(void)
	{
	   ...
	}

Source file _TKADD.ASM ASM equiv TASK_ADD
See also
_tasking_init, _task_remove, _tstack_remove

_tasking_init


Descrip
Initializes the multitasking system.

Syntax
#include <mtask.h>
void _tasking_init(satask *tspec);

Returns
None

Notes
This function initializes the multitasking system. This activates the multitasking system and initializes the task list to contain the default task. The provided task descriptor (tspec) must specify the starting address and characteristics of the default task. Multitasking begins with the first call to _task_yield within the default task. If the multitasking system is already active, this call has no effect.

tspec must be a task descriptor structure of type satask, which is defined in MTASK.H as follows:

typedef struct {
int t_handle;/* task handle (default task handle is always 0) */
void(*t_addr)(void); /* task starting address (-1=next instruction) */
unsigned int t_stksize; /* task stack size (default=256 bytes) */
void *t_stkaddr; /* task stack address (default=inherit) */
unsigned char t_priority; /* priority of task (0-255, default=0) */
unsigned char t_numskips; /* skip count (initial priority) (0-255, def=0) */
unsigned long t_waketime; /* time of day to wake up task */
void *t_nextlink; /* address of next descriptor in task list */
void *t_stksave; /* task stack address when task yields */
void near *t_dstack; /* offset of task stack relative to heap segment
(small data models only) */
unsigned char t_statbyte; /* current status of task */
char reserved; /* (RESERVED) */
} satask;

The TASK_DEFAULT define (declared in MTASK.H) may be used to initialize a task descriptor with the default settings indicated in the comments above.

Because the default task handle is always 0, the initial value of the t_handle field is ignored by this function.

The t_addr field must indicate the starting address of the default task. If t_addr is set to -1, _tasking_init simply returns after initializing the multitasking system (i.e., the code immediately following the call the _tasking_init is the default task). If an explicit starting address is specified in t_addr, control is passed to the default task by calling it at the specified address.
The current stack is allocated to the default task, so the initial value of t_stkaddr is ignored by this function. t_stksize must indicate the amount of additional stack space to leave for the default task (beyond the current stack pointer).

t_priority and t_numskips specify the priority and initial skip count for the default task. See _set_tpriority for an explanation of these fields.

The default task has the option of returning when it is finished. When this happens, control is passed to the instruction immediately following the original call to _tasking_init if an explicit starting address was specified for the default task. Otherwise, the return is treated as a normal return from the procedure which contains the default task. Because the default task cannot be removed, the initial value of the t_statbyte field is ignored by this function.

See the Multitasking technical notes for further information regarding task descriptors and the default task.

The following examples demonstrate how the multitasking system is initialized to use the instruction following _tasking_init as the start of the default task.

C/C++ Example
	{
	static satask task0 = TASK_DEFAULT;
	   ...
	   _tasking_init(&task0); /* turn on multitasking */
	task_0:        /* since no task address has been
	   	  	    specified for the default task,
	   	  	    this label is the beginning address 
	   	  	    of the default task */
	   ...
	   _task_yield()/* multitasking begins */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	static satask task0 = TASK_DEFAULT;
	   ...
	   mov si,offset task0
	   	  /* SI = offset of default task descriptor */
	   tasking_init();/* initialize multitasking */
	task_0:       /* since no task address has been
	   	  	    specified for the default task,
	   	  	    this label is the beginning address 
	   	  	    of the default task */
	   ...
	   task_yield();/* multitasking begins */
	   ...
	}

Source file _TKINIT.ASM ASM equiv TASKING_INIT
See also
_task_add

_task_remove


Descrip
Removes a task from the scheduler task list.

Syntax
#include <mtask.h>
void far *_task_remove(int handle);
Returns
A far pointer to the stack buffer of the removed task.

NULL if handle is invalid.

Notes
This function removes the task associated with handle from the task list. The active task is removed if handle is -1. If the function is successful, a far pointer to the stack buffer of the removed task is returned. NULL is returned if handle is invalid.

It is the responsibility of the programmer to properly dispose of the stack buffer. Typically, the buffer is freed immediately after this function is called. If the stack was allocated with _tstack_malloc, the buffer may be freed by calling _tstack_free.

C/C++ Example
	{
	   char far *stkaddr;
	   ...
	   if ((stkaddr = (char far *)_task_remove(-1)) == NULL)
	      _put_str("Error removing current task.\n\r"); 
	   if (_tstack_free((char far *)stkaddr) != 0)
	      _put_str("Error freeing task's stack space.");
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   char *str;
	   ...
	   mov bx,-1/* BX = handle of current task */
	   task_remove();/* remove task, ES:DI -> stack blk */
	    jc label_020 /*   if error, go give error message */
	   tstack_free();/* free task's stack mem */
	    jnclabel_020 /*   if error, give error message */
	   str = "Error removing current task.\n\r";
	   mov si,str
	   put_str();/* display error message */
	label_020:
	   ...
	}

Source file _TKRMOVE.ASM ASM equiv TASK_REMOVE
See also
_task_add

_task_resume


Descrip
Resumes a suspended task.

Syntax
#include <mtask.h>
int _task_resume(int handle);

Returns
0 if the task was successfully resumed.

-1 if handle was invalid.

Notes
This function resumes the task associated with handle. This reactivates the task, allowing it to receive control from the task scheduler. If handle is -1, the active task is resumed. 0 is returned if the specified task was successfully resumed. -1 is returned if handle is invalid.

The resumed task does not receive control until the task scheduler passes control to it or until it is yielded to directly. If the task was not previously suspended, 0 is returned and this function has no effect.

A suspended task can only resume itself after it receives control from another task (via _task_yieldto).

C/C++ Example
	   ...
	   if (_task_resume(handle) != 0) /* resume task */
	      _put_str("Invalid handle");
	   ...

Inline Assembly Example
	#include <inline.h>
	{
	   char str[] = "Invalid handle";
	   ...
	   mov bx,-1/* BX = handle of active task */
	   task_resume();/* resume task 1 */
	    jnelabel_010
	   lea str
	   put_str();/* display error message */
	label_010:
	   ...

Source file _TKRSUME.ASM ASM equiv TASK_RESUME
See also
_task_sleep, _task_sleep, _task_suspend

_task_sleep


Descrip
Suspends a task for a specified period of time.

Syntax
#include <mtask.h>
int _task_sleep(int handle, const std_time *duration);

Returns
0 if function was successful.

-1 if handle is invalid.

Notes
This function suspends the task associated with handle for a specified period of time. duration specifies the amount of time which must pass before the task is again selected for control by the task scheduler. If handle is -1, the active task is suspended. 0 is returned if the function was successful. -1 is returned if handle is invalid.

duration must be a structure of type std_time (defined in DATETIME.H) as follows:

typedef struct {
unsigned char hseconds;/* 0-99 */
unsigned char seconds;/* 0-59 */
unsigned char minutes;/* 0-59 */
unsigned char hours; /* 0-231 */
} std_time;

The actual precision of duration is limited by the system timer (about 18.2 ticks/second) as well as the interval between the wake-up time and the actual time the task scheduler passes control to the task.

If the task is already sleeping when this function is called, _task_sleep overwrites any previous settings established by _task_sleep or _task_sleeptime.

C/C++ Example
	{
	   std_time tskslp;
	   ...
	   tskslp.hours = 0;
	   tskslp.minutes = 0;
	   tskslp.seconds = 5;
	   tskslp.hseconds = 0;
	   _task_sleep(-1,&tskslp);
		   /* current task sleeping for 5 seconds */
	   _task_yield();/* sleep assignment takes affect now */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   ...
	   xor dx,dx
	   mov al,dl
	   mov ah,5	/* DX;AX = time (5 seconds) */
	   mov bx,-1	/* BX = handle of current task */
	   task_sleep();	/* sleep this task */
	   task_yield();	/* yield, sleep takes effect */
	   ...
	}

Source file _TKSLP.ASM ASM equiv TASK_SLEEP
See also
_get_tstatus, _task_sleep, _task_yield

_task_sleeptime


Descrip
Suspends a task until a specified time of day.

Syntax
#include <mtask.h>
int _task_sleeptime(int handle, const std_time *waketime);

Returns
0 if the function was successful.

-1 if handle is invalid.

Notes
This function suspends the task associated with handle until the time of day specified in waketime. The wake-up time is assumed to refer to the next day if it is less than the current time of day. If handle is -1, the active task is suspended. 0 is returned if the function was successful. -1 is returned if handle is invalid.

waketime must be a structure of type std_time (defined in DATETIME.H) as follows:

typedef struct {
unsigned char hseconds;/* not used by this function */
unsigned char seconds;/* not used by this function */
unsigned char minutes;/* 0-59 */
unsigned char hours; /* 0-23 */
} std_time;

The accuracy of waketime is limited by the system timer (about 18.2 ticks/second) as well as the interval between the wake-up time and the actual time the task scheduler passes control to the task.

If the task is already sleeping when this function is called, _task_sleeptime overwrites any previous settings established by _task_sleep or _task_sleeptime.

C/C++ Example
	{
	   std_time tskslp;
	   ...
	   tskslp.hours = 5;
	   tskslp.minutes = 30;
	   _task_sleeptime(-1,&tskslp);
		   /* current task wake up a 5:30 am */
	   _task_yield();/* sleep assignment takes effect */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   ...
	   mov bx,-1/* BX = handle of current task */
	   mov dh,5
	   mov dl,30/* DX = hour:minute to wake up */
	   task_sleeptime(); /* current task wake up at 5:30 am */
	   task_yield();/* default task begins sleeping */
	   ...
	}

Source file _TKSLPTM.ASM ASM equiv TASK_SLEEPTIME
See also
_get_tstatus, _task_sleep, _task_yield

_task_suspend


Descrip
Suspends a task.

Syntax
#include <mtask.h>
int _task_suspend(int handle);

Returns
0 if the task was suspended.

-1 if handle was invalid.

Notes
This function suspends the task associated with handle. The suspended task does not receive control from the task scheduler until it is resumed by _task_resume. 0 is returned if the function was successful. -1 is returned if handle is invalid.

If the task was previously suspended, 0 is returned and this function has no effect.

C/C++ Example
	   ...
	   if (_task_suspend(-1) != 0)/* suspend active task */
	   _put_str("Invalid handle.\n\r");
	   _task_yield();	/* task becomes suspended now */
	   ...

Inline Assembly Example
	#include <inline.h>
	{
	   ...
	   mov bx,-1	/* BX = handle of current task */
	   task_suspend();    /* suspend active task */
	   task_yield();	/* task becomes suspended now */
	   ...
	}

Source file _TKSPND.ASM ASM equiv TASK_SUSPEND
See also
_task_resume, _task_sleep, _task_sleep

_task_yield


Descrip
Saves the state of the active task and yields to the task scheduler.

Syntax
#include <mtask.h>
void _task_yield(void);

Returns
None

Notes
This function saves the state of the current task and passes control to the task scheduler. The scheduler checks the current task for stack overflow and then determines the next available task based on the handle number, priority, and status of each task in the system. The selected task is then given control. If stack overflow is detected, control is passed to the stack overflow handler specified in overflow_addr. The default stack overflow handler is _exit_overflow.

This function must be called to allow other tasks to gain control of the CPU. The strategic placement of calls to _task_yield and _task_yieldto allows the programmer to control when a task is interrupted and how much processing time elapses before control is passed to the other tasks in the system.

This function may be suspended with _yield_suspend and resumed with _yield_resume. If multitasking has been suspended with _yield_suspend, this function immediately returns without checking for stack overflow or determining the next available task.

This function does NOT modify the state of the CPU flags.

C/C++ Example
	   
	{
	   static satask task0 = TASK_DEFAULT;
	   ...
	   task0.t_addr = task_0;
	   _tasking_init(&task0); /* turn on multitasking on */
	   ...	  /* add additional tasks */
	   task_0();/* call default task */
	   ...
	}
	void task_0(void)
	{
	   ...
	   _task_yield();/* tasking begins */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   static satask task0 = TASK_DEFAULT;
	   task0.t_addr = task_0;
	   ...
	   mov si,offset task0
	   	  /* SI = offset of default task descriptor */
	   tasking_init();/* initialize multitasking */
	   ... 	 /* add additional tasks */
	   task_0();/* call default task */
	   ...
	}
	void task_0(void)
	{
	   ...
	   _task_yield();/* tasking begins */
	   ...
	}

Source file TKYIELD.ASM ASM equiv TASK_YIELD
See also
overflow_addr, _task_add, _task_yield

_task_yieldto


Descrip
Saves the state of the active task and yields to a specific task.

Syntax
#include <mtask.h>
int _task_yieldto(int handle);

Returns
0 if the function was successful.

-1 if handle is invalid.

Notes
This function saves the state of the current task and passes control to the task associated with handle. The scheduler checks the current task for stack overflow and then passes control to the selected task (even if that task is suspended, sleeping, or its skip count is greater than zero). If stack overflow is detected, control is passed to the stack overflow handler specified in overflow_addr. The default stack overflow handler is _exit_overflow.

This function selectively allows other tasks to gain control of the CPU. The strategic placement of calls to _task_yield and _task_yieldto allows the programmer to control when a task is interrupted and how much processing time elapses before control is passed to the other tasks in the system.

This function may be suspended with _yield_suspend and resumed with _yield_resume. If multitasking has been suspended with _yield_suspend, this function immediately returns 0 without checking for stack overflow or determining the next available task.

If the task associated with handle calls _task_yield, the task scheduler determines the next available task as described for_task_yield. Return of control to the parent is not automatic.

C/C++ Example
	   ...
	   if (!_get_tstatus(0, T_SUSPEND+T_SLEEP))
	      _task_yieldto(0);
	   else
	      _put_str("Unable to yield default task.\n\r")

Inline Assembly Example
	#include <inline.h>
	   ...
	   xor bx,bx	/* BX = task to yield to */
	   mov al,T_SUSPEND+T_SLEEP
	   get_tstatus();	/* get status of default task */
	    je label_010/* if match, don't yield */
	   task_yieldto();    /* yield to default task */
	label_010:
	   ...

Source file _TKYLDTO.ASM ASM equiv TASK_YIELDTO
See also
overflow_addr, _task_add, _task_yield

_tstack_avail


Descrip
Returns the number of available bytes on the stack of the active task.

Syntax
#include <mtask.h>
int _tstack_avail(void);

Returns
The available stack space for the current task, in bytes.

-1 if the stack has already overflowed.

Notes
This function calculates the total remaining space on the stack of the current task. The amount of remaining stack space is returned. -1 is returned if the stack pointer is beyond the end of the stack. This function does NOT call the stack overflow handler when stack overflow is detected. This function works with dynamically or statically allocated stacks.

C/C++ Example
	#include <mtask.h>
	{
	   char buffer[40];
	   ...
	   _i_to_dec(_tstack_avail(), buffer);
	   _put_str(buffer); /* display remaining stack space */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{  
	   char buffer[40];
	   ...
	   lea si,buffer/* SI -> buffer */
	   tstack_avail();    /* AX = remaining stack space */
	   i_to_dec();	/* int -> "string" */
	   put_str();	/* display result */
	   ...
	}

Source file _TKSAVL.ASM ASM equiv TSTACK_AVAIL
See also
_tstack_init, _tstack_max

_tstack_free


Descrip
Frees a block on the stack heap.

Syntax
#include <memalloc.h>
int _tstack_free(void far *stkaddr);

Returns
0 if the block was successfully released.

-1 if the function was unsuccessful.

Notes
This function releases the stack block at stkaddr on the stack heap, making its memory available for future allocation. stkaddr must be a valid block address within the stack heap obtained by calling _tstack_malloc. stkaddr is returned by _task_remove to facilitate freeing of task stack blocks when a task is removed. -1 is returned if stkaddr is invalid.

WARNING! Only limited checking is performed to detect an invalid stkaddr. If an attempt is made to free a block using an invalid stkaddr and -1 is not returned, system memory and/or the stack heap may be corrupted.

C/C++ Example
	{
	   char far *stkaddr;
	   ...
	   if ((stkaddr = (char far *)_task_remove(-1)) == NULL)
	      _put_str("Error removing current task.\n\r"); 
	   if (_tstack_free((char far *)stkaddr) != 0)
	      _put_str("Error freeing task's stack space.");
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   char *str;
	   ...
	   mov bx,-1	/* BX = handle of current task */
	   task_remove();	/* remove task, ES:DI- stk blk */
	    jc label_020/*   if error, go give message */
	   tstack_free();	/* free task's stack mem */
	    jc label_020/*   if error, go give message */
	   ...
	label_020:
	   str = "Error removing current task.\n\r";
	   mov si,str
	   put_str();	/* display error message */
	   ...
	}

Source file _TKSFREE.ASM ASM equiv TSTACK_FREE
See also
_tstack_initc, _tstack_malloc

_tstack_initc


Descrip
Initializes the stack heap to a custom size and location.

Syntax
#include <mtask.h>
void _tstack_initc(unsigned int stksize, segaddr stkseg);

Returns
None

Notes
This function performs a custom stack heap initialization for the multitasking system. stkseg indicates the location of the stack heap, and stksize indicates the size of the heap (in bytes).

Memory for the task heap may be allocated statically or dynamically. The total memory requirements of the task heap (in bytes) may be calculated as follows:

Required stack heap size = (16 + 2*(number of tasks)) + (sum of task stack sizes)

The default task stack is independent and does not need to be considered in this calculation. (The default task uses the stack that is in use when _tasking_init is called.)

WARNING! In small data models, the stack heap must reside within the 64K region beginning at the start of DGROUP (global or static non-far data). This condition is satisfied if the stack heap is allocated on the near heap. In large data models the stack heap may reside anywhere in conventional memory.

Because of the difficulty of locating a default task stack starting address in a C environment and because of variations between compilers, a default _tstack_init function has not been provided.

C/C++ Example
	satask task0 = TASK_DEFAULT;
	satask task1 = TASK_DEFAULT;
	void main(void)
	{
	   segaddr tstkseg;
	   tstkseg = _ptr_to_seg(malloc(1600));
	   _tstack_initc(1600,tstkseg);
	   ...
	   task1.t_addr = task_1;
	   _tasking_init(&task0);/* initialize multitasking */
	   _tstack_malloc(&task1);/* alloc 256 byte stk for task 1*/
	   _task_add(&task1);/* add task 1 to tasking list */
	   _task_yield();
	   ...
	}
	void task_1(void)
	{
	   _put_str("Task 1.\n\r");
	   _task_yield();
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	satask task0 = TASK_DEFAULT;
	satask task1 = TASK_DEFAULT;
	void main ()
	{
	#if __SMALL_DATA__
	   segaddr tstkseg;
	   tstkseg = _ptr_to_seg(malloc(1600));
	   mov dx,tstkseg
	#else
	   mov ax,100
	   dos_malloc ();
	#endif
	   task1.t_addr = task_1;
	   ...
	   mov ax,1600	    /* AX = size of heap in bytes */
	   tstack_initc();    /* initialize stack heap */
	   mov si,offset task0
	   	  /* SI = offset of default task descriptor */
	   tasking_init();    /* initialize multitasking */
	   mov si,offset task1
	   	  /* SI = offset of task 1 descriptor */
	   tstack_malloc();/* alloc 256 byte stack, task 1 */
	   task_add();	/* add task 1 to tasking list */
	         ...
	}
	void task_1(void)
	{
	   _put_str("Task 1.\n\r");
	   _task_yield();
	   ...
	}

Source file _TKSINTC.ASM ASM equiv TSTACK_INITC
See also
_tstack_avail, _tstack_malloc

_tstack_malloc


Descrip
Allocates space for a task stack on the stack heap.

Syntax
#include <mtask.h>
int _tstack_malloc(const satask *tspec);

Returns
0 if the stack heap block specified in tspec was successfully allocated.

-1 if the function was unsuccessful.

Notes
This function allocates a block of memory on the stack heap for use as a task stack. The allocated task stack is assigned to the task associated with tspec. The size of the allocated block must be specified in tspec. -1 is returned if the task stack block could not be allocated or if the task descriptor belongs to the default task.

tspec must be a task descriptor structure of type satask, which is defined in MTASK.H as follows:

typedef struct {
int t_handle; /* task handle (-1 to use next avail handle) */
void(*t_addr)(void); /* task starting address */
unsigned int t_stksize; /* task stack size (default=256 bytes) */
void *t_stkaddr; /* task stack address (default=inherit) */
unsigned char t_priority; /* priority of task (0-255, default=0) */
unsigned char t_numskips; /* skip count (initial priority) (0-255, def=0) */
unsigned long t_waketime; /* time of day to wake up task */
void *t_nextlink; /* address of next descriptor in task list */
void *t_stksave; /* task stack address when task yields */
void near *t_dstack; /* offset of task stack relative to heap segment
(small data models only) */
unsigned char t_statbyte; /* current status of task */
char reserved; /* (RESERVED) */
} satask;

The t_stksize field must indicate the required task stack size. The stack address is placed in tspec.t_stkaddr if the stack was successfully allocated. This function also sets the T_STACKHEAP bit of the t_statbyte field.

_tstack_initc must be called to initialize the stack heap prior to using this function.

C/C++ Example
	satask task0 = TASK_DEFAULT;
	satask task1 = TASK_DEFAULT;
	void main(void)
	{
	   segaddr *tstkseg;
	   ...
	#if __SMALL_DATA__
	   tstkseg = _ptr_to_seg(malloc(1600));
	   _tstack_initc(1600,tstkseg);
	#else
	   tstkseg = _dos_malloc(100);
	   _tstack_initc(1600, tstkseg);
	#endif
	   ...
	   task1.t_addr = task_1;
	   _tasking_init(&task0); /* initialize multitasking */
	   
	   _tstack_malloc(&task1);/* alloc 256 byte stack for task 1 */
	   _task_add(&task1); /* add task 1 to task list */
	   _task_yield();
	   ...
	}
	void task_1(void)
	{
	   _put_str("Task 1.\n\r");
	   _task_yield();
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	satask task0 = TASK_DEFAULT;
	satask task1 = TASK_DEFAULT;
	void main()
	{
	#if __SMALL_DATA__
	   segaddr tstkseg;
	   tstkseg = _ptr_to_seg(malloc(1600));
	   mov dx,tstkseg
	#else
	   mov ax,100;
	   dos_malloc();
	#endif
	   mov ax,1600	    /* AX = size of heap in bytes */
	   tstack_initc();    /* initialize stack heap */
	   task1.t_addr = task_1;
	   mov si,offset task0
	   	  /* SI = offset of default task descriptor */
	   tasking_init();    /* initialize multitasking */
	   mov si,offset task1/* SI = offset of task 1 desc */
	   tstack_malloc();/* alloc 256 byte task 1 stack */
	   task_add();	/* add task 1 to tasking list */
	   ...
	}
	void task_1(void)
	{
	   _put_str("Task 1.\n\r");
	   _task_yield();
	   ...
	}

Source file _TKSMALC.ASM ASM equiv TSTACK_MALLOC
See also
_tstack_free, _tstack_initc, _tstack_max

_tstack_max


Descrip
Returns the size of the largest available block on the stack heap.

Syntax
#include <mtask.h>
int _tstack_max(void);

Returns
The size, in bytes, of the largest available block on the stack heap.

Notes
This function returns the number of bytes in the largest available block on the stack heap. 0 is returned if no space is available on the stack heap.

_tstack_initc must be called before this function may be used. The return value is undefined otherwise.

C/C++ Example
	   
	{
	   char buffer[40];
	   ...
	   _i_to_dec(_tstack_max(), buffer);
	   _put_str(buffer); /* display largest available block size */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{  
	   char buffer[40];
	   ...
	   lea si,buffer/* SI -> buffer */
	   tstack_max();/* AX = largest available block size */
	   i_to_dec();/* int -> "string" */
	   put_str();/* display largest available blk size */
	   ...
	}

Source file TKSMAX.ASM ASM equiv TSTACK_MAX
See also
_tstack_avail, _tstack_initc

_yield_resume


Descrip
Resumes multitasking.

Syntax
#include <mtask.h>
void _yield_resume(void);

Returns
None

Notes
This function resumes multitasking beginning with the next call to _task_yield or _task_yieldto. It only needs to be called after _yield_suspend has been called.

This function has no effect if multitasking is not initialized or if _yield_suspend has not been called.

C/C++ Example
	{
	   char rset0 = 0;
	   /* individual bits are set for resources in use */
	   ...
	   if (rset0 == 0)/* resources in set 0 available? */
	      _yield_suspend();/*  y:suspend multitasking */
	   ...
	   _yield_resume();/* resume multitasking */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   char rset0 = 0;
	   /* individual bits are set for resources in use */
	   ...
	   testrset0,0	    /* set 0 resources available? */
	    jnzlabel_010/*   n: keep multitasking on */
	   yield_suspend();/*   y: suspend multitasking */
	label_010:
	   ...
	   yield_resume();    /* resume multitasking */
	   ...
	}

Source file _TKYRSME.ASM ASM equiv.YIELD_RESUME
See also
_task_yield, _yield_suspend

_yield_suspend


Descrip
Temporarily suspends multitasking.

Syntax
#include <mtask.h>
void _yield_suspend(void);

Returns
None

Notes
This function suspends multitasking until the end of the active task is reached (i.e., the task returns) or until _yield_resume is called.

This function has no effect if multitasking is not initialized.

C/C++ Example
	{
	   char rset0 = 0;
	   /* individual bits are set for resources in use */
	   ...
	   if (rset0 == 0)/* if all resources in set 0 available */
	      _yield_suspend();/*   suspend multitasking */
	   ...
	   _yield_resume();/* resume multitasking */
	   ...
	}

Inline Assembly Example
	#include <inline.h>
	{
	   char rset0 = 0;
	   /* individual bits are set for resources in use */
	   ...
	   testrset0,0	    /* set 0 resources available? */
	    jnzlabel_010/*   n: keep multitasking on */
	   yield_suspend();/*   y: suspend multitasking */
	label_010:...
	   ...
	   yield_resume();    /* resume multitasking */
	   ...
	}

Source file _TKYSPND.ASM ASM equiv.YIELD_SUSPEND
See also
_task_yield, _yield_resume