shithub: libvpx

Download patch

ref: 8a7cc1f47bde271c5200550f1f7e7f6a55872b65
parent: c00e9c4709c1ac3828ce13aae158011495e7de35
parent: 8701ed0270dd8da44efff5e19f3b0b6d3cac5b8b
author: James Zern <jzern@google.com>
date: Thu Jul 10 19:19:55 EDT 2014

Merge "update vp9_thread.c"

--- a/test/vp9_thread_test.cc
+++ b/test/vp9_thread_test.cc
@@ -35,6 +35,15 @@
     vp9_get_worker_interface()->end(&worker_);
   }
 
+  void Run(VP9Worker* worker) {
+    const bool synchronous = GetParam();
+    if (synchronous) {
+      vp9_get_worker_interface()->execute(worker);
+    } else {
+      vp9_get_worker_interface()->launch(worker);
+    }
+  }
+
   VP9Worker worker_;
 };
 
@@ -57,12 +66,7 @@
     worker_.data1 = &hook_data;
     worker_.data2 = &return_value;
 
-    const bool synchronous = GetParam();
-    if (synchronous) {
-      vp9_get_worker_interface()->execute(&worker_);
-    } else {
-      vp9_get_worker_interface()->launch(&worker_);
-    }
+    Run(&worker_);
     EXPECT_NE(vp9_get_worker_interface()->sync(&worker_), 0);
     EXPECT_FALSE(worker_.had_error);
     EXPECT_EQ(5, hook_data);
@@ -81,12 +85,7 @@
   worker_.data1 = &hook_data;
   worker_.data2 = &return_value;
 
-  const bool synchronous = GetParam();
-  if (synchronous) {
-    vp9_get_worker_interface()->execute(&worker_);
-  } else {
-    vp9_get_worker_interface()->launch(&worker_);
-  }
+  Run(&worker_);
   EXPECT_FALSE(vp9_get_worker_interface()->sync(&worker_));
   EXPECT_EQ(1, worker_.had_error);
 
@@ -97,6 +96,39 @@
   vp9_get_worker_interface()->launch(&worker_);
   EXPECT_NE(vp9_get_worker_interface()->sync(&worker_), 0);
   EXPECT_FALSE(worker_.had_error);
+}
+
+TEST_P(VP9WorkerThreadTest, EndWithoutSync) {
+  // Create a large number of threads to increase the chances of detecting a
+  // race. Doing more work in the hook is no guarantee as any race would occur
+  // post hook execution in the main thread loop driver.
+  static const int kNumWorkers = 64;
+  VP9Worker workers[kNumWorkers];
+  int hook_data[kNumWorkers];
+  int return_value[kNumWorkers];
+
+  for (int n = 0; n < kNumWorkers; ++n) {
+    vp9_get_worker_interface()->init(&workers[n]);
+    return_value[n] = 1;  // return successfully from the hook
+    workers[n].hook = ThreadHook;
+    workers[n].data1 = &hook_data[n];
+    workers[n].data2 = &return_value[n];
+  }
+
+  for (int i = 0; i < 2; ++i) {
+    for (int n = 0; n < kNumWorkers; ++n) {
+      EXPECT_NE(vp9_get_worker_interface()->reset(&workers[n]), 0);
+      hook_data[n] = 0;
+    }
+
+    for (int n = 0; n < kNumWorkers; ++n) {
+      Run(&workers[n]);
+    }
+
+    for (int n = kNumWorkers - 1; n >= 0; --n) {
+      vp9_get_worker_interface()->end(&workers[n]);
+    }
+  }
 }
 
 TEST(VP9WorkerThreadTest, TestInterfaceAPI) {
--- a/vp9/common/vp9_thread.c
+++ b/vp9/common/vp9_thread.c
@@ -11,7 +11,7 @@
 //
 // Original source:
 //  http://git.chromium.org/webm/libwebp.git
-//  100644 blob 08ad4e1fecba302bf1247645e84a7d2779956bc3  src/utils/thread.c
+//  100644 blob 264210ba2807e4da47eb5d18c04cf869d89b9784  src/utils/thread.c
 
 #include <assert.h>
 #include <string.h>   // for memset()
@@ -144,18 +144,19 @@
 }
 
 static void end(VP9Worker *const worker) {
-  if (worker->status_ >= OK) {
 #if CONFIG_MULTITHREAD
+  if (worker->impl_ != NULL) {
     change_state(worker, NOT_OK);
     pthread_join(worker->impl_->thread_, NULL);
     pthread_mutex_destroy(&worker->impl_->mutex_);
     pthread_cond_destroy(&worker->impl_->condition_);
+    vpx_free(worker->impl_);
+    worker->impl_ = NULL;
+  }
 #else
-    worker->status_ = NOT_OK;
+  worker->status_ = NOT_OK;
+  assert(worker->impl_ == NULL);
 #endif
-  }
-  vpx_free(worker->impl_);
-  worker->impl_ = NULL;
   assert(worker->status_ == NOT_OK);
 }