[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [MiNT] tfork() bug.
Am Di, 15.05.2012, 23:42 schrieb Alan Hourihane:
>> Can somebody confirm this bug and that I understand it correctly?
>
> A small test case would help. Can you code one up ?
I think it is more about looking at the source, but sure - here it is. And
as I said, the race condition is taking place first. The PoC is attached.
compile:
m68k-atari-mint-gcc ./poc_tfork.c -Wall -o test_tfork.prg
output of test_tfork.prg:
1: env pointer: 0x158e000
3: env pointer: 0x158e000
4: env pointer: 0x15ae000
Thread 0 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 0: 165
1: env pointer: 0x1590000
3: env pointer: 0x1590000
4: env pointer: 0x15ae000
Thread 1 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 1: 166
1: env pointer: 0x1592000
3: env pointer: 0x1592000
4: env pointer: 0x15ae000
Thread 2 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 2: 167
1: env pointer: 0x1594000
3: env pointer: 0x1594000
4: env pointer: 0x15ae000
Thread 3 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 3: 168
1: env pointer: 0x1596000
3: env pointer: 0x1596000
4: env pointer: 0x15ae000
Thread 4 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 4: 169
1: env pointer: 0x1598000
3: env pointer: 0x1598000
4: env pointer: 0x15ae000
Thread 5 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 5: 170
1: env pointer: 0x159a000
3: env pointer: 0x159a000
4: env pointer: 0x15ae000
Thread 6 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 6: 171
1: env pointer: 0x159c000
3: env pointer: 0x159c000
4: env pointer: 0x15ae000
Thread 7 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 7: 172
1: env pointer: 0x159e000
3: env pointer: 0x159e000
4: env pointer: 0x15ae000
Thread 8 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 8: 173
1: env pointer: 0x15a0000
3: env pointer: 0x15a0000
4: env pointer: 0x15ae000
Thread 9 is active!
2: env pointer: 0x15ae000
start_and_wait_for_several_threads thread 9: 174
Thread 0 is active!
Thread 9 is active!
Thread 8 is active!
Thread 7 is active!
Thread 6 is active!
Thread 5 is active!
Thread 4 is active!
Thread 3 is active!
Thread 2 is active!
Thread 1 is active!
Thread 0 is active!
Thread 1 is active!
Thread 2 is active!
Thread 3 is active!
Thread 4 is active!
Thread 5 is active!
Thread 6 is active!
Thread 7 is active!
Thread 8 is active!
Thread 9 is active!
Thread 0 is active!
Thread 9 is active!
Thread 8 is active!
Thread 7 is active!
Thread 6 is active!
Thread 5 is active!
Thread 4 is active!
Thread 3 is active!
Thread 2 is active!
Thread 1 is active!
Thread 0 is active!
Thread 1 is active!
Thread 2 is active!
Thread 3 is active!
Thread 4 is active!
Thread 5 is active!
Thread 6 is active!
Thread 7 is active!
Thread 8 is active!
Thread 9 is active!
--
Greets,
Ole
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <time.h>
#include <support.h>
#include <string.h>
#include <unistd.h>
#include <compiler.h>
#include <errno.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <mint/osbind.h>
#include <mint/mintbind.h>
#include <mint/basepage.h>
extern void _setstack( void *newsp );
#define SIZE 4096L
static void __CDECL
startup(register BASEPAGE *b)
{
register int (*func)(long);
register long arg;
_setstack(((char *)b) + SIZE);
func = (int (*)(long))b->p_dbase;
arg = b->p_dlen;
/* If this is a thread, it doesn't need
* own copy of the environment, right?
*/
printf( "3: env pointer: %p\n", b->p_env );
Mfree(b->p_env);
b->p_env = _base->p_env;
printf( "4: env pointer: %p\n", b->p_env );
/* copy from parents basepage for debuggers... */
b->p_tbase = _base->p_tbase;
b->p_tlen = _base->p_tlen;
b->p_dbase = _base->p_dbase;
b->p_dlen = _base->p_dlen;
b->p_bbase = _base->p_bbase;
b->p_blen = _base->p_blen;
Pterm((*func)(arg));
}
/* this is the the equivalent of tfork(), implemented here so that I can */
/* ad my own modifications */
/* the TOS fallback was ripped out. */
/* use long instead of int so vfork works OK with -mshort */
long
my_tfork(int (*func)(long), long arg)
{
register BASEPAGE *b;
register long pid;
b = (BASEPAGE *)Pexec(PE_CBASEPAGE, 0L, "", 0L);
(void)Mshrink(b, SIZE+256);
b->p_tbase = (char *)startup;
b->p_dbase = (char *)func;
b->p_dlen = arg;
b->p_hitpa = ((char *)b) + SIZE + 256;
printf( "1: env pointer: %p\n", b->p_env );
pid = Pexec(104, 0L, b, 0L);
printf( "2: env pointer: %p\n", b->p_env );
(void)Mfree(b->p_env); /* free the memory */
(void)Mfree(b);
return pid;
}
static int start_and_wait_for_several_threads( int (*func)(long) )
{
#define NTHREADS 10
int stats[NTHREADS];
int tids[NTHREADS];
int options[NTHREADS];
bool threads_running = true;
bool running[NTHREADS];
int i, err, res=0;
for( i=0; i<NTHREADS; i++ ) {
tids[i] = my_tfork( func, i );
printf("%s thread %d: %d\n", __FUNCTION__, i, tids[i] );
if( tids[i] > 0 ) {
threads_running = true;
running[i] = true;
}
}
/* wait until all threads have finished: */
while( threads_running ) {
sleep( 1 );
for( i=0; i<NTHREADS; i++ ) {
options[i] = WNOHANG;
err = waitpid( tids[i], &stats[i], options[i] );
if( err == tids[i] && stats[i] == 0 ) {
running[i] = false;
}
}
threads_running = false;
for( i=0; i<NTHREADS; i++ ) {
if( running[i] == true ){
threads_running = true;
}
}
}
return( res );
#undef NTHREADS
}
int test_thread( long arg ) {
#define NRUNS 5
int i;
struct timeval tv;
for( i=0; i<NRUNS; i++){
printf("Thread %li is active!\n", arg );
tv.tv_sec = 0;
tv.tv_usec = 90000;
select(0, NULL, NULL, NULL, &tv);
}
return( 0 );
#undef NRUNS
}
int main( void ) {
start_and_wait_for_several_threads( test_thread );
return( 0 );
}