1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #ifndef GRPC_SUPPORT_SYNC_H
20 #define GRPC_SUPPORT_SYNC_H
21 
22 /* Platform-specific type declarations of gpr_mu and gpr_cv.   */
23 #include <grpc/support/port_platform.h>
24 
25 #include <grpc/support/time.h> /* for gpr_timespec */
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 
31 /** Synchronization primitives for GPR.
32 
33    The type  gpr_mu              provides a non-reentrant mutex (lock).
34 
35    The type  gpr_cv              provides a condition variable.
36 
37    The type  gpr_once            provides for one-time initialization.
38 
39    The type gpr_event            provides one-time-setting, reading, and
40                                  waiting of a void*, with memory barriers.
41 
42    The type gpr_refcount         provides an object reference counter,
43                                  with memory barriers suitable to control
44                                  object lifetimes.
45 
46    The type gpr_stats_counter    provides an atomic statistics counter. It
47                                  provides no memory barriers.
48  */
49 
50 #include <grpc/support/sync_generic.h>  // IWYU pragma: export
51 
52 #if defined(GPR_CUSTOM_SYNC)
53 #include <grpc/support/sync_custom.h>  // IWYU pragma: export
54 #elif defined(GPR_ABSEIL_SYNC)
55 #include <grpc/support/sync_abseil.h>  // IWYU pragma: export
56 #elif defined(GPR_POSIX_SYNC)
57 #include <grpc/support/sync_posix.h>  // IWYU pragma: export
58 #elif defined(GPR_WINDOWS)
59 #include <grpc/support/sync_windows.h>  // IWYU pragma: export
60 #else
61 #error Unable to determine platform for sync
62 #endif
63 
64 /** --- Mutex interface ---
65 
66    At most one thread may hold an exclusive lock on a mutex at any given time.
67    Actions taken by a thread that holds a mutex exclusively happen after
68    actions taken by all previous holders of the mutex.  Variables of type
69    gpr_mu are uninitialized when first declared.  */
70 
71 /** Initialize *mu.  Requires:  *mu uninitialized.  */
72 GPRAPI void gpr_mu_init(gpr_mu* mu);
73 
74 /** Cause *mu no longer to be initialized, freeing any memory in use.  Requires:
75  *mu initialized; no other concurrent operation on *mu.  */
76 GPRAPI void gpr_mu_destroy(gpr_mu* mu);
77 
78 /** Wait until no thread has a lock on *mu, cause the calling thread to own an
79    exclusive lock on *mu, then return.  May block indefinitely or crash if the
80    calling thread has a lock on *mu.  Requires:  *mu initialized.  */
81 GPRAPI void gpr_mu_lock(gpr_mu* mu);
82 
83 /** Release an exclusive lock on *mu held by the calling thread.  Requires:  *mu
84    initialized; the calling thread holds an exclusive lock on *mu.  */
85 GPRAPI void gpr_mu_unlock(gpr_mu* mu);
86 
87 /** Without blocking, attempt to acquire an exclusive lock on *mu for the
88    calling thread, then return non-zero iff success.  Fail, if any thread holds
89    the lock; succeeds with high probability if no thread holds the lock.
90    Requires:  *mu initialized.  */
91 GPRAPI int gpr_mu_trylock(gpr_mu* mu);
92 
93 /** --- Condition variable interface ---
94 
95    A while-loop should be used with gpr_cv_wait() when waiting for conditions
96    to become true.  See the example below.  Variables of type gpr_cv are
97    uninitialized when first declared.  */
98 
99 /** Initialize *cv.  Requires:  *cv uninitialized.  */
100 GPRAPI void gpr_cv_init(gpr_cv* cv);
101 
102 /** Cause *cv no longer to be initialized, freeing any memory in use.  Requires:
103  *cv initialized; no other concurrent operation on *cv.*/
104 GPRAPI void gpr_cv_destroy(gpr_cv* cv);
105 
106 /** Atomically release *mu and wait on *cv.  When the calling thread is woken
107    from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
108    and return whether the deadline was exceeded.  Use
109    abs_deadline==gpr_inf_future for no deadline.  abs_deadline can be either
110    an absolute deadline, or a GPR_TIMESPAN.  May return even when not
111    woken explicitly.  Requires:  *mu and *cv initialized; the calling thread
112    holds an exclusive lock on *mu.  */
113 GPRAPI int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline);
114 
115 /** If any threads are waiting on *cv, wake at least one.
116    Clients may treat this as an optimization of gpr_cv_broadcast()
117    for use in the case where waking more than one waiter is not useful.
118    Requires:  *cv initialized.  */
119 GPRAPI void gpr_cv_signal(gpr_cv* cv);
120 
121 /** Wake all threads waiting on *cv.  Requires:  *cv initialized.  */
122 GPRAPI void gpr_cv_broadcast(gpr_cv* cv);
123 
124 /** --- One-time initialization ---
125 
126    gpr_once must be declared with static storage class, and initialized with
127    GPR_ONCE_INIT.  e.g.,
128      static gpr_once once_var = GPR_ONCE_INIT;     */
129 
130 /** Ensure that (*init_function)() has been called exactly once (for the
131    specified gpr_once instance) and then return.
132    If multiple threads call gpr_once() on the same gpr_once instance, one of
133    them will call (*init_function)(), and the others will block until that call
134    finishes.*/
135 GPRAPI void gpr_once_init(gpr_once* once, void (*init_function)(void));
136 
137 /** --- One-time event notification ---
138 
139   These operations act on a gpr_event, which should be initialized with
140   gpr_ev_init(), or with GPR_EVENT_INIT if static, e.g.,
141        static gpr_event event_var = GPR_EVENT_INIT;
142   It requires no destruction.  */
143 
144 /** Initialize *ev. */
145 GPRAPI void gpr_event_init(gpr_event* ev);
146 
147 /** Set *ev so that gpr_event_get() and gpr_event_wait() will return value.
148    Requires:  *ev initialized; value != NULL; no prior or concurrent calls to
149    gpr_event_set(ev, ...) since initialization.  */
150 GPRAPI void gpr_event_set(gpr_event* ev, void* value);
151 
152 /** Return the value set by gpr_event_set(ev, ...), or NULL if no such call has
153    completed.  If the result is non-NULL, all operations that occurred prior to
154    the gpr_event_set(ev, ...) set will be visible after this call returns.
155    Requires:  *ev initialized.  This operation is faster than acquiring a mutex
156    on most platforms.  */
157 GPRAPI void* gpr_event_get(gpr_event* ev);
158 
159 /** Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is
160    exceeded, then return gpr_event_get(ev).  Requires:  *ev initialized.  Use
161    abs_deadline==gpr_inf_future for no deadline.  When the event has been
162    signalled before the call, this operation is faster than acquiring a mutex
163    on most platforms.  */
164 GPRAPI void* gpr_event_wait(gpr_event* ev, gpr_timespec abs_deadline);
165 
166 /** --- Reference counting ---
167 
168    These calls act on the type gpr_refcount.  It requires no destruction.  */
169 
170 /** Initialize *r to value n.  */
171 GPRAPI void gpr_ref_init(gpr_refcount* r, int n);
172 
173 /** Increment the reference count *r.  Requires *r initialized. */
174 GPRAPI void gpr_ref(gpr_refcount* r);
175 
176 /** Increment the reference count *r.  Requires *r initialized.
177    Crashes if refcount is zero */
178 GPRAPI void gpr_ref_non_zero(gpr_refcount* r);
179 
180 /** Increment the reference count *r by n.  Requires *r initialized, n > 0. */
181 GPRAPI void gpr_refn(gpr_refcount* r, int n);
182 
183 /** Decrement the reference count *r and return non-zero iff it has reached
184    zero. .  Requires *r initialized. */
185 GPRAPI int gpr_unref(gpr_refcount* r);
186 
187 /** Return non-zero iff the reference count of *r is one, and thus is owned
188    by exactly one object. */
189 GPRAPI int gpr_ref_is_unique(gpr_refcount* r);
190 
191 /** --- Stats counters ---
192 
193    These calls act on the integral type gpr_stats_counter.  It requires no
194    destruction.  Static instances may be initialized with
195        gpr_stats_counter c = GPR_STATS_INIT;
196    Beware:  These operations do not imply memory barriers.  Do not use them to
197    synchronize other events.  */
198 
199 /** Initialize *c to the value n. */
200 GPRAPI void gpr_stats_init(gpr_stats_counter* c, intptr_t n);
201 
202 /** *c += inc.  Requires: *c initialized. */
203 GPRAPI void gpr_stats_inc(gpr_stats_counter* c, intptr_t inc);
204 
205 /** Return *c.  Requires: *c initialized. */
206 GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter* c);
207 
208 /** ==================Example use of interface===================
209    A producer-consumer queue of up to N integers,
210    illustrating the use of the calls in this interface. */
211 #if 0
212 
213 #define N 4
214 
215    typedef struct queue {
216      gpr_cv non_empty;  /* Signalled when length becomes non-zero. */
217      gpr_cv non_full;   /* Signalled when length becomes non-N. */
218      gpr_mu mu;         /* Protects all fields below.
219                             (That is, except during initialization or
220                             destruction, the fields below should be accessed
221                             only by a thread that holds mu.) */
222      int head;           /* Index of head of queue 0..N-1. */
223      int length;         /* Number of valid elements in queue 0..N. */
224      int elem[N];        /* elem[head .. head+length-1] are queue elements. */
225    } queue;
226 
227    /* Initialize *q. */
228    void queue_init(queue *q) {
229      gpr_mu_init(&q->mu);
230      gpr_cv_init(&q->non_empty);
231      gpr_cv_init(&q->non_full);
232      q->head = 0;
233      q->length = 0;
234    }
235 
236    /* Free storage associated with *q. */
237    void queue_destroy(queue *q) {
238      gpr_mu_destroy(&q->mu);
239      gpr_cv_destroy(&q->non_empty);
240      gpr_cv_destroy(&q->non_full);
241    }
242 
243    /* Wait until there is room in *q, then append x to *q. */
244    void queue_append(queue *q, int x) {
245      gpr_mu_lock(&q->mu);
246      /* To wait for a predicate without a deadline, loop on the negation of the
247         predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
248         to release the lock, wait, and reacquire on each iteration.  Code that
249         makes the condition true should use gpr_cv_broadcast() on the
250         corresponding condition variable.  The predicate must be on state
251         protected by the lock.  */
252      while (q->length == N) {
253        gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
254      }
255      if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
256        /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
257           holding the lock. */
258        gpr_cv_broadcast(&q->non_empty);
259      }
260      q->elem[(q->head + q->length) % N] = x;
261      q->length++;
262      gpr_mu_unlock(&q->mu);
263    }
264 
265    /* If it can be done without blocking, append x to *q and return non-zero.
266       Otherwise return 0. */
267    int queue_try_append(queue *q, int x) {
268      int result = 0;
269      if (gpr_mu_trylock(&q->mu)) {
270        if (q->length != N) {
271          if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
272            gpr_cv_broadcast(&q->non_empty);
273          }
274          q->elem[(q->head + q->length) % N] = x;
275          q->length++;
276          result = 1;
277        }
278        gpr_mu_unlock(&q->mu);
279      }
280      return result;
281    }
282 
283    /* Wait until the *q is non-empty or deadline abs_deadline passes.  If the
284       queue is non-empty, remove its head entry, place it in *head, and return
285       non-zero.  Otherwise return 0.  */
286    int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
287      int result = 0;
288      gpr_mu_lock(&q->mu);
289      /* To wait for a predicate with a deadline, loop on the negation of the
290         predicate or until gpr_cv_wait() returns true.  Code that makes
291         the condition true should use gpr_cv_broadcast() on the corresponding
292         condition variable.  The predicate must be on state protected by the
293         lock. */
294      while (q->length == 0 &&
295             !gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
296      }
297      if (q->length != 0) {    /* Queue is non-empty. */
298        result = 1;
299        if (q->length == N) {  /* Wake threads blocked in queue_append(). */
300          gpr_cv_broadcast(&q->non_full);
301        }
302        *head = q->elem[q->head];
303        q->head = (q->head + 1) % N;
304        q->length--;
305      } /* else deadline exceeded */
306      gpr_mu_unlock(&q->mu);
307      return result;
308    }
309 #endif /* 0 */
310 
311 #ifdef __cplusplus
312 }  // extern "C"
313 #endif
314 
315 #endif /* GRPC_SUPPORT_SYNC_H */
316