summaryrefslogtreecommitdiff
path: root/media/libaom/src/aom_ports/aom_once.h
blob: d1a031bf177eef78e7cc938d862e7e8d3fad02b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#ifndef AOM_AOM_PORTS_AOM_ONCE_H_
#define AOM_AOM_PORTS_AOM_ONCE_H_

#include "config/aom_config.h"

/* Implement a function wrapper to guarantee initialization
 * thread-safety for library singletons.
 *
 * NOTE: This function uses static locks, and can only be
 * used with one common argument per compilation unit. So
 *
 * file1.c:
 *   aom_once(foo);
 *   ...
 *   aom_once(foo);
 *
 * file2.c:
 *   aom_once(bar);
 *
 * will ensure foo() and bar() are each called only once, but in
 *
 * file1.c:
 *   aom_once(foo);
 *   aom_once(bar):
 *
 * bar() will never be called because the lock is used up
 * by the call to foo().
 */

#if CONFIG_MULTITHREAD && defined(_WIN32)
#include <windows.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.
 */
static INIT_ONCE aom_init_once = INIT_ONCE_STATIC_INIT;

static void aom_once(void (*func)(void)) {
  BOOL pending;
  InitOnceBeginInitialize(&aom_init_once, 0, &pending, NULL);
  if (!pending) {
    // Initialization has already completed.
    return;
  }
  func();
  InitOnceComplete(&aom_init_once, 0, NULL);
}

#elif CONFIG_MULTITHREAD && defined(__OS2__)
#define INCL_DOS
#include <os2.h>
static void aom_once(void (*func)(void)) {
  static int done;

  /* If the initialization is complete, return early. */
  if (done) return;

  /* Causes all other threads in the process to block themselves
   * and give up their time slice.
   */
  DosEnterCritSec();

  if (!done) {
    func();
    done = 1;
  }

  /* Restores normal thread dispatching for the current process. */
  DosExitCritSec();
}

#elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H
#include <pthread.h>
static void aom_once(void (*func)(void)) {
  static pthread_once_t lock = PTHREAD_ONCE_INIT;
  pthread_once(&lock, func);
}

#else
/* Default version that performs no synchronization. */

static void aom_once(void (*func)(void)) {
  static int done;

  if (!done) {
    func();
    done = 1;
  }
}
#endif

#endif  // AOM_AOM_PORTS_AOM_ONCE_H_