DosCreateThread2

DosCreateThread2 creates an asynchronous thread of execution under the current process using a pre-allocated stack.

Syntax
DosCreateThread2 ( ptc, cbSize, pTid, pfnStart, lParam, lFlag,                   pStack, cbStack)

Parameters
typedef struct_THREADCREATE{ ULONG      cbSize; PTID       pTid; PFNTHREAD  pfnStart; ULONG      lParam; ULONG      lFlag; PBYTE      pStack; ULONG      cbStack; } THREADCREATE; typedef THREADCREATE *PTHREADCREATE;
 * ptc (PTHREADCREATE) input/output : Address of the thread create data structure
 * cbSize (ULONG) input : The size, in bytes, of the thread create structure.
 * pTid (PTID) output : The thread identifier of the created thread is returned.
 * pfnStart (PFNTHREAD) input : Address of the code to be executed when the thread begins execution.

This function is called using a 32 bit near-call, accepts a single parameter, lParam, and returns a doubleword exit status (see DosExit). Returning from the function without executing DosExit causes the thread to end. In this case, the exit status is the value in the EAX register when the thread ends.
 * lParam (ULONG) input : An argument that is passed to the target thread routine as a parameter. It is usually a pointer to a parameter block.
 * lFlag (ULONG) input : Thread flags.
 * Possible values are a combination of the following
 * CREATE_READY (0x00000000) : The new thread starts immediately.
 * CREATE_SUSPEND (0x00000001): The thread is created in the suspended state, and the creator of the thread must issue DosResumeThread to start the new thread's execution.
 * STACK_SPARSE (0x00000000): The system uses the default method for initializing the thread's stack.
 * STACK_COMMITTED (0x00000002) : The system precommits all the pages in the stack. One page is 4KB


 * pStack (PBYTE) input : Address of the top of the stack (not the bottom of the stack).
 * cbStack (ULONG) input : The size, in bytes, of the new thread's stack.

Return Code

 * ulrc (APIRET) returns:DosCreateThread2 returns one of the following values
 * 0 NO_ERROR
 * 8 ERROR_NOT_ENOUGH_MEMORY
 * 87 ERROR_INVALID_PARAMETER
 * 95 ERROR_INTERRUPT
 * 115 ERROR_PROTECTION_VIOLATION
 * 164 ERROR_MAX_THRDS_REACHED

Remarks
The difference between DosCreateThread and DosCreateThread2 is the use and management of the thread's stack.

Using DosCreateThread, the application is not responsible for allocating the stack. The application simply supplies the size of the stack, and the operating system will manage the allocation and location of that storage on behalf of the application. DosCreateThread also employs guard pages and exception handling for stack related situations, such as stack growth. One of the problems with DosCreateThread is that for each thread, a minimum 64K of virtual address space is reserved, but only 8K of physical storage is actually committed. Therefore, 56K of virtual address space is wasted initially.

Using DosCreateThread2, the application is responsible for allocating the stack before calling the API. With DosCreateThread2, the operating system gives the application total control over stack size and location. Therefore, more efficient use of virtual address space within the system can be achieved.

The address of the stack, pStack, must be in the compatibility region, that is, the first 512MB (0x20000000). If DosCreateThread2 is called with a stack address higher than 512MB, ERROR_INVALID_PARAMETER will be returned.

Example Code
In this example, the main thread first allocates 64K worth of memory. It then calls DosCreateThread2 four times to create 4 child threads. Each child thread has 16K of stack space. Finally, the main thread sets the termination flag to allow all child threads to terminate.

Compile this example with MULTITHREAD LIBRARIES. If you are using C Set/2 or VisualAge C++, use the /Gm+ switch. 
 * 1) define INCL_DOSMEMMGR
 * 2) define INCL_DOSPROCESS
 * 3) define INCL_DOSERRORS


 * 1) include 
 * 2) include 
 * 3) include 


 * 1) define _64K 64*1024
 * 2) define _48K 48*1024
 * 3) define _32K 32*1024
 * 4) define _16K 16*1024

void _System TestThread1(void); void _System TestThread2(void); void _System TestThread3(void); void _System TestThread4(void);

BOOL flTerminate = FALSE;

int main (VOID) {

APIRET rc;              /* Return code */ void *pStackBase;       /* Pointer to stack base */ THREADCREATE tc[4]={0}; /* Thread create structures */ int i;

/* Allocate 64K of memory */

rc = DosAllocMem( pStackBase, _64K, PAG_COMMIT | PAG_WRITE);

if (rc != NO_ERROR) { printf("DosAllocMem failed, rc=%d\n", rc); return(1); }

/* Set up thread structures (4 threads). */

tc[0].cbSize  = sizeof(THREADCREATE); tc[0].pfnStart = (PFNTHREAD) TestThread1; tc[0].pStack  = (PBYTE)pStackBase + _64K;    /* Top of stack (not bottom) */ tc[0].lFlag   = CREATE_READY | STACK_SPARSE; tc[0].cbStack = _16K;                        /* Each thread has 16K stack */

tc[1].cbSize  = sizeof(THREADCREATE); tc[1].pfnStart = (PFNTHREAD) TestThread2; tc[1].pStack  = (PBYTE)pStackBase + _48K;    /* Top of stack (not bottom) */ tc[1].lFlag   = CREATE_READY | STACK_SPARSE; tc[1].cbStack = _16K;                        /* Each thread has 16K stack */

tc[2].cbSize  = sizeof(THREADCREATE); tc[2].pfnStart = (PFNTHREAD) TestThread3; tc[2].pStack  = (PBYTE)pStackBase + _32K;    /* Top of stack (not bottom) */ tc[2].lFlag   = CREATE_READY | STACK_SPARSE; tc[2].cbStack = _16K;                        /* Each thread has 16K stack */

tc[3].cbSize  = sizeof(THREADCREATE); tc[3].pfnStart = (PFNTHREAD) TestThread4; tc[3].pStack  = (PBYTE)pStackBase + _16K;    /* Top of stack (not bottom) */ tc[3].lFlag   = CREATE_READY | STACK_SPARSE; tc[3].cbStack = _16K;                        /* Each thread has 16K stack */

/* Create 4 child threads. */

for (i=0; i<4; i++) { rc = DosCreateThread2(&tc[i]); if (rc != NO_ERROR) { printf( "DosCreateThread2 failed, rc = %d\n", rc); return(1); } else printf("DosCreateThread2 was successful, tid=%d\n", tc[i].pTid); }

flTerminate = TRUE;

/* Wait for all child threads to terminate. */  for (i=0; i<4; i++) { DosWaitThread( (tc[i].pTid), DCWW_WAIT); }

DosFreeMem(pStackBase); return(0); }

void _System TestThread1(void) {  APIRET rc; PTIB  ptib; PPIB  ppib;

rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread1 DosGetInfoBlocks failed rc = %d\n", rc); return; }

printf("TestThread1 base of stack at 0x%08X, top of stack at 0x%08X\n",             ptib->tib_pstack, ptib->tib_pstacklimit);

while (flTerminate == FALSE) { DosSleep(1000); } }

void _System TestThread2(void) {  APIRET rc; PTIB  ptib; PPIB  ppib;

rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread2 DosGetInfoBlocks failed rc = %d\n", rc); return; }

printf("TestThread2 base of stack at 0x%08X, top of stack at 0x%08X\n",             ptib->tib_pstack, ptib->tib_pstacklimit);

while (flTerminate == FALSE) { DosSleep(1000); } }

void _System TestThread3(void) {  APIRET rc; PTIB  ptib; PPIB  ppib;

rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread3 DosGetInfoBlocks failed rc = %d\n", rc); return; }

printf("TestThread3 base of stack at 0x%08X, top of stack at 0x%08X\n",             ptib->tib_pstack, ptib->tib_pstacklimit);

while (flTerminate == FALSE) { DosSleep(1000); } }

void _System TestThread4(void) {  APIRET rc; PTIB  ptib; PPIB  ppib;

rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread4 DosGetInfoBlocks failed rc = %d\n", rc); return; }

printf("TestThread4 base of stack at 0x%08X, top of stack at 0x%08X\n",             ptib->tib_pstack, ptib->tib_pstacklimit);

while (flTerminate == FALSE) { DosSleep(1000); } } 