Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : /* Generic implementation of synchronization primitives. */
35 :
36 : #include <grpc/support/log.h>
37 : #include <grpc/support/sync.h>
38 : #include <grpc/support/atm.h>
39 :
40 : /* Number of mutexes to allocate for events, to avoid lock contention.
41 : Should be a prime. */
42 : enum { event_sync_partitions = 31 };
43 :
44 : /* Events are partitioned by address to avoid lock contention. */
45 : static struct sync_array_s {
46 : gpr_mu mu;
47 : gpr_cv cv;
48 : } sync_array[event_sync_partitions];
49 :
50 : /* This routine is executed once on first use, via event_once */
51 : static gpr_once event_once = GPR_ONCE_INIT;
52 26 : static void event_initialize(void) {
53 : int i;
54 832 : for (i = 0; i != event_sync_partitions; i++) {
55 806 : gpr_mu_init(&sync_array[i].mu);
56 806 : gpr_cv_init(&sync_array[i].cv);
57 : }
58 26 : }
59 :
60 : /* Hash ev into an element of sync_array[]. */
61 21224 : static struct sync_array_s *hash(gpr_event *ev) {
62 21224 : return &sync_array[((gpr_uintptr)ev) % event_sync_partitions];
63 : }
64 :
65 452 : void gpr_event_init(gpr_event *ev) {
66 452 : gpr_once_init(&event_once, &event_initialize);
67 452 : ev->state = 0;
68 452 : }
69 :
70 421 : void gpr_event_set(gpr_event *ev, void *value) {
71 421 : struct sync_array_s *s = hash(ev);
72 421 : gpr_mu_lock(&s->mu);
73 421 : GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0);
74 421 : gpr_atm_rel_store(&ev->state, (gpr_atm)value);
75 421 : gpr_cv_broadcast(&s->cv);
76 421 : gpr_mu_unlock(&s->mu);
77 419 : GPR_ASSERT(value != NULL);
78 419 : }
79 :
80 19 : void *gpr_event_get(gpr_event *ev) {
81 19 : return (void *)gpr_atm_acq_load(&ev->state);
82 : }
83 :
84 20981 : void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) {
85 20981 : void *result = (void *)gpr_atm_acq_load(&ev->state);
86 20981 : if (result == NULL) {
87 20803 : struct sync_array_s *s = hash(ev);
88 20803 : gpr_mu_lock(&s->mu);
89 : do {
90 21162 : result = (void *)gpr_atm_acq_load(&ev->state);
91 21162 : } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline));
92 20803 : gpr_mu_unlock(&s->mu);
93 : }
94 20981 : return result;
95 : }
96 :
97 24260680 : void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
98 :
99 116595705 : void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
100 :
101 8943925 : void gpr_refn(gpr_refcount *r, int n) {
102 8943925 : gpr_atm_no_barrier_fetch_add(&r->count, n);
103 8943925 : }
104 :
105 186025822 : int gpr_unref(gpr_refcount *r) {
106 186025822 : gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1);
107 186025822 : GPR_ASSERT(prior > 0);
108 186025822 : return prior == 1;
109 : }
110 :
111 58 : void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n) {
112 58 : gpr_atm_rel_store(&c->value, n);
113 58 : }
114 :
115 55336419 : void gpr_stats_inc(gpr_stats_counter *c, gpr_intptr inc) {
116 55336419 : gpr_atm_no_barrier_fetch_add(&c->value, inc);
117 55336419 : }
118 :
119 120 : gpr_intptr gpr_stats_read(const gpr_stats_counter *c) {
120 : /* don't need acquire-load, but we have no no-barrier load yet */
121 120 : return gpr_atm_acq_load(&c->value);
122 : }
|