1233d2500723e5594f3e7c70896ffeeef32b9c950ywan/*
2233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Copyright (c) 2011 The WebM project authors. All Rights Reserved.
3233d2500723e5594f3e7c70896ffeeef32b9c950ywan *
4233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Use of this source code is governed by a BSD-style license
5233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  that can be found in the LICENSE file in the root of the source
6233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  tree. An additional intellectual property rights grant can be found
7233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  in the file PATENTS.  All contributing project authors may
8233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  be found in the AUTHORS file in the root of the source tree.
9233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
10233d2500723e5594f3e7c70896ffeeef32b9c950ywan
11233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifndef VPX_PORTS_VPX_ONCE_H_
12233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define VPX_PORTS_VPX_ONCE_H_
13233d2500723e5594f3e7c70896ffeeef32b9c950ywan
14233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx_config.h"
15233d2500723e5594f3e7c70896ffeeef32b9c950ywan
16233d2500723e5594f3e7c70896ffeeef32b9c950ywan#if CONFIG_MULTITHREAD && defined(_WIN32)
17233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <windows.h>
18233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdlib.h>
19233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void once(void (*func)(void))
20233d2500723e5594f3e7c70896ffeeef32b9c950ywan{
21233d2500723e5594f3e7c70896ffeeef32b9c950ywan    static CRITICAL_SECTION *lock;
22233d2500723e5594f3e7c70896ffeeef32b9c950ywan    static LONG waiters;
23233d2500723e5594f3e7c70896ffeeef32b9c950ywan    static int done;
24233d2500723e5594f3e7c70896ffeeef32b9c950ywan    void *lock_ptr = &lock;
25233d2500723e5594f3e7c70896ffeeef32b9c950ywan
26233d2500723e5594f3e7c70896ffeeef32b9c950ywan    /* If the initialization is complete, return early. This isn't just an
27233d2500723e5594f3e7c70896ffeeef32b9c950ywan     * optimization, it prevents races on the destruction of the global
28233d2500723e5594f3e7c70896ffeeef32b9c950ywan     * lock.
29233d2500723e5594f3e7c70896ffeeef32b9c950ywan     */
30233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if(done)
31233d2500723e5594f3e7c70896ffeeef32b9c950ywan        return;
32233d2500723e5594f3e7c70896ffeeef32b9c950ywan
33233d2500723e5594f3e7c70896ffeeef32b9c950ywan    InterlockedIncrement(&waiters);
34233d2500723e5594f3e7c70896ffeeef32b9c950ywan
35233d2500723e5594f3e7c70896ffeeef32b9c950ywan    /* Get a lock. We create one and try to make it the one-true-lock,
36233d2500723e5594f3e7c70896ffeeef32b9c950ywan     * throwing it away if we lost the race.
37233d2500723e5594f3e7c70896ffeeef32b9c950ywan     */
38233d2500723e5594f3e7c70896ffeeef32b9c950ywan
39233d2500723e5594f3e7c70896ffeeef32b9c950ywan    {
40233d2500723e5594f3e7c70896ffeeef32b9c950ywan        /* Scope to protect access to new_lock */
41233d2500723e5594f3e7c70896ffeeef32b9c950ywan        CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION));
42233d2500723e5594f3e7c70896ffeeef32b9c950ywan        InitializeCriticalSection(new_lock);
43233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL)
44233d2500723e5594f3e7c70896ffeeef32b9c950ywan        {
45233d2500723e5594f3e7c70896ffeeef32b9c950ywan            DeleteCriticalSection(new_lock);
46233d2500723e5594f3e7c70896ffeeef32b9c950ywan            free(new_lock);
47233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
48233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
49233d2500723e5594f3e7c70896ffeeef32b9c950ywan
50233d2500723e5594f3e7c70896ffeeef32b9c950ywan    /* At this point, we have a lock that can be synchronized on. We don't
51233d2500723e5594f3e7c70896ffeeef32b9c950ywan     * care which thread actually performed the allocation.
52233d2500723e5594f3e7c70896ffeeef32b9c950ywan     */
53233d2500723e5594f3e7c70896ffeeef32b9c950ywan
54233d2500723e5594f3e7c70896ffeeef32b9c950ywan    EnterCriticalSection(lock);
55233d2500723e5594f3e7c70896ffeeef32b9c950ywan
56233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (!done)
57233d2500723e5594f3e7c70896ffeeef32b9c950ywan    {
58233d2500723e5594f3e7c70896ffeeef32b9c950ywan        func();
59233d2500723e5594f3e7c70896ffeeef32b9c950ywan        done = 1;
60233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
61233d2500723e5594f3e7c70896ffeeef32b9c950ywan
62233d2500723e5594f3e7c70896ffeeef32b9c950ywan    LeaveCriticalSection(lock);
63233d2500723e5594f3e7c70896ffeeef32b9c950ywan
64233d2500723e5594f3e7c70896ffeeef32b9c950ywan    /* Last one out should free resources. The destructed objects are
65233d2500723e5594f3e7c70896ffeeef32b9c950ywan     * protected by checking if(done) above.
66233d2500723e5594f3e7c70896ffeeef32b9c950ywan     */
67233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if(!InterlockedDecrement(&waiters))
68233d2500723e5594f3e7c70896ffeeef32b9c950ywan    {
69233d2500723e5594f3e7c70896ffeeef32b9c950ywan        DeleteCriticalSection(lock);
70233d2500723e5594f3e7c70896ffeeef32b9c950ywan        free(lock);
71233d2500723e5594f3e7c70896ffeeef32b9c950ywan        lock = NULL;
72233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
73233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
74233d2500723e5594f3e7c70896ffeeef32b9c950ywan
75233d2500723e5594f3e7c70896ffeeef32b9c950ywan
76233d2500723e5594f3e7c70896ffeeef32b9c950ywan#elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H
77233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <pthread.h>
78233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void once(void (*func)(void))
79233d2500723e5594f3e7c70896ffeeef32b9c950ywan{
80233d2500723e5594f3e7c70896ffeeef32b9c950ywan    static pthread_once_t lock = PTHREAD_ONCE_INIT;
81233d2500723e5594f3e7c70896ffeeef32b9c950ywan    pthread_once(&lock, func);
82233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
83233d2500723e5594f3e7c70896ffeeef32b9c950ywan
84233d2500723e5594f3e7c70896ffeeef32b9c950ywan
85233d2500723e5594f3e7c70896ffeeef32b9c950ywan#else
86233d2500723e5594f3e7c70896ffeeef32b9c950ywan/* No-op version that performs no synchronization. vp8_rtcd() is idempotent,
87233d2500723e5594f3e7c70896ffeeef32b9c950ywan * so as long as your platform provides atomic loads/stores of pointers
88233d2500723e5594f3e7c70896ffeeef32b9c950ywan * no synchronization is strictly necessary.
89233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
90233d2500723e5594f3e7c70896ffeeef32b9c950ywan
91233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void once(void (*func)(void))
92233d2500723e5594f3e7c70896ffeeef32b9c950ywan{
93233d2500723e5594f3e7c70896ffeeef32b9c950ywan    static int done;
94233d2500723e5594f3e7c70896ffeeef32b9c950ywan
95233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if(!done)
96233d2500723e5594f3e7c70896ffeeef32b9c950ywan    {
97233d2500723e5594f3e7c70896ffeeef32b9c950ywan        func();
98233d2500723e5594f3e7c70896ffeeef32b9c950ywan        done = 1;
99233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
100233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
101233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
102233d2500723e5594f3e7c70896ffeeef32b9c950ywan
103233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif  // VPX_PORTS_VPX_ONCE_H_
104