summaryrefslogtreecommitdiff
path: root/src/upb_atomic.h
blob: c1a60b9003f8e63662735b20999b4293bb287a6c (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 * upb - a minimalist implementation of protocol buffers.
 *
 * Copyright (c) 2009 Joshua Haberman.  See LICENSE for details.
 *
 * Only a very small part of upb is thread-safe.  Notably, individual
 * messages, arrays, and strings are *not* thread safe for mutating.
 * However, we do make message *metadata* such as upb_msgdef and
 * upb_context thread-safe, and their ownership is tracked via atomic
 * refcounting.  This header implements the small number of atomic
 * primitives required to support this.  The primitives we implement
 * are:
 *
 * - a reader/writer lock (wrappers around platform-provided mutexes).
 * - an atomic refcount.
 */

#ifndef UPB_ATOMIC_H_
#define UPB_ATOMIC_H_

#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/* inline if possible, emit standalone code if required. */
#ifndef INLINE
#define INLINE static inline
#endif

#ifdef UPB_THREAD_UNSAFE

/* Non-thread-safe implementations. ******************************************/

typedef struct {
  int val;
} upb_atomic_refcount_t;

INLINE void upb_atomic_refcount_init(upb_atomic_refcount_t *a, int val) {
  a->val = val;
}

INLINE bool upb_atomic_ref(upb_atomic_refcount_t *a) {
  return a->val++ == 0;
}

INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
  return --a->val == 0;
}

typedef struct {
} upb_rwlock_t;

INLINE void upb_rwlock_init(upb_rwlock_t *l) { (void)l; }
INLINE void upb_rwlock_destroy(upb_rwlock_t *l) { (void)l; }
INLINE void upb_rwlock_rdlock(upb_rwlock_t *l) { (void)l; }
INLINE void upb_rwlock_wrlock(upb_rwlock_t *l) { (void)l; }
INLINE void upb_rwlock_unlock(upb_rwlock_t *l) { (void)l; }

#endif

/* Atomic refcount ************************************************************/

#ifdef UPB_THREAD_UNSAFE

/* Already defined above. */

#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4

/* GCC includes atomic primitives. */

typedef struct {
  volatile int val;
} upb_atomic_refcount_t;

INLINE void upb_atomic_refcount_init(upb_atomic_refcount_t *a, int val) {
  a->val = val;
  __sync_synchronize();   /* Ensure the initialized value is visible. */
}

INLINE bool upb_atomic_ref(upb_atomic_refcount_t *a) {
  return __sync_fetch_and_add(&a->val, 1) == 0;
}

INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
  return __sync_sub_and_fetch(&a->val, 1) == 0;
}

#elif defined(WIN32)

/* Windows defines atomic increment/decrement. */
#include <Windows.h>

typedef struct {
  volatile LONG val;
} upb_atomic_refcount_t;

INLINE void upb_atomic_refcount_init(upb_atomic_refcount_t *a, int val) {
  InterlockedExchange(&a->val, val);
}

INLINE bool upb_atomic_ref(upb_atomic_refcount_t *a) {
  return InterlockedIncrement(&a->val) == 1;
}

INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
  return InterlockedDecrement(&a->val) == 0;
}

#else
#error Atomic primitives not defined for your platform/CPU.  \
       Implement them or compile with UPB_THREAD_UNSAFE.
#endif

/* Reader/Writer lock. ********************************************************/

#ifdef UPB_THREAD_UNSAFE

/* Already defined. */

#elif defined(UPB_USE_PTHREADS)

#include <pthread.h>

typedef struct {
  pthread_rwlock_t lock;
} upb_rwlock_t;

INLINE void upb_rwlock_init(upb_rwlock_t *l) {
  /* TODO: check return value. */
  pthread_rwlock_init(&l->lock, NULL);
}

INLINE void upb_rwlock_destroy(upb_rwlock_t *l) {
  /* TODO: check return value. */
  pthread_rwlock_destroy(&l->lock);
}

INLINE void upb_rwlock_rdlock(upb_rwlock_t *l) {
  /* TODO: check return value. */
  pthread_rwlock_rdlock(&l->lock);
}

INLINE void upb_rwlock_wrlock(upb_rwlock_t *l) {
  /* TODO: check return value. */
  pthread_rwlock_wrlock(&l->lock);
}

INLINE void upb_rwlock_unlock(upb_rwlock_t *l) {
  /* TODO: check return value. */
  pthread_rwlock_unlock(&l->lock);
}

#else
#error Reader/writer lock is not defined for your platform/CPU.  \
       Implement it or compile with UPB_THREAD_UNSAFE.
#endif

#ifdef __cplusplus
}  /* extern "C" */
#endif

#endif  /* UPB_ATOMIC_H_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback