Implement aom_once using Win32 InitOnce functions.

On Windows Vista and later, we can use InitOnceBeginInitialize() and
InitOnceComplete() to implement aom_once().

BUG=aomedia:2224

Change-Id: I2f38c7f4386a618df07ab1e765889050f3f666c2
diff --git a/aom_ports/aom_once.h b/aom_ports/aom_once.h
index 4d77aac..d1a031b 100644
--- a/aom_ports/aom_once.h
+++ b/aom_ports/aom_once.h
@@ -40,56 +40,22 @@
 
 #if CONFIG_MULTITHREAD && defined(_WIN32)
 #include <windows.h>
-#include <stdlib.h>
 /* Declare a per-compilation-unit state variable to track the progress
  * of calling func() only once. This must be at global scope because
  * local initializers are not thread-safe in MSVC prior to Visual
  * Studio 2015.
- *
- * As a static, aom_once_state will be zero-initialized as program start.
  */
-static LONG aom_once_state;
+static INIT_ONCE aom_init_once = INIT_ONCE_STATIC_INIT;
+
 static void aom_once(void (*func)(void)) {
-  /* Try to advance aom_once_state from its initial value of 0 to 1.
-   * Only one thread can succeed in doing so.
-   */
-  if (InterlockedCompareExchange(&aom_once_state, 1, 0) == 0) {
-    /* We're the winning thread, having set aom_once_state to 1.
-     * Call our function. */
-    func();
-    /* Now advance aom_once_state to 2, unblocking any other threads. */
-    InterlockedIncrement(&aom_once_state);
+  BOOL pending;
+  InitOnceBeginInitialize(&aom_init_once, 0, &pending, NULL);
+  if (!pending) {
+    // Initialization has already completed.
     return;
   }
-
-  /* We weren't the winning thread, but we want to block on
-   * the state variable so we don't return before func()
-   * has finished executing elsewhere.
-   *
-   * Try to advance aom_once_state from 2 to 2, which is only possible
-   * after the winning thead advances it from 1 to 2.
-   */
-  while (InterlockedCompareExchange(&aom_once_state, 2, 2) != 2) {
-    /* State isn't yet 2. Try again.
-     *
-     * We are used for singleton initialization functions,
-     * which should complete quickly. Contention will likewise
-     * be rare, so it's worthwhile to use a simple but cpu-
-     * intensive busy-wait instead of successive backoff,
-     * waiting on a kernel object, or another heavier-weight scheme.
-     *
-     * We can at least yield our timeslice.
-     */
-    Sleep(0);
-  }
-
-  /* We've seen aom_once_state advance to 2, so we know func()
-   * has been called. And we've left aom_once_state as we found it,
-   * so other threads will have the same experience.
-   *
-   * It's safe to return now.
-   */
-  return;
+  func();
+  InitOnceComplete(&aom_init_once, 0, NULL);
 }
 
 #elif CONFIG_MULTITHREAD && defined(__OS2__)