[Avida-SVN] r2789 - in branches/interrupt/source: cpu main

beckma24 at myxo.css.msu.edu beckma24 at myxo.css.msu.edu
Sun Sep 14 20:42:40 PDT 2008


Author: beckma24
Date: 2008-09-14 23:42:39 -0400 (Sun, 14 Sep 2008)
New Revision: 2789

Modified:
   branches/interrupt/source/cpu/cHardwareCPU.cc
   branches/interrupt/source/cpu/cHardwareCPU.h
   branches/interrupt/source/cpu/cOrganismThread.h
   branches/interrupt/source/main/cAvidaConfig.h
   branches/interrupt/source/main/cOrganism.h
Log:
cleaned up interrupt context switching code.  Hooked in movement interrupt code.  Still need to add code for message interrupt and move threading to software-level.  This will enable the use of multiple threading types simultaneously within a single organism

Modified: branches/interrupt/source/cpu/cHardwareCPU.cc
===================================================================
--- branches/interrupt/source/cpu/cHardwareCPU.cc	2008-09-15 02:36:57 UTC (rev 2788)
+++ branches/interrupt/source/cpu/cHardwareCPU.cc	2008-09-15 03:42:39 UTC (rev 2789)
@@ -60,6 +60,162 @@
 using namespace std;
 
 
+// Interrupt Handler code
+
+/* interrupt handling - MSG arrives, add to waiting pool, and process interrupts until all have been processed
+ 
+ ***an interrupts cannot be preempted***
+ 
+ 
+ Processing interrupt
+ Save current state
+ Push interrupt arguments into registers, i.e. MSG contents are placed in BX & CX
+ Jump 1 instruction passed MSG_received_handler_START
+ Process instructions until MSG_received_handler_END
+ On MSG_received_handler_END, process next interrupt or restore previous state
+ */
+
+void cLocalThread::saveState() {
+	assert(!interrupted);
+	// save registers
+	// save heads
+	// save thread stack
+	
+	for(int i = 0; i < NUM_REGISTERS; i++) {
+		pushedState.reg[i] = reg[i];
+	}
+	
+	for(int i = 0; i < NUM_HEADS; i++) {
+		pushedState.heads[i] = heads[i];
+	}
+	
+	pushedState.stack = stack;
+	pushedState.cur_stack = cur_stack;
+	pushedState.cur_head = cur_head;
+	pushedState.read_label = read_label;
+	pushedState.next_label = next_label;
+}
+
+void cLocalThread::restoreState() {
+	assert(!interrupted);
+	// restore registers
+	// restore heads
+	// save thread stack
+	
+	for(int i = 0; i < NUM_REGISTERS; i++) {
+		reg[i] = pushedState.reg[i];
+	}
+	
+	for(int i = 0; i < NUM_HEADS; i++) {
+		heads[i] = pushedState.heads[i];
+	}
+	
+	stack = pushedState.stack;
+	cur_stack = pushedState.cur_stack;
+	cur_head = pushedState.cur_head;
+	read_label = pushedState.read_label;
+	next_label = pushedState.next_label;
+}
+
+// push interrupt arguments into registers, i.e. MSG contents are placed in BX & CX, nothing for movement
+void cLocalThread::initializeInterruptState(const cString& handlerHeadInstructionString) {
+  for (int i = 0; i < NUM_REGISTERS; i++)
+		hardware->GetRegister(i) = 0;
+  
+  stack.Clear();
+  cur_stack = 0;
+  cur_head = nHardware::HEAD_IP;
+  read_label.Clear();
+  next_label.Clear();
+
+	
+	//Jump all heads 1 instruction passed MSG_received_handler_START
+	cInstruction label_inst = hardware->GetInstSet().GetInst(handlerHeadInstructionString);  //cStringUtil::Stringf("MSG_received_handler_END"));
+	
+	cHeadCPU search_head(hardware->IP());
+	int start_pos = search_head.GetPosition();
+	search_head++;
+	
+	while (start_pos != search_head.GetPosition()) {
+		if (search_head.GetInst() == label_inst) {
+			search_head++;  // one instruction past instruction
+			break;
+		}
+		search_head++;
+	}
+	
+	// set all other heads to same spot
+	for(int i = 0; i < NUM_HEADS; i++) {
+		hardware->GetHead(i,m_id).Set(search_head.GetPosition());
+	}
+}
+
+void cLocalThread::interruptContextSwitch(int interruptType) {
+	// note: movement interrupts cannot be blocked, just message interrupts
+	// note: movements within an interrupt handler do not cause another interrupt
+	// note: interrupt handlers can be jumped into and out of
+  // TODO: config arg to disallow jumping into and out of interrupt handler
+	
+	if(!interrupted && interruptType != cLocalThread::INTERRUPT_COMPLETE) { //normal -> interrupt
+		//Save current state
+		saveState();
+		interrupted = true;
+		
+		switch (interruptType) {
+			case cLocalThread::MSG_INTERRUPT:
+				initializeInterruptState("MSG_received_handler_START");
+				hardware->Inst_RetrieveMessage(m_world->GetDefaultContext());
+				break;
+			case cLocalThread::MOVE_INTERRUPT:
+				initializeInterruptState("Moved_handler_START");
+				break;
+			default:
+				cerr <<  "Unknown intrerrupt type " << interruptType << "  Exitting.\n\n";
+				exit(-1);
+				break;
+		}
+	}
+	else if(interrupted && interruptType == cLocalThread::INTERRUPT_COMPLETE) { // currently interrupted	
+		if(hardware->GetOrganism()->GetReceivedBufferSize() > 0) { // more messages to process
+			initializeInterruptState("MSG_received_handler_START");  // this line only affect else clause
+			hardware->Inst_RetrieveMessage(m_world->GetDefaultContext());
+		} else { // interrupt -> normal
+			interrupted = false;
+			restoreState();
+		}
+	}
+}
+
+void cLocalThread::operator=(const cLocalThread& in_thread)
+{
+  m_id = in_thread.m_id;
+  for (int i = 0; i < NUM_REGISTERS; i++) reg[i] = in_thread.reg[i];
+  for (int i = 0; i < NUM_HEADS; i++) heads[i] = in_thread.heads[i];
+  stack = in_thread.stack;
+}
+
+void cLocalThread::Reset(cWorld* world, cHardwareCPU* in_hardware, int in_id)
+{
+	m_world = world;
+	hardware = in_hardware;
+  m_id = in_id;
+  
+  for (int i = 0; i < NUM_REGISTERS; i++) reg[i] = 0;
+  for (int i = 0; i < NUM_HEADS; i++) heads[i].Reset(in_hardware);
+  
+  stack.Clear();
+  cur_stack = 0;
+  cur_head = nHardware::HEAD_IP;
+  read_label.Clear();
+  next_label.Clear();
+  
+	interrupted = false;
+	
+  // Promoter model
+  m_promoter_inst_executed = 0;
+}
+
+
 tInstLib<cHardwareCPU::tMethod>* cHardwareCPU::s_inst_slib = cHardwareCPU::initInstLib();
 
 tInstLib<cHardwareCPU::tMethod>* cHardwareCPU::initInstLib(void)
@@ -570,34 +726,6 @@
   }
 }
 
-void cLocalThread::operator=(const cLocalThread& in_thread)
-{
-  m_id = in_thread.m_id;
-  for (int i = 0; i < NUM_REGISTERS; i++) reg[i] = in_thread.reg[i];
-  for (int i = 0; i < NUM_HEADS; i++) heads[i] = in_thread.heads[i];
-  stack = in_thread.stack;
-}
-
-void cLocalThread::Reset(cWorld* world, cHardwareCPU* in_hardware, int in_id)
-{
-	m_world = world;
-  m_id = in_id;
-  
-  for (int i = 0; i < NUM_REGISTERS; i++) reg[i] = 0;
-  for (int i = 0; i < NUM_HEADS; i++) heads[i].Reset(in_hardware);
-  
-  stack.Clear();
-  cur_stack = 0;
-  cur_head = nHardware::HEAD_IP;
-  read_label.Clear();
-  next_label.Clear();
-  
-	interrupted = false;
-	
-  // Promoter model
-  m_promoter_inst_executed = 0;
-}
-
 // This function processes the very next command in the genome, and is made
 // to be as optimized as possible.  This is the heart of avida.
 
@@ -687,7 +815,7 @@
       if (m_promoters_enabled) m_threads[m_cur_thread].IncPromoterInstExecuted();
 
       if (exec == true) SingleProcess_ExecuteInst(ctx, cur_inst);
-      
+			      
       // Some instruction (such as jump) may turn m_advance_ip off.  Usually
       // we now want to move to the next instruction in the memory.
       if (m_advance_ip == true) ip.Advance();
@@ -704,7 +832,15 @@
       }
 
     } // if exec
-        
+      
+		if(m_world->GetConfig().INTERRUPT_ENABLED.Get()) {
+		static const cInstruction moveInst = GetInstSet().GetInst("move");
+			if(cur_inst == moveInst) {
+				// fire move interrupt
+				m_threads[m_cur_thread].interruptContextSwitch(cLocalThread::MOVE_INTERRUPT);
+				m_advance_ip = false;
+			}
+		}
   } // Previous was executed once for each thread...
 
   // Kill creatures who have reached their max num of instructions executed
@@ -5162,121 +5298,6 @@
 }
 
 
-
-// Interrupt Handler code
-
-/* interrupt handling - MSG arrives, add to waiting pool, and process interrupts until all have been processed
-   
- ***an interrupts cannot be preempted***
- 
- 
-Processing interrupt
- Save current state
- Push interrupt arguments into registers, i.e. MSG contents are placed in BX & CX
- Jump 1 instruction passed MSG_received_handler_START
- Process instructions until MSG_received_handler_END
- On MSG_received_handler_END, process next interrupt or restore previous state
- */
-
-void cLocalThread::saveState() {
-	assert(!interrupted);
-	// save registers
-	// save heads
-	// save thread stack
-	
-	for(int i = 0; i < NUM_REGISTERS; i++) {
-		pushedState.reg[i] = reg[i];
-	}
-	
-	for(int i = 0; i < NUM_HEADS; i++) {
-		pushedState.heads[i] = heads[i];
-	}
-	
-	pushedState.stack = stack;
-	pushedState.cur_stack = cur_stack;
-	pushedState.cur_head = cur_head;
-	pushedState.read_label = read_label;
-	pushedState.next_label = next_label;
-}
-
-void cLocalThread::restoreState() {
-	assert(interrupted);
-	// restore registers
-	// restore heads
-	// save thread stack
-
-	for(int i = 0; i < NUM_REGISTERS; i++) {
-		reg[i] = pushedState.reg[i];
-	}
-	
-	for(int i = 0; i < NUM_HEADS; i++) {
-		heads[i] = pushedState.heads[i];
-	}
-	
-	stack = pushedState.stack;
-	cur_stack = pushedState.cur_stack;
-	cur_head = pushedState.cur_head;
-	read_label = pushedState.read_label;
-	next_label = pushedState.next_label;
-}
-
-// push interrupt arguments into registers, i.e. MSG contents are placed in BX & CX, nothing for movement
-void cLocalThread::setInterruptState() {
-  for (int i = 0; i < NUM_REGISTERS; i++) hardware->GetRegister(i) = 0;
-  for (int i = 0; i < NUM_HEADS; i++) hardware->GetHead(i).Reset(hardware);///  TODO:????  // what do we do with the heads?
-  
-  stack.Clear();
-  cur_stack = 0;
-  cur_head = nHardware::HEAD_IP;
-  read_label.Clear();
-  next_label.Clear();
-}
-
-void cLocalThread::moveInstructionHeadToMSGHandler() {
-	//Jump 1 instruction passed MSG_received_handler_START
-	cInstruction label_inst = hardware->GetInstSet().GetInst("MSG_received_handler_START");  //cStringUtil::Stringf("MSG_received_handler_END"));
-	
-	cHeadCPU search_head(hardware->IP());
-	int start_pos = search_head.GetPosition();
-	search_head++;
-	
-	while (start_pos != search_head.GetPosition()) {
-		if (search_head.GetInst() == label_inst) {
-			// move IP to here
-			search_head++;
-			hardware->IP().Set(search_head.GetPosition());
-		}
-		search_head++;
-	}	
-}
-
-void cLocalThread::interruptContextSwitch() {
-	if(!interrupted) { //normal -> interrupt
-		interrupted = true;
-		//Save current state
-		saveState();
-		
-		setInterruptState();
-		hardware->Inst_RetrieveMessage(m_world->GetDefaultContext());  // if movement interrupt then registers remain zero
-
-		moveInstructionHeadToMSGHandler();
-		
-	} else { // currently interrupted
-		setInterruptState();  // this line only affect else clause
-		// note: movement interrupts cannot be blocked (just message interrupts), so following if statement is OK
-		if(hardware->Inst_RetrieveMessage(m_world->GetDefaultContext())) {  // interrupt -> normal
-			interrupted = false;
-			//restore state
-			restoreState();
-		} else {  // more messages interrupts to process
-			// thread state is set
-			// move IP to MSG_received_handler_START
-			moveInstructionHeadToMSGHandler();
-		}
-	}
-	
-}
-
 bool cHardwareCPU::moveInstructionHeadToInterruptEnd() {
 	//Jump 1 instruction passed MSG_received_handler_START
 	cInstruction label_inst = GetInstSet().GetInst("interrupt_handler_END");  //cStringUtil::Stringf("MSG_received_handler_END"));
@@ -5299,10 +5320,12 @@
 
 // jumps one instruction passed MSG_received_handler_END
 bool cHardwareCPU::Inst_MSG_received_handler_START(cAvidaContext& ctx) {
+	m_advance_ip = false;
 	return moveInstructionHeadToInterruptEnd();
 }
 
 bool cHardwareCPU::Inst_Moved_handler_START(cAvidaContext& ctx) {
+	m_advance_ip = false;
 	return moveInstructionHeadToInterruptEnd();
 }
 
@@ -5313,7 +5336,7 @@
 	 On MSG_received_handler_END, process next interrupt or restore previous state
 	 */
 	const int threadID = GetCurThread();
-	m_threads[threadID].interruptContextSwitch();
+	m_threads[threadID].interruptContextSwitch(cLocalThread::INTERRUPT_COMPLETE);
 	return true;
 }
 

Modified: branches/interrupt/source/cpu/cHardwareCPU.h
===================================================================
--- branches/interrupt/source/cpu/cHardwareCPU.h	2008-09-15 02:36:57 UTC (rev 2788)
+++ branches/interrupt/source/cpu/cHardwareCPU.h	2008-09-15 03:42:39 UTC (rev 2789)
@@ -82,13 +82,19 @@
 class cOrganism;
 class cHardwareCPU;
 
-// --------  Data Structures  --------
+
+// TODO: remove threads from hardware put in organism.
+// Imp. ideas:
+// Use organism as process which has threads that execute on top of hardware.
+// Visiter pattern for executing threads to allow an organism to have different thread types executing on single hardware type.  
+//   The same genome cannot be executed on different hardware types without major restrictions... one genome per process (multi-process organism, could be very interesting)
+
 class cLocalThread : public cOrganismThread
 {
 private:
 	cWorld* m_world;
 	int m_promoter_inst_executed;
-public:
+public:	
 	static const int NUM_REGISTERS = 3;
   static const int NUM_HEADS = nHardware::NUM_HEADS >= NUM_REGISTERS ? nHardware::NUM_HEADS : NUM_REGISTERS;
 	
@@ -101,6 +107,8 @@
 	cCodeLabel read_label;
 	cCodeLabel next_label;
 	
+	enum interruptTypes {INTERRUPT_COMPLETE = 0, MSG_INTERRUPT, MOVE_INTERRUPT};
+	
 	struct savedState {
 		int reg[NUM_REGISTERS];
 		cHeadCPU heads[NUM_HEADS];
@@ -113,7 +121,6 @@
 	};
 	
 	savedState pushedState;  //<! state of thread before interrupt
-	bool interrupted;        //<! is thread interrupted
 	cHardwareCPU* hardware;  //<! hardware that this thread is running on
 	
 	cLocalThread(cWorld* world = NULL, cHardwareCPU* in_hardware = NULL, int in_id = -1) : m_world(world), hardware(in_hardware) { Reset(world, in_hardware, in_id); }
@@ -126,19 +133,13 @@
 	void IncPromoterInstExecuted() { m_promoter_inst_executed++; }
 	void ResetPromoterInstExecuted() { m_promoter_inst_executed = 0; }
 	
-	// save registers
-	// save heads
-	// save thread stack		
-	void saveState();
 	
-	// restore registers
-	// restore heads
-	// save thread stack		
-	void restoreState();
-	void setInterruptState();
-	void interruptContextSwitch();  //!< performs context switch between normal thread execution and interrupt handler
-	void moveInstructionHeadToMSGHandler();
-	void moveInstructionHeadToInterruptEnd();
+	void saveState();  //!< saves registers, heads, and thread stack
+	void restoreState();  //!< restores thread state to preinterrupt state;  restores registers, heads, and thread stack
+	void initializeInterruptState(const cString&);  //!< sets thread state to default interrupted state
+	
+	//! Performs context switch between normal thread execution and interrupt handler.  Interrupts are handled by the currently executing thread.
+	void interruptContextSwitch(int interruptType);
 };
 
 

Modified: branches/interrupt/source/cpu/cOrganismThread.h
===================================================================
--- branches/interrupt/source/cpu/cOrganismThread.h	2008-09-15 02:36:57 UTC (rev 2788)
+++ branches/interrupt/source/cpu/cOrganismThread.h	2008-09-15 03:42:39 UTC (rev 2789)
@@ -10,18 +10,26 @@
 #ifndef cOrganismThread_h
 #define cOrganismThread_h
 
+class cString;
+
 class cOrganismThread {
 private:
 	
 protected:
 	int m_id;
+	bool interrupted;        //<! is thread interrupted
 
 public:
+	cOrganismThread() : m_id(-1), interrupted(false) {;}
+	virtual ~cOrganismThread() {;}
+	
 	int GetID() const { return m_id; }
 	void SetID(int in_id) { m_id = in_id; }
 	
-	void saveState() {;}
-	void restoreState() {;}
+	virtual void saveState() = 0;  //!< saves thread's current state
+	virtual void restoreState() = 0;  //!< restores thread's saved state
+	virtual void initializeInterruptState(const cString&) = 0;  //!< sets thread state to default interrupted state
+	virtual void interruptContextSwitch(int) = 0;  //!< performs context switch between normal thread execution and interrupt handler
 };
 
 #endif

Modified: branches/interrupt/source/main/cAvidaConfig.h
===================================================================
--- branches/interrupt/source/main/cAvidaConfig.h	2008-09-15 02:36:57 UTC (rev 2788)
+++ branches/interrupt/source/main/cAvidaConfig.h	2008-09-15 03:42:39 UTC (rev 2789)
@@ -489,6 +489,9 @@
   CONFIG_ADD_VAR(INHERIT_EXE_RATE, int, 0, "Inherit energy rate from parent? 0=no  1=yes");
   CONFIG_ADD_VAR(ATTACK_DECAY_RATE, double, 0.0, "Percent of cell's energy decayed by attack");
 
+	CONFIG_ADD_GROUP(INTERRUPT_GROUP, "Interrupt Settings");
+  CONFIG_ADD_VAR(INTERRUPT_ENABLED, bool, 0, "Enable Interrupt Model. 0/1 (off/on)");
+	
   CONFIG_ADD_GROUP(SECOND_PASS_GROUP, "Tracking metrics known after the running experiment previously");
   CONFIG_ADD_VAR(TRACK_CCLADES, int, 0, "Enable tracking of coalescence clades");
   CONFIG_ADD_VAR(TRACK_CCLADES_IDS, cString, "coalescence.ids", "File storing coalescence IDs");

Modified: branches/interrupt/source/main/cOrganism.h
===================================================================
--- branches/interrupt/source/main/cOrganism.h	2008-09-15 02:36:57 UTC (rev 2788)
+++ branches/interrupt/source/main/cOrganism.h	2008-09-15 03:42:39 UTC (rev 2789)
@@ -353,6 +353,7 @@
   //! Returns the list of all messages sent by this organism.
   const message_list_type& GetSentMessages() { InitMessaging(); return m_msg->sent; }
   
+	int GetReceivedBufferSize() const { if(!m_msg) return 0; return m_msg->received.size(); }
 protected:
   /*! Contains all the different data structures needed to support messaging within
   cOrganism.  Inspired by cNetSupport (above), the idea is to minimize impact on




More information about the Avida-cvs mailing list