MTHREAD.TXT for MicroThread V2.5

This file contains details of the various MicroThread functions and 
how to use them.

---------------------------------------------------------------------

void MTInitialise(void);

Before you can use MicroThread in your program, you will have to 
initialise it by calling this function. In fact, you will need to 
call this function every time you want to start a new multi-threading 
session. That is, once the function MTStartMultiThreading() returns, 
MicroThread has been put back into an un-initialised state, and 
MTInitialise() will need to be call again if you want to re-start 
multi-threading.

---------------------------------------------------------------------

enum MTReturnCode MTStartMultiThreading(void);

This function starts the MicroThread scheduler and thus multi-
threading. All threads which have been created usng MTAddNewThread() 
will start executing concurrently. MTStartMultiThreading will return 
if thee is an error condition or if one of the thread executes the 
function MTEndMultiThreading(). When MTStartMultiThreading() returns, 
its return value would indicate the terminating conditions, which 
would be one of the following:

enum MTReturnCode { 
	NORMAL, 
	DEADLOCKED, 
	CTRLBREAK,
	NOT_INITIALISED,
	TOO_DEEP_CRITICAL_NEST 
};

NORMAL indicates a normal exit, usually as a result of calling 
MTEndMultiThreading(). DEADLOCKED means that the scheduler wasn't 
able to find a thread to dispatch, so all the active threads must be 
deadlocked. The scheduler can also be easily fooled by the fact that 
all the threads have ended and thus assume that no thread = deadlock. 
CTRLBREAK basically indicates that multi-threading was stopped by the 
user hitting Control-BREAK. NOT_INITIALISED is obvious. 
TOO_DEEP_CRITICAL_NEST is returned if one of the threads calls 
MTEnterCritical() too many times without calling MTLeaveCritical().

---------------------------------------------------------------------

int MTAddNewThread(PThreadFunc pThreadFunc, unsigned priority, 
unsigned sizeArg, void *pArg);

This function creates and adds a new thread to the scheduler's READY 
queue, ready to be activated by the scheduling. Threads can only be 
added after MTInitialise() has been called. Threads can be added 
before MTStartMultThreading() or by one or more of the threads when 
multi-threading. The first parameter, pThreadFunc, is a pointer to 
the function which is to execute as a thread, and is of the type:

typedef int (far *PThreadFunc) (void *pArg);

The second parameter is the priority of the thread, from 1 to 5, with 
1 being the lowest priority and 5 being the highest priority. The 
parameter sizeArg describes the size of the memory block pointed to 
by the next parameter *pArg, which is passed as an argument to the 
thread function. A copy of this block of memory is made to another 
area before the function returns, thus you can deallocate the 
original memory when the function returns. The scheduler will take 
care of deallocating the copy when the thread terminates. If you pass 
a NULL for pArg, sizeArg is ignored, and no copy will be made.

There are two macros which are just variations on this funtion call: 
MTAddThread(pThreadFunc, priority) which are more convenient for 
functions which don't take parameters, and 
MTAddArgThread(pThreadFunc, priority, sizeArg, *pArg) which is mainly 
for backward compatibility with an older version of MicroThread.

MTAddNewThread() returns a thread identifier which is a handle to the 
thread. If it returns zero, then an error has occurred and no new 
thread was created.

---------------------------------------------------------------------

void MTKillThread(unsigned threadID);

This function just kills the specified thread. Can only be used 
during multi-threading.

---------------------------------------------------------------------

void MTEndThread(void);

This function kills the current thread.

---------------------------------------------------------------------
void MTEndMultiThreading(void);

This kills all known threads dead, i.e., it stops multi-threading, 
and cause MTStartMultiThreading() to return.

---------------------------------------------------------------------

Semaphore MTCreateSema(void);

This function creates and returns a unique semaphore. A semaphore of 
the following type:

typedef unsigned int Semaphore;

---------------------------------------------------------------------

unsigned MTDestroySema(Semaphore semaphore);

This function destroys the specified semaphore. Trying to destroy a 
semaphore which is still in use, i.e. have threads blocked on it or 
is n possesion by a thread, is an error and will fail. The functon 
return 1 on success, and 0 on failure.

---------------------------------------------------------------------

void MTWait(Semaphore Semaphore);

This function will acquire the semaphore for the calling thread or 
will cause the thread to block if another thread has acquired the 
semaphore, until the semaphore become free.

---------------------------------------------------------------------
int MTTestAndSet(Semaphore Semaphore);

This is similar to MTWait(), except that the calling thread will not 
be block if the semaphore is not free. It return 1 if the thread is 
successful in acquiring the semaphore, zero if not.

---------------------------------------------------------------------

void MTSignal(Semaphore Semaphore);

This signals(frees) the specified semaphore. The calling thread must 
have possession of the semaphore before calling this function.

---------------------------------------------------------------------

unsigned MTEnterCritical(void);
Causes MicroThread to single-threading mode temporarily with only the 
calling thread executing. Zero return value indicates failure - too 
many nested critical sections - > MAX_CRITICAL_NESTING error.

---------------------------------------------------------------------

void MTLeaveCritical(void);
Causes MicroThread to revert back to multi-threading.

---------------------------------------------------------------------

void MTYield(void);

This causes the calling thread to yield to another thread.

---------------------------------------------------------------------

void MTSetPreemptive(int bPreempt);

MicroThread can be run in either pre-emptive or non pre-emptive 
multi-threading mode. The pre-emptive mode uses the timer interrupt 
to switch between threads. The non-pre-emptive mode only switches 
when MTYield() is called.  The default mode is pre-emptive. If 
MTSetPreemptive() is called with the parameter bPreempt=1, then the 
pre-emptive mode is selected. If MTSetPreemptive() is called with the 
parameter bPreempt=0, then the non pre-emptive mode is selected. This 
function can only be called after MTInitialise() and before 
MTStartMultiThreading().

---------------------------------------------------------------------

Semaphore MTGetCRTLibSema(void);

This function returns semaphore used in MTCRTLIB.C to serialise 
access to Turbo C's runtime libraries.

---------------------------------------------------------------------

unsigned long MTGetClockTick(void);

This returns the number of clock ticks since MTStartMultiThreading().
One second is approx. 18.2 clock ticks.

---------------------------------------------------------------------

void MTSleep(unsigned long ticks);

Puts the current thread to sleep for the specified number of clock 
ticks (at least). The length of time that the thread actually sleeps 
may be a few ticks more depending on however many thread are running 
and what they are doing.

---------------------------------------------------------------------

unsigned MTCreateMailbox(char *name);

MicroThread supports named mailboxes for sending messages between 
threads. This function creates a mailbox with the specified name, and 
returns a handle to the mailbox. A zero return value indicates 
failure.

---------------------------------------------------------------------

unsigned MTDestroyMailbox(unsigned mailboxHnd);

This destroys the specified mailbox. Goes without saying that 
destroying a mailbox which is in active use is an error. Return 1 on 
success and zero on failure.

---------------------------------------------------------------------

unsigned MTGetMailboxHandle(char *mbxName);

Retrieves the handle to the named mailbox. Returns zero if the 
mailbox doesn't exist.

---------------------------------------------------------------------

int MTSendMsg(unsigned mailboxHnd, unsigned msgSize, void *pMsg);

Sends a message(data) to the specified mailbox. The function doesn't 
return until a reciver has picked up the message (the rendevous 
method). This is also a good way of synchronizing different 
cooperating threads. The message is in the form of a pointer to a 
block of memory of size 'msgSize'. A copy of the message is made by 
the receiver. 

---------------------------------------------------------------------

int MTReceiveMsg(unsigned mailboxHnd, unsigned bufferSize, void 
*pBuffer);

The counter part to MTSendMsg(). The calling thread will wait until 
there is a message in the mailbox. The memory block specified by the 
message is copied into the buffer pointed to by 'pBuffer'.

---------------------------------------------------------------------

The following are functions in MTCRTLIB.C. They are basically 
semaphored-wrappers around the Turbo C runtime library functions.

int MTfprintf (FILE *stream, const char *format,...);
int MTprintf (const char *format,...);
int MTfputs(const char *s, FILE *stream);
int MTputs(char *s);
int MTfputc(int c, FILE *stream);
int MTputc(int c);
int MTputchar(int c);
FILE *MTfopen(const char *filename, const char *mode);
int MTfclose(FILE *stream);
int MTfeof(FILE *stream);
int MTsprintf (char *buffer, const char *format,...);
char *MTfgets(char *s, int n, FILE *stream);
int MTfgetc(FILE *stream);
int MTxyputc(int x, int y, int c);
int MTxyputs(int x, int y, const char *s);
int MTxyprintf (int x, int y, const char *format, ...);
int MTkbhit(void);
int MTgetch(void);
char * MTgets(char *buf);
void MTclrscr(void);
int MTrandom(int num);
void *MTmalloc(size_t size);
void MTfree(void *block);
char *MTstrcpy(char *source, char *dest);
size_t MTfread(void *ptr, size_t size, size_t n, FILE *stream);
size_t MTfwrite(const void *ptr, size_t size, size_t n, FILE*stream);

