ia64/xen-unstable

changeset 18678:ecdbcd27490f

timer: No dynamic memory allocation with IRQs disabled.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Oct 21 11:39:57 2008 +0100 (2008-10-21)
parents 3ba06e8098cb
children 4b5823f292ea
files xen/common/timer.c
line diff
     1.1 --- a/xen/common/timer.c	Tue Oct 21 11:39:22 2008 +0100
     1.2 +++ b/xen/common/timer.c	Tue Oct 21 11:39:57 2008 +0100
     1.3 @@ -114,34 +114,19 @@ static int remove_from_heap(struct timer
     1.4  
     1.5  
     1.6  /* Add new entry @t to @heap. Return TRUE if new top of heap. */
     1.7 -static int add_to_heap(struct timer ***pheap, struct timer *t)
     1.8 +static int add_to_heap(struct timer **heap, struct timer *t)
     1.9  {
    1.10 -    struct timer **heap = *pheap;
    1.11      int sz = GET_HEAP_SIZE(heap);
    1.12  
    1.13 -    /* Copy the heap if it is full. */
    1.14 +    /* Fail if the heap is full. */
    1.15      if ( unlikely(sz == GET_HEAP_LIMIT(heap)) )
    1.16 -    {
    1.17 -        /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */
    1.18 -        int old_limit = GET_HEAP_LIMIT(heap);
    1.19 -        int new_limit = ((old_limit + 1) << 4) - 1;
    1.20 -        if ( in_irq() )
    1.21 -            goto out;
    1.22 -        heap = xmalloc_array(struct timer *, new_limit + 1);
    1.23 -        if ( heap == NULL )
    1.24 -            goto out;
    1.25 -        memcpy(heap, *pheap, (old_limit + 1) * sizeof(*heap));
    1.26 -        SET_HEAP_LIMIT(heap, new_limit);
    1.27 -        if ( old_limit != 0 )
    1.28 -            xfree(*pheap);
    1.29 -        *pheap = heap;
    1.30 -    }
    1.31 +        return 0;
    1.32  
    1.33      SET_HEAP_SIZE(heap, ++sz);
    1.34      heap[sz] = t;
    1.35      t->heap_offset = sz;
    1.36      up_heap(heap, sz);
    1.37 - out:
    1.38 +
    1.39      return (t->heap_offset == 1);
    1.40  }
    1.41  
    1.42 @@ -210,7 +195,7 @@ static int add_entry(struct timers *time
    1.43      /* Try to add to heap. t->heap_offset indicates whether we succeed. */
    1.44      t->heap_offset = 0;
    1.45      t->status = TIMER_STATUS_in_heap;
    1.46 -    rc = add_to_heap(&timers->heap, t);
    1.47 +    rc = add_to_heap(timers->heap, t);
    1.48      if ( t->heap_offset != 0 )
    1.49          return rc;
    1.50  
    1.51 @@ -368,6 +353,27 @@ static void timer_softirq_action(void)
    1.52      void          *data;
    1.53  
    1.54      ts = &this_cpu(timers);
    1.55 +    heap = ts->heap;
    1.56 +
    1.57 +    /* If we are using overflow linked list, try to allocate a larger heap. */
    1.58 +    if ( unlikely(ts->list != NULL) )
    1.59 +    {
    1.60 +        /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */
    1.61 +        int old_limit = GET_HEAP_LIMIT(heap);
    1.62 +        int new_limit = ((old_limit + 1) << 4) - 1;
    1.63 +        struct timer **newheap = xmalloc_array(struct timer *, new_limit + 1);
    1.64 +        if ( newheap != NULL )
    1.65 +        {
    1.66 +            spin_lock_irq(&ts->lock);
    1.67 +            memcpy(newheap, heap, (old_limit + 1) * sizeof(*heap));
    1.68 +            SET_HEAP_LIMIT(newheap, new_limit);
    1.69 +            ts->heap = newheap;
    1.70 +            spin_unlock_irq(&ts->lock);
    1.71 +            if ( old_limit != 0 )
    1.72 +                xfree(heap);
    1.73 +            heap = newheap;
    1.74 +        }
    1.75 +    }
    1.76  
    1.77      spin_lock_irq(&ts->lock);
    1.78  
    1.79 @@ -380,9 +386,8 @@ static void timer_softirq_action(void)
    1.80          t->status = TIMER_STATUS_inactive;
    1.81          add_entry(ts, t);
    1.82      }
    1.83 -    
    1.84 -    heap = ts->heap;
    1.85 -    now  = NOW();
    1.86 +
    1.87 +    now = NOW();
    1.88  
    1.89      while ( (GET_HEAP_SIZE(heap) != 0) &&
    1.90              ((t = heap[1])->expires < (now + TIMER_SLOP)) )
    1.91 @@ -397,9 +402,6 @@ static void timer_softirq_action(void)
    1.92          spin_unlock_irq(&ts->lock);
    1.93          (*fn)(data);
    1.94          spin_lock_irq(&ts->lock);
    1.95 -
    1.96 -        /* Heap may have grown while the lock was released. */
    1.97 -        heap = ts->heap;
    1.98      }
    1.99  
   1.100      deadline = GET_HEAP_SIZE(heap) ? heap[1]->expires : 0;