Writing Your Own C 6.00/6.00a Multithreaded __chkstk Routine

ID Number: Q70258

6.00 6.00a

OS/2

Summary:

Writing your own stack checking functions for the C version 6.00 or

6.00a multithreaded libraries is similar to writing them for the

standard, single-threaded libraries. For complete information on

writing your own version of the standard stack checking routine, query

on the following words:

standard and __chkstk and 6.00a

The following is a list of the differences needed to write your own

multithreaded __chkstk routines for use with the various multithreaded

libraries:

1. The symbol STKHQQ, which indicates the limit of the stack, must be

defined for each thread. This pertains to all the multithreaded

libraries.

2. You must be sure you are operating on the correct data segment when

you are inside the __chkstk function. This pertains only to the

LLIBCDLL.LIB and CDLLOBJS.LIB libraries.

3. If you are replacing the __chkstk functions in the run-time DLL

version (CDLLOBJS.LIB), you must define the near model to call the

far model.

More Information:

The following information is a more thorough discussion of the three

points above:

1. In order to access the thread instance data, there is a new

function in C 6.00 called __gettidtab. This function takes no

arguments and returns a pointer to an instance data structure in

AX:DX. Below is the format of that structure C and assembly

notation:

C Notation

----------

struct _tiddata {

unsigned int _terrno; // errno value

unsigned int _tdoserrno; // _doserrno value

unsigned int _stkhqq; // stack limit

unsigned int _fpds; // Floating Point data segment

unsigned long _holdrand; // rand() seed value

char far * _token; // far * to strtok() token

char far * _errmsg; // far * to strerror() buffer

char far * _namebuf; // far * to tmpfile() buffer

char far * _asctimebuf; // far * to asctime() buffer

void far * _gmtimebuf; // far * to gmtime() structure

void far * _stackalloc; // far * to thread's stack

char _padding[28]; // pad up to pow2 boundary

};

struct _tiddata far * cdecl near _gettidtab(void);

ASM Notation

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

_tiddata struc

__terrno dw 0 ; errno value

__tdoserrno dw 0 ; _doserrno value

__stkhqq dw 0 ; stack limit

__fpds dw 0 ; Floating Point data segment

__holdrand dd 0 ; rand() seed value

__token dd 0 ; far * to strtok() token

__errmsg dd 0 ; far * to strerror() buffer

__namebuf dd 0 ; far * to tmpfile() buffer

__asctimebuf dd 0 ; far * to asctime() buffer

__gmtimebuf dd 0 ; far * to gmtime() structure

__stackalloc dd 0 ; far * to thread's stack

__padding db 28 dup (0) ; pad up to next pow2 boundary

_tiddata ends

extrn __gettidtab:near

2. Because __chkstk is the *first* thing executed when a function is

called (even before _loadds takes effect), it is imperative that

the data segment be set up correctly. This is easily accomplished

by the following code fragment:

push DS

push DGROUP

pop DS

{ __chkstk code goes here }

pop DS

3. In the CDLLOBJS.LIB model, the actual run-time code is in a

separate DLL. Therefore, all calls to the run time must be made as

far calls. For that reason, the near versions of the __chkstk

function (_aNchkstk and _aNrchkstk) must use the far versions to do

the actual work. Below is an example of the code needed to make that

happen for _aNchkstk:

pop cx ; convert near call into a far call

push cs

push cx

jmp _aFchkstk