Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : Implement a barrier 4 : Copyright (C) Volker Lendecke 2012 5 : 6 : This program is free software; you can redistribute it and/or modify 7 : it under the terms of the GNU General Public License as published by 8 : the Free Software Foundation; either version 3 of the License, or 9 : (at your option) any later version. 10 : 11 : This program is distributed in the hope that it will be useful, 12 : but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : GNU General Public License for more details. 15 : 16 : You should have received a copy of the GNU General Public License 17 : along with this program. If not, see <http://www.gnu.org/licenses/>. 18 : */ 19 : 20 : #include "replace.h" 21 : #include "tevent_barrier.h" 22 : #include "lib/util/tevent_unix.h" 23 : 24 : struct tevent_barrier_waiter { 25 : struct tevent_immediate *im; 26 : struct tevent_context *ev; 27 : struct tevent_req *req; 28 : }; 29 : 30 : struct tevent_barrier { 31 : unsigned count; 32 : struct tevent_barrier_waiter *waiters; 33 : void (*trigger_cb)(void *private_data); 34 : void *private_data; 35 : }; 36 : 37 : static int tevent_barrier_destructor(struct tevent_barrier *b); 38 : static void tevent_barrier_release(struct tevent_barrier *b); 39 : static void tevent_barrier_release_one(struct tevent_context *ctx, 40 : struct tevent_immediate *im, 41 : void *private_data); 42 : static void tevent_barrier_release_trigger(struct tevent_context *ctx, 43 : struct tevent_immediate *im, 44 : void *private_data); 45 : 46 0 : struct tevent_barrier *tevent_barrier_init( 47 : TALLOC_CTX *mem_ctx, unsigned count, 48 : void (*trigger_cb)(void *private_data), void *private_data) 49 : { 50 0 : struct tevent_barrier *b; 51 0 : unsigned i; 52 : 53 0 : if (count == 0) { 54 0 : return NULL; 55 : } 56 : 57 0 : b = talloc(mem_ctx, struct tevent_barrier); 58 0 : if (b == NULL) { 59 0 : return NULL; 60 : } 61 0 : b->count = 0; 62 0 : b->trigger_cb = trigger_cb; 63 0 : b->private_data = private_data; 64 : 65 0 : b->waiters = talloc_array(b, struct tevent_barrier_waiter, count); 66 0 : if (b->waiters == NULL) { 67 0 : goto fail; 68 : } 69 0 : for (i=0; i<count; i++) { 70 0 : struct tevent_barrier_waiter *w = &b->waiters[i]; 71 : 72 0 : w->im = tevent_create_immediate(b->waiters); 73 0 : if (w->im == NULL) { 74 0 : goto fail; 75 : } 76 0 : w->req = NULL; 77 : } 78 0 : talloc_set_destructor(b, tevent_barrier_destructor); 79 0 : return b; 80 0 : fail: 81 0 : TALLOC_FREE(b); 82 0 : return NULL; 83 : } 84 : 85 0 : static int tevent_barrier_destructor(struct tevent_barrier *b) 86 : { 87 0 : tevent_barrier_release(b); 88 0 : return 0; 89 : } 90 : 91 : struct tevent_barrier_wait_state { 92 : struct tevent_barrier *b; 93 : int index; 94 : }; 95 : 96 0 : static void tevent_barrier_release(struct tevent_barrier *b) 97 : { 98 0 : unsigned i; 99 : 100 0 : for (i=0; i<b->count; i++) { 101 0 : struct tevent_barrier_waiter *w = &b->waiters[i]; 102 0 : struct tevent_barrier_wait_state *state; 103 : 104 0 : if (w->req == NULL) { 105 0 : continue; 106 : } 107 0 : tevent_schedule_immediate( 108 0 : w->im, w->ev, tevent_barrier_release_one, w->req); 109 : 110 0 : state = tevent_req_data( 111 : w->req, struct tevent_barrier_wait_state); 112 0 : talloc_set_destructor(state, NULL); 113 : 114 0 : w->req = NULL; 115 0 : w->ev = NULL; 116 : } 117 0 : b->count = 0; 118 0 : if (b->trigger_cb != NULL) { 119 0 : b->trigger_cb(b->private_data); 120 : } 121 0 : } 122 : 123 0 : static void tevent_barrier_release_one(struct tevent_context *ctx, 124 : struct tevent_immediate *im, 125 : void *private_data) 126 : { 127 0 : struct tevent_req *req = talloc_get_type_abort( 128 : private_data, struct tevent_req); 129 0 : tevent_req_done(req); 130 0 : } 131 : 132 : static int tevent_barrier_wait_state_destructor( 133 : struct tevent_barrier_wait_state *s); 134 : 135 0 : struct tevent_req *tevent_barrier_wait_send(TALLOC_CTX *mem_ctx, 136 : struct tevent_context *ev, 137 : struct tevent_barrier *b) 138 : { 139 0 : struct tevent_req *req; 140 0 : struct tevent_barrier_wait_state *state; 141 0 : struct tevent_barrier_waiter *w; 142 0 : struct tevent_immediate *im; 143 : 144 0 : req = tevent_req_create(mem_ctx, &state, 145 : struct tevent_barrier_wait_state); 146 0 : if (req == NULL) { 147 0 : return NULL; 148 : } 149 0 : state->b = b; 150 0 : state->index = b->count; 151 : 152 0 : w = &b->waiters[b->count]; 153 0 : w->ev = ev; 154 0 : w->req = req; 155 0 : b->count += 1; 156 : 157 0 : talloc_set_destructor(state, tevent_barrier_wait_state_destructor); 158 : 159 0 : if (b->count < talloc_array_length(b->waiters)) { 160 0 : return req; 161 : } 162 : 163 0 : im = tevent_create_immediate(req); 164 0 : if (tevent_req_nomem(im, req)) { 165 0 : return tevent_req_post(req, ev); 166 : } 167 0 : tevent_schedule_immediate(im, ev, tevent_barrier_release_trigger, b); 168 0 : return req; 169 : } 170 : 171 0 : static int tevent_barrier_wait_state_destructor( 172 : struct tevent_barrier_wait_state *s) 173 : { 174 0 : struct tevent_barrier *b = s->b; 175 0 : b->waiters[s->index].req = b->waiters[b->count-1].req; 176 0 : b->count -= 1; 177 0 : return 0; 178 : } 179 : 180 0 : static void tevent_barrier_release_trigger(struct tevent_context *ctx, 181 : struct tevent_immediate *im, 182 : void *private_data) 183 : { 184 0 : struct tevent_barrier *b = talloc_get_type_abort( 185 : private_data, struct tevent_barrier); 186 0 : tevent_barrier_release(b); 187 0 : } 188 : 189 0 : int tevent_barrier_wait_recv(struct tevent_req *req) 190 : { 191 0 : return tevent_req_simple_recv_unix(req); 192 : }