/*
  sample solution to hw3:  banker's algorithm

  I haven't thoroughly tested this yet -- it does work on the example
  from the assignment, though.

  Note a couple of compile-time options:

  -DEBUG will turn on debugging output
  -NDEBUG will turn off assertion checking
  
*/
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>

typedef enum {FALSE=0, TRUE=1} Bool;

/*
  utility function to keep from duplicating code on syscall returns.
*/
void crash(char *message)
{
    perror(message);
    exit(1);
}

/******************************************************************************
  Definition of resource vectors.  I need an empty constructor, an input
  constructor, a copy constructor, and a function to print the vector
  (this last is only for debugging.  So, I'll print to stderr), and a
  destructor.

  I'm being just a bit sloppy here and in resource matrices, as I'm
  just going to directly use [] operators to access the elements and
  I'm not going to store the size of the vector in the data structure.

  Something I'm being very careful about is making sure my parameters
  are good, even at the cost of redundant checks.
*/
typedef int *ResourceVector;

/*
  default constructor.

  Pass it the number of resources to be managed by the program
*/
ResourceVector RV_new(int resources)
{
    ResourceVector newVector;

    assert(resources > 0);
    
    if ((newVector = calloc(resources, sizeof(int))) == NULL)
        crash("RV_new calloc");

    return newVector;
}

/*
  copy constructor.

  It uses the default constructor to create a new resource vector, and
  then copies the complete contents of the old vector to the newly
  created vector.  The new vector is returned
*/
ResourceVector RV_copy(ResourceVector old, int resources)
{
    ResourceVector new;
    int i;
    
    assert(old != NULL);
    assert(resources > 0);

    new = RV_new(resources);
    for (i = 0; i < resources; i++)
        new[i] = old[i];

    return(new);
}

/*
  input constructor

  Again, the default constructor is used to allocate space for the
  vector; then, the contents of the vector are read from stdin
*/
ResourceVector RV_read(int resources)
{
    ResourceVector newVector;
    int i;

    assert(resources >  0);
    
    newVector = RV_new(resources);

    for (i = 0; i < resources; i++)
        if (scanf("%d", &newVector[i]) != 1)
            crash("RV_read scanf");

    return newVector;
}

/*
  print routine

  prints the contents of a resource vector (for debugging only)
*/
void RV_print(ResourceVector vector, int resources)
{
    int i;

    assert(vector != NULL);
    assert(resources > 0);
    
    for (i = 0; i < resources; i++) {
        if (i > 0)
            putchar(' ');
        printf("%d", vector[i]);
    }
    printf("\n");
}

/*
  destructor
*/
void RV_free(ResourceVector vector)
{
    assert(vector != NULL);
    free(vector);
}

/******************************************************************************
  And I also need to define resource allocation matrices.  As with
  resource vectors, I need a default constructor, a copy constructor,
  an input constructor, a print function, and a destructor.

  Allocation matrices are built on top of resource vectors; each row
  of an allocation matrix is a resource vector.
*/
typedef ResourceVector *ResourceMatrix;

/*
  If the number of resources is non-zero, I'll allocate the vectors.
  If not, I'll assume the caller has another trick up their sleeve.
  This is to make it easier to implement the copy and input
  constructors in terms of the resource vectors.
*/
ResourceMatrix RM_new(int processes, int resources)
{
    ResourceMatrix newMatrix;
    int i;

    assert(processes > 0);
    assert(resources >= 0);
    
    if ((newMatrix = calloc(processes, sizeof(ResourceVector))) == NULL)
        crash("RM_new calloc");

    if (resources > 0)
        for (i = 0; i < processes; i++)
            newMatrix[i] = RV_new(resources);
    
    return newMatrix;
}

/*
  Create a new resource matrix using RM_new(), and then fill its rows
  using RV_copy
*/
ResourceMatrix RM_copy(ResourceMatrix old, int processes, int resources)
{
    ResourceMatrix new;
    int process;

    assert(old != NULL);
    assert(processes > 0);
    assert(resources > 0);
    
    new = RM_new(processes, 0);
    
    for (process = 0; process < processes; process++)
        new[process] = RV_copy(old[process], resources);

    return new;
}

/*
  Create a new resource matrix using RM_new(), and then fill its rows
  using RV_read()
*/
ResourceMatrix RM_read(int processes, int resources)
{
    int i;
    ResourceMatrix newMatrix;

    assert(processes > 0);
    assert(resources > 0);

    newMatrix = RM_new(processes, 0);
    
    for (i = 0; i < processes; i++)
        newMatrix[i] = RV_read(resources);

    return newMatrix;
}

/*
  print the rows of the matrix using RV_print.  This is also for
  debugging only
*/
void RM_print(ResourceMatrix matrix, int processes, int resources)
{
    int i;

    assert(matrix != NULL);
    assert(processes > 0);
    assert(resources > 0);
    
    for (i = 0; i < processes; i++)
        RV_print(matrix[i], resources);
}

/*
  first get rid of all the rows, then get rid of the matrix
*/
void RM_free(ResourceMatrix matrix, int processes)
{
    int process;

    assert(matrix != NULL);
    assert(processes > 0);

    for (process = 0; process < processes; process++)
        RV_free(matrix[process]);
    free(matrix);
}

/******************************************************************************
  Last datatype I need is a resource allocation request.  It'll have
  to specify which process wants what resource, and how many units.

  Let's see...  I'll need a read constructor and a destructor.  As above,
  I'll be a bit sloppy and access the fields directly

*/

typedef struct ResourceRequest *ResourceRequest;
struct ResourceRequest {
    int process;
    int resource;
    int quantity;
    ResourceRequest next;
};

/*
  Default constructor.  I pass the value for the next pointer.  The
  only reason this constructor is really needed is for when I set up
  my pending requests list; all other times, the resource request is
  read using RR_read().  Note, though, that it is implemented using
  this constructor (since I had to write this one anyway).
*/
ResourceRequest RR_new(ResourceRequest next)
{
    ResourceRequest newRequest;

    if ((newRequest = calloc(1, sizeof (struct ResourceRequest))) == NULL)
        crash("RR_new malloc");
    
    newRequest->next = next;
    
    return newRequest;
}

/*
  Allocate a resource request and read it from stdin.  Also, echo the
  request.

  If we request process -1 it's time to terminate; we'll report this to
  the caller with a NULL request.
*/
ResourceRequest RR_read(ResourceRequest next)
{
    ResourceRequest newRequest;

    newRequest = RR_new(next);
    
    if (scanf("%d%d%d",
              &newRequest->process,
              &newRequest->resource,
              &newRequest->quantity) != 3)
              crash("RR_read scanf");
    printf("R %d %d %d\n",
           newRequest->process,
           newRequest->resource,
           newRequest->quantity);

    assert(newRequest->process >= -1);
    assert(newRequest->resource >= 0);

    if (newRequest->process == -1) {
        free(newRequest);
        newRequest = NULL;
    }

    return newRequest;
}

/*
  Destructor
*/
void RR_free(ResourceRequest oldRequest)
{
    assert(oldRequest != NULL);
    
    free(oldRequest);
}

/******************************************************************************
  code to grant a resource request.  This isn't called until after a
  decision has been made to grant the request, so it should always be
  possible.  We will, however, put a little bit of error-checking code
  in here so that we'll crash if we try to grant more resource
  requests than we have resources.

  We have to distinguish between real requests and trial requests.  A
  real request will print the results, consume the request, and return
  the next request in the RR queue.  A trial won't do the print, and
  will return the request itself
*/
#define FORREAL TRUE
#define NOTFORREAL FALSE
ResourceRequest RR_grant(ResourceRequest request,
                         ResourceMatrix allocations,
                         ResourceVector available,
                         Bool forreal)
{
    ResourceRequest retReq;
    
    assert(allocations != NULL);
    assert(available != NULL);
    assert(request != NULL);
    assert(request->process >= 0);
    assert(request->resource >= 0);
    
    available[request->resource] -= request->quantity;
    allocations[request->process][request->resource] += request->quantity;

    assert(available[request->resource] >= 0);

    if (forreal) {
        printf("G %d %d %d\n",
               request->process,
               request->resource,
               request->quantity);
		retReq = request->next;
		free(request);
    } else
        retReq = request;

    return retReq;
}

/*
  And... the banker's algorithm!
*/

Bool banker(ResourceRequest request,
            ResourceMatrix maxClaim,
            ResourceMatrix allocations,
            ResourceVector available,
            int processes, int resources)
{
    ResourceMatrix allocprime;
    ResourceVector availprime;
    Bool *marked, progress, procCanTerminate;
    int numMarked;
    int process;
    int resource;

    assert(request != NULL);
    assert(maxClaim != NULL);
    assert(allocations != NULL);
    assert(available != NULL);
    
    assert(processes > 0);
    assert(resources > 0);
    assert((allocations[request->process][request->resource] +
            request->quantity) <=
           maxClaim[request->process][request->resource]);

#ifdef EBUG
	printf("Trying %d %d %d\n", request->process, request->resource, request->quantity);
#endif
    /*
      We can always grant a "request" for a negative quantity, and
       can never grant a request for more than the total amount of the
       resource.  I don't remember off-hand whether the algorithm
       allows partial grants of resources, but it can't be a good
       idea:  the requesting process remains blocked, and the total
       amount of resources available goes down.
    */
    if (request->quantity < 0)
        return TRUE;
    else if (available[request->resource] < request->quantity )
        return FALSE;
    else {

        /*
          And, the algorithm itself.  First, we make copies of the
          allocation and available tables, so we can try all this in
          the copies without affecting the real data.
        */
        allocprime = RM_copy(allocations, processes, resources);
        availprime = RV_copy(available, resources);

        /*
          As we determine a process can terminate, we mark it.  We
          keep track of the number of marked processes
        */
        marked = calloc(sizeof(Bool), processes);
        numMarked = 0;

        /*
          "grant" the request in the copy of the allocation table
        */
        RR_grant(request, allocprime, availprime, NOTFORREAL);

        /*
          Keep going through this loop looking for processes that can
          run to completion, and take away their resources (in the
          trial table, not the real one).  As long as each pass
          through the loop keeps finding more processes that can
          finish, we keep going.  Eventually we've either found a way
          they can all terminate, or we stop making progress.

          At that point, we either report TRUE or FALSE
        */
        do {
            progress = FALSE;

            /* so, for each process ... */
            for (process = 0; process < processes; process++)
                /* ... that isn't already marked ... */
                if (!marked[process]) {
                    procCanTerminate = TRUE;
                    /* ... for each resource ... */
                    for (resource = 0; resource < resources; resource++)
                        /* ... can we allocate our whole max claim? */
                        if ((maxClaim[process][resource] -
                             allocprime[process][resource]) >
                            availprime[resource])
                            procCanTerminate = FALSE;
                    
                    /* if we can ... */
                    if (procCanTerminate) {
                        /* ... we release all its resources ... */
                        for (resource = 0; resource < resources; resource++) {
                            availprime[resource] +=
                              allocprime[process][resource];
                            allocprime[process][resource] = 0;
                        }
                        /* ... mark the process, and update our count */
                        marked[process] = TRUE;
                        numMarked++;
                        progress = TRUE;
#ifdef EBUG
                        printf("Process %d can terminate\n", process);
#endif
                        
                    }
                }
        } while ((progress == TRUE) && (numMarked < processes));

#ifdef EBUG
        for (process = 0; process < processes; process++)
            if (!marked[process])
                printf("Process %d CANNOT terminate\n", process);
#endif
        /*
          Free our temporaries.
        */
        free(marked);
        RM_free(allocprime, processes);
        RV_free(availprime);

        if (numMarked < processes)
            return FALSE;
        else
            return TRUE;
    }
}

int main()
{
    int processes, resources;
    ResourceVector existingResources, available;
    ResourceMatrix maxClaim, allocations;
    ResourceRequest pendingRequestsHead, pendingRequestsTail, pendingRequest, newRequest;
    
    /*
      read the numbers of processes and resources, and read the
      existingResources vector and maxClaim table
    */

    scanf("%d%d", &processes, &resources);
    
    existingResources = RV_read(resources);
    maxClaim = RM_read(processes, resources);

    /*
      create an empty current allocations table, and mark all
      resources as available
    */
    available = RV_copy(existingResources, resources);
    allocations = RM_new(processes, resources);

    /*
      create an empty pending request to use as a queue header
    */
    pendingRequestsHead = RR_new(NULL);
    pendingRequestsTail = pendingRequestsHead;
    
#ifdef EBUG
    printf("Existing Resources:\n");
    RV_print(existingResources, resources);
    printf("\n\nMax Claim:\n");
    RM_print(maxClaim, processes, resources);
    printf("\n\n");
#endif

    newRequest = RR_read(NULL);
    while (newRequest != NULL) {
        if (banker(newRequest, maxClaim, allocations, available,
                   processes, resources)) {
            RR_grant(newRequest, allocations, available, FORREAL);

            /*
              Any time we successfully grant a request, we'll go
              through the list and see if we can grant any others.  We
              won't actually succeed unless the request was to free
              resources, but efficiency isn't a really big deal here
            */
			pendingRequest = pendingRequestsHead;
			while (pendingRequest->next != NULL) {
                if (banker(pendingRequest->next,
                           maxClaim, allocations, available,
                           processes, resources)) {
                    /*
                      a little bit of special case code if we're going
                      to delete the last element in the list
                    */
                    if (pendingRequest->next == pendingRequestsTail)
                        pendingRequestsTail = pendingRequest;
                    
                    pendingRequest->next = RR_grant(pendingRequest->next,
                                                    allocations, available,
                                                    FORREAL);
                } else
					pendingRequest = pendingRequest->next;
            }
        } else {
            pendingRequestsTail->next = newRequest;
            pendingRequestsTail = newRequest;
        }
        newRequest = RR_read(NULL);
    }
        
    exit(0);
}


