V4L/DVB (7319): pvrusb2: Close potential race condition during initialization
authorMike Isely <isely@pobox.com>
Tue, 22 Apr 2008 17:45:44 +0000 (14:45 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Thu, 24 Apr 2008 17:07:48 +0000 (14:07 -0300)
There is a callback that is issued to into pvr2_context from pvr2_hdw
after initialization is done.  There was a probability that this
callback could get missed.  Fixed.

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/pvrusb2/pvrusb2-context.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h

index 2a6726e..953784c 100644 (file)
@@ -75,10 +75,9 @@ struct pvr2_context *pvr2_context_create(
                mp = NULL;
                goto done;
        }
-       pvr2_hdw_set_state_callback(mp->hdw,
-                                   (void (*)(void *))pvr2_context_state_check,
-                                   mp);
-       pvr2_context_state_check(mp);
+       pvr2_hdw_initialize(mp->hdw,
+                           (void (*)(void *))pvr2_context_state_check,
+                           mp);
  done:
        return mp;
 }
index c51c5ce..f2d2677 100644 (file)
@@ -1813,8 +1813,23 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
 }
 
 
-/* Create and return a structure for interacting with the underlying
-   hardware */
+/* Perform second stage initialization.  Set callback pointer first so that
+   we can avoid a possible initialization race (if the kernel thread runs
+   before the callback has been set). */
+void pvr2_hdw_initialize(struct pvr2_hdw *hdw,
+                        void (*callback_func)(void *),
+                        void *callback_data)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               hdw->state_data = callback_data;
+               hdw->state_func = callback_func;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       queue_work(hdw->workqueue,&hdw->workinit);
+}
+
+
+/* Create, set up, and return a structure for interacting with the
+   underlying hardware.  */
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                 const struct usb_device_id *devid)
 {
@@ -2039,7 +2054,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        mutex_init(&hdw->ctl_lock_mutex);
        mutex_init(&hdw->big_lock_mutex);
 
-       queue_work(hdw->workqueue,&hdw->workinit);
        return hdw;
  fail:
        if (hdw) {
@@ -2521,17 +2535,6 @@ static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
 }
 
 
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
-                                void (*callback_func)(void *),
-                                void *callback_data)
-{
-       LOCK_TAKE(hdw->big_lock); do {
-               hdw->state_data = callback_data;
-               hdw->state_func = callback_func;
-       } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 {
index 57e1ff4..597ee50 100644 (file)
@@ -101,14 +101,15 @@ struct pvr2_hdw;
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                 const struct usb_device_id *devid);
 
+/* Perform second stage initialization, passing in a notification callback
+   for when the master state changes. */
+void pvr2_hdw_initialize(struct pvr2_hdw *,
+                        void (*callback_func)(void *),
+                        void *callback_data);
+
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *);
 
-/* Register a function to be called whenever the master state changes. */
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
-                                void (*callback_func)(void *),
-                                void *callback_data);
-
 /* Return true if in the ready (normal) state */
 int pvr2_hdw_dev_ok(struct pvr2_hdw *);