Przemek, Maurilio:

I checked all compiler flags info and for us just -s is critical, rest
are mainly default values
Without -s MT run fine, including "speedtst.prg --scale" which based on my tests revealed problem with threads except 1
-s seem to be the end of a week plenty of tests  :-)

>I'think I've found something:

>first of all, I started from config/win32/owatcom flags, then I had to
>remove -bt=OS2 which is wrong, should be -bt=OS2V2 but this gives an >undefined function referenced error when building, so I removed every
>thing, then I changed -5 to -5r because -5 is for 16bit code.

Maurilio, flags were based in win32 flags and just -bt was changed
-bt=OS2 is correct and we will use later for cross platform tests
OS2V2 is for linker SYSTEM directive
-5 in 32bit default to r if r or s are not specified

>It still did non build though, so I started looking at optimization
>flags where I found that -s disables stack overlow checking; and it was >it!

Yes, it is. An entire week in order to found it  :-)
And KbdCharIn(), Mou..() functions are not guilty

>So I changed it to -sg which means grow stack upon need, so now I have

>CPPFLAGS = -w2 -zq

>#architecture flags
>CPPFLAGS += -6r -fp6

># optimization flags
># don't enable -ol optimization in OpenWatcom 1.1 - gives buggy code
>CPPFLAGS += -onaehtzr -oi+ -ei -zp8 -sg -zt0

>I've used -6r since, given we're building for a peculiar cpu, at least
>we use a modern one as target and -sg as explained earlier.

We can ignore -5[r], -fp5, -6[r], -fp6

You are missing -bm for MT

>For LDFLAGS I have this

>LDFLAGS = OP stack=65536 OP CASEEXACT

>given that now stack can be grown, it does not give problems.

stack linker option is value for thread 1 and rest of threads are based in _beginthread() stack parameter

In source\vm\thread.c we have:
----------------------
#elif defined( HB_OS_WIN_32 )
th_h = ( HANDLE ) _beginthreadex( NULL, 0, start_func, Cargo, 0, th_id );
   if( !th_h )
      *th_id = ( HB_THREAD_ID ) 0;
#elif defined( HB_OS_OS2 )
   *th_id = _beginthread( start_func, NULL, 128 * 1024, Cargo );
   th_h = *th_id;
----------------------

For OS/2 is 128*1024=131,072
I am not sure if using -sg it start with 4K and is growing but with stack option limit, for threads except 1

Entire page info for -sg are below

Przemek: Why Win32 is using _beginthreadx() ?
_beginthread() can be used in Win32/OpenWatcom too
In OS/2 return thread ID but not in Win32

Entire page info for _beginthread() are below

>All mttest?? do work (apart from nr. 10) and speedtst works as well.

I rebuilt Harbour with original win32 flags but changed:
-bt=OS2   Platform target
-bm       For MT
-s        Removed

Except -s remove, rest is equal to all my previous tests

Using hbrun_mt.exe runs
- mttest??.prg, except 9 and 10 due missing functions HB_DBDETACH (9), HB_GT_STD_DEFAULT (10)
-
[E:\harbour811\harbour\tests]e:\harbour811\ow\bin\hbrun_mt.exe speedtst.prg --exclude=mem --scale --thread=2

====>  Now run without GPF, BUT extremaly slow
Sometimes it seem freezed for very long time


As we can see:
- Remove -s fixed problem with threads except 1
- "-sg" flag for stack grow is unnecessary

I rebuilt Harbour clean with -sg added
Results are the same

[E:\harbour811\harbour\tests]e:\harbour811\ow\bin\hbrun_mtsg.exe speedtst.prg --exclude=mem --scale --thread=2

run extremaly slow too


Congratulatios for both ( and me ), GPF is solved

Now we have to find why speedtst.prg is so slow, but seem due to compilers / linker flags too

Any hints ?

David Macias


-sg flag
========
This option is useful for 32-bit OS/2 and Win32 multi-threaded applications. It requests the code generator to emit a run-time call at the start of any function that has more than 4K bytes of automatic variables (variables located on the stack). Under 32-bit OS/2, the stack is grown automatically in 4K pages for any threads, other than the primary thread, using the stack "guard page" mechanism. The stack consists of in-use committed pages topped off with a special guard page. A memory reference into the 4K guard page causes the operating system to grow the stack by one 4K page and to add a new 4K guard page. This works fine when there is less than 4K of automatic variables in a function. When there is more than 4K of automatic data, the stack must be grown in an orderly fashion, 4K bytes at a time, until the stack has grown sufficiently to accommodate all the automatic variable storage requirements. Hence the requirement for a stack-growing run-time routine. The stack-growing run-time routine is called __GRO.

The "stack=" linker option specifies how much stack is available and committed for the primary thread when an executable starts. The stack size parameter to _beginthread() specifies how much stack is available for a child thread. The child thread starts with just 4k of stack committed. The stack will not grow to be bigger than the size specified by the stack size parameter.

Under 32-bit Windows (Win32), the stack is grown automatically in 4K pages for all threads using a similar stack "guard page" mechanism. The stack consists of in-use committed pages topped off with a special guard page. The techniques for growing the stack in an orderly fashion are the same as that described above for OS/2.

The "stack=" linker option specifies how much stack is available for the primary thread when an executable starts. The "commit stack=" linker directive specifies how much of that stack is committed when the executable starts. If no "commit stack=" directive is used, it defaults to the same value as the stack size. The stack size parameter to _beginthread() specifies how much stack is committed for a child thread. If the size is set to zero, the size of the primary thread stack is used for the child thread stack. When the child thread executes, the stack space is not otherwise restricted.

The macro __SW_SG will be predefined if "sg" is selected.

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

_beginthread()
==============

Synopsis:

#include <process.h>
#if defined(__386__)
#   define FAR
#else
#   define FAR __far
#endif

#if defined(__NT__)
unsigned long _beginthread(
        void (*start_address)(void *),
        unsigned stack_size,
        void     *arglist);
unsigned long _beginthreadex(
        void *security,
        unsigned stack_size,
        unsigned (__stdcall *start_address)(void *),
        void *arglist,
        unsigned initflag,
        unsigned *thrdid );
#else
int FAR _beginthread(
        void (FAR *start_address)(void FAR *),
        void FAR *stack_bottom,
        unsigned stack_size,
        void FAR *arglist );
#endif

Description:
The _beginthread function is used to start a new thread of execution at the function identified by start_address with a single parameter identified by arglist.

For each operating environment under which _beginthread is supported, the _beginthread function uses the appropriate system call to begin a new thread of execution.

The new thread will use the memory identified by stack_bottom and stack_size for its stack.

Note for 16-bit applications: If the stack is not in DGROUP (i.e., the stack pointer does not point to an area in DGROUP) then you must compile your application with the "zu" option. For example, the pointer returned by malloc in a large data model may not be in DGROUP. The "zu" option relaxes the restriction that the SS register contains the base address of the default data segment, "DGROUP". Normally, all data items are placed into the group DGROUP and the SS register contains the base address of this group. In a thread, the SS register will likely not contain the base address of this group. When the "zu" option is selected, the SS register is volatile (assumed to point to another segment) and any global data references require loading a segment register such as DS with the base address of DGROUP.

Note for OS/2 32-bit applications: Memory for a stack need not be provided by the application. The stack_bottom may be NULL in which case the run-time system will provide a stack. You must specify a non-zero stack_size for this stack.

Note for Win32 applications: Memory for a stack is provided by the run-time system. The size of the stack is determined by stack_size and must not be zero.

The _beginthreadex function can be used to create a new thread, in a running or suspended state specified by initflag, with security attributes specified by security.

The initial state of the new thread (running or suspended) is specified by the initflag argument. If the CREATE_SUSPENDED flag (WINBASE.H) is specified, the thread is created in a suspended state, and will not run until the Win32 ResumeThread function is called with the thread handle as an argument. If this value is zero, the thread runs immediately after creation.

The security descriptor for the new thread is specified by the security argument. This is a pointer to a Win32 SECURITY_ATTRIBUTES structure (see Microsoft's Win32 Programmer's Reference for more information). For default behaviour, the security structure pointer can be NULL.

The thread identifier is returned in the location identified by the thrdid argument.

The thread ends when it exits from its main function or calls exit, _exit, _endthread or _endthreadex.

The variable/function _threadid which is defined in <stddef.h> may be used by the executing thread to obtain its thread ID. In the 16-bit libraries, __threadid is a far pointer to an int. In the 32-bit libraries, it is a function that returns an int.

There is no limit to the number of threads an application can create under Win32 platforms.

There is a limit to the number of threads an application can create under 16-bit OS/2 and 32-bit NetWare. The default limit is 32. This limit can be adjusted by statically initializing the unsigned global variable __MaxThreads.

Under 32-bit OS/2, there is no limit to the number of threads an application can create. However, due to the way in which multiple threads are supported in the Watcom libraries, there is a small performance penalty once the number of threads exceeds the default limit of 32 (this number includes the initial thread). If you are creating more than 32 threads and wish to avoid this performance penalty, you can redefine the threshold value of 32. You can statically initialize the global variable __MaxThreads.

By adding the following line to your multi-threaded application, the new threshold value will be set to 48.


     unsigned __MaxThreads = { 48 };

Returns:
Under Win32, the _beginthread function returns the thread handle for the new thread if successful; otherwise it returns -1 to indicate that the thread could not be started.

Under all other systems that support the _beginthread function (OS/2, Netware and QNX), it returns the thread ID for the new thread if successful; otherwise it returns -1 to indicate that the thread could not be started.

The _beginthreadex function returns the thread handle for the new thread if successful; otherwise it returns 0 to indicate that the thread could not be started.

When the thread could not be started, the value of errno could be set to EAGAIN if there are too many threads, or to EINVAL if the argument is invalid or the stack size is incorrect, or to ENOMEM if there is not enough available memory.

See Also:
_endthread

Example:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <malloc.h>
#include <process.h>
#include <dos.h>

#if defined(__386__)
  #define FAR
  #define STACK_SIZE    8192
#else
  #define FAR           __far
  #define STACK_SIZE    4096
#endif

static volatile int     WaitForThread;

void FAR child( void FAR *parm )
  {
    char * FAR *argv = (char * FAR *) parm;
    int  i;

    printf( "Child thread ID = %x\n", *_threadid );
    for( i = 0; argv[i]; i++ ) {
      printf( "argv[%d] = %s\n", i, argv[i] );
    }
    WaitForThread = 0;
    _endthread();
  }

void main()
  {
    char           *args[3];
#if defined(__NT__)
    unsigned long   tid;
#else
    char           *stack;
    int             tid;
#endif

    args[0] = "child";
    args[1] = "parm";
    args[2] = NULL;
    WaitForThread = 1;
#if defined(__NT__)
    tid = _beginthread( child, STACK_SIZE, args );
    printf( "Thread handle = %lx\n", tid );
#else
  #if defined(__386__)
    stack = (char *) malloc( STACK_SIZE );
  #else
    stack = (char *) _nmalloc( STACK_SIZE );
  #endif
    tid = _beginthread( child, stack, STACK_SIZE, args );
    printf( "Thread ID = %x\n", tid );
#endif
    while( WaitForThread ) {
        sleep( 0 );
    }
  }

Classification:
WATCOM

Systems:
_beginthread - Win32, QNX/32, OS/2 1.x(MT), OS/2 1.x(DL), OS/2-32, Netware

_beginthreadex - Win32

_______________________________________________
Harbour mailing list
Harbour@harbour-project.org
http://lists.harbour-project.org/mailman/listinfo/harbour

Reply via email to