From 1fa5fa9a723b314f72db9b52114eebf01111c5f0 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Tue, 28 Jun 2011 15:55:48 +0000 Subject: Revert "dahdi: Group dahdi timers into "rates" for improved CPU utilization." This reverts commit r9891 and is part of two commits to revert all the timer changes. Grouping the timer into rates did not allow a timers rate to be changed after another thread is already blocked on the poll call The problem that was reported was if a sip call was made to a DAHDI channel and the sip call was disconnected before answer, the DAHDI channel would never stop rining. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9991 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/dahdi-base.c | 209 ++++++++++++++++----------------------------- 1 file changed, 74 insertions(+), 135 deletions(-) (limited to 'drivers/dahdi/dahdi-base.c') diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index b72576d..84aea3e 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -289,44 +289,18 @@ static inline void dahdi_kernel_fpu_end(void) #endif -/** - * struct dahdi_timer_rate - A collection of timers of a given rate. - * @rate_samples: Samples until these timers fire. - * @cur_samples: Samples processed since last firing. - * @sel: Wait queue for timer waiters. - * @timers: List of individual timers at this rate. - * @node: For storing on dahdi_timer_rates list. - * - */ -struct dahdi_timer_rate { - int rate_samples; - int cur_samples; +struct dahdi_timer { + int ms; /* Countdown */ + int pos; /* Position */ + int ping; /* Whether we've been ping'd */ + int tripped; /* Whether we're tripped */ + struct list_head list; wait_queue_head_t sel; - struct list_head timers; - struct list_head node; }; -/** - * struct dahdi_timer - A dahdi timer opened from user space. - * @ping: 1 if we should operate in "continuous mode". - * @tripped: Count of times we've tripped. - * @rate: The rate this timer fires at. - * @node: To store on rate->timers list. - * - * When a timer is in "continuous" mode, it should always return immediately - * from a poll call from user space. - * - */ -struct dahdi_timer { - atomic_t ping; - atomic_t tripped; - struct dahdi_timer_rate *rate; - struct list_head node; -}; +static LIST_HEAD(dahdi_timers); -static LIST_HEAD(dahdi_timer_rates); static DEFINE_SPINLOCK(dahdi_timer_lock); -static DEFINE_MUTEX(dahdi_timer_mutex); #define DEFAULT_TONE_ZONE (-1) @@ -2856,47 +2830,48 @@ static int initialize_channel(struct dahdi_chan *chan) static int dahdi_timing_open(struct file *file) { struct dahdi_timer *t; + unsigned long flags; - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (!t) + if (!(t = kzalloc(sizeof(*t), GFP_KERNEL))) return -ENOMEM; - INIT_LIST_HEAD(&t->node); + init_waitqueue_head(&t->sel); + INIT_LIST_HEAD(&t->list); file->private_data = t; + spin_lock_irqsave(&dahdi_timer_lock, flags); + list_add(&t->list, &dahdi_timers); + spin_unlock_irqrestore(&dahdi_timer_lock, flags); + return 0; } -/** - * _dahdi_remove_timer - Removes the timer from the rate it's associated with. - * - * Must be called with dahdi_timer_mutex held. - */ -static void _dahdi_remove_timer(struct dahdi_timer *timer) +static int dahdi_timer_release(struct file *file) { + struct dahdi_timer *t, *cur, *next; unsigned long flags; - struct dahdi_timer_rate *const rate = timer->rate; + + if (!(t = file->private_data)) + return 0; spin_lock_irqsave(&dahdi_timer_lock, flags); - list_del(&timer->node); - if (rate && list_empty(&rate->timers)) { - list_del(&rate->node); - kfree(rate); + + list_for_each_entry_safe(cur, next, &dahdi_timers, list) { + if (t == cur) { + list_del(&cur->list); + break; + } } + spin_unlock_irqrestore(&dahdi_timer_lock, flags); - timer->rate = NULL; -} -static int dahdi_timer_release(struct file *file) -{ - struct dahdi_timer *timer = file->private_data; - if (!timer) + if (!cur) { + module_printk(KERN_NOTICE, "Timer: Not on list??\n"); return 0; + } + + kfree(cur); - mutex_lock(&dahdi_timer_mutex); - _dahdi_remove_timer(timer); - mutex_unlock(&dahdi_timer_mutex); - file->private_data = NULL; return 0; } @@ -3784,80 +3759,48 @@ void dahdi_alarm_notify(struct dahdi_span *span) } } -static int -dahdi_timer_ioctl(struct file *file, unsigned int cmd, - unsigned long data, struct dahdi_timer *timer) +static int dahdi_timer_ioctl(struct file *file, unsigned int cmd, unsigned long data, struct dahdi_timer *timer) { int j; - struct dahdi_timer_rate *rate, *c_rate; unsigned long flags; - switch(cmd) { case DAHDI_TIMERCONFIG: get_user(j, (int __user *)data); if (j < 0) j = 0; - - mutex_lock(&dahdi_timer_mutex); - if (timer->rate) - _dahdi_remove_timer(timer); - - rate = NULL; - list_for_each_entry(c_rate, &dahdi_timer_rates, node) { - if (c_rate->rate_samples == j) { - rate = c_rate; - break; - } - } - if (!rate) { - /* If we didn't find a rate, we need to create a new - * one */ - rate = kzalloc(sizeof(*rate), GFP_KERNEL); - if (!rate) { - mutex_unlock(&dahdi_timer_mutex); - return -ENOMEM; - } - init_waitqueue_head(&rate->sel); - rate->rate_samples = rate->cur_samples = j; - INIT_LIST_HEAD(&rate->timers); - timer->rate = rate; - list_add_tail(&timer->node, &rate->timers); - spin_lock_irqsave(&dahdi_timer_lock, flags); - list_add_tail(&rate->node, &dahdi_timer_rates); - spin_unlock_irqrestore(&dahdi_timer_lock, flags); - } else { - /* Otherwise, just add this new timer to the existing - * rates. */ - timer->rate = rate; - spin_lock_irqsave(&dahdi_timer_lock, flags); - list_add_tail(&timer->node, &rate->timers); - spin_unlock_irqrestore(&dahdi_timer_lock, flags); - } - mutex_unlock(&dahdi_timer_mutex); + spin_lock_irqsave(&dahdi_timer_lock, flags); + timer->ms = timer->pos = j; + spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; - case DAHDI_TIMERACK: get_user(j, (int __user *)data); - if ((j < 1) || (j > atomic_read(&timer->tripped))) - j = atomic_read(&timer->tripped); - atomic_sub(j, &timer->tripped); + spin_lock_irqsave(&dahdi_timer_lock, flags); + if ((j < 1) || (j > timer->tripped)) + j = timer->tripped; + timer->tripped -= j; + spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; case DAHDI_GETEVENT: /* Get event on queue */ j = DAHDI_EVENT_NONE; + spin_lock_irqsave(&dahdi_timer_lock, flags); /* set up for no event */ - if (atomic_read(&timer->tripped)) + if (timer->tripped) j = DAHDI_EVENT_TIMER_EXPIRED; - if (atomic_read(&timer->ping)) + if (timer->ping) j = DAHDI_EVENT_TIMER_PING; + spin_unlock_irqrestore(&dahdi_timer_lock, flags); put_user(j, (int __user *)data); break; case DAHDI_TIMERPING: - atomic_set(&timer->ping, 1); - if (timer->rate) - wake_up_interruptible(&timer->rate->sel); + spin_lock_irqsave(&dahdi_timer_lock, flags); + timer->ping = 1; + wake_up_interruptible(&timer->sel); + spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; case DAHDI_TIMERPONG: - atomic_set(&timer->ping, 0); + spin_lock_irqsave(&dahdi_timer_lock, flags); + timer->ping = 0; + spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; default: return -ENOTTY; @@ -8727,26 +8670,21 @@ int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int static void process_timers(void) { - struct dahdi_timer_rate *cur_rate; - struct dahdi_timer *cur_timer; + struct dahdi_timer *cur; - if (list_empty(&dahdi_timer_rates)) + if (list_empty(&dahdi_timers)) return; spin_lock(&dahdi_timer_lock); - list_for_each_entry(cur_rate, &dahdi_timer_rates, node) { - if (!cur_rate->rate_samples) - continue; - - cur_rate->cur_samples -= DAHDI_CHUNKSIZE; - if (cur_rate->cur_samples > 0) - continue; - - list_for_each_entry(cur_timer, &cur_rate->timers, node) - atomic_inc(&cur_timer->tripped); - - cur_rate->cur_samples = cur_rate->rate_samples; - wake_up_interruptible(&cur_rate->sel); + list_for_each_entry(cur, &dahdi_timers, list) { + if (cur->ms) { + cur->pos -= DAHDI_CHUNKSIZE; + if (cur->pos <= 0) { + cur->tripped++; + cur->pos = cur->ms; + wake_up_interruptible(&cur->sel); + } + } } spin_unlock(&dahdi_timer_lock); } @@ -8754,16 +8692,17 @@ static void process_timers(void) static unsigned int dahdi_timer_poll(struct file *file, struct poll_table_struct *wait_table) { struct dahdi_timer *timer = file->private_data; - struct dahdi_timer_rate *rate = timer->rate; - - if (!rate || !timer) - return -EINVAL; - - poll_wait(file, &rate->sel, wait_table); - if (atomic_read(&timer->tripped) || atomic_read(&timer->ping)) - return POLLPRI; - - return 0; + unsigned long flags; + int ret = 0; + if (timer) { + poll_wait(file, &timer->sel, wait_table); + spin_lock_irqsave(&dahdi_timer_lock, flags); + if (timer->tripped || timer->ping) + ret |= POLLPRI; + spin_unlock_irqrestore(&dahdi_timer_lock, flags); + } else + ret = -EINVAL; + return ret; } /* device poll routine */ -- cgit v1.2.3