浏览代码

UnixAos Generic -- TrapHandler works

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@6910 8c9fc860-2736-0410-a75d-ab315db34111
felixf 8 年之前
父节点
当前提交
3caa9ca2ce

+ 19 - 2
source/Generic.Linux.I386.Glue.Mod

@@ -187,6 +187,12 @@ VAR
 	BEGIN
 		Init;
 	END Init0;
+	
+	PROCEDURE Initialize*;
+	BEGIN
+		(* nothing, only for compatibility *)
+	END Initialize;
+	
 
 
 BEGIN
@@ -198,10 +204,21 @@ SystemTools.FreeDownTo FoxIntermediateBackend ~
 SystemTools.DoCommands
 	Compiler.Compile -p=Linux32G
 		Runtime.Mod Trace.Mod Generic.Linux.I386.Glue.Mod Generic.Linux.I386.Unix.Mod Generic.Unix.I386.Machine.Mod Heaps.Mod  Generic.Modules.Mod 
-		Generic.Unix.Objects.Mod  TestLinux.Mod ~ 
+		Generic.Unix.Objects.Mod
+		Unix.Kernel.Mod KernelLog.Mod Plugins.Mod Streams.Mod 
+		Pipes.Mod Commands.Mod I386.Reals.Mod Generic.Reflection.Mod TrapWriters.Mod CRC.Mod SystemVersion.Mod 
+		Unix.StdIO.Mod Generic.Unix.Traps.Mod Locks.Mod Unix.Clock.Mod Disks.Mod Files.Mod Dates.Mod Strings.Mod 
+		UTF8Strings.Mod FileTrapWriter.Mod Caches.Mod DiskVolumes.Mod OldDiskVolumes.Mod RAMVolumes.Mod 
+		DiskFS.Mod OldDiskFS.Mod OberonFS.Mod FATVolumes.Mod FATFiles.Mod ISO9660Volumes.Mod 
+		ISO9660Files.Mod Unix.UnixFiles.Mod RelativeFileSystem.Mod BitSets.Mod StringPool.Mod DIagnostics.Mod ObjectFile.Mod GenericLinker.Mod GenericLoader.Mod Unix.BootConsole.Mod 
+		TestLinux.Mod  ~
 
 	StaticLinker.Link --fileFormat=Raw --fileName=simple_elf --extension=.GofU --displacement=08048000H
-		Runtime Trace Glue Unix Machine Heaps Modules Objects Test ~
+		Runtime Trace Glue Unix Machine Heaps Modules Objects Kernel KernelLog Test 
+Streams Commands StdIO TrapWriters Traps FIles UnixFiles Clock Dates Reals Strings Diagnostics 
+BitSets StringPool ObjectFile GenericLinker Reflection  GenericLoader  BootConsole 
+ ~
+~
 
 	FSTools.CloseFiles simple_elf ~
 		~ 

+ 70 - 3
source/Generic.Linux.I386.Unix.Mod

@@ -125,6 +125,13 @@ CONST
 	SIG_BLOCK = 0;
 	SIG_UNBLOCK=1;
 	SIG_SETMASK=2;
+
+	SA_NOCLDSTOP  = 0x00000001;
+	SA_SIGINFO =       0x00000004;
+	SA_ONSTACK  =    0x08000000;
+	SA_RESTART  =    0x10000000;
+	SA_NODEFER  =     0x40000000;
+	SA_RESETHAND  =  0x80000000;
 	
   PTHREAD_CANCEL_ENABLE 	= 0;
   PTHREAD_CANCEL_DISABLE	= 1;
@@ -146,6 +153,7 @@ TYPE
 	ConditionType = ARRAY 12 OF WORD;
 
 	Sigset_t= ARRAY 32 OF ADDRESS; 
+	SignalHandler = PROCEDURE ( sig: LONGINT; scp, ucp, dum: ADDRESS );  
 
 	
 CONST
@@ -532,6 +540,7 @@ VAR
 	VAR cond: Condition_t;
 	BEGIN
 		cond := malloc(SIZEOF(ConditionType));
+		TRACE(cond);
 		ASSERT(cond # 0);
 		ASSERT(pthread_cond_init(cond, NIL)=0);
 		RETURN cond;
@@ -861,6 +870,7 @@ VAR
 	END GetArgval;
 
 
+
 	PROCEDURE getSysinfo;
 	VAR res: LONGINT;  p: INTEGER;
 		buf: ARRAY 4096 OF CHAR;
@@ -884,6 +894,64 @@ VAR
 		copy( p, sysinfo.version );
 		copy( p, sysinfo.machine );
 	END getSysinfo;
+
+	PROCEDURE CreateSignalStack;
+	BEGIN
+		sigstk.sp := ADDRESS OF sigstack;
+		sigstk.size := LEN(sigstack);
+		sigstk.flags := {};
+	END CreateSignalStack;
+	
+	(*
+static void sighandler( int sig, siginfo_t *scp, void *ucp ) {
+	
+	if (debug | (AosTrap == NULL)) {
+	    printf("\nhandler for signal %d got called, ucp = %p\n", sig, ucp);
+	    if (AosTrap == NULL) exit(1);
+	}
+	AosTrap(0, ucp, scp, sig); /* rev. order: Oberon <--> C */
+}
+	*)
+	
+	VAR trap: SignalHandler; 
+	
+	PROCEDURE {C} SigHandler  ( sig: LONGINT; scp: ADDRESS; ucp: ADDRESS); (* reversed arguments !! *)
+	BEGIN
+		TRACE(sig, scp, ucp);
+		trap(sig, scp, ucp, 0);  
+	END SigHandler;
+	
+	PROCEDURE InstallSignalHandler* ( h: SignalHandler );
+	BEGIN
+		trap := h;
+	END InstallSignalHandler;
+
+	
+	
+	PROCEDURE InstallHandler(sig: LONGINT);
+	VAR 
+		act: Sigaction;
+		mask: Sigset_t;
+	BEGIN
+		sigemptyset(ADDRESS OF mask);
+		act.sa_mask := mask;
+		act.sa_flags :=  SA_SIGINFO + SA_ONSTACK + SA_NODEFER;
+		act.sa_handler := ADDRESS OF SigHandler;
+		IF sigaction( sig, ADDRESS OF act, 0 ) # 0 THEN
+			Perror("sigaction");
+		END;
+
+	END InstallHandler;
+	
+	
+	PROCEDURE InitSignalHandler;
+	VAR i: LONGINT;
+	BEGIN
+		FOR i := 1 TO 15 DO
+			IF i # 9 THEN InstallHandler(i) END;
+		END;
+	END InitSignalHandler;
+	
 	
 	PROCEDURE Init;
 	VAR test: ADDRESS; 
@@ -1014,9 +1082,8 @@ VAR
 
 		getSysinfo;
 		
-		sigstk.sp := ADDRESS OF sigstack;
-		sigstk.size := LEN(sigstack);
-		sigstk.flags := {};
+		CreateSignalStack;
+		InitSignalHandler;
 		
 		TRACE("Unix init end");
 	END Init;

+ 2 - 1
source/Generic.Unix.I386.Machine.Mod

@@ -39,7 +39,7 @@ CONST
 	MaxLocks* = 11;   (* { <= 32 } *)
 	
 	MaxCPU* = 4;
-	
+	IsCooperative* = FALSE;
 
 TYPE	
 	Vendor* = ARRAY 13 OF CHAR;	
@@ -302,6 +302,7 @@ VAR
 			IF (p >= mb.beginBlockAdr) & (p <= mb.endBlockAdr) THEN  RETURN TRUE  END;  
 			mb := mb.next;  
 		END;  
+		RETURN TRUE;
 		RETURN FALSE  
 	END ValidHeapAddress;
 	

+ 34 - 15
source/Generic.Unix.Objects.Mod

@@ -64,6 +64,10 @@ VAR
 
 TYPE
 
+	LockT= POINTER TO RECORD
+		mtx, enter: ADDRESS;
+	END;
+
 	CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
 
 	ProtectedObject = POINTER TO RECORD END;
@@ -309,8 +313,11 @@ TYPE
 	(*---------------------   create,  lock,  await,  unlock   -------------------------*)
 	
 	PROCEDURE InitProtHeader( hdr: ObjectHeader );
+	VAR lock: LockT;
 	BEGIN
-		hdr.mtx := Unix.MtxInit( 0 );  hdr.enter := Unix.ConInit( 0 );  hdr.lockedBy := NIL;  
+		NEW(lock);
+		hdr.lock := lock;
+		lock.mtx := Unix.MtxInit( 0 );  lock.enter := Unix.ConInit( 0 );  hdr.lockedBy := NIL;  
 	END InitProtHeader;
 	
 	
@@ -327,51 +334,62 @@ TYPE
 	END CreateProcess;
 
 	PROCEDURE Lock*( obj: ProtectedObject;  exclusive: BOOLEAN );
-	VAR hdr: ObjectHeader;  p: Process; 
+	VAR hdr: ObjectHeader;  p: Process; lock: LockT;
 	BEGIN
 		ASSERT( exclusive );   (* shared not implemented yet *)
 		S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
+		TRACE(hdr);
 		p := CurrentProcess();
 		p.mode := AwaitingLock;
-		IF hdr.mtx = 0 THEN  InitProtHeader( hdr )  END;
-		Unix.MtxLock( hdr.mtx );
+		IF hdr.lock = NIL THEN  InitProtHeader( hdr )  END;
+		lock := S.VAL(LockT, hdr.lock);
+		Unix.MtxLock( lock.mtx );
 		WHILE hdr.lockedBy # NIL DO
 			(* wait until threads with complied AWAIT conditions have left the monitor *)
-			Unix.ConWait( hdr.enter, hdr.mtx );
+			Unix.ConWait( lock.enter, lock.mtx );
 		END;
 		p.mode := Running;  hdr.lockedBy := p;  p.waitingOn := NIL
 	END Lock;
 
 	PROCEDURE Await*( cond: Condition;  slink: ADDRESS;  obj: ProtectedObject;  flags: SET );
-	VAR hdr: ObjectHeader;  p, c: Process;
+	VAR hdr: ObjectHeader;  p, c: Process; lock: LockT;
 	BEGIN
 		IF 1 IN flags THEN  (* compiler did not generate IF *)
 			IF cond( slink ) THEN  (* condition already true *)  RETURN  END
 		END;
 		S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );  c := NIL;
+		lock := S.VAL(LockT, hdr.lock);
 		IF hdr.awaitingCond.head # NIL THEN  c := FindCondition( hdr.awaitingCond )  END;
 		
 		p := CurrentProcess();  p.succ := NIL;  p.condition := cond;  p.condFP := slink;   
 		p.waitingOn := obj;  p.mode := AwaitingCond;
 		
 		Put( hdr.awaitingCond, p );
-		
 		hdr.lockedBy := c;
-		IF c # NIL THEN  Unix.ConSignal( c.continue )  ELSE  Unix.ConSignal( hdr.enter )  END;
-		Unix.ConWait( p.continue, hdr.mtx );   
+		IF c # NIL THEN  Unix.ConSignal( c.continue )  ELSE  Unix.ConSignal( lock.enter )  END;
+		Unix.ConWait( p.continue, lock.mtx );   
 		
 		p.mode := Running;  hdr.lockedBy := p;  p.waitingOn := NIL
 	END Await;
 
 	PROCEDURE Unlock*( obj: ProtectedObject;  dummy: BOOLEAN );
-	VAR hdr: ObjectHeader;  c: Process;
+	VAR hdr: ObjectHeader;  c: Process; lock: LockT;
 	BEGIN
+		TRACE("unlock");
 		S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );  c := NIL;
+		lock := S.VAL(LockT,hdr.lock);
+		TRACE(hdr);
+		TRACE(c);
 		IF hdr.awaitingCond.head # NIL THEN  c := FindCondition( hdr.awaitingCond )  END;
+		TRACE(c);
+		TRACE("unlock2");
 		
 		hdr.lockedBy := c;
-		IF c # NIL THEN  Unix.ConSignal( c.continue )  ELSE  Unix.ConSignal( hdr.enter )  END;
-		Unix.MtxUnlock( hdr.mtx );
+		TRACE("unlock3");
+		IF c # NIL THEN  Unix.ConSignal( c.continue )  ELSE  Unix.ConSignal( lock.enter )  END;
+		TRACE("unlock4");
+		Unix.MtxUnlock( lock.mtx );
+		TRACE("unlock5");
 	END Unlock;
 	
 	
@@ -521,11 +539,12 @@ TYPE
 	END FinalizeActiveObj;
 
 	PROCEDURE FinalizeProtObject( obj: ANY );
-	VAR hdr: ObjectHeader;
+	VAR hdr: ObjectHeader; lock: LockT;
 	BEGIN
 		S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
-		IF hdr.mtx # 0 THEN
-			Unix.MtxDestroy( hdr.mtx );  hdr.mtx := 0
+		IF hdr.lock # NIL THEN
+			lock := S.VAL(LockT, hdr.lock);
+			Unix.MtxDestroy( lock.mtx );  lock.mtx := 0
 		END
 	END FinalizeProtObject;
 

+ 250 - 0
source/Generic.Unix.Traps.Mod

@@ -0,0 +1,250 @@
+(* ETH Oberon, Copyright 2000 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich.
+Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *)
+
+MODULE Traps;  (** AUTHOR "G.F."; PURPOSE "Exception Trap and symbolic debugging"; *)
+
+(* 2000.02.06	g.f.	UnixOberon release 2.3.6d	*)
+(* 2006.07.09	g.f.	UnixAos version	*)
+
+IMPORT S := SYSTEM, Trace, Glue, Unix, Objects, Machine, Heaps, Streams, Modules, Reflection, 
+		TrapWriters, Commands, StdIO;  
+
+CONST
+	AddrSize = SIZEOF( ADDRESS );
+	
+TYPE 		
+	
+	ExceptionHandler = RECORD  pc, fp, sp: ADDRESS  END;
+	
+VAR 
+	
+	TrapHandlingLevel: INTEGER;  
+	
+	trace: BOOLEAN;  
+	
+	unix: Commands.Context;
+			
+	
+	PROCEDURE Append( VAR ar: ARRAY OF CHAR;  CONST this: ARRAY OF CHAR );
+	VAR i, j: LONGINT;
+	BEGIN
+		i := 0;  j := 0;
+		WHILE ar[i] # 0X DO  INC( i )  END;
+		WHILE (i < LEN( ar ) - 1) & (this[j] # 0X) DO  ar[i] := this[j];  INC( i );  INC( j )  END;
+		ar[i] := 0X
+	END Append;
+	
+	
+	PROCEDURE TimeTag( w: Streams.Writer );
+	VAR 
+		tv: Unix.Timeval;  tz: Unix.Timezone;  t: Unix.TmPtr;  ret: LONGINT;
+			
+		PROCEDURE Int( i: LONGINT );
+		BEGIN
+			IF i < 10 THEN  w.Char( '0' )  END;
+			w.Int( i, 0 )
+		END Int;
+			
+	BEGIN
+		ret := Unix.gettimeofday( tv, tz );
+		t := Unix.localtime( tv );
+		w.Int( 1900 + t.year, 4 );  w.Char( '/' );  Int( t.mon + 1 );  w.Char( '/' );  Int( t.mday );  
+		w.String( "  " );  Int( t.hour );  w.Char( ':' );  Int( t.min );  w.Ln;
+	END TimeTag;
+	
+	
+		
+	PROCEDURE FinishTrap( w: Streams.Writer;  p: Objects.Process );
+	VAR tag: ADDRESS;  td: Modules.TypeDesc;  name: ARRAY 72 OF CHAR;
+	BEGIN
+		w.Char( 2X );   (* end of trap text *) 
+		w.Update;
+		TrapWriters.Trapped;
+			
+		IF p.obj = NIL THEN	(* the main thread is not associated with any object *)
+			Unix.exit( -1 )
+		ELSE
+			S.GET( S.VAL( ADDRESS, p.obj ) - AddrSize, tag );
+			S.GET( tag - AddrSize, td );  
+			IF td.mod # NIL THEN  
+				COPY( td.mod.name, name );  Append( name,  "." );  Append( name, td.name );
+				IF name = "Oberon.System.OberonRunner" THEN  UnlockOberon  END
+			END
+		END;
+		TrapHandlingLevel := 0;
+		Machine.Release( Machine.Trap )
+	END FinishTrap;
+	
+	
+
+	PROCEDURE Trap( sig: LONGINT;  ucp: Unix.Ucontext;  fatalerror: BOOLEAN );  
+	VAR 
+		pc, sp, bp: ADDRESS;  
+		trapno: LONGINT;  
+		process: Objects.Process;  
+		handler: ExceptionHandler;  
+		w: Streams.Writer;
+	BEGIN 
+		INC( TrapHandlingLevel ); 
+		IF trace THEN  
+			Trace.String( "Aos Trap:  signal = " );  Trace.Int( sig, 0 );  
+			Trace.String( ",  ucp = " );  Trace.Address( S.VAL( ADDRESS, ucp ) );  
+			Trace.String( ", traphandling  level = " ); Trace.Int( TrapHandlingLevel, 1 );  
+			Trace.Ln;  
+		END;  
+		
+		IF fatalerror THEN 
+			w := unix.error  
+		ELSE  
+			w := TrapWriters.GetWriter();
+			w.Char( 1X );   (* begin of trap text *) 
+		END;
+
+		w.Ln;  
+		w.String( Machine.version ); w.String( "   " );  TimeTag( w );  w.Ln; 
+		IF TrapHandlingLevel = 1 THEN  
+			IF ~fatalerror THEN  Machine.Acquire( Machine.Trap )  END;
+			w.String( "Trap " ) 
+		ELSE  
+			w.String( "[recursive Trap] " )  
+		END;  
+		CASE sig OF 
+		| 1:		w.String( "1 (Hangup signal)" );   
+		| 2:  	w.String( "2 (User interrupt)" );   
+		| 3:		w.String( "3 (Quit signal)" );   
+		| 4:  	w.String( "4 (Illegal instruction)" );   
+		| 5:   	w.String( "5." );  
+				sp := ucp.mc.r_sp;
+				S.GET( sp, trapno );  w.Int( trapno, 0 );  
+				CASE trapno OF 
+				| 1:		w.String( "  (WITH guard failed)" ) 
+				| 2:		w.String( "  (CASE invalid)" ) 
+				| 3:		w.String( "  (RETURN missing)" ) 
+				| 5:		w.String( "  (implicit type guard failed)" ) 
+				| 6:		w.String( "  (type guard failed)" ) 
+				| 7:		w.String( "  (index out of range)" ) 
+				| 8:		w.String( "  (ASSERT failed)" ) 
+				| 9:		w.String( "  (array dimension error)" ) 
+				|12:	w.String( "  (division error)" )
+				ELSE 
+					IF trapno >= 30 THEN  w.String( "  (programmed HALT)" )  
+					ELSE  w.String( "  (unknown exception)" )   
+					END  
+				END;   
+		|  8:	w.String( "8 (Arithmetic exception)" );   
+		|10: 	w.String( "10 (Bus Error)" ) 
+		|11:	w.String( "11 (Segmentation violation)" ) 
+		|13:	w.String( "13 (Broken pipe)" ) 
+		|14:	w.String( "14 (Alarm signal)" ) 
+		ELSE 
+			w.String( "(Signal " );  w.Int( sig, 0 );  w.Char( ')' );  
+		END;  
+		w.Ln;
+		IF TrapHandlingLevel = 1 THEN
+			process := Objects.CurrentProcess( ); 
+			pc := ucp.mc.r_pc;  bp := ucp.mc.r_bp;
+			IF pc = 0 THEN  
+				(* assume call of procedure variable with value NIL *)
+				S.GET( sp, pc );   (* get return address on top of stack *)
+			END;  	
+			w.Ln;
+			w.String( "    sp = " );  w.Address( sp );  w.String( ", fp = " );  w.Address( bp ); 
+			w.String( ", pc = " );  w.Address( pc );  w.Ln;  
+			w.Ln;  
+			Reflection.StackTraceBack( w, pc, bp, sp, Objects.GetStackBottom( process ), TRUE, FALSE );
+			SearchExceptionHandler( process, ucp, handler ); 
+		END;
+		w.Ln; w.Ln; 
+		w.String("----------------------------------------------------"); w.Ln; 
+		
+		IF fatalerror OR (TrapHandlingLevel > 2) THEN  Machine.Shutdown( FALSE )  END;
+		
+		FinishTrap( w, process );
+		
+		IF handler.pc # 0 THEN  
+			IF Unix.Version # "Darwin" THEN
+				(* in the Darwin port Unix.ModifyContext fails with bus error. Stack alignment problem? *)
+				w.Ln;  
+				w.String( "### program continues with exception handler ###" );   w.Ln;
+				
+				Unix.ModifyContext( ucp, handler.pc, handler.fp, handler.sp );
+				RETURN  (*! to exception handler !! *)  
+			END
+		END;
+			
+		IF Machine.standaloneAppl THEN	
+			unix.error.Ln;  unix.error.Ln;
+			unix.error.String( "### Program aborted. Stack traceback in logfile" );  unix.error.Ln;
+			unix.error.Update;
+			Machine.Shutdown( FALSE )
+		ELSIF TrapHandlingLevel > 1 THEN 
+			Objects.Terminate
+		ELSE
+			Objects.ExitTrap() 
+		END
+	END Trap;  
+	
+	
+	PROCEDURE UnlockOberon;
+	CONST OberonKernel = "Oberon.Kernel";
+	VAR c: PROCEDURE;
+	BEGIN
+		IF Modules.ModuleByName( OberonKernel ) # NIL THEN
+			GETPROCEDURE( OberonKernel, "UnlockOberon", c );
+			IF c # NIL THEN  c  END
+		END;
+	END UnlockOberon;
+	
+
+	PROCEDURE SearchExceptionHandler( process: Objects.Process;  cont: Unix.Ucontext;  VAR handler: ExceptionHandler );  
+	VAR entry, fp, sp, pc: ADDRESS;
+	BEGIN 
+		handler.pc := 0;  (* no handler *)
+		pc := cont.mc.r_pc;  fp := cont.mc.r_bp;  sp := cont.mc.r_sp;
+		IF pc = 0 THEN  
+			(* assume call of procedure variable with value NIL *)
+			S.GET( sp, pc );   (* get return address on top of stack *)
+		END;  
+		entry := Modules.GetExceptionHandler( pc );   
+		WHILE (entry = -1) & (fp <= process.stackBottom) DO  
+			S.GET( fp + AddrSize, pc );  
+			pc := pc - 1;   (*  CALL instruction, machine dependent!!! *)
+			entry := Modules.GetExceptionHandler( pc );  
+			sp := fp;   (* Save the old framepointer into the stack pointer *)
+			S.GET( fp, fp ) (* Unwind PAF *)
+		END;  
+		IF entry # -1 THEN 
+			handler.pc := entry;  handler.fp := fp;  handler.sp := sp
+		END  
+	END SearchExceptionHandler;  
+	
+	
+	PROCEDURE SignalHandler( signal: LONGINT;  scp, ucp, dummy: ADDRESS );   
+		(* 'dummy' for 16 byte stack alignment, MacOS! *)
+	BEGIN 
+		IF ~(signal IN  {1, 2, 14, 15}) (* SIGHUP, SIGINT, SIGALRM, SIGTERM *) THEN  
+			IF trace THEN  
+				Trace.String( "Traps.SignalHander: received signal " );  
+				Trace.Int( signal, 1 );  Trace.Ln  
+			END;
+			(*IF Heaps.collecting THEN  
+				Trace.Ln;  Trace.String( "PANIC: Trap " );  Trace.Int( signal, 0 );  
+				Trace.String( " in garbage collector" );  Trace.Ln;  Trace.Ln;
+				Machine.Release( Machine.Heaps );
+			
+				Trap( signal, S.VAL( Unix.Ucontext, ucp ), TRUE )  
+			ELSE  
+			*)
+				Trap( signal, S.VAL( Unix.Ucontext, ucp ), FALSE )  
+	(*		END  *)
+		END
+	END SignalHandler;  
+	
+
+
+BEGIN 
+	trace := 3 IN Glue.debug; 
+	(*Unix.Dlsym( 0, "InstallTrap", ADDRESSOF( InstallSignalHandler ) );*)
+	Unix.InstallSignalHandler( SignalHandler );
+	unix := StdIO.env
+END Traps.

+ 1 - 1
source/Unix.UnixFiles.Mod

@@ -982,7 +982,7 @@ TYPE
 		a := Unix.getenv( ADDRESSOF( "AOSPATH" ) );  i := 0;
 		IF a = 0 THEN
 			Log.String( "UnixFiles.Initialize: environment variable AOSPATH not defined" );  Log.Ln;
-			Unix.exit( 1 )
+			(* Unix.exit( 1 ) *)
 		ELSE
 			REPEAT
 				S.GET( a, ch );  INC( a );