Browse Source

Patched problem with processes that could not be resumed after GC (list protection).

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@8595 8c9fc860-2736-0410-a75d-ab315db34111
felixf 6 years ago
parent
commit
3169d7c35a
3 changed files with 48 additions and 28 deletions
  1. 15 19
      source/Linux.Unix.Mod
  2. 19 1
      source/Unix.Machine.Mod
  3. 14 8
      source/Unix.Objects.Mod

+ 15 - 19
source/Linux.Unix.Mod

@@ -789,7 +789,7 @@ VAR
 	VAR
 	VAR
 		attr: PThreadAttr;
 		attr: PThreadAttr;
 		id: Thread_t;
 		id: Thread_t;
-		res,i: LONGINT;
+		res: WORD;
 	CONST
 	CONST
 		PTHREAD_SCOPE_SYSTEM = 0;
 		PTHREAD_SCOPE_SYSTEM = 0;
 		PTHREAD_CREATE_DETACHED = 1;
 		PTHREAD_CREATE_DETACHED = 1;
@@ -837,12 +837,12 @@ VAR
 	PROCEDURE ThrResume*( thr: Thread_t );
 	PROCEDURE ThrResume*( thr: Thread_t );
 	VAR  res: WORD;
 	VAR  res: WORD;
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
-		res := pthread_mutex_lock( ADDRESS OF suspend_mutex );
+		res := pthread_mutex_lock(ADDRESS OF suspend_mutex );
 		resume_done := 0; 
 		resume_done := 0; 
 		res := pthread_kill( thr, T_SIGRESUME );
 		res := pthread_kill( thr, T_SIGRESUME );
+		ASSERT(res = 0);
 
 
-		WHILE (resume_done # 1)  DO ThrSleep(1); END;
-
+		WHILE (CAS(resume_done,0,0) # 1) DO ThrSleep(1) END;
 		res := pthread_mutex_unlock( ADDRESS OF suspend_mutex );
 		res := pthread_mutex_unlock( ADDRESS OF suspend_mutex );
 	END ThrResume;
 	END ThrResume;
 
 
@@ -852,23 +852,22 @@ VAR
 	VAR block: Sigset_t; res: WORD;
 	VAR block: Sigset_t; res: WORD;
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 		IF suspendHandler # NIL THEN suspendHandler( S.VAL( Ucontext, ucp) ) END;
 		IF suspendHandler # NIL THEN suspendHandler( S.VAL( Ucontext, ucp) ) END;
-	    res := sigfillset( ADDRESS OF block );
-	    sigdelset(  ADDRESS OF block, T_SIGRESUME );
-	    suspend_done := 1;   (*this is ok because ThrSuspend is protected by a mutex, so no race condidtion. It may alert the ThrSuspend too early though!*)
-	    res := sigsuspend(  ADDRESS OF block ); (* await T_SIGRESUME *)
-	    resume_done := 1; (*makes no difference if we do that here or in the resume handler*)
+		res := sigfillset( ADDRESS OF block );
+		sigdelset(  ADDRESS OF block, T_SIGRESUME );
+		ASSERT(CAS(suspend_done,0,1)=0);
+		res := sigsuspend(  ADDRESS OF block ); (* await T_SIGRESUME *)
+		ASSERT(CAS(resume_done,0,1) = 0); (*makes no difference if we do that here or in the resume handler*)
 	END suspend_handler;
 	END suspend_handler;
 
 
 	PROCEDURE ThrSuspend*(thr: Thread_t; saveContext: BOOLEAN);
 	PROCEDURE ThrSuspend*(thr: Thread_t; saveContext: BOOLEAN);
 	VAR res: WORD;
 	VAR res: WORD;
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
-	    res := pthread_mutex_lock(ADDRESS OF suspend_mutex );
-	    suspend_done := 0;
-	    res := pthread_kill( thr, T_SIGSUSPEND );
-	    WHILE (suspend_done # 1) DO ThrSleep( 1 ) END; (*this should bettr check the actual thread status!*)
-	    ThrSleep( 1 ); (*improves the probability of the suspednd actually being done*)
-	    
-	    res := pthread_mutex_unlock( ADDRESS OF suspend_mutex );
+		res := pthread_mutex_lock(ADDRESS OF suspend_mutex );
+		suspend_done := 0;
+		res := pthread_kill( thr, T_SIGSUSPEND );
+		ASSERT(res = 0); 
+		WHILE (CAS(suspend_done,0,0) # 1) DO ThrSleep( 1 ) END;  
+		res := pthread_mutex_unlock( ADDRESS OF suspend_mutex );
 	END ThrSuspend;
 	END ThrSuspend;
 
 
 
 
@@ -1084,7 +1083,6 @@ VAR
 	PROCEDURE {C} X11ErrorHandler(d: ADDRESS; err: ADDRESS): WORD;
 	PROCEDURE {C} X11ErrorHandler(d: ADDRESS; err: ADDRESS): WORD;
 	VAR res: WORD;
 	VAR res: WORD;
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
-		TRACE(d,err);
 		IF oberonXErrorHandler # NIL THEN
 		IF oberonXErrorHandler # NIL THEN
 			res := oberonXErrorHandler(d, err);
 			res := oberonXErrorHandler(d, err);
 		END;
 		END;
@@ -1094,7 +1092,6 @@ VAR
 	PROCEDURE {C} X11IOErrorHandler(d: ADDRESS): WORD;
 	PROCEDURE {C} X11IOErrorHandler(d: ADDRESS): WORD;
 	VAR res: WORD;
 	VAR res: WORD;
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
-		TRACE(d);
 		IF oberonXIOErrorHandler # NIL THEN
 		IF oberonXIOErrorHandler # NIL THEN
 			res := oberonXIOErrorHandler(d);
 			res := oberonXIOErrorHandler(d);
 		END;
 		END;
@@ -1111,7 +1108,6 @@ VAR
 	END InitXErrorHandlers;
 	END InitXErrorHandlers;
 
 
 	PROCEDURE Init;
 	PROCEDURE Init;
-	VAR test: ADDRESS; i: LONGINT; s: ARRAY 256 OF CHAR;
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 	BEGIN {UNCOOPERATIVE, UNCHECKED}
 		argc := Glue.argc;
 		argc := Glue.argc;
 		argv := Glue.argv;
 		argv := Glue.argv;

+ 19 - 1
source/Unix.Machine.Mod

@@ -37,6 +37,7 @@ CONST
 	
 	
 	MaxCPU* = 4;
 	MaxCPU* = 4;
 	IsCooperative* = FALSE;
 	IsCooperative* = FALSE;
+	StrongChecks = FALSE;
 
 
 TYPE	
 TYPE	
 	Vendor* = ARRAY 13 OF CHAR;	
 	Vendor* = ARRAY 13 OF CHAR;	
@@ -57,6 +58,7 @@ TYPE
 	
 	
 VAR
 VAR
 	mtx	: ARRAY MaxLocks OF Unix.Mutex_t;
 	mtx	: ARRAY MaxLocks OF Unix.Mutex_t;
+	taken: ARRAY MaxLocks OF ADDRESS; (* for lock order check *)
 	
 	
 	version-: ARRAY 64 OF CHAR;	(** Aos version *)
 	version-: ARRAY 64 OF CHAR;	(** Aos version *)
 	
 	
@@ -736,7 +738,7 @@ END GetTimer;
 	VAR i: LONGINT; 
 	VAR i: LONGINT; 
 	BEGIN 
 	BEGIN 
 		i := 0;  
 		i := 0;  
-		WHILE i < MaxLocks DO  mtx[i] := Unix.NewMtx( );  INC( i )  END;   
+		WHILE i < MaxLocks DO  mtx[i] := Unix.NewMtx( );  taken[i] := NIL; INC( i )  END;   
 	END InitLocks;  
 	END InitLocks;  
 
 
 	PROCEDURE CleanupLocks*;  
 	PROCEDURE CleanupLocks*;  
@@ -748,13 +750,29 @@ END GetTimer;
 	
 	
 	(** Acquire a spin-lock. *)
 	(** Acquire a spin-lock. *)
 	PROCEDURE  Acquire*( level: LONGINT );   (* non reentrant lock *)
 	PROCEDURE  Acquire*( level: LONGINT );   (* non reentrant lock *)
+	VAR i: WORD; 
 	BEGIN 
 	BEGIN 
 		Unix.MtxLock( mtx[level] );
 		Unix.MtxLock( mtx[level] );
+		IF StrongChecks THEN
+			ASSERT(taken[level] = NIL); 
+			taken[level] := Unix.ThrThis( );
+			FOR i := 0 TO level-1 DO
+				ASSERT(taken[i] # Unix.ThrThis( )); (*! lock order *)
+			END;
+		END;
 	END Acquire;  
 	END Acquire;  
 
 
 	(** Release a spin-lock. *)
 	(** Release a spin-lock. *)
 	PROCEDURE  Release*( level: LONGINT );   
 	PROCEDURE  Release*( level: LONGINT );   
+	VAR i: WORD;
 	BEGIN 
 	BEGIN 
+		IF StrongChecks THEN
+			ASSERT(taken[level] = Unix.ThrThis( )); 
+			taken[level] := NIL;
+			FOR i := 0 TO level-1 DO
+				ASSERT(taken[i] # Unix.ThrThis( )); (*! lock order *)
+			END;		
+		END;
 		Unix.MtxUnlock( mtx[level] );
 		Unix.MtxUnlock( mtx[level] );
 	END Release;  
 	END Release;  
 	
 	

+ 14 - 8
source/Unix.Objects.Mod

@@ -50,6 +50,7 @@ VAR
 	processList		: Unix.Mutex_t;
 	processList		: Unix.Mutex_t;
 	createProcess	: Unix.Mutex_t;
 	createProcess	: Unix.Mutex_t;
 	startProcess		: Unix.Mutex_t;
 	startProcess		: Unix.Mutex_t;
+	startEventLock		: Unix.Mutex_t;
 	lockMutex		: Unix.Mutex_t;
 	lockMutex		: Unix.Mutex_t;
 	childrunning		: Unix.Condition_t;
 	childrunning		: Unix.Condition_t;
 	
 	
@@ -302,8 +303,10 @@ TYPE
 				ASSERT( bodyProc # NIL );
 				ASSERT( bodyProc # NIL );
 				body := bodyProc;  
 				body := bodyProc;  
 				Unix.MtxLock( startProcess );
 				Unix.MtxLock( startProcess );
+				Unix.MtxLock( startEventLock ); (* the cond wait below opens this lock again! *)
 				threadId := Unix.ThrStart( BodyStarter, stacksize );
 				threadId := Unix.ThrStart( BodyStarter, stacksize );
-				Unix.CondWait( childrunning, startProcess );
+				Unix.CondWait( childrunning, startEventLock );
+				Unix.MtxUnlock( startEventLock );
 				Unix.MtxUnlock( startProcess );
 				Unix.MtxUnlock( startProcess );
 				RegisterFinalizer( SELF, FinalizeProcess );
 				RegisterFinalizer( SELF, FinalizeProcess );
 			ELSE 
 			ELSE 
@@ -335,13 +338,11 @@ TYPE
 				cur.state.SP := S.GetStackPointer();
 				cur.state.SP := S.GetStackPointer();
 				cur.state.BP := S.GetFramePointer();
 				cur.state.BP := S.GetFramePointer();
 				cur.state.PC := ADDRESSOF( GCLoop );
 				cur.state.PC := ADDRESSOF( GCLoop );
-					
 				SuspendActivities;
 				SuspendActivities;
 				Heaps.CollectGarbage( Modules.root );
 				Heaps.CollectGarbage( Modules.root );
-					
+				ResumeActivities;
 				Machine.Release( Machine.Heaps );
 				Machine.Release( Machine.Heaps );
 				Machine.Release( Machine.Objects );
 				Machine.Release( Machine.Objects );
-				ResumeActivities;
 				finalizerCaller.Activate;
 				finalizerCaller.Activate;
 			END;	
 			END;	
 		END SetgcOngoing;
 		END SetgcOngoing;
@@ -353,7 +354,7 @@ TYPE
 	PROCEDURE BodyStarter;
 	PROCEDURE BodyStarter;
 	VAR p: Process;  res: WORD; prevBP, sp: ADDRESS;
 	VAR p: Process;  res: WORD; prevBP, sp: ADDRESS;
 	BEGIN
 	BEGIN
-		Unix.MtxLock( startProcess );
+		Unix.MtxLock( startEventLock );
 			p := newProcess;  newProcess := NIL;
 			p := newProcess;  newProcess := NIL;
 			Unix.WriteKey( processPointer, p );
 			Unix.WriteKey( processPointer, p );
 			p.id := nextPID;  INC( nextPID );
 			p.id := nextPID;  INC( nextPID );
@@ -364,7 +365,7 @@ TYPE
 				p.nextProcess := root;  root := p;
 				p.nextProcess := root;  root := p;
 			Unix.MtxUnlock( processList );
 			Unix.MtxUnlock( processList );
 			Unix.CondSignal( childrunning );
 			Unix.CondSignal( childrunning );
-		Unix.MtxUnlock( startProcess );
+		Unix.MtxUnlock( startEventLock );
 
 
 		p.SetPriority( p.priority );
 		p.SetPriority( p.priority );
 
 
@@ -766,19 +767,22 @@ TYPE
 	PROCEDURE SuspendActivities;
 	PROCEDURE SuspendActivities;
 	VAR t, me: Process;  
 	VAR t, me: Process;  
 	BEGIN
 	BEGIN
+		Unix.MtxLock( processList ); (* no process should silently quit during global thread suspension *) 		
 		me := CurrentProcess();
 		me := CurrentProcess();
 		t := root;
 		t := root;
 		WHILE t # NIL DO
 		WHILE t # NIL DO
-			IF t # me THEN  
+			IF t # me THEN 
 				Unix.ThrSuspend( t.threadId, t.mode = Running );
 				Unix.ThrSuspend( t.threadId, t.mode = Running );
 			END;
 			END;
 			t := t.nextProcess
 			t := t.nextProcess
 		END;
 		END;
+		Unix.MtxUnlock( processList );
 	END SuspendActivities;
 	END SuspendActivities;
 
 
 	PROCEDURE ResumeActivities;
 	PROCEDURE ResumeActivities;
 	VAR t, me: Process;  
 	VAR t, me: Process;  
 	BEGIN
 	BEGIN
+		Unix.MtxLock( processList ); (* no process should silently quit during global thread suspension *) 		
 		me := CurrentProcess();
 		me := CurrentProcess();
 		t := root;
 		t := root;
 		WHILE t # NIL DO
 		WHILE t # NIL DO
@@ -787,6 +791,7 @@ TYPE
 			END;
 			END;
 			t := t.nextProcess
 			t := t.nextProcess
 		END;
 		END;
+		Unix.MtxUnlock( processList );
 	END ResumeActivities;
 	END ResumeActivities;
 	
 	
 
 
@@ -874,8 +879,9 @@ TYPE
 		Unix.suspendHandler := GetContext;
 		Unix.suspendHandler := GetContext;
 		
 		
 		createProcess := Unix.NewMtx( );  processList := Unix.NewMtx( );
 		createProcess := Unix.NewMtx( );  processList := Unix.NewMtx( );
-		startProcess := Unix.NewMtx( );  childrunning := Unix.NewCond( ); 
+		startEventLock := Unix.NewMtx( );  childrunning := Unix.NewCond( ); 
 		lockMutex := Unix.NewMtx( );
 		lockMutex := Unix.NewMtx( );
+		startProcess := Unix.NewMtx( ); 
 		
 		
 		processPointer := Unix.NewKey( );
 		processPointer := Unix.NewKey( );