1ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang/*
2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  Copyright (c) 2011 The WebM project authors. All Rights Reserved.
3ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *
4ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  Use of this source code is governed by a BSD-style license
5ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  that can be found in the LICENSE file in the root of the source
6ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  tree. An additional intellectual property rights grant can be found
7ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  in the file PATENTS.  All contributing project authors may
8ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  be found in the AUTHORS file in the root of the source tree.
9ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang */
102ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
112ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#ifndef VPX_PORTS_VPX_ONCE_H_
122ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#define VPX_PORTS_VPX_ONCE_H_
132ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
14ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "vpx_config.h"
15ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
16ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#if CONFIG_MULTITHREAD && defined(_WIN32)
17ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include <windows.h>
18ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include <stdlib.h>
19ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangstatic void once(void (*func)(void))
20ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang{
21ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    static CRITICAL_SECTION *lock;
22ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    static LONG waiters;
23ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    static int done;
24ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void *lock_ptr = &lock;
25ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
26ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    /* If the initialization is complete, return early. This isn't just an
27ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     * optimization, it prevents races on the destruction of the global
28ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     * lock.
29ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     */
30ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    if(done)
31ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        return;
32ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
33ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    InterlockedIncrement(&waiters);
34ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
35ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    /* Get a lock. We create one and try to make it the one-true-lock,
36ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     * throwing it away if we lost the race.
37ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     */
38ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
39ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
40ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        /* Scope to protect access to new_lock */
41ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION));
42ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        InitializeCriticalSection(new_lock);
43ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL)
44ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        {
45ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang            DeleteCriticalSection(new_lock);
46ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang            free(new_lock);
47ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        }
48ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
49ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
50ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    /* At this point, we have a lock that can be synchronized on. We don't
51ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     * care which thread actually performed the allocation.
52ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     */
53ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
54ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    EnterCriticalSection(lock);
55ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
56ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    if (!done)
57ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
58ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        func();
59ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        done = 1;
60ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
61ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
62ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    LeaveCriticalSection(lock);
63ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
64ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    /* Last one out should free resources. The destructed objects are
65ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     * protected by checking if(done) above.
66ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang     */
67ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    if(!InterlockedDecrement(&waiters))
68ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
69ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        DeleteCriticalSection(lock);
70ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        free(lock);
71ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        lock = NULL;
72ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
73ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang}
74ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
75ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
76ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian#elif CONFIG_MULTITHREAD && defined(__OS2__)
77ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian#define INCL_DOS
78ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian#include <os2.h>
79ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanianstatic void once(void (*func)(void))
80ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian{
81ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    static int done;
82ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
83ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    /* If the initialization is complete, return early. */
84ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    if(done)
85ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian        return;
86ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
87ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    /* Causes all other threads in the process to block themselves
88ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian     * and give up their time slice.
89ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian     */
90ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    DosEnterCritSec();
91ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
92ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    if (!done)
93ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    {
94ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian        func();
95ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian        done = 1;
96ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    }
97ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
98ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    /* Restores normal thread dispatching for the current process. */
99ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    DosExitCritSec();
100ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian}
101ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
102ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
103ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H
104ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include <pthread.h>
105ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangstatic void once(void (*func)(void))
106ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang{
107ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    static pthread_once_t lock = PTHREAD_ONCE_INIT;
108ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    pthread_once(&lock, func);
109ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang}
110ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
111ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
112ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#else
113da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/* No-op version that performs no synchronization. *_rtcd() is idempotent,
114ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * so as long as your platform provides atomic loads/stores of pointers
115ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * no synchronization is strictly necessary.
116ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang */
117ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
118ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangstatic void once(void (*func)(void))
119ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang{
120ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    static int done;
121ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
122ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    if(!done)
123ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
124ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        func();
125ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        done = 1;
126ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
127ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang}
128ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#endif
1292ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1302ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#endif  // VPX_PORTS_VPX_ONCE_H_
131