Share Pastebin
Guest
Public paste!

Untitled

By: a guest | Mar 17th, 2010 | Syntax: C | Size: 30.90 KB | Hits: 118 | Expires: Never
Copy text to clipboard
  1. /**
  2.         obj3.c
  3.  
  4.  
  5.         Simulator Project for COP 4600
  6.  
  7.         Objective 3 project that implements loading program scripts into
  8.         memory for the OS simulator.
  9.  
  10.         Revision List:
  11.                 Original Design:  Dr. David Workman, 1990
  12.                 Revised by Tim Hughey and Mark Stephens, 1993
  13.                 Revised by Wade Spires, Spring 2005
  14.                 Minor Revisions by Sean Szumlanski, Spring 2010
  15. */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "osdefs.h"
  21. #include "externs.h"
  22.  
  23. void print_free_list( );
  24.  
  25. /**
  26.         Service user logon events.
  27.  
  28.         <b> Important Notes:</b>
  29.         \li Events of type LOGON_EVT will result in this call via
  30.         Interrupt_Handler() in simulator.c after interrupt() in obj1.c sets the
  31.         global Event variable.
  32.  
  33.         <b> Algorithm: </b>
  34.         \verbatim
  35.         Allocate new Process Control Block with all fields initialized to 0
  36.  
  37.         Initialize specific PCB fields:
  38.                 Mark status as new
  39.                 Save terminal table position
  40.                 Set logon time
  41.                 Set user name
  42.  
  43.         Save PCB in global terminal table
  44.  
  45.         Initialize list of programs user will run--call Get_Script()
  46.         Execute first program of PCB--call Next_pgm()
  47.  
  48.         If objective 4 or higher, set scheduling flags:
  49.                 If no process is active in the CPU currently
  50.                         Turn off scheduling and CPU switches
  51.                 Otherwise,
  52.                         Turn on switches
  53.         \endverbatim
  54.  
  55.         @retval None
  56.  */
  57. void
  58. Logon_Service( )
  59. {
  60.                char username[USER_NAME_LENGTH + 1];
  61.                struct pcb_type* newPCB;
  62.                //Set everything to zero
  63.                newPCB = calloc( 1, sizeof( pcb_type ) );
  64.                
  65.                newPCB->status = NEW_PCB;              
  66.                newPCB->term_pos = Agent;
  67.                newPCB->logon_time = Clock;
  68.                
  69.                
  70.                //Set the user name
  71.                sprintf(username, "%d", Agent);
  72.                username[3] = username[0];
  73.                username[0] = 'U';
  74.                username[1] = '0';
  75.                username[2] = '0';
  76.                username[4] = '\0';
  77.                strcpy(newPCB->username, username);
  78.                Term_Table[Agent-1] = newPCB;
  79.                //Num_Terminals++;
  80.                Get_Script(newPCB);
  81.                
  82.                Next_pgm(newPCB);
  83.                
  84.                //newPCB->
  85.                
  86.                if(Objective >= 4) {
  87.                  //Turn on scheduling and CPU switches
  88.                  }
  89.                
  90. }
  91.  
  92. /**
  93.         Read set of all programs that a user will run.
  94.        
  95.         <b> Important Notes:</b>
  96.         \li The global va
  97.     riable Script_fp is a file pointer to the script file to
  98.         be read. It is opened by the simulator when it is initialized. Hence, it
  99.         should neither be opened nor closed in this function--only read from.
  100.         \li The script file has no specific format, that is, the names for all
  101.         programs that all users will run appear together in this file and are not
  102.         necessarily on different lines. Script names for a single user must be
  103.         repeatedly read from the file until encountering the script name "LOGOFF",
  104.         which marks the last program the user will run.
  105.         \li Since the number of scripts is unknown, it should be allocated to have
  106.         Max_Num_Scripts elements.
  107.         \li The given PCB's 'scripts' array, after allocation, must set each entry
  108.         to the script ID corresponding to each script name. Even after Get_Script()
  109.         stores all script IDs, the end of the scripts array is not explicitly
  110.         stored; however, this can still be determined as the last valid entry of the
  111.         array has the LOGOFF ID.
  112.  
  113.         <b> Algorithm: </b>
  114.         \verbatim
  115.         Allocate PCB's array of scripts
  116.         Mark index of first script
  117.  
  118.         Read each script name in file
  119.                 Capitalize script name so that case does not matter
  120.  
  121.                 Output name of the script to output file
  122.  
  123.                 Determine script ID for script name read
  124.                         Compare script name to each name in Prog_Names array
  125.                                 If names match
  126.                                 Mark ID in PCB's scripts array
  127.                 Stop reading script names when "LOGOFF" script name encountered
  128.         \endverbatim
  129.  
  130.         @param[in,out] pcb -- process control block for the script being read
  131.         @retval None
  132.  */
  133. void
  134. Get_Script( pcb_type *pcb )
  135. {
  136.  
  137.             print_out("Script for User %s is: \n", pcb->username);
  138.             char scriptToRead[9];
  139.             int len, z, scriptpos = 0;
  140.             pcb->script = calloc(Max_Num_Scripts, sizeof( prog_type ) );
  141.            
  142. //Index of first script... No idea what they want here
  143.             pcb->current_prog = 0;
  144.             fscanf(Script_fp, "%s", scriptToRead);
  145.  
  146.             //While scriptToRead != LOGOFF
  147.             while(strcmp(scriptToRead, Prog_Names[6]) != 0) {
  148.               len = strlen(scriptToRead);
  149.             //Capitalize the string
  150.                 for(z = 0; z < len; z++)
  151.                   scriptToRead[z] = toupper(scriptToRead[z]);
  152.                  
  153.             //Printing out to output file... apparently?
  154.             print_out(scriptToRead);
  155.             print_out("  ");
  156.            
  157.             for(z = 0; z < (NUM_PROGRAMS-1); z++) {
  158.                   if(strcmp(scriptToRead, Prog_Names[z]) == 0)
  159.                     pcb->script[scriptpos] = z;
  160.             }
  161.  
  162.             scriptpos++;
  163.             fscanf(Script_fp, "%s", scriptToRead);
  164.                  
  165.             }
  166.             //Has to be logoff, so set it to such
  167.             pcb->script[scriptpos] = LOGOFF;
  168.             print_out(scriptToRead);
  169.             print_out("\n\n");
  170.            
  171.            
  172. }
  173.  
  174. /**
  175.         Load the next program script for the given PCB into memory.
  176.  
  177.         <b> Important Notes:</b>
  178.         \li Despite the name of the function, the "next" program to run may
  179.         actually be the very first program script that the user wishes to run--hence
  180.         the initial check as the first step of the algorithm.
  181.  
  182.         This function makes the transition to the next program in the script
  183.         for (pcb), if there is one. A 1 is returned if the transition to the
  184.         next program is successful, a 0 otherwise. The transition is possible
  185.         only if the RB-list for the current program is empty and the script
  186.         is not empty.
  187.  
  188.         <b> Algorithm: </b>
  189.         \verbatim
  190.         If the next program is not the first program the user will run
  191.                 And
  192.         No unserviced I/O request blocks exist
  193.                 Deallocate memory used for the previous program--call Dealloc_pgm()
  194.  
  195.         If process has an unserviced I/O request block
  196.                 Do not load a new program
  197.  
  198.         If encountered last program script
  199.                 Mark PCB as terminated and do not load another program
  200.                 Calculate total time logged on
  201.  
  202.         Allocate and initialize a new segment table for the PCB's program--call Get_Memory()
  203.         If failed to allocate space (pcb->seg_table is NULL)
  204.                 Do not load another program
  205.  
  206.         Load the next program into memory--call Loader()
  207.  
  208.         Clear (set to 0) PCB's area for saving CPU information during an interrupt
  209.  
  210.         Mark PCB as ready to run
  211.  
  212.         If objective 4 or greater
  213.                 Insert process into CPU's ready queue
  214.  
  215.         Increment index position of program script for next call to Next_pgm()
  216.         \endverbatim
  217.  
  218.         @param[in,out] pcb -- PCB for which to load the next program
  219.         @retval was_new_prog_loaded -- whether a new program was loaded (1) or
  220.         not (0)
  221.  */
  222. int
  223. Next_pgm( pcb_type* pcb )
  224. {
  225.          
  226.           struct time_type* total_logon;
  227.          
  228.           if(pcb->current_prog != 0 && pcb->wait_rb == NULL)
  229.                                Dealloc_pgm(pcb);
  230.                                
  231.           if(pcb->wait_rb != NULL)
  232.                   return 0;
  233.          
  234.           if(pcb->script[pcb->current_prog] == LOGOFF) {
  235.                   pcb->status = TERMINATED_PCB;
  236.                  
  237.                   //Current time minus when the user logged on is their total
  238.                   total_logon = &Clock;
  239.                   Diff_time(&pcb->logon_time, total_logon);
  240.                   pcb->total_logon_time = *total_logon;
  241.                  
  242.                   return 0;
  243.           }
  244.          
  245.           Get_Memory(pcb);
  246.          
  247.           if(pcb->seg_table == NULL) {
  248.                             printf("SEG_TABLE IS NULL\n");
  249.             return 0;
  250.           }
  251.            
  252.          Loader(pcb);
  253.          print_out("\t\tProgram number %d, %s, has been loaded for user %s\n\n", pcb->current_prog+1, Prog_Names[ pcb->script[ pcb->current_prog]], pcb->username);
  254.          
  255.          //Set them to zeroes
  256.          pcb->cpu_save.mode = '\0';
  257.          pcb->cpu_save.pc.offset = 0;
  258.          pcb->cpu_save.pc.segment = 0;
  259.          
  260.          //PCB is now ready
  261.          pcb->status = READY_PCB;
  262.          
  263.          //Do stuff        
  264.          if(Objective >= 4) {
  265.          }
  266.          
  267.          pcb->current_prog++;
  268.          return 1;
  269.          
  270.          
  271.  
  272.                                
  273.         // temporary return value
  274.         return( 0 );
  275. }
  276.  
  277. /**
  278.         Allocate space for a new by program by reading segment table information.
  279.  
  280.         <b> Important Notes:</b>
  281.         \li The global variables Prog_Files and Prog_File_Names are arrays holding
  282.         the file pointers to all program files and the respective program names.
  283.         To access the needed program file, use the given PCB's current script ID to
  284.         index into the PCB's script array. Then use this value to index into each
  285.         array as each script entry holds a program ID of program the user is
  286.         running. More simply put, just use pcb->script[ pcb->current_prog ] to
  287.         index into either array (Prog_Files or Prog_File_Names) for the needed
  288.         program.
  289.         \li The file pointers held in Prog_Files are opened by the simulator when it
  290.         is initialized. Hence, they should neither be opened nor closed in this
  291.         function--only read from.
  292.         \li The format of each program is the same as the other "program.dat"
  293.         files as described in "intro.doc", so it is divided into two sections:
  294.         segment table information and instructions. This is the same format as
  295.         boot.dat in objective 2, except multiple programs may be in the same file
  296.         as the same program type, such as the editor program, might be used by
  297.         multiple users or multiple times by the same user.
  298.         \li Once the segment table has been allocated and constructed, memory is
  299.         allocated to each segment.
  300.         \li Note that the call to Compact_mem() in the algorithm is guaranteed to
  301.         free enough memory to load a new program since the total amount of free
  302.         space is checked prior to the function call.
  303.  
  304.         <b> Algorithm: </b>
  305.         \verbatim
  306.         Read the fields "PROGRAM" and number of segments from program file
  307.  
  308.         Allocate pcb's segment table
  309.  
  310.         Read segment table information from program file:
  311.                 For each segment in user's program
  312.                         Read "SEGMENT size_of_segment access_bits" from program file
  313.                         Set size of current segment
  314.                         Set access bits of current segment
  315.                         Increment amount of memory used
  316.                         Go to next segment in user's segment table
  317.  
  318.         If program cannot fit into memory (total amount of free space < needed size)
  319.                 Clear user's segment table, which marks allocation failure
  320.                 Return without allocating a segment
  321.  
  322.         Allocate each segment:
  323.                 For each segment
  324.                         Try to allocate a new segment and save returned base pointer position--call Alloc_seg()
  325.  
  326.                         If no space was available (invalid position returned)
  327.                                 Compact memory to eliminate external fragmentation and try to get the base pointer again--call Alloc_seg()
  328.         }
  329.         \endverbatim
  330.  
  331.         @param[in,out] pcb -- process for which to allocate segment
  332.         @retval None
  333.  */
  334. void
  335. Get_Memory( pcb_type* pcb )
  336. {
  337.               char c;
  338.    
  339.     int i;
  340.     int j;
  341.     unsigned int num_programs = 0;
  342.     unsigned int segment_size = 0;
  343.     unsigned int access_bits = 0;
  344.     char access[2];
  345.     unsigned int required_mem = 0;
  346.     int base = 0;
  347.     char read_input[10];
  348.     char program[] = "PROGRAM";
  349.     char segment[] = "SEGMENT";
  350.     struct instr_type* instruction;
  351.     struct seg_list* seglist_head;
  352.     struct seg_list* new_segment;
  353.     struct segment_type* segtable;
  354.     struct segment_type* segtemp;
  355.     struct segment_type* segtemp2;
  356.    
  357.     seglist_head = Free_Mem;
  358.    
  359.     pcb->num_segments = 0;
  360.    
  361.    
  362.     if (Prog_Files[pcb->script[pcb->current_prog]] == NULL)
  363.        return;
  364.    
  365.     fscanf(Prog_Files[pcb->script[pcb->current_prog]], "%s", read_input);
  366.     if (strcmp(read_input, program) != 0)
  367.        return;
  368.    
  369.     fscanf(Prog_Files[pcb->script[pcb->current_prog]], "%d", &num_programs);
  370.    
  371.     //pcb->seg_table = (segment_type*)malloc(sizeof(segment_type)*2);
  372.     segtable = calloc(num_programs, sizeof(segment_type));
  373.     segtemp = segtable;
  374.    
  375.     int filetmp = pcb->script[pcb->current_prog];
  376.    
  377.    
  378.     for(i = 0; i < num_programs; i++) {
  379.           //printf("PROGRAM ID: %d\n", pcb->script[pcb->current_prog]);
  380.           //c = getc(stdin);
  381.           segment_size = 0;
  382.           access_bits = 0;
  383.          
  384.           fscanf(Prog_Files[pcb->script[pcb->current_prog]], "%s", read_input);
  385.        
  386.              fscanf(Prog_Files[pcb->script[pcb->current_prog]], "%d", &segment_size);
  387.              fscanf(Prog_Files[pcb->script[pcb->current_prog]], "%x", &access_bits);
  388.              sprintf(access, "%x", access_bits);
  389.        
  390.          
  391.           segtemp[i].access = access_bits;
  392.           segtemp[i].size = segment_size;
  393.           pcb->num_segments++;
  394.           //segtemp->base = base;
  395.          
  396.          
  397.           /*
  398.           new_segment = (seg_list*)malloc(sizeof(seg_list));
  399.          
  400.          
  401.           // Add new segment of free memory to the segment list.
  402.           new_segment->base = base;
  403.           new_segment->size = Total_Free - (segment_size + base);
  404.           new_segment->next = NULL;
  405.           seglist_head->next = new_segment;
  406.           seglist_head = seglist_head->next;
  407.           */
  408.          
  409.           required_mem += segment_size;  
  410.           //printf("FILE ID: %d\n", pcb->script[pcb->current_prog]);
  411.          
  412.          
  413.     }
  414.    
  415.     //pcb->script[pcb->current_prog] = filetmp;
  416.    
  417.     pcb->seg_table = segtable;
  418.     //pcb->script[pcb->current_prog] = filetmp;
  419.    
  420.     if (required_mem > Total_Free) {
  421.                      printf("ERROR: NOT ENOUGH MEMORY\n");
  422.        for (i = 0; i <= pcb->num_segments; i++) {
  423.              segtable[i].access = 0;
  424.              segtable[i].size = -1;
  425.              segtable[i].base = -1;
  426.        }
  427.        
  428.        
  429.        
  430.        return;
  431.     }
  432.    
  433.     //int basepos = 0;
  434.    
  435.     for (j = 0; j < pcb->num_segments; j++) {
  436.           base = Alloc_seg(segtable[j].size);
  437.          
  438.           // Check for invalid memory position.
  439.           if (base < 0) {
  440.              
  441.               print_free_list();
  442.               Compact_mem();
  443.              
  444.               print_free_list();
  445.               base = Alloc_seg(segtable[j].size);
  446.           }
  447.          
  448.           segtable[j].base = base;
  449.     }
  450. }
  451.  
  452. /**
  453.         Allocate segment of given size and return base memory pointer to this
  454.         segment.
  455.  
  456.         This function searches the list of free memory segments for a segment
  457.         of at least length 'size' and returns the address of this free segment.
  458.         If the request cannot be satisfied, -1 is returned.
  459.  
  460.         <b> Important Notes:</b>
  461.         \li The head of the free list is the pointed to by the global variable
  462.         Free_Mem. The list is in order by base address of each free segment in the
  463.         list. That is, if free node A has base address 5 and free node B has base
  464.         address 10, then A precedes B in the list.
  465.         \li The base addresses held by free list nodes are integer values denoting
  466.         indices into memory. Hence, the index (array position) into memory (Mem)
  467.         held by the free list node to be used should be returned, not '&Mem[i]'.
  468.  
  469.         <b> Algorithm: </b>
  470.         \verbatim
  471.         Search free list for a block large enough to hold the segment
  472.                 If block is large enough to hold segment
  473.                         Stop searching
  474.  
  475.         If no block was large enough
  476.                 Return invalid position
  477.  
  478.         Else, if block is an exact fit
  479.                 Use free block's base address for segment
  480.  
  481.                 If block is first in list
  482.                         Set the head of the free list to the next node
  483.                 Else, segment is in middle or at end of list
  484.                         By-pass removed node in list
  485.  
  486.                 Delete node
  487.                 Decrement total amount of free memory
  488.  
  489.         Else, if block is larger than needed
  490.                 Use free block's base address for segment
  491.  
  492.                 Adjust node's size and starting position:
  493.                         Increment base address and decrement block size by given size
  494.  
  495.                 Decrement total amount of free memory
  496.         \endverbatim
  497.  
  498.         @param[in] size -- size of segment to allocate
  499.         @retval segment_base -- base address segment should begin at in memory
  500.  */
  501. int
  502. Alloc_seg( int size )
  503. {
  504.            int counter = 0, index=0;
  505.            struct seg_list* temp;
  506.            struct seg_list* prev;
  507.            
  508.            //Set temp to current head
  509.            temp = Free_Mem;
  510.            
  511.            //While not the end of the list
  512.            while(temp != NULL) {
  513.               //If it finds a free block of size less than size looking for, stop
  514.               if(temp->size >= size)
  515.                 break;
  516.               //Else keep looking, and count
  517.               else {
  518.                 prev = temp;
  519.                 temp = temp->next;
  520.                 counter++;
  521.               }
  522.            }        
  523.            //Couldn't find a fit
  524.            if(temp == NULL)
  525.              return -1;  
  526.            
  527.            //If it fits exactly
  528.            if(temp->size == size) {
  529.               index = temp->base;
  530.                //If it's at the head, skip over the head next time
  531.                if(counter == 0)
  532.                  Free_Mem = Free_Mem->next;
  533.                //Else you need to skip over this node next time
  534.                else
  535.                  prev->next = temp->next;
  536.               //Free the node and increment total free memory
  537.                
  538.               free(temp);
  539.               Total_Free = Total_Free - size;
  540.            }
  541.            
  542.            //If block's bigger than needed, update the blocks current free size
  543.            else {
  544.                 index = temp->base;
  545.                 temp->base = temp->base + size;
  546.                 temp->size = temp->size - size;
  547.                 Total_Free = Total_Free - size;
  548.            }
  549.            return index;
  550.            
  551.            
  552.         // temporary return value
  553.         return( 0 );
  554. }
  555.  
  556. /**
  557.         Load user program from file into memory.
  558.  
  559.         <b> Important Notes:</b>
  560.         \li Get_Instr() from objective 2 is used to read each instruction from the
  561.         program file. Recall that Get_Instr() accepts two parameters: a FILE ID
  562.         and an instruction. The FILE ID is an index into the array Prog_Files for
  563.         the program file to read. This index is obtained in the same manner as in
  564.         Get_Memory()--use pcb->script[ pcb->current_prog ]. The instruction is a
  565.         pointer to memory at the position in which to store the instruction for the
  566.         segment, i.e., &Mem[ base + offset ], where the base and offset are from
  567.         the user's segment, should be passed to Get_Instr().
  568.         \li The segment table, pcb->seg_table, contains the length of each segment
  569.         and where it should be loaded into memory. The number of segments is given
  570.         by pcb->num_segments.
  571.  
  572.         <b> Algorithm: </b>
  573.         \verbatim
  574.         For each segment in the user's segment table
  575.                 For each instruction in the segment
  576.                         Read instruction from program file into memory--call Get_Instr()
  577.                 Display each segment of program
  578.         \endverbatim
  579.  
  580.         @retval None
  581.  
  582.         @param[in,out] pcb -- process for which to load segments
  583.  */
  584. void
  585. Loader( pcb_type* pcb )
  586. {
  587.         struct segment_type* segtable;
  588.         struct segment_type* segtemp;
  589.         struct segment_type* segtemp2;
  590.         int d, j;
  591.         int main_memory_pos = 0;
  592.         instr_type* instruction;
  593.        
  594.         segtable = pcb->seg_table;
  595.        
  596.         for (d = 0; d < pcb->num_segments; d++) {
  597.           //loop through each program
  598.           for(j = 0; j < segtable[d].size; j++) {
  599.                 //instruction = (instr_type*)calloc(sizeof(instr_type));
  600.                 //printf("GETTING INSTRUCTION\n");
  601.                 Get_Instr(pcb->script[pcb->current_prog], &Mem[segtable[d].base+j]);
  602.                   //Mem[segtable[d].base+j] = *instruction;
  603.                   //printf("%d \n", instruction->opcode);
  604.                
  605.                 //Total_Free--;
  606.                 //Main_Memory_Pos = segtable[d].base+j
  607.                 //seglist_head->size--;
  608.                
  609.           }
  610.           Display_pgm(segtable, d, pcb);
  611.          
  612.                
  613.     }
  614. }
  615.  
  616. /**
  617.         Deallocate user's segments and segment table for current program.
  618.  
  619.         <b> Algorithm: </b>
  620.         \verbatim
  621.         For each segment
  622.                 Deallocate the segment--call Dealloc_seg()
  623.         Free segment table
  624.         \endverbatim
  625.  
  626.         @param[in,out] pcb -- process for which to deallocate segments
  627.         @retval None
  628.  */
  629. void
  630. Dealloc_pgm( pcb_type* pcb )
  631. {
  632.              
  633.              int i = 0;
  634.              //Go through number of segments and call dealloc on the base and size of each segment
  635.              for(i = 0; i < pcb->num_segments; i++) {
  636.                    Dealloc_seg(pcb->seg_table[i].base, pcb->seg_table[i].size);
  637.              }
  638.              free(pcb->seg_table);
  639.              pcb->seg_table == NULL;
  640.              
  641. }
  642.  
  643. /**
  644.         Deallocate segment at given base position and size.
  645.  
  646.         <b> Important Notes:</b>
  647.         \li The elements in the free list are ordered by the address of the segment
  648.         they represent.
  649.  
  650.         <b> Algorithm: </b>
  651.         \verbatim
  652.         Allocate and initialize a new free segment
  653.         Increment total amount of free memory
  654.  
  655.         If free list is empty
  656.                 Set new segment as the start of the free list
  657.  
  658.         Else, if new segment goes at start of list
  659.                 Set new segment as the start of the free list
  660.  
  661.         Otherwise, new segment goes in the middle or at the end of the list:
  662.                 Search free list to find segments to the left and right of the segment being freed
  663.                         If previous segment's base < new segment's base < next segment's base
  664.                                 Insert new segment between two segments in list
  665.  
  666.                 If search failed, then the new segment belongs at end of the list
  667.                         Add new segment to end of the list
  668.  
  669.         Merge adjacent segments into a single, larger segment--call Merge_seg()
  670.         \endverbatim
  671.  
  672.         @param[in] base -- position in memory (Mem array)
  673.         @param[in] size -- size of memory block being freed
  674.         @retval None
  675.  */
  676. void
  677. Dealloc_seg( int base, int size )
  678. {
  679.              struct seg_list* new_seg;
  680.              struct seg_list* head;
  681.              struct seg_list* prev;
  682.              struct seg_list* cur;
  683.              
  684.              new_seg = malloc(sizeof(struct seg_list));
  685.              
  686.              if(base == 82)
  687.              printf("Base is 82\n");
  688.              
  689.              head = Free_Mem;
  690.              prev = NULL;
  691.              
  692.              new_seg->base = base;
  693.              new_seg->size = size;
  694.              new_seg->next = NULL;
  695.              
  696.              Total_Free = Total_Free + size;
  697.              
  698.              //There is no free mem
  699.              if(Free_Mem == NULL) {
  700.                Free_Mem = new_seg;
  701.                return;
  702.              }
  703.              //If it's before the current head
  704.              else if(new_seg->base < Free_Mem->base) {
  705.                new_seg->next = Free_Mem;
  706.                Free_Mem = new_seg;
  707.                          if(Objective == 3)
  708.                          print_free_list();
  709.                Merge_seg(new_seg, new_seg->next, prev);
  710.                          if(Objective == 3)
  711.                          print_free_list();
  712.              }
  713.              
  714.              else {
  715.                   prev = head;
  716.                   cur = head->next;
  717.                  
  718.                   while(cur != NULL) {
  719.                      //printf("DEALLOCATE LOOP\n");
  720.                      //If the new segment base is less than cur, put it before it.
  721.                      if(new_seg->base < cur->base) {
  722.                        prev->next = new_seg;
  723.                        new_seg->next = cur;
  724.                        break;
  725.                      }
  726.                      prev = cur;
  727.                      cur = cur->next;
  728.                   }
  729.                   //If it went through loop, at end of it
  730.                   if(cur == NULL)
  731.                   prev->next = new_seg;
  732.                  
  733.                          if(Objective == 3)
  734.                          print_free_list();
  735.              Merge_seg(prev, new_seg, new_seg->next);
  736.                          if(Objective == 3)
  737.                          print_free_list();
  738.              }
  739.                  
  740.                      
  741.                  
  742.                  
  743.              
  744. }
  745.  
  746. /**
  747.         Merge adjacent free blocks into a single, larger block (if possible).
  748.  
  749.         For example, suppose the newly freed segment starts at position 5 and ends
  750.         at 10 while the next free segment starts at 11 and ends at 20. Then these
  751.         two segments would be merged into a single segment starting at 5 and ending
  752.         at 20.
  753.  
  754.         <b> Important Notes:</b>
  755.         \li The elements in the free list are ordered by the address of the segment
  756.         they represent.
  757.         \li The total amount of free memory does not change due to merging.
  758.         \li The new segment added to memory, via Dealloc_seg(), is given as the
  759.         second parameter. Either prev_seg or next_seg (or both) may be NULL, but
  760.         the algorithm accounts for this and does not attempt to merge.
  761.  
  762.         <b> Algorithm: </b>
  763.         \verbatim
  764.  
  765.         If the previous free segment is not invalid
  766.                 And
  767.         The new free segment follows directly after the previous segment
  768.                 Add the new segment's size to the previous segment
  769.                 Set previous segment's next link to new segment's next link
  770.                 Free node representing new segment
  771.                 Set new segment pointer to previous segment
  772.  
  773.         If the next free segment is not invalid
  774.                 And
  775.         The new free segment directly precedes the next segment
  776.                 Add the next segment's size to the new segment
  777.                 Set new segment's next link to next segment's next link
  778.                 Free node representing next segment
  779.         \endverbatim
  780.  
  781.         @param[in,out] prev_seg -- segment before new_seg to potentially merge
  782.         with new_seg
  783.         @param[in,out] new_seg -- new segment added to memory
  784.         @param[in,out] next_seg -- segment after new_seg to potentially merge with
  785.         new_seg
  786.         @retval None
  787.  */
  788. void
  789. Merge_seg( seg_list* prev_seg, seg_list* new_seg, seg_list* next_seg )
  790. {
  791.            printf("Entering Merge Seg\n");
  792.            //As long as they aren't both null
  793.            if(prev_seg != NULL && new_seg != NULL) {  
  794.              //If the next segments base is right where previous one ends        
  795.              if((prev_seg->base + prev_seg->size) == new_seg->base) {
  796.                 prev_seg->size = prev_seg->size + new_seg->size;
  797.                 prev_seg->next = new_seg->next;
  798.                 free(new_seg);
  799.                 new_seg = prev_seg;
  800.              }
  801.            }
  802.            
  803.            if(next_seg != NULL) {
  804.              if((new_seg->base + new_seg->size) == next_seg->base) {
  805.                 new_seg->size = new_seg->size + next_seg->size;
  806.                 new_seg->next = next_seg->next;
  807.                 free(next_seg);
  808.              }                
  809.            }
  810. }
  811.  
  812.  
  813. /**
  814.         Service end program events.
  815.  
  816.         <b> Important Notes:</b>
  817.         \li Events of type END_EVT will result in this call via
  818.         Interrupt_Handler() in simulator.c after interrupt() in obj1.c sets the
  819.         global Event variable.
  820.         \li The PCB status DONE_PCB is not the same as TERMINATED_PCB. Only the
  821.         current program is ended, but the user's PCB may still be active as the user
  822.         may be running multiple programs.
  823.  
  824.         <b> Algorithm: </b>
  825.         \verbatim
  826.         Retrieve PCB associated with program from terminal table
  827.         Mark pcb as done
  828.         Remove PCB from CPU's active process
  829.  
  830.         Calculate active time for process and busy time for CPU
  831.    Record time process became blocked
  832.  
  833.         If objective 4 or higher
  834.                 Deallocate all I/O request blocks associated with PCB--call Purge_rb()
  835.  
  836.         If the PCB has no outstanding I/O request blocks
  837.                 Load the next program for the user--call Next_pgm()
  838.  
  839.         If objective 4 or higher
  840.                 Turn both the scheduling and CPU switches on in order to retrieve the next process to run
  841.         \endverbatim
  842.  
  843.         @retval None
  844.  */
  845. void
  846. End_Service( )
  847. {
  848.              struct pcb_type* endPCB;
  849.              struct time_type* totaltime;
  850.              //endPCB = calloc( 1, sizeof( pcb_type ) );
  851.              endPCB = Term_Table[Agent-1];
  852.              
  853.              endPCB->status = DONE_PCB;
  854.              CPU.active_pcb = NULL;
  855.              
  856.              //Add PCBS total busy time to the CPUs
  857.              Add_time(&endPCB->total_busy_time, &CPU.total_busy_time);
  858.              
  859.              //Calculate the PCBs total active time
  860.              totaltime = &endPCB->total_logon_time;
  861.              Diff_time(&endPCB->total_busy_time, totaltime);
  862.              Diff_time(&endPCB->total_block_time, totaltime);
  863.              endPCB->total_run_time = *totaltime;
  864.              
  865.              //The PCB was blocked at this time in the clock.
  866.              endPCB->block_time = Clock;
  867.              int current_prog;
  868.              current_prog = endPCB->current_prog;
  869.              
  870.              print_out("Program %d, %s", endPCB->current_prog, Prog_Names[endPCB->script[endPCB->current_prog]]);
  871.              print_out(" has ended for user ");
  872.              print_out(endPCB->username);
  873.              print_out(".\n CPU burst was 0 instructions.\n ", endPCB->seg_table->size);
  874.              
  875.              //Do Stuff
  876.              if(Objective >= 4) {
  877.              }
  878.              
  879.              if(endPCB->wait_rb == NULL)
  880.               Next_pgm(endPCB);
  881.              
  882.              //Do Stuff
  883.              if(Objective >= 4) {
  884.              }
  885. }          
  886.  
  887. /**
  888.         Service segmentation fault and address fault events.
  889.  
  890.         <b> Important Notes:</b>
  891.         \li This function services causes an abnormal end to the simulated program.
  892.         \li Events of type SEGFAULT_EVT and ADRFAULT_EVT will result in this call
  893.         via Interrupt_Handler() in simulator.c after interrupt() in obj1.c sets the
  894.         global Event variable.
  895.         \li Use print_out() function for output.
  896.  
  897.         <b> Algorithm: </b>
  898.         \verbatim
  899.         Print output message indicating that process was terminated due to some abnormal condition
  900.         Call End_Service() to handle terminating process.
  901.         \endverbatim
  902.  
  903.         @retval None
  904.  */
  905. void
  906. Abend_Service( )
  907. {
  908.                
  909.                print_out("Process was terminated due to some abnormal condition\n");
  910.                End_Service();
  911. }
  912.  
  913. /**
  914.         Print contents of free list.
  915.  
  916.         <b> Important Notes:</b>
  917.         \li This function should be useful for debugging and verifying memory
  918.         allocation and deallocation functions, especially Merge_seg().
  919.  
  920.         <b> Algorithm: </b>
  921.         \verbatim
  922.         For each free block
  923.                 Print base position and last position in block
  924.         \endverbatim
  925.  */
  926. void print_free_list( )
  927. {
  928.      printf("Entering Print List\n");
  929.      
  930.      struct seg_list* temp;
  931.      
  932.      temp = Free_Mem;
  933.      while(temp != NULL) {
  934.      printf("Base: %d Last Position in block: %d \n", temp->base, (temp->base + temp->size));
  935.      temp = temp->next;
  936.      }
  937. }
  938.  
  939. /**
  940.         Print debugging message about Term_Table.
  941.  
  942.         <b> Important Notes:</b>
  943.         \li The debugging message is only printed if the variable DEBUG_PCB is
  944.         turned on (set to 1). This is done by adding the following line to
  945.         config.dat: <br>
  946.         DEBUG_PCB= ON
  947.         \li The function is not necessary to implement as it serves only to help
  948.         the programmer in debugging the implementation of common data structures.
  949.  
  950.         @retval None
  951.  */
  952. void
  953. Dump_pcb( )
  954. {
  955.         // if debug flag is turned on
  956.         if( DEBUG_PCB )
  957.         {
  958.                 /* print debugging message */
  959.         }
  960.         else // do not print any message
  961.         { ; }
  962. }