136 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
See README.alpha for Linux on DEC AXP info.
 | 
						|
 | 
						|
This file applies mostly to Linux/Intel IA32.  Ports to Linux on an M68K
 | 
						|
and PowerPC are also integrated.  They should behave similarly, except that
 | 
						|
the PowerPC port lacks incremental GC support, and it is unknown to what
 | 
						|
extent the Linux threads code is functional.  See below for M68K specific
 | 
						|
notes.
 | 
						|
 | 
						|
Incremental GC is supported on Intel IA32 and M68K.
 | 
						|
 | 
						|
Dynamic libraries are supported on an ELF system.  A static executable
 | 
						|
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
 | 
						|
 | 
						|
The collector appears to work with Linux threads.  We have seen
 | 
						|
intermittent hangs in sem_wait.  So far we have been unable to reproduce
 | 
						|
these unless the process was being debugged or traced.  Thus it's
 | 
						|
possible that the only real issue is that the debugger loses
 | 
						|
signals on rare occasions.
 | 
						|
 | 
						|
The garbage collector uses SIGPWR and SIGXCPU if it is used with
 | 
						|
Linux threads.  These should not be touched by the client program.
 | 
						|
 | 
						|
To use threads, you need to abide by the following requirements:
 | 
						|
 | 
						|
1) You need to use LinuxThreads (which are included in libc6).
 | 
						|
 | 
						|
   The collector relies on some implementation details of the LinuxThreads
 | 
						|
   package.  It is unlikely that this code will work on other
 | 
						|
   pthread implementations (in particular it will *not* work with
 | 
						|
   MIT pthreads).
 | 
						|
 | 
						|
2) You must compile the collector with -DGC_LINUX_THREADS and -D_REENTRANT
 | 
						|
   specified in the Makefile.
 | 
						|
 | 
						|
3a) Every file that makes thread calls should define GC_LINUX_THREADS and 
 | 
						|
   _REENTRANT and then include gc.h.  Gc.h redefines some of the
 | 
						|
   pthread primitives as macros which also provide the collector with
 | 
						|
   information it requires.
 | 
						|
 | 
						|
3b) A new alternative to (3a) is to build the collector and compile GC clients
 | 
						|
   with -DGC_USE_LD_WRAP, and to link the final program with
 | 
						|
 | 
						|
   (for ld) --wrap read --wrap dlopen --wrap pthread_create \
 | 
						|
	    --wrap pthread_join --wrap pthread_detach \
 | 
						|
	    --wrap pthread_sigmask --wrap sleep
 | 
						|
 | 
						|
   (for gcc) -Wl,--wrap -Wl,read -Wl,--wrap -Wl,dlopen -Wl,--wrap \
 | 
						|
	     -Wl,pthread_create -Wl,--wrap -Wl,pthread_join -Wl,--wrap \
 | 
						|
	     -Wl,pthread_detach -Wl,--wrap -Wl,pthread_sigmask \
 | 
						|
	     -Wl,--wrap -Wl,sleep
 | 
						|
 | 
						|
   In any case, _REENTRANT should be defined during compilation.
 | 
						|
 | 
						|
4) Dlopen() disables collection during its execution.  (It can't run
 | 
						|
   concurrently with the collector, since the collector looks at its
 | 
						|
   data structures.  It can't acquire the allocator lock, since arbitrary
 | 
						|
   user startup code may run as part of dlopen().)  Under unusual
 | 
						|
   conditions, this may cause unexpected heap growth.
 | 
						|
 | 
						|
5) The combination of GC_LINUX_THREADS, REDIRECT_MALLOC, and incremental
 | 
						|
   collection fails in seemingly random places.  This hasn't been tracked
 | 
						|
   down yet, but is perhaps not completely astonishing.  The thread package
 | 
						|
   uses malloc, and thus can presumably get SIGSEGVs while inside the
 | 
						|
   package.  There is no real guarantee that signals are handled properly
 | 
						|
   at that point.
 | 
						|
 | 
						|
6) Thread local storage may not be viewed as part of the root set by the
 | 
						|
   collector.  This probably depends on the linuxthreads version.  For the
 | 
						|
   time being, any collectable memory referenced by thread local storage should
 | 
						|
   also be referenced from elsewhere, or be allocated as uncollectable.
 | 
						|
   (This is really a bug that should be fixed somehow.)
 | 
						|
 | 
						|
 | 
						|
M68K LINUX:
 | 
						|
(From Richard Zidlicky)
 | 
						|
The bad news is that it can crash every linux-m68k kernel on a 68040,
 | 
						|
so an additional test is needed somewhere on startup. I have meanwhile
 | 
						|
patches to correct the problem in 68040 buserror handler but it is not
 | 
						|
yet in any standard kernel.
 | 
						|
 | 
						|
Here is a simple test program to detect whether the kernel has the
 | 
						|
problem. It could be run as a separate check in configure or tested 
 | 
						|
upon startup. If it fails (return !0) than mprotect can't be used
 | 
						|
on that system.
 | 
						|
 | 
						|
/*
 | 
						|
 * test for bug that may crash 68040 based Linux
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/mman.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
 | 
						|
char *membase;
 | 
						|
int pagesize=4096;
 | 
						|
int pageshift=12;
 | 
						|
int x_taken=0;
 | 
						|
 | 
						|
int sighandler(int sig)
 | 
						|
{
 | 
						|
   mprotect(membase,pagesize,PROT_READ|PROT_WRITE);
 | 
						|
   x_taken=1;
 | 
						|
}
 | 
						|
 | 
						|
main()
 | 
						|
{
 | 
						|
  long l;
 | 
						|
 | 
						|
   signal(SIGSEGV,sighandler);
 | 
						|
   l=(long)mmap(NULL,pagesize,PROT_READ,MAP_PRIVATE | MAP_ANON,-1,0);
 | 
						|
  if (l==-1)
 | 
						|
     {
 | 
						|
       perror("mmap/malloc");
 | 
						|
       abort();
 | 
						|
     }
 | 
						|
  membase=(char*)l;
 | 
						|
    *(long*)(membase+sizeof(long))=123456789;
 | 
						|
  if (*(long*)(membase+sizeof(long)) != 123456789 )
 | 
						|
    {
 | 
						|
      fprintf(stderr,"writeback failed !\n");
 | 
						|
      exit(1);
 | 
						|
    }
 | 
						|
  if (!x_taken)
 | 
						|
    {
 | 
						|
      fprintf(stderr,"exception not taken !\n");
 | 
						|
      exit(1);
 | 
						|
    }
 | 
						|
  fprintf(stderr,"vmtest Ok\n");
 | 
						|
  exit(0);
 | 
						|
}
 | 
						|
 | 
						|
 |