Search code examples
calgorithmoperating-systemschedulinground-robin

Round Robin Implementation with Different Arrival Time


I have created a Round Robin Algorithm with C. The output I get for 5 processes with the same arrival time is correct but incorrect for different arrival times. Below is an example,

RRB.C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>

typedef struct Process {
    int burst_time;
    int arrival_time;
    int remaining_time;
    double wait_time;
    double turnaround_time;
    double response_time;
} Process;

Process *processes;

// Function to check if input is a valid non-negative integer
int check_is_int(char input[10]) {
    char *endptr;
    int num = strtol(input, &endptr, 10);

    if ((!isspace(*endptr) && *endptr != 0) || num < 0) {
        return -1; // Return -1 for invalid input
    }

    return num; // Return the integer if input is valid
}

// Function to calculate the response time of each process
void calc_response_time(int i) {
    int prev_process_cpu_time = processes[i - 1].burst_time - processes[i - 1].remaining_time;
    processes[i].response_time = processes[i - 1].response_time + prev_process_cpu_time;
}

// Function to simulate the execution of a process by the CPU
void execute_process(int i, int time_slice, double *utilised_cpu_time, int *num_processes_completed, double *total_wait_time, double *total_turnaround_time, double *total_response_time) {
    if (processes[i].remaining_time > time_slice) {
        *utilised_cpu_time += time_slice;
        processes[i].remaining_time -= time_slice;
    } else if (processes[i].remaining_time <= time_slice) {
        *utilised_cpu_time += processes[i].remaining_time;
        processes[i].remaining_time = 0;
        processes[i].turnaround_time = *utilised_cpu_time;
        processes[i].wait_time = *utilised_cpu_time - processes[i].burst_time;

        *total_wait_time += processes[i].wait_time;
        *total_turnaround_time += processes[i].turnaround_time;
        *total_response_time += processes[i].response_time;

        (*num_processes_completed)++;
    }
}

// Function to print header for process timings
void print_header() {
    printf("PROCESS\t\tBurst Times\t\tArrival Times\t\tWaiting Times\t\tTurnaround Times\t\tResponse Times\n");
}

// Function to print timings for an individual process
void print_process_timings(int i, int burst_time, int arrival_time, double wait_time, double turnaround_time, double response_time) {
    printf("P%d\t\t\t%d\t\t\t\t%d\t\t\t\t%.0f\t\t\t\t%.0f\t\t\t\t%.0f\n", i + 1, burst_time, arrival_time, wait_time, turnaround_time, response_time);
}

int main(void) {
    char input[12];
    bool first_run = true;
    int num_processes_completed = 0;
    double utilised_cpu_time = 0;
    double total_wait_time = 0;
    double total_turnaround_time = 0;
    double total_response_time = 0;

    // Print introduction
    printf("CPU scheduling method: Round Robin (RR)\n\n");

    // Prompt user to enter the number of processes
    printf("Enter the number of processes: ");
    fgets(input, sizeof(input), stdin);

    int num_processes = check_is_int(input); // Check if input is valid
    printf("\n");

    if (num_processes == -1) { // Check if input is invalid
        printf("Please input a valid non-negative integer!\n");
        return 1;
    }

    processes = (Process *)malloc(num_processes * sizeof(Process)); // Allocate memory for processes
    if (processes == NULL) { // Check if memory allocation failed
        printf("Memory allocation failed!\n");
        return 1;
    }

    // Input burst times and arrival times for each process
    for (int i = 0; i < num_processes; i++) {
        printf("Enter Burst Time for process %d: ", i + 1);
        fgets(input, sizeof(input), stdin);
        int burst_time = check_is_int(input); // Check if input is valid

        printf("Enter Arrival Time for process %d: ", i + 1);
        fgets(input, sizeof(input), stdin);
        int arrival_time = check_is_int(input); // Check if input is valid

        printf("\n");

        if (burst_time < 0 || arrival_time < 0) { // Check if input is invalid
            printf("Please input valid non-negative integers!\n");
            free(processes);
            return 1;
        } else {
            // Initialize a new process instance
            Process p;
            p.response_time = 0;
            p.arrival_time = arrival_time;
            p.turnaround_time = 0;
            p.wait_time = 0;
            p.burst_time = burst_time;
            p.remaining_time = burst_time;
            processes[i] = p;
        }
    }

    // Input the size of time slice
    printf("Enter the size of time slice: ");
    fgets(input, sizeof(input), stdin);
    printf("\n");

    int time_slice = check_is_int(input); // Check if input is valid
    if (time_slice == -1) { // Check if input is invalid
        printf("Please input a valid non-negative integer!\n");
        free(processes);
        return 1;
    }

    print_header(); // Print header for process timings

    // Execute processes and calculate timings
    for (int i = 0; i < num_processes; i++) {
        if (processes[i].remaining_time != 0) {
            execute_process(i, time_slice, &utilised_cpu_time, &num_processes_completed, &total_wait_time, &total_turnaround_time, &total_response_time);
        }

        if (i > 0 && first_run) {
            calc_response_time(i);
            if (i == num_processes - 1) {
                first_run = false;
            }
        }

        if (i == num_processes - 1 && num_processes_completed < num_processes) {
            i = -1; // Reset loop if there are outstanding processes
        } else if (num_processes_completed == num_processes) {
            break; // Exit loop if all processes are completed
        }
    }

    // Print timings for each process
    for (int i = 0; i < num_processes; i++) {
        print_process_timings(i, processes[i].burst_time, processes[i].arrival_time, processes[i].wait_time, processes[i].turnaround_time, processes[i].response_time);
    }

    printf("\n");
    // Print average waiting time, turnaround time, and response time
    printf("Average Waiting Time: %.1f\n", total_wait_time / (double)num_processes);
    printf("Average Turnaround Time: %.1f\n", total_turnaround_time / (double)num_processes);
    printf("Average Response Time: %.1f\n", total_response_time / (double)num_processes);

    free(processes); // Free allocated memory for processes
    return 0;
}

Output for Different Arrival Time

CPU scheduling method: Round Robin (RR)

Enter the number of processes: 5

Enter Burst Time for process 1: 45
Enter Arrival Time for process 1: 0

Enter Burst Time for process 2: 90
Enter Arrival Time for process 2: 5

Enter Burst Time for process 3: 70
Enter Arrival Time for process 3: 8

Enter Burst Time for process 4: 38
Enter Arrival Time for process 4: 15

Enter Burst Time for process 5: 55
Enter Arrival Time for process 5: 20

Enter the size of time slice: 10

PROCESS                 Burst Times                     Arrival Times                   Waiting Times                   Turnaround Times                        Response Times
P1                      45                              0                               158                             203                             0
P2                      90                              5                               208                             298                             10
P3                      70                              8                               208                             278                             20
P4                      38                              15                              150                             188                             30
P5                      55                              20                              203                             258                             40

Average Waiting Time: 185.4
Average Turnaround Time: 245.0
Average Response Time: 20.0

However, according to https://process-scheduling-solver.boonsuen.com/, the average waiting time and average turnaround time are 173.2 and 232.8 respectively, which differs from my output. I've tried to tweak my code but am still unable to figure out why my average waiting time and average turnaround time. Please help to correct my code if there's any discrepancy. Thanks.


Solution

  • This is a bit screwy. I'm not sure I have a definitive answer for this.

    The TL;DR is that I think the website may be off (more on that later).

    However, there are issues with your code ...

    1. Your main loop is [AFAICT] incorrect:
      • It assumes that by the time a given process is executed, that the master clock is greater than the arrival time.
      • This is true for your given example with arrival times of: 0, 5, 8, 15, 20
      • This would fail (e.g.) at T30 if D had an arrival time of T50 instead of T15
    2. No need to use double -- int is fine.
    3. Output has so many tabs that it's hard to read.
    4. You're only printing the final result. If the process state were printed on each iteration, it would show the history (that could be matched against the website's gantt chart).
    5. The intermediate results deviate almost immediately.
    6. There are a number of "loose" variables (e.g. utilised_cpu_time, total_turnaround_time, etc). The code can be simplified by putting these in a struct and just passing around a single pointer to the struct.
    7. You're doing a lot of (e.g.) processes[i].whatever instead of defining a pointer (e.g.) Process *p = &processes[i]; and then using p->whatever.
    8. In your main loop, you do i = -1; in the middle to start over. This a bit hacky. The clean(er) way is to have nested loops.

    Here is input to the website:

    Input data


    Here is the website's Gantt chart: gantt chart

    The issue: [I could be completely wrong about this, but] At time T30, process D is runnable (and so is E), so the sequence should start out with:

    A B C D E A B C D E
    

    But, the gantt chart's sequence is:

    A B C A D E B
    

    In other words, the website did not think that D was runnable.

    So, maybe, the website's notion of "arrival time" is different (or it has a bug of some sort?).


    Here is the website's final result

    webfinal

    This doesn't match up too well with either the results of your program (or your program as restructured by me).


    Based on all the issues I mentioned above, I had to restructure your code [quite] a bit.

    1. I was doing this a little bit at a time as I reviewed your code and tried to understand its logic.
    2. I cleaned and simplified things that I thought might be issues.
    3. I redid the main loop to accomodate the issue [I perceived] with not honoring delays due to arrival time.
    4. Note that I [probably] broke the "response time" calculations in calc_response_time
    5. I think the remainder of the code is okay, but, I could have broken other things as well ...
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <ctype.h>
    #include <string.h>
    #include <errno.h>
    #include <termios.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    typedef struct Process {
        int pidx;
    
        int arrival_time;
        int burst_time;
        int finish_time;
    
        int remaining_time;
    
        int wait_time;
        int turnaround_time;
        int response_time;
    
        int first_run;
        int pgive;
    } Process;
    
    Process *processes;
    
    typedef struct {
        int slice_numproc;                  // number of processes
        int slice_quantum;                  // length of time slice
        int slice_remainder;                // remainder of current time slice
    
        int slice_round;                    // slice round
        int slice_clock;                    // current time (utilised_cpu_time)
        int slice_start;                    // start time
        int slice_pcur;                     // index of current process
    
        int slice_completed;                // number of completed processes
        Process slice_ptot;                 // totals
    } Slice;
    
    void print_process_timings(Process *p,Slice *slice,int nlflg);
    void print_header(const char *msg);
    void prtint(int val);
    void prtrnge(int v1,int v2);
    void prtsep(const char *msg);
    
    // Function to calculate the response time of each process
    void
    calc_response_time(Process *pold,Process *pcur)
    {
    
        int prev_process_cpu_time = pold->burst_time - pold->remaining_time;
        pcur->response_time = pold->response_time + prev_process_cpu_time;
    
        pcur->first_run = 0;
    }
    
    // Function to simulate the execution of a process by the CPU
    #if 0
    void
    execute_process(int i, int time_slice, double *utilised_cpu_time, int *num_processes_completed, double *total_wait_time, double *total_turnaround_time, double *total_response_time)
    {
        if (processes[i].remaining_time > time_slice) {
            *utilised_cpu_time += time_slice;
            processes[i].remaining_time -= time_slice;
        }
        else if (processes[i].remaining_time <= time_slice) {
            *utilised_cpu_time += processes[i].remaining_time;
            processes[i].remaining_time = 0;
            processes[i].turnaround_time = *utilised_cpu_time;
            processes[i].wait_time = *utilised_cpu_time - processes[i].burst_time;
    
            *total_wait_time += processes[i].wait_time;
            *total_turnaround_time += processes[i].turnaround_time;
            *total_response_time += processes[i].response_time;
    
            (*num_processes_completed)++;
        }
    }
    #else
    void
    execute_process(Process *p, Slice *slice)
    {
        int pgive = slice->slice_quantum;
    
        if (pgive > p->remaining_time)
            pgive = p->remaining_time;
    
        int doneflg = (pgive >= p->remaining_time);
    
        slice->slice_clock += pgive;
        p->remaining_time -= pgive;
    
        p->pgive = pgive;
    
        if (doneflg) {
            p->wait_time = slice->slice_clock - p->burst_time;
            p->finish_time = slice->slice_clock;
            p->turnaround_time = p->finish_time - p->arrival_time;
    
            Process *ptot = &slice->slice_ptot;
    
            ptot->wait_time += p->wait_time;
            ptot->turnaround_time += p->turnaround_time;
            ptot->response_time += p->response_time;
    
            slice->slice_completed += 1;
        }
    }
    #endif
    
    // process_old -- Execute processes and calculate timings
    void
    process_old(Slice *slice)
    {
        int first_run = 1;
    
        for (int i = 0; i < slice->slice_numproc; i++) {
            Process *pcur = &processes[i];
    
    #if 0
            if (processes[i].remaining_time != 0) {
                execute_process(i,time_slice,
                    &utilised_cpu_time,&num_processes_completed,&total_wait_time,
                    &total_turnaround_time,&total_response_time);
            }
    #else
            if (pcur->remaining_time != 0)
                execute_process(pcur,slice);
    #endif
    
            if (i > 0 && first_run) {
                calc_response_time(pcur - 1,pcur);
                if (i == slice->slice_numproc - 1) {
                    first_run = false;
                }
            }
    
            if (i == slice->slice_numproc - 1 &&
                slice->slice_completed < slice->slice_numproc) {
                // Reset loop if there are outstanding processes
                i = -1;
            }
            else if (slice->slice_completed == slice->slice_numproc) {
                // Exit loop if all processes are completed
                break;
            }
        }
    }
    
    void
    process_new(Slice *slice)
    {
        Process *pold = NULL;
    
    #if 0
        print_header();
    #endif
    
        slice->slice_round = 0;
    
        while (slice->slice_round < 100) {
            Process *pcur = &processes[slice->slice_pcur];
    
            do {
                // process is done
                if (pcur->remaining_time == 0)
                    break;
    
                slice->slice_start = slice->slice_clock;
    
                // process not yet started
                if (slice->slice_start < pcur->arrival_time)
                    break;
    
                execute_process(pcur,slice);
    
                if ((pold != NULL) && pcur->first_run)
                    calc_response_time(pold,pcur);
                pold = pcur;
    
                if ((slice->slice_round % slice->slice_numproc) == 0)
                    print_header(NULL);
    
                print_process_timings(pcur,slice,0);
                printf("\n");
            } while (0);
    
            // Exit loop if all processes are completed
            if (slice->slice_completed >= slice->slice_numproc)
                break;
    
            // try next in round robin
            slice->slice_pcur += 1;
            slice->slice_pcur %= slice->slice_numproc;
        }
    }
    
    int getstr(char *buf,int buflen,const char *prompt);
    long getnum_strtol(const char *prompt);
    
    int
    main(int argc,char **argv)
    {
        //char input[12];
    #if 0
        bool first_run = true;
        int num_processes_completed = 0;
        double utilised_cpu_time = 0;
        double total_wait_time = 0;
        double total_turnaround_time = 0;
        double total_response_time = 0;
    #endif
    
        --argc;
        ++argv;
    
        if (argc > 0) {
            close(0);
            open(*argv,O_RDONLY);
        }
    
        Slice slice = { 0 };
    
        // Print introduction
        printf("CPU scheduling method: Round Robin (RR)\n\n");
    
        // Prompt user to enter the number of processes
        slice.slice_numproc = getnum_strtol("Enter the number of processes");
        printf("\n");
    
        if (slice.slice_numproc == -1) {
            printf("Please input a valid non-negative integer!\n");
            return 1;
        }
    
        // Allocate memory for processes
        processes = calloc(slice.slice_numproc,sizeof(Process));
        // Check if memory allocation failed
        if (processes == NULL) {
            printf("Memory allocation failed!\n");
            return 1;
        }
    
        // Input burst times and arrival times for each process
        char prompt[100];
        for (int i = 0; i < slice.slice_numproc; i++) {
            Process *p = &processes[i];
            p->pidx = i;
    
            sprintf(prompt,"Enter Burst Time for process %d", i + 1);
            p->burst_time = getnum_strtol(prompt);
    
            sprintf(prompt,"Enter Arrival Time for process %d", i + 1);
            p->arrival_time = getnum_strtol(prompt);
    
            printf("\n");
    
            // Check if input is invalid
            if (p->burst_time < 0 || p->arrival_time < 0) {
                printf("Please input valid non-negative integers!\n");
                free(processes);
                return 1;
            }
    
            p->response_time = 0;
            p->turnaround_time = 0;
            p->wait_time = 0;
            p->remaining_time = p->burst_time;
            p->first_run = 1;
    
    #if 0
            else {
                // Initialize a new process instance
                Process p;
    
                p.response_time = 0;
                p.arrival_time = arrival_time;
                p.turnaround_time = 0;
                p.wait_time = 0;
                p.burst_time = burst_time;
                p.remaining_time = burst_time;
                processes[i] = p;
            }
    #endif
        }
    
        // Input the size of time slice
        slice.slice_quantum = getnum_strtol("Enter the size of time slice");
    
        // Check if input is invalid
        if (slice.slice_quantum <= 0) {
            printf("Please input a valid non-negative integer!\n");
            free(processes);
            return 1;
        }
    
        prtsep("INITIAL CONDITIONS");
        print_header(NULL);
        for (int i = 0; i < slice.slice_numproc; i++) {
            Process *p = &processes[i];
            print_process_timings(p,&slice,1);
        }
    
        prtsep("HISTORY/GANTT");
    
        process_new(&slice);
    
        // Print timings for each process
        // Print header for process timings
        prtsep("FINAL");
        print_header(NULL);
        for (int i = 0; i < slice.slice_numproc; i++) {
            Process *p = &processes[i];
            print_process_timings(p,&slice,1);
        }
        print_process_timings(&slice.slice_ptot,&slice,1);
    
        printf("\n");
    
        // Print average waiting time, turnaround time, and response time
        printf("Average Waiting Time: %.1f\n",
            slice.slice_ptot.wait_time / (double) slice.slice_numproc);
        printf("Average Turnaround Time: %.1f\n",
            slice.slice_ptot.turnaround_time / (double) slice.slice_numproc);
        printf("Average Response Time: %.1f\n",
            slice.slice_ptot.response_time / (double) slice.slice_numproc);
    
        // Free allocated memory for processes
        free(processes);
    
        return 0;
    }
    
    struct phdr {
        const char *str;
        int len;
        int off;
        void (*prt)(struct phdr *phdr,Process *p,Slice *slice);
    };
    
    void
    prtround(struct phdr *phdr,Process *p,Slice *slice)
    {
        prtint(slice->slice_round++);
    }
    
    void
    prtclock(struct phdr *phdr,Process *p,Slice *slice)
    {
        prtrnge(slice->slice_start,slice->slice_clock - 1);
    }
    
    #define OFFOF(_sym) \
        ((size_t) &((Process *) 0)->_sym)
    #define PHDR2(_str,_sym) \
        { .str = _str, .off = OFFOF(_sym) }
    #define PHDRX(_str,_fnc) \
        { .str = _str, .off = -1, .prt = _fnc }
    struct phdr hdrlist[] = {
        PHDR2("P(i)",pidx),
        PHDR2("Arrival Time",arrival_time),
        PHDR2("Burst Time",burst_time),
        PHDR2("Finish Time",finish_time),
        PHDR2("Turn Around",turnaround_time),
        PHDR2("Wait Time",wait_time),
        PHDR2("Resp Time",response_time),
        PHDR2("Remain Time",remaining_time),
        PHDR2("Give",pgive),
    #if 1
        PHDRX("Round",prtround),
        PHDRX("Clock Range",prtclock),
    #endif
    };
    
    #define countof(_arr) \
        (sizeof(_arr) / sizeof(_arr[0]))
    
    #define PHDRFOR \
        struct phdr *phdr = &hdrlist[0]; \
        phdr < &hdrlist[countof(hdrlist)]; \
        ++phdr
    
    const char *
    phdrstr(struct phdr *phdr,int idxneed)
    {
    
        static char buf[100];
        strcpy(buf,phdr->str);
    
        char *bp = buf;
        const char *tok = NULL;
    
        for (int idxcur = 0;  ;  ++idxcur) {
            tok = strtok(bp," ");
            if (tok == NULL)
                break;
            bp = NULL;
            if (idxcur == idxneed)
                break;
        }
    
        if (tok == NULL) {
            buf[0] = 0;
            tok = buf;
        }
    
        return tok;
    }
    
    void
    pfill(struct phdr *phdr,int len)
    {
    
        for (;  len < phdr->len;  ++len)
            fputc(' ',stdout);
    
        printf("  ");
    }
    
    // Function to print header for process timings
    void
    print_header(const char *msg)
    {
        const char *str;
        int iline;
    
        printf("\n");
    
        static int count = 0;
        if (count == 0) {
            for (PHDRFOR) {
                iline = 0;
                phdr->len = 0;
    
                while (1) {
                    str = phdrstr(phdr,iline++);
                    if (str[0] == 0)
                        break;
    
                    if (iline > count)
                        count = iline;
    
                    int curlen = strlen(str);
                    if (curlen > phdr->len)
                        phdr->len = curlen;
                }
            }
        }
    
        if (msg != NULL)
            printf("%s\n",msg);
    
        for (iline = 0;  iline < count;  ++iline) {
            for (PHDRFOR) {
                str = phdrstr(phdr,iline);
                int len = printf("%s",str);
                pfill(phdr,len);
            }
            printf("\n");
        }
    }
    
    int pidx;
    
    void
    prtint(int val)
    {
    
        struct phdr *phdr = &hdrlist[pidx++];
        int len = printf("%d",val);
        pfill(phdr,len);
    }
    
    void
    prtrnge(int v1,int v2)
    {
    
        struct phdr *phdr = &hdrlist[pidx++];
        int len = printf("%d-%d",v1,v2);
        pfill(phdr,len);
    }
    
    void
    prtsym(struct phdr *phdr,Process *p,Slice *slice)
    {
        void *vp = p;
        vp += phdr->off;
        int *valp = vp;
    
        if (phdr->prt != NULL)
            phdr->prt(phdr,p,slice);
        else
            prtint(*valp);
    }
    
    void
    prtsep(const char *msg)
    {
        int len = strlen(msg);
        int margin = 80 - len - 2;
        margin /= 2;
    
        printf("\n");
    
        int col = 0;
    
        for (int wid = margin;  wid > 0;  --wid, ++col)
            printf("-");
    
        col += printf(" %s ",msg);
    
        for (;  col < 80;  ++col)
            printf("-");
    
        printf("\n");
    }
    
    // Function to print timings for an individual process
    void
    print_process_timings(Process *p, Slice *slice, int nlflg)
    {
    
        pidx = 0;
    
        for (PHDRFOR)
            prtsym(phdr,p,slice);
    
    #if 0
        prtint(i + 1);
        prtint(p->arrival_time);
        prtint(p->burst_time);
        prtint(p->finish_time);
    
        prtint(p->turnaround_time);
        prtint(p->wait_time);
        prtint(p->response_time);
    
        prtrnge(p->remaining_time + p->pgive,p->remaining_time);
        prtint(p->pgive);
    #endif
    
        if (nlflg)
            printf("\n");
    }
    
    // getstr -- get a string with prompt
    // RETURNS: length or (<0 -> error)
    int
    getstr(char *buf,int buflen,const char *prompt)
    {
        char *cp;
        int ret = 0;
    
        // decide if stdin is:
        // (1) a TTY
        // (2) a [redirected] file (e.g. invoked with ./myprogram < input)
        static int echoflg = -1;
        if (echoflg < 0) {
            struct termios tio;
            echoflg = (tcgetattr(fileno(stdin),&tio) < 0);
        }
    
        // NOTE: usage of the error codes in errno.h is arbitrary
    
        while (ret <= 0) {
            // ensure buffer has enough space
            if (buflen < 2) {
                ret = -ENOMEM;
                break;
            }
    
            // output prompt
            printf("%s: ",prompt);
            fflush(stdout);
    
            // get a line
            cp = fgets(buf,buflen,stdin);
    
            // EOF
            if (cp == NULL) {
                ret = -ENODATA;
                break;
            }
    
            // echo file input to simulate TTY input
            if (echoflg)
                fputs(buf,stdout);
    
            // get buffer length
            ret = strlen(buf);
    
            // empty string
            if (ret <= 0)
                continue;
    
            // point to last char
            cp = &buf[ret - 1];
    
            // ensure we got a newline -- if not, fgets had to chop the line (i.e.)
            // the line is too long to fit in the buffer
            if (*cp != '\n') {
                ret = -ENOSPC;
                break;
            }
    
            // strip the newline -- we are done
            *cp = 0;
            --ret;
        }
    
        return ret;
    }
    
    // getnum_strtol -- get number using strtol
    long
    getnum_strtol(const char *prompt)
    {
        int len;
        int readflg = 1;
        char *cp;
        char buf[100];
        long num = 0;
    
        while (readflg) {
            len = getstr(buf,sizeof(buf),prompt);
    
            if (len < 0)
                exit(1);
    
            num = strtol(buf,&cp,10);
    
            // ensure we got a least one digit
            if (cp <= buf)
                continue;
    
            switch (*cp) {
            case ' ':
            case '\t':
            case 0:
                readflg = 0;
                break;
            default:
                printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'\n",
                    buf,cp);
                break;
            }
        }
    
        return num;
    }
    
    // getnum_manual -- get number _not_ using strtol
    long
    getnum_manual(const char *prompt)
    {
        int len;
        int readflg = 1;
        int sign = 0;
        int valid;
        int chr;
        char *cp;
        char buf[100];
        long num = 0;
    
        while (readflg) {
            len = getstr(buf,sizeof(buf),prompt);
    
            // fatal error
            if (len < 0)
                exit(1);
    
            // point to buffer start
            cp = buf;
    
            // find first non-whitespace character
            valid = 0;
            while (1) {
                chr = *cp;
    
                // end of string
                if (chr == 0)
                    break;
    
                // found character
                valid = ((chr != ' ') && (chr != '\t'));
                if (valid)
                    break;
    
                ++cp;
            }
            if (!valid)
                continue;
    
            // reset the accumlated number and the sign
            num = 0;
            sign = 0;
            valid = 0;
    
            // loop through all characters in buffer
            while (1) {
                chr = *cp++;
    
                // get the sign of the number (and skip an explicit sign)
                if (sign == 0) {
                    switch (chr) {
                    case '+':
                        sign = 1;
                        chr = *cp++;
                        break;
                    case '-':
                        sign = -1;
                        chr = *cp++;
                        break;
                    default:
                        sign = 1;
                        break;
                    }
                }
    
                // stop decoding number on whitespace
                switch (chr) {
                case ' ':
                case '\t':
                    chr = 0;
                    break;
                }
    
                // check for clean end of number
                if (chr == 0) {
                    if (valid) {
                        readflg = 0;
                        break;
                    }
                }
    
                // not a valid digit
                if (!isdigit((unsigned char) chr)) {
                    cp -= 1;
                    printf("getnum_manual: not a valid number -- buffer '%s', invalid '%s'\n",
                        buf,cp);
                    break;
                }
    
                // add digit to number
                num *= 10;
                chr -= '0';
                num += chr;
    
                // we got at least one valid digit
                valid = 1;
            }
        }
    
        // apply sign
        num *= sign;
    
        return num;
    }
    

    In the code above, I've used cpp conditionals to denote old vs. new code:

    #if 0
    // old code
    #else
    // new code
    #endif
    
    #if 1
    // new code
    #endif
    

    Note: this can be cleaned up by running the file through unifdef -k


    Here is the program input file I used:

    5
    45
    0
    90
    5
    70
    8
    38
    15
    55
    20
    10
    

    Here is the program output:

    CPU scheduling method: Round Robin (RR)
    
    Enter the number of processes: 5
    
    Enter Burst Time for process 1: 45
    Enter Arrival Time for process 1: 0
    
    Enter Burst Time for process 2: 90
    Enter Arrival Time for process 2: 5
    
    Enter Burst Time for process 3: 70
    Enter Arrival Time for process 3: 8
    
    Enter Burst Time for process 4: 38
    Enter Arrival Time for process 4: 15
    
    Enter Burst Time for process 5: 55
    Enter Arrival Time for process 5: 20
    
    Enter the size of time slice: 10
    
    ------------------------------ INITIAL CONDITIONS ------------------------------
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     0       0       0     0     45      0     0      0--1
    1     5        90     0       0       0     0     90      0     1      0--1
    2     8        70     0       0       0     0     70      0     2      0--1
    3     15       38     0       0       0     0     38      0     3      0--1
    4     20       55     0       0       0     0     55      0     4      0--1
    
    -------------------------------- HISTORY/GANTT ---------------------------------
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     0       0       0     0     35      10    0      0-9
    1     5        90     0       0       0     10    80      10    1      10-19
    2     8        70     0       0       0     20    60      10    2      20-29
    3     15       38     0       0       0     30    28      10    3      30-39
    4     20       55     0       0       0     40    45      10    4      40-49
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     0       0       0     50    25      10    5      50-59
    1     5        90     0       0       0     10    70      10    6      60-69
    2     8        70     0       0       0     20    50      10    7      70-79
    3     15       38     0       0       0     30    18      10    8      80-89
    4     20       55     0       0       0     40    35      10    9      90-99
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     0       0       0     50    15      10    10     100-109
    1     5        90     0       0       0     10    60      10    11     110-119
    2     8        70     0       0       0     20    40      10    12     120-129
    3     15       38     0       0       0     30    8       10    13     130-139
    4     20       55     0       0       0     40    25      10    14     140-149
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     0       0       0     50    5       10    15     150-159
    1     5        90     0       0       0     10    50      10    16     160-169
    2     8        70     0       0       0     20    30      10    17     170-179
    3     15       38     188     173     150   30    0       8     18     180-187
    4     20       55     0       0       0     40    15      10    19     188-197
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     203     203     158   50    0       5     20     198-202
    1     5        90     0       0       0     10    40      10    21     203-212
    2     8        70     0       0       0     20    20      10    22     213-222
    4     20       55     0       0       0     40    5       10    23     223-232
    1     5        90     0       0       0     10    30      10    24     233-242
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    2     8        70     0       0       0     20    10      10    25     243-252
    4     20       55     258     238     203   40    0       5     26     253-257
    1     5        90     0       0       0     10    20      10    27     258-267
    2     8        70     278     270     208   20    0       10    28     268-277
    1     5        90     0       0       0     10    10      10    29     278-287
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    1     5        90     298     293     208   10    0       10    30     288-297
    
    ------------------------------------ FINAL -------------------------------------
    
    P(i)  Arrival  Burst  Finish  Turn    Wait  Resp  Remain  Give  Round  Clock
          Time     Time   Time    Around  Time  Time  Time                 Range
    0     0        45     203     203     158   50    0       5     31     288-297
    1     5        90     298     293     208   10    0       10    32     288-297
    2     8        70     278     270     208   20    0       10    33     288-297
    3     15       38     188     173     150   30    0       8     34     288-297
    4     20       55     258     238     203   40    0       5     35     288-297
    0     0        0      0       1177    927   150   0       0     36     288-297
    
    Average Waiting Time: 185.4
    Average Turnaround Time: 235.4
    Average Response Time: 30.0