1/*
2 *  Copyright (c) 2011 The WebM project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10#include "vpx_config.h"
11
12#if CONFIG_MULTITHREAD && defined(_WIN32)
13#include <windows.h>
14#include <stdlib.h>
15static void once(void (*func)(void))
16{
17    static CRITICAL_SECTION *lock;
18    static LONG waiters;
19    static int done;
20    void *lock_ptr = &lock;
21
22    /* If the initialization is complete, return early. This isn't just an
23     * optimization, it prevents races on the destruction of the global
24     * lock.
25     */
26    if(done)
27        return;
28
29    InterlockedIncrement(&waiters);
30
31    /* Get a lock. We create one and try to make it the one-true-lock,
32     * throwing it away if we lost the race.
33     */
34
35    {
36        /* Scope to protect access to new_lock */
37        CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION));
38        InitializeCriticalSection(new_lock);
39        if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL)
40        {
41            DeleteCriticalSection(new_lock);
42            free(new_lock);
43        }
44    }
45
46    /* At this point, we have a lock that can be synchronized on. We don't
47     * care which thread actually performed the allocation.
48     */
49
50    EnterCriticalSection(lock);
51
52    if (!done)
53    {
54        func();
55        done = 1;
56    }
57
58    LeaveCriticalSection(lock);
59
60    /* Last one out should free resources. The destructed objects are
61     * protected by checking if(done) above.
62     */
63    if(!InterlockedDecrement(&waiters))
64    {
65        DeleteCriticalSection(lock);
66        free(lock);
67        lock = NULL;
68    }
69}
70
71
72#elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H
73#include <pthread.h>
74static void once(void (*func)(void))
75{
76    static pthread_once_t lock = PTHREAD_ONCE_INIT;
77    pthread_once(&lock, func);
78}
79
80
81#else
82/* No-op version that performs no synchronization. vp8_rtcd() is idempotent,
83 * so as long as your platform provides atomic loads/stores of pointers
84 * no synchronization is strictly necessary.
85 */
86
87static void once(void (*func)(void))
88{
89    static int done;
90
91    if(!done)
92    {
93        func();
94        done = 1;
95    }
96}
97#endif
98