IDLE = 0
WORKER = 1
HANDLERA = 2
HANDLERB = 3
DEVICEA = 4
DEVICEB = 5
MAXTASKS = 6
$layout = 0
def main()
count = Integer(ARGV.shift || 10000)
startTicks = Process.times.utime
s = Scheduler.new
s.addIdleTask(IDLE, 0, nil, count)
wkq = Packet.new(nil, WORKER, Packet::WORK)
wkq = Packet.new(wkq, WORKER, Packet::WORK)
s.addWorkerTask(WORKER, 1000, wkq)
wkq = Packet.new(nil, DEVICEA, Packet::DEVICE)
wkq = Packet.new(wkq, DEVICEA, Packet::DEVICE)
wkq = Packet.new(wkq, DEVICEA, Packet::DEVICE)
s.addHandlerTask(HANDLERA, 2000, wkq)
wkq = Packet.new(nil, DEVICEB, Packet::DEVICE)
wkq = Packet.new(wkq, DEVICEB, Packet::DEVICE)
wkq = Packet.new(wkq, DEVICEB, Packet::DEVICE)
s.addHandlerTask(HANDLERB, 3000, wkq)
s.addDeviceTask(DEVICEA, 4000, nil)
s.addDeviceTask(DEVICEB, 5000, nil)
s.schedule
stopTicks = Process.times.utime
frequency = 1000
open('testrun-times.xml', "a") do |f|
f.print "<ExternalStat>"
f.print "<size>"
f.print count
f.print "</size>"
f.print "<ticks>"
f.print( ((stopTicks - startTicks)*frequency).to_i )
f.print "</ticks>"
f.print "<ticksPerSecond>"
f.print frequency
f.print "</ticksPerSecond>"
f.print "</ExternalStat>\n"
end
print "QueueCount = #{s.queueCount}\nHoldCount = #{s.holdCount}"
end
def trace(c)
if $layout <= 0
print "\n"
$layout = 50
end
$layout -= 1
print c
end
class Scheduler
attr_reader :queueCount, :holdCount
def initialize()
@table = Array.new(MAXTASKS,nil)
@list = nil
@queueCount = 0
@holdCount = 0
end
def holdCurrent
@holdCount += 1
@currentTcb.held
@currentTcb.link
end
def queue(packet)
task = @table.at(packet.id)
if task # not nil
@queueCount += 1
packet.link = nil
packet.id = @currentId
task.checkPriorityAdd(@currentTcb,packet)
else
task
end
end
def release(id)
task = @table.at(id)
task.notHeld
if task.pri > @currentTcb.pri
task
else
@currentTcb
end
end
def schedule()
@currentTcb = @list
while @currentTcb # not nil
if @currentTcb.isHeldOrSuspended?
@currentTcb = @currentTcb.link
else
@currentId = @currentTcb.id
# trace(@currentId + 1) #TRACE
@currentTcb = @currentTcb.run
end
end
end
def suspendCurrent()
@currentTcb.suspended
end
def addDeviceTask(id,pri,wkq)
createTcb(id,pri,wkq, DeviceTask.new(self))
end
def addHandlerTask(id,pri,wkq)
createTcb(id,pri,wkq, HandlerTask.new(self))
end
def addIdleTask(id,pri,wkq,count)
createRunningTcb(id,pri,wkq, IdleTask.new(self,1,count))
end
def addWorkerTask(id,pri,wkq)
createTcb(id,pri,wkq, WorkerTask.new(self,HANDLERA,0))
end
def createRunningTcb(id,pri,wkq,task)
createTcb(id,pri,wkq,task)
@currentTcb.setRunning
end
def createTcb(id,pri,wkq,task)
@currentTcb = Tcb.new(@list,id,pri,wkq,task)
@list = @currentTcb
@table[id] = @currentTcb
end
end
class DeviceTask
def initialize(scheduler)
@scheduler = scheduler
end
def run(packet)
if packet # not nil
@v1 = packet
# trace(packet.a1.chr) #TRACE
@scheduler.holdCurrent
else
if @v1 # not nil
pkt = @v1
@v1 = nil
@scheduler.queue(pkt)
else
@scheduler.suspendCurrent
end
end
end
end
class HandlerTask
def initialize(scheduler)
@scheduler = scheduler
end
def run(packet)
if packet # not nil
if packet.kind == Packet::WORK
@v1 = packet.addTo(@v1)
else
@v2 = packet.addTo(@v2)
end
end
if @v1 # not nil
if (count = @v1.a1) < 4
if @v2 # not nil
v = @v2
@v2 = @v2.link
v.a1 = @v1.a2.at(count)
@v1.a1 = count+1
return @scheduler.queue(v)
end
else
v = @v1
@v1 = @v1.link
return @scheduler.queue(v)
end
end
@scheduler.suspendCurrent
end
end
class IdleTask
def initialize(scheduler,v1,v2)
@scheduler = scheduler
@v1 = v1
@v2 = v2
end
def run(packet)
if ( @v2 -= 1 ).zero?
@scheduler.holdCurrent
else
if (@v1 & 1).zero?
@v1 >>= 1
@scheduler.release(DEVICEA)
else
@v1 >>= 1
@v1 ^= 0xD008
@scheduler.release(DEVICEB)
end
end
end
end
class WorkerTask
ALPHA = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def initialize(scheduler,v1,v2)
@scheduler = scheduler
@v1 = v1
@v2 = v2
end
def run(packet)
if packet # not nil
@v1 =
if @v1 == HANDLERA
HANDLERB
else
HANDLERA
end
packet.id = @v1
packet.a1 = 0
packet.a2.collect! {|x|
@v2 += 1
@v2 = 1 if @v2 > 26
ALPHA[@v2]
}
@scheduler.queue(packet)
else
@scheduler.suspendCurrent
end
end
end
class Tcb
RUNNING = 0b0
RUNNABLE = 0b1
SUSPENDED = 0b10
HELD = 0b100
SUSPENDED_RUNNABLE = SUSPENDED | RUNNABLE
NOT_HELD = ~HELD
attr_reader :link, :id, :pri
def initialize(link, id, pri, wkq, task)
@link = link
@id = id
@pri = pri
@wkq = wkq
@task = task
# SUSPENDED_RUNNABLE else SUSPENDED
@state = if wkq then 0b11 else 0b10 end
end
def checkPriorityAdd(task,packet)
if @wkq # not nil
packet.addTo(@wkq)
else
@wkq = packet
@state |= 0b1 # RUNNABLE
return self if @pri > task.pri
end
task
end
def run
if @state == 0b11 # SUSPENDED_RUNNABLE
packet = @wkq
@wkq = packet.link
@state = @wkq ? 0b1 : 0b0 # RUNNABLE : RUNNING
else
packet = nil
end
@task.run(packet)
end
def setRunning
@state = 0b0 # RUNNING
end
def suspended
@state |= 0b10 # SUSPENDED
self
end
def held
@state |= 0b100 # HELD
end
def notHeld
@state &= ~0b100 # NOT_HELD
end
def isHeldOrSuspended?
#(@state & HELD) != 0 || @state == SUSPENDED
(@state & 0b100) != 0 || @state == 0b10
end
end
class Packet
DEVICE = 0
WORK = 1
attr_accessor :link, :id, :kind, :a1
attr_reader :a2
def initialize(link, id, kind)
@link = link
@id = id
@kind = kind
@a1 = 0
@a2 = Array.new(4,0)
end
def addTo(queue)
@link = nil
unless queue
self
else
nextPacket = queue
while (peek = nextPacket.link)
nextPacket = peek
end
nextPacket.link = self
queue
end
end
end
main() |