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 : struct tevent_barrier *b;
51 : 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 : unsigned i;
99 :
100 0 : for (i=0; i<b->count; i++) {
101 0 : struct tevent_barrier_waiter *w = &b->waiters[i];
102 : struct tevent_barrier_wait_state *state;
103 :
104 0 : if (w->req == NULL) {
105 0 : continue;
106 : }
107 0 : tevent_schedule_immediate(
108 : 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 : struct tevent_req *req;
140 : struct tevent_barrier_wait_state *state;
141 : struct tevent_barrier_waiter *w;
142 : 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 : }
|