From: Eric A. <er...@an...> - 2009-01-28 05:19:52
|
Schedule a vblank signal, kill the process, and we'll go walking over freed memory. Given that no open-source userland exists using this, nor have I ever heard of a consumer, just let this code die. Signed-off-by: Eric Anholt <er...@an...> --- drivers/gpu/drm/drm_irq.c | 161 +++++++-------------------------------------- include/drm/drm.h | 2 +- include/drm/drmP.h | 9 --- 3 files changed, 24 insertions(+), 148 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 477caa1..69aa0ab 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -106,8 +106,6 @@ void drm_vblank_cleanup(struct drm_device *dev) drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, - DRM_MEM_DRIVER); drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * @@ -132,7 +130,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, (unsigned long)dev); spin_lock_init(&dev->vbl_lock); - atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, @@ -140,11 +137,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vbl_queue) goto err; - dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vbl_sigs) - goto err; - dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, DRM_MEM_DRIVER); if (!dev->_vblank_count) @@ -177,7 +169,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) /* Zero per-crtc vblank stuff */ for (i = 0; i < num_crtcs; i++) { init_waitqueue_head(&dev->vbl_queue[i]); - INIT_LIST_HEAD(&dev->vbl_sigs[i]); atomic_set(&dev->_vblank_count[i], 0); atomic_set(&dev->vblank_refcount[i], 0); } @@ -540,15 +531,10 @@ out: * \param data user argument, pointing to a drm_wait_vblank structure. * \return zero on success or a negative number on failure. * - * Verifies the IRQ is installed. - * - * If a signal is requested checks if this task has already scheduled the same signal - * for the same vblank sequence number - nothing to be done in - * that case. If the number of tasks waiting for the interrupt exceeds 100 the - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this - * task. - * - * If a signal is not requested, then calls vblank_wait(). + * This function enables the vblank interrupt on the pipe requested, then + * sleeps waiting for the requested sequence number to occur, and drops + * the vblank interrupt refcount afterwards. (vblank irq disable follows that + * after a timeout with no further vblank waits scheduled). */ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -560,6 +546,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if ((!dev->pdev->irq) || (!dev->irq_enabled)) return -EINVAL; + if (vblwait->request.type & _DRM_VBLANK_SIGNAL) + return -EINVAL; + if (vblwait->request.type & ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", @@ -597,89 +586,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->request.sequence = seq + 1; } - if (flags & _DRM_VBLANK_SIGNAL) { - unsigned long irqflags; - struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; - struct drm_vbl_sig *vbl_sig; - - spin_lock_irqsave(&dev->vbl_lock, irqflags); - - /* Check if this task has already scheduled the same signal - * for the same vblank sequence number; nothing to be done in - * that case - */ - list_for_each_entry(vbl_sig, vbl_sigs, head) { - if (vbl_sig->sequence == vblwait->request.sequence - && vbl_sig->info.si_signo == - vblwait->request.signal - && vbl_sig->task == current) { - spin_unlock_irqrestore(&dev->vbl_lock, - irqflags); - vblwait->reply.sequence = seq; - goto done; - } - } - - if (atomic_read(&dev->vbl_signal_pending) >= 100) { - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - ret = -EBUSY; - goto done; - } - - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - - vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), - DRM_MEM_DRIVER); - if (!vbl_sig) { - ret = -ENOMEM; - goto done; - } - - /* Get a refcount on the vblank, which will be released by - * drm_vbl_send_signals(). - */ - ret = drm_vblank_get(dev, crtc); - if (ret) { - drm_free(vbl_sig, sizeof(struct drm_vbl_sig), - DRM_MEM_DRIVER); - goto done; - } - - atomic_inc(&dev->vbl_signal_pending); - - vbl_sig->sequence = vblwait->request.sequence; - vbl_sig->info.si_signo = vblwait->request.signal; - vbl_sig->task = current; + DRM_DEBUG("waiting on vblank count %d, crtc %d\n", + vblwait->request.sequence, crtc); + dev->last_vblank_wait[crtc] = vblwait->request.sequence; + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + (((drm_vblank_count(dev, crtc) - + vblwait->request.sequence) <= (1 << 23)) || + !dev->irq_enabled)); - spin_lock_irqsave(&dev->vbl_lock, irqflags); - - list_add_tail(&vbl_sig->head, vbl_sigs); + if (ret != -EINTR) { + struct timeval now; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + do_gettimeofday(&now); - vblwait->reply.sequence = seq; + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; + vblwait->reply.sequence = drm_vblank_count(dev, crtc); + DRM_DEBUG("returning %d to client\n", + vblwait->reply.sequence); } else { - DRM_DEBUG("waiting on vblank count %d, crtc %d\n", - vblwait->request.sequence, crtc); - dev->last_vblank_wait[crtc] = vblwait->request.sequence; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - (((drm_vblank_count(dev, crtc) - - vblwait->request.sequence) <= (1 << 23)) || - !dev->irq_enabled)); - - if (ret != -EINTR) { - struct timeval now; - - do_gettimeofday(&now); - - vblwait->reply.tval_sec = now.tv_sec; - vblwait->reply.tval_usec = now.tv_usec; - vblwait->reply.sequence = drm_vblank_count(dev, crtc); - DRM_DEBUG("returning %d to client\n", - vblwait->reply.sequence); - } else { - DRM_DEBUG("vblank wait interrupted by signal\n"); - } + DRM_DEBUG("vblank wait interrupted by signal\n"); } done: @@ -688,46 +614,6 @@ done: } /** - * Send the VBLANK signals. - * - * \param dev DRM device. - * \param crtc CRTC where the vblank event occurred - * - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. - * - * If a signal is not requested, then calls vblank_wait(). - */ -static void drm_vbl_send_signals(struct drm_device *dev, int crtc) -{ - struct drm_vbl_sig *vbl_sig, *tmp; - struct list_head *vbl_sigs; - unsigned int vbl_seq; - unsigned long flags; - - spin_lock_irqsave(&dev->vbl_lock, flags); - - vbl_sigs = &dev->vbl_sigs[crtc]; - vbl_seq = drm_vblank_count(dev, crtc); - - list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info(vbl_sig->info.si_signo, - &vbl_sig->info, vbl_sig->task); - - list_del(&vbl_sig->head); - - drm_free(vbl_sig, sizeof(*vbl_sig), - DRM_MEM_DRIVER); - atomic_dec(&dev->vbl_signal_pending); - drm_vblank_put(dev, crtc); - } - } - - spin_unlock_irqrestore(&dev->vbl_lock, flags); -} - -/** * drm_handle_vblank - handle a vblank event * @dev: DRM device * @crtc: where this event occurred @@ -739,6 +625,5 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) { atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); - drm_vbl_send_signals(dev, crtc); } EXPORT_SYMBOL(drm_handle_vblank); diff --git a/include/drm/drm.h b/include/drm/drm.h index 32e5096..8e77357 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -458,7 +458,7 @@ enum drm_vblank_seq_type { _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ - _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ }; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index afb7858..8190b9b 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -545,13 +545,6 @@ struct drm_ctx_list { struct drm_file *tag; /**< associated fd private data */ }; -struct drm_vbl_sig { - struct list_head head; - unsigned int sequence; - struct siginfo info; - struct task_struct *task; -}; - /* location of GART table */ #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 @@ -903,8 +896,6 @@ struct drm_device { wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ spinlock_t vbl_lock; - struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ - atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ -- 1.5.6.5 |
From: Dave A. <ai...@li...> - 2009-01-28 09:30:49
|
> Schedule a vblank signal, kill the process, and we'll go walking over freed > memory. Given that no open-source userland exists using this, nor have I > ever heard of a consumer, just let this code die. > > Signed-off-by: Eric Anholt <er...@an...> I'm quite happy to push this, if nobody objects with a good reason. Dave. > --- > drivers/gpu/drm/drm_irq.c | 161 +++++++-------------------------------------- > include/drm/drm.h | 2 +- > include/drm/drmP.h | 9 --- > 3 files changed, 24 insertions(+), 148 deletions(-) > > diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c > index 477caa1..69aa0ab 100644 > --- a/drivers/gpu/drm/drm_irq.c > +++ b/drivers/gpu/drm/drm_irq.c > @@ -106,8 +106,6 @@ void drm_vblank_cleanup(struct drm_device *dev) > > drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, > DRM_MEM_DRIVER); > - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, > - DRM_MEM_DRIVER); > drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * > dev->num_crtcs, DRM_MEM_DRIVER); > drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * > @@ -132,7 +130,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) > setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, > (unsigned long)dev); > spin_lock_init(&dev->vbl_lock); > - atomic_set(&dev->vbl_signal_pending, 0); > dev->num_crtcs = num_crtcs; > > dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, > @@ -140,11 +137,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) > if (!dev->vbl_queue) > goto err; > > - dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, > - DRM_MEM_DRIVER); > - if (!dev->vbl_sigs) > - goto err; > - > dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, > DRM_MEM_DRIVER); > if (!dev->_vblank_count) > @@ -177,7 +169,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) > /* Zero per-crtc vblank stuff */ > for (i = 0; i < num_crtcs; i++) { > init_waitqueue_head(&dev->vbl_queue[i]); > - INIT_LIST_HEAD(&dev->vbl_sigs[i]); > atomic_set(&dev->_vblank_count[i], 0); > atomic_set(&dev->vblank_refcount[i], 0); > } > @@ -540,15 +531,10 @@ out: > * \param data user argument, pointing to a drm_wait_vblank structure. > * \return zero on success or a negative number on failure. > * > - * Verifies the IRQ is installed. > - * > - * If a signal is requested checks if this task has already scheduled the same signal > - * for the same vblank sequence number - nothing to be done in > - * that case. If the number of tasks waiting for the interrupt exceeds 100 the > - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this > - * task. > - * > - * If a signal is not requested, then calls vblank_wait(). > + * This function enables the vblank interrupt on the pipe requested, then > + * sleeps waiting for the requested sequence number to occur, and drops > + * the vblank interrupt refcount afterwards. (vblank irq disable follows that > + * after a timeout with no further vblank waits scheduled). > */ > int drm_wait_vblank(struct drm_device *dev, void *data, > struct drm_file *file_priv) > @@ -560,6 +546,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, > if ((!dev->pdev->irq) || (!dev->irq_enabled)) > return -EINVAL; > > + if (vblwait->request.type & _DRM_VBLANK_SIGNAL) > + return -EINVAL; > + > if (vblwait->request.type & > ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { > DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", > @@ -597,89 +586,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data, > vblwait->request.sequence = seq + 1; > } > > - if (flags & _DRM_VBLANK_SIGNAL) { > - unsigned long irqflags; > - struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; > - struct drm_vbl_sig *vbl_sig; > - > - spin_lock_irqsave(&dev->vbl_lock, irqflags); > - > - /* Check if this task has already scheduled the same signal > - * for the same vblank sequence number; nothing to be done in > - * that case > - */ > - list_for_each_entry(vbl_sig, vbl_sigs, head) { > - if (vbl_sig->sequence == vblwait->request.sequence > - && vbl_sig->info.si_signo == > - vblwait->request.signal > - && vbl_sig->task == current) { > - spin_unlock_irqrestore(&dev->vbl_lock, > - irqflags); > - vblwait->reply.sequence = seq; > - goto done; > - } > - } > - > - if (atomic_read(&dev->vbl_signal_pending) >= 100) { > - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); > - ret = -EBUSY; > - goto done; > - } > - > - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); > - > - vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), > - DRM_MEM_DRIVER); > - if (!vbl_sig) { > - ret = -ENOMEM; > - goto done; > - } > - > - /* Get a refcount on the vblank, which will be released by > - * drm_vbl_send_signals(). > - */ > - ret = drm_vblank_get(dev, crtc); > - if (ret) { > - drm_free(vbl_sig, sizeof(struct drm_vbl_sig), > - DRM_MEM_DRIVER); > - goto done; > - } > - > - atomic_inc(&dev->vbl_signal_pending); > - > - vbl_sig->sequence = vblwait->request.sequence; > - vbl_sig->info.si_signo = vblwait->request.signal; > - vbl_sig->task = current; > + DRM_DEBUG("waiting on vblank count %d, crtc %d\n", > + vblwait->request.sequence, crtc); > + dev->last_vblank_wait[crtc] = vblwait->request.sequence; > + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, > + (((drm_vblank_count(dev, crtc) - > + vblwait->request.sequence) <= (1 << 23)) || > + !dev->irq_enabled)); > > - spin_lock_irqsave(&dev->vbl_lock, irqflags); > - > - list_add_tail(&vbl_sig->head, vbl_sigs); > + if (ret != -EINTR) { > + struct timeval now; > > - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); > + do_gettimeofday(&now); > > - vblwait->reply.sequence = seq; > + vblwait->reply.tval_sec = now.tv_sec; > + vblwait->reply.tval_usec = now.tv_usec; > + vblwait->reply.sequence = drm_vblank_count(dev, crtc); > + DRM_DEBUG("returning %d to client\n", > + vblwait->reply.sequence); > } else { > - DRM_DEBUG("waiting on vblank count %d, crtc %d\n", > - vblwait->request.sequence, crtc); > - dev->last_vblank_wait[crtc] = vblwait->request.sequence; > - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, > - (((drm_vblank_count(dev, crtc) - > - vblwait->request.sequence) <= (1 << 23)) || > - !dev->irq_enabled)); > - > - if (ret != -EINTR) { > - struct timeval now; > - > - do_gettimeofday(&now); > - > - vblwait->reply.tval_sec = now.tv_sec; > - vblwait->reply.tval_usec = now.tv_usec; > - vblwait->reply.sequence = drm_vblank_count(dev, crtc); > - DRM_DEBUG("returning %d to client\n", > - vblwait->reply.sequence); > - } else { > - DRM_DEBUG("vblank wait interrupted by signal\n"); > - } > + DRM_DEBUG("vblank wait interrupted by signal\n"); > } > > done: > @@ -688,46 +614,6 @@ done: > } > > /** > - * Send the VBLANK signals. > - * > - * \param dev DRM device. > - * \param crtc CRTC where the vblank event occurred > - * > - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. > - * > - * If a signal is not requested, then calls vblank_wait(). > - */ > -static void drm_vbl_send_signals(struct drm_device *dev, int crtc) > -{ > - struct drm_vbl_sig *vbl_sig, *tmp; > - struct list_head *vbl_sigs; > - unsigned int vbl_seq; > - unsigned long flags; > - > - spin_lock_irqsave(&dev->vbl_lock, flags); > - > - vbl_sigs = &dev->vbl_sigs[crtc]; > - vbl_seq = drm_vblank_count(dev, crtc); > - > - list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { > - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { > - vbl_sig->info.si_code = vbl_seq; > - send_sig_info(vbl_sig->info.si_signo, > - &vbl_sig->info, vbl_sig->task); > - > - list_del(&vbl_sig->head); > - > - drm_free(vbl_sig, sizeof(*vbl_sig), > - DRM_MEM_DRIVER); > - atomic_dec(&dev->vbl_signal_pending); > - drm_vblank_put(dev, crtc); > - } > - } > - > - spin_unlock_irqrestore(&dev->vbl_lock, flags); > -} > - > -/** > * drm_handle_vblank - handle a vblank event > * @dev: DRM device > * @crtc: where this event occurred > @@ -739,6 +625,5 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) > { > atomic_inc(&dev->_vblank_count[crtc]); > DRM_WAKEUP(&dev->vbl_queue[crtc]); > - drm_vbl_send_signals(dev, crtc); > } > EXPORT_SYMBOL(drm_handle_vblank); > diff --git a/include/drm/drm.h b/include/drm/drm.h > index 32e5096..8e77357 100644 > --- a/include/drm/drm.h > +++ b/include/drm/drm.h > @@ -458,7 +458,7 @@ enum drm_vblank_seq_type { > _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ > _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ > _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ > - _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ > + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ > }; > > #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) > diff --git a/include/drm/drmP.h b/include/drm/drmP.h > index afb7858..8190b9b 100644 > --- a/include/drm/drmP.h > +++ b/include/drm/drmP.h > @@ -545,13 +545,6 @@ struct drm_ctx_list { > struct drm_file *tag; /**< associated fd private data */ > }; > > -struct drm_vbl_sig { > - struct list_head head; > - unsigned int sequence; > - struct siginfo info; > - struct task_struct *task; > -}; > - > /* location of GART table */ > #define DRM_ATI_GART_MAIN 1 > #define DRM_ATI_GART_FB 2 > @@ -903,8 +896,6 @@ struct drm_device { > wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ > atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ > spinlock_t vbl_lock; > - struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ > - atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ > atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ > u32 *last_vblank; /* protected by dev->vbl_lock, used */ > /* for wraparound handling */ > |
From: Linus T. <tor...@li...> - 2009-01-28 15:51:41
|
On Wed, 28 Jan 2009, Dave Airlie wrote: > > I'm quite happy to push this, if nobody objects with a good reason. Heh, since I was the one asking for this, I already applied it. If it breaks something, people can blame me. Linus |