Jump to content

DosCreateThread2: Difference between revisions

From EDM2
Created page with "==Description== DosCreateThread2 creates an asynchronous thread of execution under the current process using a pre-allocated stack. ==Syntax== <PRE> #define INCL_DOSPROCESS ..."
 
Ak120 (talk | contribs)
mNo edit summary
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
==Description==
DosCreateThread2 creates an asynchronous thread of execution under the current process using a pre-allocated stack.
DosCreateThread2 creates an asynchronous thread of execution under the current process using a pre-allocated stack.  


==Syntax==
==Syntax==
<PRE>
DosCreateThread2 ( ptc, cbSize, pTid, pfnStart, lParam, lFlag,
#define INCL_DOSPROCESS
                    pStack, cbStack)
#include  os2.h>


    APIRET DosCreateThread2 (PTHREADCREATE ptc, ULONG cbSize, PTID pTid,
                            PFNTHREAD pfnStart, ULONG lParam, ULONG lFlag,
                            PBYTE pStack, ULONG cbStack)
</PRE>
==Parameters==
==Parameters==
; ptc(PTHREADCREATE) input/output : Address of the thread create data structure
;ptc (PTHREADCREATE) input/output : Address of the thread create data structure
 
typedef struct_THREADCREATE{
    typedef struct_THREADCREATE{   ULONG      cbSize;
    ULONG      cbSize;
      PTID        pTid;
    PTID        pTid;
      PFNTHREAD  pfnStart;
    PFNTHREAD  pfnStart;
      ULONG      lParam;
    ULONG      lParam;
      ULONG      lFlag;
    ULONG      lFlag;
      PBYTE      pStack;
    PBYTE      pStack;
      ULONG      cbStack;
    ULONG      cbStack;
    }  THREADCREATE;
}  THREADCREATE;
    typedef THREADCREATE *PTHREADCREATE;
typedef THREADCREATE *PTHREADCREATE;
 
;cbSize (ULONG) input : The size, in bytes, of the thread create 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.
; 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).  
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.
; cbStack (ULONG) input : The size, in bytes, of the new thread's stack.  
;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==
==Return Code==
ulrc (APIRET) returns
;ulrc (APIRET) returns:DosCreateThread2 returns one of the following values
 
* 0 NO_ERROR
DosCreateThread2 returns one of the following values
* 8 ERROR_NOT_ENOUGH_MEMORY
 
* 87 ERROR_INVALID_PARAMETER
* 0         NO_ERROR
* 95 ERROR_INTERRUPT
*           ERROR_NOT_ENOUGH_MEMORY
*115 ERROR_PROTECTION_VIOLATION
* 87         ERROR_INVALID_PARAMETER  
*164 ERROR_MAX_THRDS_REACHED
* 95         ERROR_INTERRUPT  
* 115       ERROR_PROTECTION_VIOLATION  
* 164       ERROR_MAX_THRDS_REACHED  


==Remarks==
==Remarks==
Line 69: Line 48:
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.
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.  
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==
==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.
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 CSet/2 or VisualAge(R) C/C++, use the /Gm+ switch.
Compile this example with MULTITHREAD LIBRARIES. If you are using C Set/2 or VisualAge C++, use the /Gm+ switch.
<PRE>
<PRE>
#define INCL_DOSMEMMGR#define INCL_DOSPROCESS
#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_DOSERRORS


#include os2.h>
#include <os2.h>
#include stdio.h>
#include <stdio.h>
#include stdlib.h>
#include <stdlib.h>


#define _64K 64*1024
#define _64K 64*1024
Line 114: Line 94:


   tc[0].cbSize  = sizeof(THREADCREATE);
   tc[0].cbSize  = sizeof(THREADCREATE);
   tc[0].pfnStart = (PFNTHREAD) TestThread1
   tc[0].pfnStart = (PFNTHREAD) TestThread1;
   tc[0].pStack  = (PBYTE)pStackBase + _64K;    /* Top of stack (not bottom) */
   tc[0].pStack  = (PBYTE)pStackBase + _64K;    /* Top of stack (not bottom) */
   tc[0].lFlag    = CREATE_READY | STACK_SPARSE;
   tc[0].lFlag    = CREATE_READY | STACK_SPARSE;
Line 120: Line 100:


   tc[1].cbSize  = sizeof(THREADCREATE);
   tc[1].cbSize  = sizeof(THREADCREATE);
   tc[1].pfnStart = (PFNTHREAD) TestThread2
   tc[1].pfnStart = (PFNTHREAD) TestThread2;
   tc[1].pStack  = (PBYTE)pStackBase + _48K;    /* Top of stack (not bottom) */
   tc[1].pStack  = (PBYTE)pStackBase + _48K;    /* Top of stack (not bottom) */
   tc[1].lFlag    = CREATE_READY | STACK_SPARSE;
   tc[1].lFlag    = CREATE_READY | STACK_SPARSE;
Line 126: Line 106:


   tc[2].cbSize  = sizeof(THREADCREATE);
   tc[2].cbSize  = sizeof(THREADCREATE);
   tc[2].pfnStart = (PFNTHREAD) TestThread3
   tc[2].pfnStart = (PFNTHREAD) TestThread3;
   tc[2].pStack  = (PBYTE)pStackBase + _32K;    /* Top of stack (not bottom) */
   tc[2].pStack  = (PBYTE)pStackBase + _32K;    /* Top of stack (not bottom) */
   tc[2].lFlag    = CREATE_READY | STACK_SPARSE;
   tc[2].lFlag    = CREATE_READY | STACK_SPARSE;
Line 132: Line 112:


   tc[3].cbSize  = sizeof(THREADCREATE);
   tc[3].cbSize  = sizeof(THREADCREATE);
   tc[3].pfnStart = (PFNTHREAD) TestThread4
   tc[3].pfnStart = (PFNTHREAD) TestThread4;
   tc[3].pStack  = (PBYTE)pStackBase + _16K;    /* Top of stack (not bottom) */
   tc[3].pStack  = (PBYTE)pStackBase + _16K;    /* Top of stack (not bottom) */
   tc[3].lFlag    = CREATE_READY | STACK_SPARSE;
   tc[3].lFlag    = CREATE_READY | STACK_SPARSE;
Line 139: Line 119:
   /* Create 4 child threads. */
   /* Create 4 child threads. */


   for (i=0; i 4; i++) {
   for (i=0; i<4; i++) {
       rc = DosCreateThread2( tc[i]);
       rc = DosCreateThread2(&tc[i]);
       if (rc != NO_ERROR) {
       if (rc != NO_ERROR) {
         printf( "DosCreateThread2 failed, rc = %d\n", rc);
         printf( "DosCreateThread2 failed, rc = %d\n", rc);
Line 151: Line 131:


   /* Wait for all child threads to terminate. */
   /* Wait for all child threads to terminate. */
   for (i=0; i 4; i++) {
   for (i=0; i<4; i++) {
       DosWaitThread( (tc[i].pTid), DCWW_WAIT);
       DosWaitThread( (tc[i].pTid), DCWW_WAIT);
   }
   }
Line 238: Line 218:
   }
   }
}
}
</PRE>
</PRE>
==Related Functions==
* [[OS2 API:CPI:DosCreateThread|DosCreateThread]]


[[Category:The OS/2 API Project]]
[[Category:Dos16]]

Latest revision as of 02:58, 26 January 2020

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

ptc (PTHREADCREATE) input/output
Address of the thread create data structure
typedef struct_THREADCREATE{
   ULONG       cbSize;
   PTID        pTid;
   PFNTHREAD   pfnStart;
   ULONG       lParam;
   ULONG       lFlag;
   PBYTE       pStack;
   ULONG       cbStack;
}  THREADCREATE;
typedef THREADCREATE *PTHREADCREATE;
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.

#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#define INCL_DOSERRORS

#include <os2.h>
#include <stdio.h>
#include <stdlib.h>

#define _64K 64*1024
#define _48K 48*1024
#define _32K 32*1024
#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);
   }
}