《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
6.2 KiB

  1. #! /usr/bin/env python
  2. import sys
  3. from optparse import OptionParser
  4. import random
  5. # process states
  6. STATE_RUNNING = 'RUNNING'
  7. STATE_READY = 'READY'
  8. STATE_DONE = 'DONE'
  9. # members of process structure
  10. PROC_CODE = 'code_'
  11. PROC_PC = 'pc_'
  12. PROC_ID = 'pid_'
  13. PROC_STATE = 'proc_state_'
  14. # things a process can do
  15. DO_COMPUTE = 'cpu'
  16. DO_YIELD = 'yld'
  17. class scheduler:
  18. def __init__(self):
  19. # keep set of instructions for each of the processes
  20. self.proc_info = {}
  21. return
  22. def new_process(self):
  23. proc_id = len(self.proc_info)
  24. self.proc_info[proc_id] = {}
  25. self.proc_info[proc_id][PROC_PC] = 0
  26. self.proc_info[proc_id][PROC_ID] = proc_id
  27. self.proc_info[proc_id][PROC_CODE] = []
  28. self.proc_info[proc_id][PROC_STATE] = STATE_READY
  29. return proc_id
  30. def load(self, program_description):
  31. proc_id = self.new_process()
  32. tmp = program_description.split(':')
  33. if len(tmp) != 2:
  34. print 'Bad description (%s): Must be number <x:y>'
  35. print ' where X is the number of instructions'
  36. print ' and Y is the percent change that an instruction is CPU not YIELD'
  37. exit(1)
  38. num_instructions, chance_cpu = int(tmp[0]), float(tmp[1])/100.0
  39. for i in range(num_instructions):
  40. if random.random() < chance_cpu:
  41. self.proc_info[proc_id][PROC_CODE].append(DO_COMPUTE)
  42. else:
  43. self.proc_info[proc_id][PROC_CODE].append(DO_YIELD)
  44. return
  45. #change to READY STATE, the current proc's state should be expected
  46. #if pid==-1, then pid=self.curr_proc
  47. def move_to_ready(self, expected, pid=-1):
  48. #YOUR CODE
  49. return
  50. #change to RUNNING STATE, the current proc's state should be expected
  51. def move_to_running(self, expected):
  52. #YOUR CODE
  53. return
  54. #change to DONE STATE, the current proc's state should be expected
  55. def move_to_done(self, expected):
  56. #YOUR CODE
  57. return
  58. #choose next proc using FIFO/FCFS scheduling, If pid==-1, then pid=self.curr_proc
  59. def next_proc(self, pid=-1):
  60. #YOUR CODE
  61. return
  62. def get_num_processes(self):
  63. return len(self.proc_info)
  64. def get_num_instructions(self, pid):
  65. return len(self.proc_info[pid][PROC_CODE])
  66. def get_instruction(self, pid, index):
  67. return self.proc_info[pid][PROC_CODE][index]
  68. def get_num_active(self):
  69. num_active = 0
  70. for pid in range(len(self.proc_info)):
  71. if self.proc_info[pid][PROC_STATE] != STATE_DONE:
  72. num_active += 1
  73. return num_active
  74. def get_num_runnable(self):
  75. num_active = 0
  76. for pid in range(len(self.proc_info)):
  77. if self.proc_info[pid][PROC_STATE] == STATE_READY or \
  78. self.proc_info[pid][PROC_STATE] == STATE_RUNNING:
  79. num_active += 1
  80. return num_active
  81. def space(self, num_columns):
  82. for i in range(num_columns):
  83. print '%10s' % ' ',
  84. def check_if_done(self):
  85. if len(self.proc_info[self.curr_proc][PROC_CODE]) == 0:
  86. if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING:
  87. self.move_to_done(STATE_RUNNING)
  88. self.next_proc()
  89. return
  90. def run(self):
  91. clock_tick = 0
  92. if len(self.proc_info) == 0:
  93. return
  94. # make first one active
  95. self.curr_proc = 0
  96. self.move_to_running(STATE_READY)
  97. # OUTPUT: heade`[rs for each column
  98. print '%s' % 'Time',
  99. for pid in range(len(self.proc_info)):
  100. print '%10s' % ('PID:%2d' % (pid)),
  101. print ''
  102. # init statistics
  103. cpu_busy = 0
  104. while self.get_num_active() > 0:
  105. clock_tick += 1
  106. # if current proc is RUNNING and has an instruction, execute it
  107. # statistics clock_tick
  108. instruction_to_execute = ''
  109. if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING and \
  110. len(self.proc_info[self.curr_proc][PROC_CODE]) > 0:
  111. #YOUR CODE
  112. # OUTPUT: print what everyone is up to
  113. print '%3d ' % clock_tick,
  114. for pid in range(len(self.proc_info)):
  115. if pid == self.curr_proc and instruction_to_execute != '':
  116. print '%10s' % ('RUN:'+instruction_to_execute),
  117. else:
  118. print '%10s' % (self.proc_info[pid][PROC_STATE]),
  119. print ''
  120. # if this is an YIELD instruction, switch to ready state
  121. # and add an io completion in the future
  122. if instruction_to_execute == DO_YIELD:
  123. #YOUR CODE
  124. # ENDCASE: check if currently running thing is out of instructions
  125. self.check_if_done()
  126. return (clock_tick)
  127. #
  128. # PARSE ARGUMENTS
  129. #
  130. parser = OptionParser()
  131. parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
  132. parser.add_option('-l', '--processlist', default='',
  133. help='a comma-separated list of processes to run, in the form X1:Y1,X2:Y2,... where X is the number of instructions that process should run, and Y the chances (from 0 to 100) that an instruction will use the CPU or issue an YIELD',
  134. action='store', type='string', dest='process_list')
  135. parser.add_option('-p', '--printstats', help='print statistics at end; only useful with -c flag (otherwise stats are not printed)', action='store_true', default=False, dest='print_stats')
  136. (options, args) = parser.parse_args()
  137. random.seed(options.seed)
  138. s = scheduler()
  139. # example process description (10:100,10:100)
  140. for p in options.process_list.split(','):
  141. s.load(p)
  142. print 'Produce a trace of what would happen when you run these processes:'
  143. for pid in range(s.get_num_processes()):
  144. print 'Process %d' % pid
  145. for inst in range(s.get_num_instructions(pid)):
  146. print ' %s' % s.get_instruction(pid, inst)
  147. print ''
  148. print 'Important behaviors:'
  149. print ' System will switch when the current process is FINISHED or ISSUES AN YIELD'
  150. (clock_tick) = s.run()
  151. if options.print_stats:
  152. print ''
  153. print 'Stats: Total Time %d' % clock_tick
  154. print ''