Class: Risc::Sim

Inherits:
Object
  • Object
show all
Defined in:
lib/risc/Sim.rb

Overview

A generic discrete-event sequential simulator. This class implements a generic discrete-event sequential simulator. Sim maintains and executes a time-ordered schedule of actions (or discrete events).

Constant Summary collapse

A_Event =
0
A_Timeout =
1
A_Init =
2
A_Stop =
3
@@m_current_time =

Virtual time in the simulated world.

INIT_TIME
@@m_current_process =

Currently running process.

Process::NULL_PROCESSID
@@m_current_delay =

Duration of the current action.

INIT_TIME
@@m_running =

Is simulation running?

false
@@m_actions =
{}
@@m_processes =
{}
@@m_lock =
false

Class Method Summary collapse

Class Method Details

.advance_delay(delay) ⇒ Object

Advance the execution time of the current process. This method can be used to specify the duration of certain actions, or certain steps within the same action.



146
147
148
149
150
151
# File 'lib/risc/Sim.rb', line 146

def Sim.advance_delay(delay)
	return unless @@m_running
	pd = @@m_processes[@@m_current_process]
	pd.total_action_time += delay
	@@m_current_delay += delay
end

.clearObject

Clears out internal data structures. Resets the simulator making it available for a completely new simulation. All scheduled actions are deleted together with the associated events. All process identifiers returned by previoius invocations of link create_process(Process*,char) create_processendlink are invalidated by this operation. Notice however that it is the responsibility of the simulation programmer to delete process objects used in the simulation.



117
118
119
120
121
122
123
# File 'lib/risc/Sim.rb', line 117

def Sim.clear
	@@m_running = false
	@@m_current_time = INIT_TIME
	@@m_current_delay = INIT_TIME
	@@m_processes.clear
	@@m_actions.clear
end

.clockObject

Returns the current virtual time for the current process.



159
160
161
# File 'lib/risc/Sim.rb', line 159

def Sim.clock
	@@m_current_time + @@m_current_delay
end

.create_process(process, mode = 0) ⇒ Object

Creates a new process with the given Process object. mode specifies the execution flags of the process. If the P_SEQUENTIAL flag is set, then the process will process one event at a time with respect to the simulation virtual time, otherwise (default) the actions of this process will be considered reentrant and may be executed in parallel. By default, the simulator discards the events signalled to a P_SEQUENTIAL process while that process is busy executing other actions. The P_QUEUEING flag can be set to instruct the simulator to queue those events. In this case, the simulator will deliver signals to that process as the process is available to respond to them.



94
95
96
97
98
99
# File 'lib/risc/Sim.rb', line 94

def Sim.create_process(process,mode = 0)
	newpid = @@m_processes.size
	@@m_processes[newpid] = PDescr.new(process,mode & (P_SEQUENTIAL | P_QUEUEING))
	schedule_now(Action.new(A_Init,newpid))
	newpid
end

.run_simulationObject

Starts execution of the simulation.



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/risc/Sim.rb', line 164

def Sim.run_simulation
	# Prevents anyone from re-entering the main loop.  Note that this
	# isn't meant to be thread-safe, it works if some process calls
	# Sim::run_simulation() within their process_event() or
	# process_timeout() function.
	return if @@m_lock

	@@m_lock = true
	@@m_running = true

	# While there is at least a scheduled action...
	while (@@m_running && !@@m_actions.empty?) do
		# I'm purposely excluding any kind of checks in this version
		# of the simulator.
		# I should say something like this:
		# assert(current_time <= (*a).first);
		key = @@m_actions.keys.sort.first
		@@m_current_time = key
		actions = @@m_actions[key]
		action = actions.delete_at(0)
		@@m_actions.delete(key) if actions.empty?
		@@m_current_process = action.pid
		@@m_current_delay = 0

		# Right now I don't check if current_process is indeed a
		# valid process.  Keep in mind that this is the heart of the
		# simulator main loop, therefore efficiency is crucial.
		# Perhaps I should check.  This is somehow a design choice.
		pd = @@m_processes[@@m_current_process]
   
		if ((pd.status & P_TERMINATED) > 0) then
			# ...work in progress...
			action.event = nil
		elsif ((pd.status & P_SEQUENTIAL) > 0 && @@m_current_time < pd.available_at) then
			# This process is sequential and is currently executing
			# another action (in virtual time of course), so we
			# reschedule this action to the time the process is
			# available.
			schedule(action,pd.available_at) if ((pd.status & P_QUEUEING) > 0)
			# If the process can not queue actions, this action is simply dropped.
		else
			case action.type
				when A_Event
					pd.process.process_event(action.event)
				when A_Timeout
					pd.process.process_timeout
				when A_Init
					pd.process.init
				when A_Stop
					pd.process.stop
					pd.status |= P_TERMINATED
				else
					# Add paranoia checks/logging here?
			end
			pd.available_at = clock if ((pd.status & P_SEQUENTIAL) > 0)
		end
	end
	@@m_lock = false
end

.schedule(action, time) ⇒ Object



229
230
231
# File 'lib/risc/Sim.rb', line 229

def Sim.schedule(action,time)
	(@@m_actions[clock + time] ||= []) << action
end

.schedule_now(action) ⇒ Object



233
234
235
# File 'lib/risc/Sim.rb', line 233

def Sim.schedule_now(action)
	schedule(action,@@m_current_time)
end

.set_timeout(time) ⇒ Object

Sets a timeout for the current process. Schedules the execution of process_timeout() on the current process after the given amount of (virtual) time.



139
140
141
# File 'lib/risc/Sim.rb', line 139

def Sim.set_timeout(time)
	schedule(Action.new(A_Timeout,@@m_current_process),time)
end

.signal_event(event, pid, delay = 0) ⇒ Object

Signal an event to the given process. Signal an event to the given process. The response is scheduled for the current time.

See Also:

  • Process.process_event(Event)


129
130
131
132
133
134
# File 'lib/risc/Sim.rb', line 129

def Sim.signal_event(event,pid,delay = 0)
	pd = @@m_processes[pid]
	return -1 if pd.status & P_TERMINATED > 0
	schedule(Action.new(A_Event,pid,event),delay)
	0
end

.stop_process(pid = @@m_current_process) ⇒ Object

Stops the execution of a given process.



102
103
104
105
106
107
# File 'lib/risc/Sim.rb', line 102

def Sim.stop_process(pid = @@m_current_process)
	pd = @@m_processes[pid]
	return -1 if pd.status & P_TERMINATED > 0
	schedule_now(Action.new(A_Stop,pid))
	0
end

.stop_simulationObject

Stops execution of the simulation.



225
226
227
# File 'lib/risc/Sim.rb', line 225

def Sim.stop_simulation
	@@m_running = false
end

.this_processObject

Returns the current process.



154
155
156
# File 'lib/risc/Sim.rb', line 154

def Sim.this_process
	@@m_current_process
end