"Fossies" - the Fresh Open Source Software archive

Member "scalpel-2.0/src/prioque.c" of archive scalpel-2.0.tar.gz:


//
// implementation of "prioque.h" priority queue functions */
// (c) 198x/1998/2001 (minor updates) by Golden G. Richard III, Ph.D. */
//
// Major update in 2007.  See prioque.h for details.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "prioque.h"

// global lock on entire package
pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;

// for init purposes
pthread_mutex_t initial_mutex = PTHREAD_MUTEX_INITIALIZER;

// function prototypes for internal functions
void nolock_next_element(Queue * q);
void nolock_rewind_queue(Queue * q);
int nolock_element_in_queue(Queue * q, void *element);
void nolock_destroy_queue(Queue * q);
void local_nolock_next_element(Context * ctx);
void local_nolock_rewind_queue(Context * ctx);


void
init_queue(Queue * q, int elementsize, int duplicates,
	   int (*compare) (void *e1, void *e2), int priority_is_tag_only) {

  q->queuelength = 0;
  q->elementsize = elementsize;
  q->queue = 0;
  q->duplicates = duplicates;
  q->compare = compare;
  q->priority_is_tag_only = priority_is_tag_only;
  nolock_rewind_queue(q);
  q->lock = initial_mutex;

}


void destroy_queue(Queue * q) {

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

  nolock_destroy_queue(q);

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));
}


void nolock_destroy_queue(Queue * q) {

  Queue_element temp;

  if(q != 0) {
    while (q->queue != 0) {
      free(q->queue->info);
      temp = q->queue;
      q->queue = q->queue->next;
      free(temp);
      (q->queuelength)--;
    }
  }

  nolock_rewind_queue(q);
}




int element_in_queue(Queue * q, void *element) {

  int found;
  // lock entire queue
  pthread_mutex_lock(&(q->lock));

  found = nolock_element_in_queue(q, element);

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));

  return found;
}

int nolock_element_in_queue(Queue * q, void *element) {

  int found = 0;

  if(q->queue != 0) {
    nolock_rewind_queue(q);
    while (!end_of_queue(q) && !found) {
      if(q->compare(element, q->current->info) == 0) {
	found = 1;
      }
      else {
	nolock_next_element(q);
      }
    }
  }
  if(!found) {
    nolock_rewind_queue(q);
  }

  return found;
}



void nolock_add_to_queue(Queue * q, void *element, int priority) {

  Queue_element new_element, ptr, prev = 0;

  if(!q->queue ||
     (q->queue && (q->duplicates || !nolock_element_in_queue(q, element)))) {

    new_element = (Queue_element) malloc(sizeof(struct _Queue_element));
    if(new_element == 0) {
      fprintf(stderr, "Malloc failed in function add_to_queue()\n");
      exit(1);
    }
    new_element->info = (void *)malloc(q->elementsize);
    if(new_element->info == 0) {
      fprintf(stderr, "Malloc failed in function add_to_queue()\n");
      exit(1);
    }

    memcpy(new_element->info, element, q->elementsize);

    new_element->priority = priority;

    (q->queuelength)++;

    if(q->queue == 0) {
      new_element->next = 0;
      q->queue = new_element;
    }
    else if(q->priority_is_tag_only || (q->queue)->priority >= priority) {
      new_element->next = q->queue;
      q->queue = new_element;
    }
    else {
      ptr = q->queue;
      while (ptr != 0 && priority >= ptr->priority) {


	putchar('.');		//**//

	prev = ptr;
	ptr = ptr->next;
      }

      new_element->next = prev->next;
      prev->next = new_element;
    }

    nolock_rewind_queue(q);
  }
}


void add_to_queue(Queue * q, void *element, int priority) {

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

  nolock_add_to_queue(q, element, priority);

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));

}


int empty_queue(Queue * q) {

  return q->queue == 0;
}



void remove_from_front(Queue * q, void *element) {

  Queue_element temp;

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0) {
    fprintf(stderr, "NULL pointer in function remove_from_front()\n");
    exit(1);
  }
  else
#endif
  {

    memcpy(element, q->queue->info, q->elementsize);

    free(q->queue->info);
    temp = q->queue;
    q->queue = q->queue->next;
    free(temp);
    (q->queuelength)--;
  }

  nolock_rewind_queue(q);

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));
}



void peek_at_current(Queue * q, void *element) {

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0 || q->current == 0) {
    fprintf(stderr, "NULL pointer in function peek_at_current()\n");
    exit(1);
  }
  else
#endif
  {

    memcpy(element, (q->current)->info, q->elementsize);

    // release lock on queue
    pthread_mutex_unlock(&(q->lock));
  }
}


void *pointer_to_current(Queue * q) {

  void *data;

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0 || q->current == 0) {
    fprintf(stderr, "NULL pointer in function pointer_to_current()\n");
    exit(1);
  }
  else
#endif
  {

    data = (q->current)->info;

    // release lock on queue
    pthread_mutex_unlock(&(q->lock));

    return data;
  }
}



int current_priority(Queue * q) {

  int priority;

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0 || q->current == 0) {
    fprintf(stderr, "NULL pointer in function peek_at_current()\n");
    exit(1);
  }
  else
#endif
  {

    priority = (q->current)->priority;

    // release lock on queue
    pthread_mutex_unlock(&(q->lock));

    return priority;
  }
}



void update_current(Queue * q, void *element) {

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0 || q->current == 0) {
    fprintf(stderr, "NULL pointer in function update_current()\n");
    exit(1);
  }
  else
#endif
  {
    memcpy(q->current->info, element, q->elementsize);
  }

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));
}



void delete_current(Queue * q) {

  Queue_element temp;

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0 || q->current == 0) {
    fprintf(stderr, "NULL pointer in function delete_current()\n");
    exit(1);
  }
  else
#endif
  {

    free(q->current->info);
    temp = q->current;

    if(q->previous == 0) {	/* deletion at beginning */
      q->queue = q->queue->next;
      q->current = q->queue;
    }
    else {			/* internal deletion */
      q->previous->next = q->current->next;
      q->current = q->previous->next;
    }

    free(temp);
    (q->queuelength)--;

  }

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));

}



int end_of_queue(Queue * q) {

  return (q->current == 0);

}


void next_element(Queue * q) {

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

  nolock_next_element(q);

  // release lock on queue
  pthread_mutex_unlock(&(q->lock));
}


void nolock_next_element(Queue * q) {

#if defined(CONSISTENCY_CHECKING)
  if(q->queue == 0) {
    fprintf(stderr, "NULL pointer in function next_element()\n");
    exit(1);
  }
  else if(q->current == 0) {
    fprintf(stderr,
	    "Advance past end in NULL pointer in function next_element()\n");
    exit(1);
  }
  else
#endif
  {
    q->previous = q->current;
    q->current = q->current->next;
  }
}



void rewind_queue(Queue * q) {

  // lock entire queue
  pthread_mutex_lock(&(q->lock));

  nolock_rewind_queue(q);
  // release lock on queue
  pthread_mutex_unlock(&(q->lock));
}

void nolock_rewind_queue(Queue * q) {

  q->current = q->queue;
  q->previous = 0;

}


int queue_length(Queue * q) {

  return q->queuelength;
}


void copy_queue(Queue * q1, Queue * q2) {

  Queue_element temp, new_element, endq1;

  // to avoid deadlock, this function acquires a global package
  // lock!
  pthread_mutex_lock(&global_lock);

  // lock entire queues q1, q2
  pthread_mutex_lock(&(q1->lock));
  pthread_mutex_lock(&(q2->lock));

  /* free elements in q1 before copy */

  nolock_destroy_queue(q1);

  /* now make q1 a clone of q2 */

  q1->queuelength = 0;
  q1->elementsize = q2->elementsize;
  q1->queue = 0;
  q1->duplicates = q2->duplicates;
  q1->compare = q2->compare;

  temp = q2->queue;
  endq1 = q1->queue;

  while (temp != 0) {
    new_element = (Queue_element) malloc(sizeof(struct _Queue_element));

    if(new_element == 0) {
      fprintf(stderr, "Malloc failed in function copy_queue()\n");
      exit(1);
    }

    new_element->info = (void *)malloc(q1->elementsize);
    if(new_element->info == 0) {
      fprintf(stderr, "Malloc failed in function copy_queue()\n");
      exit(1);
    }
    memcpy(new_element->info, temp->info, q1->elementsize);

    new_element->priority = temp->priority;
    new_element->next = 0;

    (q1->queuelength)++;

    if(endq1 == 0) {
      q1->queue = new_element;
    }
    else {
      endq1->next = new_element;
    }
    endq1 = new_element;
    temp = temp->next;
  }

  nolock_rewind_queue(q1);

  // release locks on q1, q2
  pthread_mutex_unlock(&(q2->lock));
  pthread_mutex_unlock(&(q1->lock));

  // release global package lock
  pthread_mutex_unlock(&global_lock);

}



int equal_queues(Queue * q1, Queue * q2) {

  Queue_element temp1, temp2;
  int same = TRUE;

  // to avoid deadlock, this function acquires a global package
  // lock!
  pthread_mutex_lock(&global_lock);

  // lock entire queues q1, q2
  pthread_mutex_lock(&(q1->lock));
  pthread_mutex_lock(&(q2->lock));

  if(q1->queuelength != q2->queuelength || q1->elementsize != q2->elementsize) {
    same = FALSE;
  }
  else {
    temp1 = q1->queue;
    temp2 = q2->queue;
    while (same && temp1 != 0) {
      same = (!memcmp(temp1->info, temp2->info, q1->elementsize) &&
	      temp1->priority == temp2->priority);
      temp1 = temp1->next;
      temp2 = temp2->next;
    }
  }

  // release locks on q1, q2
  pthread_mutex_unlock(&(q2->lock));
  pthread_mutex_unlock(&(q1->lock));

  // release global package lock
  pthread_mutex_unlock(&global_lock);

  return same;
}


void merge_queues(Queue * q1, Queue * q2) {

  Queue_element temp;

  // to avoid deadlock, this function acquires a global package
  // lock!
  pthread_mutex_lock(&global_lock);

  // lock entire queues q1, q2
  pthread_mutex_lock(&(q1->lock));
  pthread_mutex_lock(&(q2->lock));

  temp = q2->queue;

  while (temp != 0) {
    nolock_add_to_queue(q1, temp->info, temp->priority);
    temp = temp->next;
  }

  nolock_rewind_queue(q1);

  // release locks on q1, q2
  pthread_mutex_unlock(&(q2->lock));
  pthread_mutex_unlock(&(q1->lock));

  // release global package lock
  pthread_mutex_unlock(&global_lock);

}



void local_peek_at_current(Context * ctx, void *element) {

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

#if defined(CONSISTENCY_CHECKING)
  if(ctx->queue == 0 || ctx->current == 0) {
    fprintf(stderr, "NULL pointer in function peek_at_current()\n");
    exit(1);
  }
  else
#endif
  {

    memcpy(element, (ctx->current)->info, ctx->queue->elementsize);

    // release lock on queue
    pthread_mutex_unlock(&(ctx->queue->lock));

  }
}


void *local_pointer_to_current(Context * ctx) {

  void *data;

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

#if defined(CONSISTENCY_CHECKING)
  if(ctx->queue == 0 || ctx->current == 0) {
    fprintf(stderr, "NULL pointer in function pointer_to_current()\n");
    exit(1);
  }
  else
#endif
  {

    data = (ctx->current)->info;

    // release lock on queue
    pthread_mutex_unlock(&(ctx->queue->lock));

    return data;
  }
}


int local_current_priority(Context * ctx) {

  int priority;

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

#if defined(CONSISTENCY_CHECKING)
  if(ctx->queue == 0 || ctx->current == 0) {
    fprintf(stderr, "NULL pointer in function peek_at_current()\n");
    exit(1);
  }
  else
#endif
  {
    priority = (ctx->current)->priority;

    // release lock on queue
    pthread_mutex_unlock(&(ctx->queue->lock));

    return priority;
  }
}



void local_update_current(Context * ctx, void *element) {

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

#if defined(CONSISTENCY_CHECKING)
  if(ctx->queue == 0 || ctx->current == 0) {
    fprintf(stderr, "NULL pointer in function update_current()\n");
    exit(1);
  }
  else
#endif
  {
    memcpy(ctx->current->info, element, ctx->queue->elementsize);
  }

  // release lock on queue
  pthread_mutex_unlock(&(ctx->queue->lock));
}



void local_delete_current(Context * ctx) {

  Queue_element temp;

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

#if defined(CONSISTENCY_CHECKING)
  if(ctx->queue == 0 || ctx->current == 0) {
    fprintf(stderr, "NULL pointer in function delete_current()\n");
    exit(1);
  }
  else
#endif
  {

    free(ctx->current->info);
    temp = ctx->current;

    if(ctx->previous == 0) {	/* deletion at beginning */
      ctx->queue->queue = ctx->queue->queue->next;
      ctx->current = ctx->queue->queue;
    }
    else {			/* internal deletion */
      ctx->previous->next = ctx->current->next;
      ctx->current = ctx->current->next;
    }

    free(temp);
    (ctx->queue->queuelength)--;

  }

  // release lock on queue
  pthread_mutex_unlock(&(ctx->queue->lock));

}



int local_end_of_queue(Context * ctx) {

  return (ctx->current == 0);

}


void local_next_element(Context * ctx) {

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

  local_nolock_next_element(ctx);

  // release lock on queue
  pthread_mutex_unlock(&(ctx->queue->lock));
}


void local_nolock_next_element(Context * ctx) {

#if defined(CONSISTENCY_CHECKING)
  if(ctx->queue == 0) {
    fprintf(stderr, "NULL pointer in function next_element()\n");
    exit(1);
  }
  else if(ctx->current == 0) {
    fprintf(stderr,
	    "Advance past end in NULL pointer in function next_element()\n");
    exit(1);
  }
  else
#endif
  {
    ctx->previous = ctx->current;
    ctx->current = ctx->current->next;
  }
}



void local_rewind_queue(Context * ctx) {

  // lock entire queue
  pthread_mutex_lock(&(ctx->queue->lock));

  local_nolock_rewind_queue(ctx);

  // release lock on queue
  pthread_mutex_unlock(&(ctx->queue->lock));
}

void local_nolock_rewind_queue(Context * ctx) {

  ctx->current = ctx->queue->queue;
  ctx->previous = 0;

}

void local_init_context(Queue * q, Context * ctx) {
  ctx->queue = q;
  ctx->current = q->queue;
  ctx->previous = 0;
}