diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-10-21 11:39:57 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-10-21 11:39:57 +0100 |
commit | 2712dbc3e5beb83742309eed10ee4f788043588e (patch) | |
tree | 8adf7b671d960f86c268d6148e90e53b1ff79faf /xen/common/timer.c | |
parent | 35bb5ffbddc9a1331ccdfb51c2129c4d9da4fcd6 (diff) | |
download | xen-2712dbc3e5beb83742309eed10ee4f788043588e.tar.gz xen-2712dbc3e5beb83742309eed10ee4f788043588e.tar.bz2 xen-2712dbc3e5beb83742309eed10ee4f788043588e.zip |
timer: No dynamic memory allocation with IRQs disabled.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/common/timer.c')
-rw-r--r-- | xen/common/timer.c | 54 |
1 files changed, 28 insertions, 26 deletions
diff --git a/xen/common/timer.c b/xen/common/timer.c index 8bfef0d760..81630ce5ec 100644 --- a/xen/common/timer.c +++ b/xen/common/timer.c @@ -114,34 +114,19 @@ static int remove_from_heap(struct timer **heap, struct timer *t) /* Add new entry @t to @heap. Return TRUE if new top of heap. */ -static int add_to_heap(struct timer ***pheap, struct timer *t) +static int add_to_heap(struct timer **heap, struct timer *t) { - struct timer **heap = *pheap; int sz = GET_HEAP_SIZE(heap); - /* Copy the heap if it is full. */ + /* Fail if the heap is full. */ if ( unlikely(sz == GET_HEAP_LIMIT(heap)) ) - { - /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */ - int old_limit = GET_HEAP_LIMIT(heap); - int new_limit = ((old_limit + 1) << 4) - 1; - if ( in_irq() ) - goto out; - heap = xmalloc_array(struct timer *, new_limit + 1); - if ( heap == NULL ) - goto out; - memcpy(heap, *pheap, (old_limit + 1) * sizeof(*heap)); - SET_HEAP_LIMIT(heap, new_limit); - if ( old_limit != 0 ) - xfree(*pheap); - *pheap = heap; - } + return 0; SET_HEAP_SIZE(heap, ++sz); heap[sz] = t; t->heap_offset = sz; up_heap(heap, sz); - out: + return (t->heap_offset == 1); } @@ -210,7 +195,7 @@ static int add_entry(struct timers *timers, struct timer *t) /* Try to add to heap. t->heap_offset indicates whether we succeed. */ t->heap_offset = 0; t->status = TIMER_STATUS_in_heap; - rc = add_to_heap(&timers->heap, t); + rc = add_to_heap(timers->heap, t); if ( t->heap_offset != 0 ) return rc; @@ -368,6 +353,27 @@ static void timer_softirq_action(void) void *data; ts = &this_cpu(timers); + heap = ts->heap; + + /* If we are using overflow linked list, try to allocate a larger heap. */ + if ( unlikely(ts->list != NULL) ) + { + /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */ + int old_limit = GET_HEAP_LIMIT(heap); + int new_limit = ((old_limit + 1) << 4) - 1; + struct timer **newheap = xmalloc_array(struct timer *, new_limit + 1); + if ( newheap != NULL ) + { + spin_lock_irq(&ts->lock); + memcpy(newheap, heap, (old_limit + 1) * sizeof(*heap)); + SET_HEAP_LIMIT(newheap, new_limit); + ts->heap = newheap; + spin_unlock_irq(&ts->lock); + if ( old_limit != 0 ) + xfree(heap); + heap = newheap; + } + } spin_lock_irq(&ts->lock); @@ -380,9 +386,8 @@ static void timer_softirq_action(void) t->status = TIMER_STATUS_inactive; add_entry(ts, t); } - - heap = ts->heap; - now = NOW(); + + now = NOW(); while ( (GET_HEAP_SIZE(heap) != 0) && ((t = heap[1])->expires < (now + TIMER_SLOP)) ) @@ -397,9 +402,6 @@ static void timer_softirq_action(void) spin_unlock_irq(&ts->lock); (*fn)(data); spin_lock_irq(&ts->lock); - - /* Heap may have grown while the lock was released. */ - heap = ts->heap; } deadline = GET_HEAP_SIZE(heap) ? heap[1]->expires : 0; |