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