cvsuser     03/07/12 10:45:02

  Modified:    .        tsq.c
  Log:
  Rework of some of the TSQ stuff
  
  Revision  Changes    Path
  1.3       +75 -77    parrot/tsq.c
  
  Index: tsq.c
  ===================================================================
  RCS file: /cvs/public/parrot/tsq.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- tsq.c     1 Jun 2003 00:17:44 -0000       1.2
  +++ tsq.c     12 Jul 2003 17:45:01 -0000      1.3
  @@ -1,9 +1,9 @@
   /* tsq.c
    *  Copyright: 2003, Yet Another Society
    *  CVS Info
  - *     $Id: tsq.c,v 1.2 2003/06/01 00:17:44 josh Exp $
  + *     $Id: tsq.c,v 1.3 2003/07/12 17:45:01 dan Exp $
    *  Overview:
  - *     Thread-safe and interrupt safe queues
  + *     Thread-safe queues
    *  Data Structure and Algorithms:
    *  History:
    *  Notes:
  @@ -12,87 +12,85 @@
   
   #include "parrot/parrot.h"
   
  -/* This code implements thread-safe and interrupt safe code, with the
  -   following caveats:
  -
  -   Only mainline code may remove entries from the queue
  -
  -   Mainline code may add entries to the queue
  -
  -   Interrupt code may add entries to the queue
  -
  -   Interrupt code may not interrupt other interrupt code (no nested
  -   interrupts) 
  -
  -   Interrupt code, in this case, is a C-level signal handler, AST
  -   callbacks, interrupt handlers, or any code that may have been
  -   invoked by the system while our user-level program is in an
  -   inconsistent state.
  -
  -   Basically if you're not allowed to allocate memory or call a
  -   thread routine, it's interrupt code.
  -
  -   Entries are *always* added at the tail of the queue, and *always*
  -   removed from the head of the queue
  -
  -   In the case where there's a native queue management system, we'll
  -   use that instead, as doing this portably is profoundly nasty. And
  -   if an OS provides atomic queue management, who are we to disagree?
  -   They probably use Secret Hardware Tricks (like the VAX's queue
  -   management instructions, which are emulated in PAL code on the
  -   Alphas)
  -
  -   To make this all work we *MUST* disable any and all instruction
  -   reordering, caching, and other compiler trickery. The code must
  -   execute in the order it is written in, and all queue and entry
  -   members must be treated as volatile and thus not cached in
  -   registers. Yeah, it'll make the code slower, but that beats bad
  -   code, and bad code at this level will likely kill things really
  -   badly which would be bad.
  -
  -
  -   The order of operations for interrupt code:
  +/* A synchronized entry popper */
  +QUEUE_ENTRY *
  +pop_entry(QUEUE *queue) {
  +    QUEUE_ENTRY *returnval;
  +    queue_lock(queue);
  +    returnval = nosync_pop_entry(queue);
  +    queue_unlock(queue);
  +    return returnval;
  +}
   
  -   * Check queue in use flag. If false, just go do it since nothing's
  -     using the queue. If true, 
  +/* Grab an entry off the queue with no synchronization. Internal only,
  +   because it's darned evil and shouldn't be used outside the
  +   module. It's in here so we don't have to duplicate pop code */
  +static
  +QUEUE_ENTRY *
  +nosync_pop_entry(QUEUE *queue) {
  +    QUEUE_ENTRY *returnval;
  +    if (!queue->head) {
  +        return NULL;
  +    }
  +    returnval = queue->head;
  +    if (queue->head == queue->tail) {
  +        queue->head = NULL;
  +        queue->tail = NULL;
  +    } else {
  +        queue->head = queue->head->next;
  +    }
  +    returnval->next = NULL;
  +    return returnval;
  +}
   
  +QUEUE_ENTRY *
  +wait_for_entry(QUEUE *queue) {
  +    QUEUE_ENTRY *returnval;
  +    queue_lock(queue);
  +    while (queue->head == NULL) {
  +        queue_wait(queue);
  +    }
  +    returnval = nosync_pop_entry(queue);
  +    queue_unlock(queue);
  +    return returnval;
   
  -*/
  +}
   
  -#if defined(__GNUC__)
  -#  if defined(__OPTIMIZE__)
  -#    error "Can't compile this with optimizations of any sort"
  -#  endif
  -#endif
  -
  -/* Insert an entry to the passed in queue. Callable only from within
  -   interrupt code */
  -void Parrot_ins_queue_interrupt(QUEUE *queue, QUEUE_ENTRY *entry) {
  -    /* entry's next pointer is always NULL */
  -    entry->next = NULL;
  -
  -    /* Is something using us? If not, just go do this */
  -    if (!queue->queue_in_use) {
  -        /* Is there a tail entry? */
  +void
  +push_entry(QUEUE *queue, QUEUE_ENTRY *entry) {
  +    queue_lock(queue);
  +    /* Is there something in the queue? */
           if (queue->tail) {
  -            entry->next = NULL;
               queue->tail->next = entry;
               queue->tail = entry;
  -        }
  -        else {
  -            /* If no tail, then no head. Empty queue */
  +    } else {
               queue->head = entry;
               queue->tail = entry;
           }
  +    queue_signal(queue);
  +    queue_unlock(queue);
  +}
  +
  +void
  +queue_lock(QUEUE *queue) {
  +    LOCK(queue->queue_mutex);
       }
  -    else {
  -        /* This is the tricky bit. The queue is in use, which means
  -           something is mutating it. That means the queue header or
  -           entries could be in an inconsistent state. We need to tread
  -           really carefully here */
  +
  +void
  +queue_unlock(QUEUE *queue) {
  +    UNLOCK(queue->queue_mutex);
       }
  +
  +/* This function wakes up *every* thread waiting on the queue */
  +void
  +queue_signal(QUEUE *queue) {
  +    CONDITION_BROADCAST(queue->queue_condition);
   }
   
  +void
  +queue_wait(QUEUE *queue) {
  +    COND_WAIT(queue->queue_condition, queue->queue_mutex);
  +}
   
   /*
    * Local variables:
  
  
  

Reply via email to