mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
13958236a9
Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
193 lines
4.7 KiB
C
193 lines
4.7 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
Implement a barrier
|
|
Copyright (C) Volker Lendecke 2012
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "replace.h"
|
|
#include "tevent_barrier.h"
|
|
#include "lib/util/tevent_unix.h"
|
|
|
|
struct tevent_barrier_waiter {
|
|
struct tevent_immediate *im;
|
|
struct tevent_context *ev;
|
|
struct tevent_req *req;
|
|
};
|
|
|
|
struct tevent_barrier {
|
|
unsigned count;
|
|
struct tevent_barrier_waiter *waiters;
|
|
void (*trigger_cb)(void *private_data);
|
|
void *private_data;
|
|
};
|
|
|
|
static int tevent_barrier_destructor(struct tevent_barrier *b);
|
|
static void tevent_barrier_release(struct tevent_barrier *b);
|
|
static void tevent_barrier_release_one(struct tevent_context *ctx,
|
|
struct tevent_immediate *im,
|
|
void *private_data);
|
|
static void tevent_barrier_release_trigger(struct tevent_context *ctx,
|
|
struct tevent_immediate *im,
|
|
void *private_data);
|
|
|
|
struct tevent_barrier *tevent_barrier_init(
|
|
TALLOC_CTX *mem_ctx, unsigned count,
|
|
void (*trigger_cb)(void *private_data), void *private_data)
|
|
{
|
|
struct tevent_barrier *b;
|
|
unsigned i;
|
|
|
|
if (count == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
b = talloc(mem_ctx, struct tevent_barrier);
|
|
if (b == NULL) {
|
|
return NULL;
|
|
}
|
|
b->count = 0;
|
|
b->trigger_cb = trigger_cb;
|
|
b->private_data = private_data;
|
|
|
|
b->waiters = talloc_array(b, struct tevent_barrier_waiter, count);
|
|
if (b->waiters == NULL) {
|
|
goto fail;
|
|
}
|
|
for (i=0; i<count; i++) {
|
|
struct tevent_barrier_waiter *w = &b->waiters[i];
|
|
|
|
w->im = tevent_create_immediate(b->waiters);
|
|
if (w->im == NULL) {
|
|
goto fail;
|
|
}
|
|
w->req = NULL;
|
|
}
|
|
talloc_set_destructor(b, tevent_barrier_destructor);
|
|
return b;
|
|
fail:
|
|
TALLOC_FREE(b);
|
|
return NULL;
|
|
}
|
|
|
|
static int tevent_barrier_destructor(struct tevent_barrier *b)
|
|
{
|
|
tevent_barrier_release(b);
|
|
return 0;
|
|
}
|
|
|
|
struct tevent_barrier_wait_state {
|
|
struct tevent_barrier *b;
|
|
int index;
|
|
};
|
|
|
|
static void tevent_barrier_release(struct tevent_barrier *b)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i=0; i<b->count; i++) {
|
|
struct tevent_barrier_waiter *w = &b->waiters[i];
|
|
struct tevent_barrier_wait_state *state;
|
|
|
|
if (w->req == NULL) {
|
|
continue;
|
|
}
|
|
tevent_schedule_immediate(
|
|
w->im, w->ev, tevent_barrier_release_one, w->req);
|
|
|
|
state = tevent_req_data(
|
|
w->req, struct tevent_barrier_wait_state);
|
|
talloc_set_destructor(state, NULL);
|
|
|
|
w->req = NULL;
|
|
w->ev = NULL;
|
|
}
|
|
b->count = 0;
|
|
if (b->trigger_cb != NULL) {
|
|
b->trigger_cb(b->private_data);
|
|
}
|
|
}
|
|
|
|
static void tevent_barrier_release_one(struct tevent_context *ctx,
|
|
struct tevent_immediate *im,
|
|
void *private_data)
|
|
{
|
|
struct tevent_req *req = talloc_get_type_abort(
|
|
private_data, struct tevent_req);
|
|
tevent_req_done(req);
|
|
}
|
|
|
|
static int tevent_barrier_wait_state_destructor(
|
|
struct tevent_barrier_wait_state *s);
|
|
|
|
struct tevent_req *tevent_barrier_wait_send(TALLOC_CTX *mem_ctx,
|
|
struct tevent_context *ev,
|
|
struct tevent_barrier *b)
|
|
{
|
|
struct tevent_req *req;
|
|
struct tevent_barrier_wait_state *state;
|
|
struct tevent_barrier_waiter *w;
|
|
struct tevent_immediate *im;
|
|
|
|
req = tevent_req_create(mem_ctx, &state,
|
|
struct tevent_barrier_wait_state);
|
|
if (req == NULL) {
|
|
return NULL;
|
|
}
|
|
state->b = b;
|
|
state->index = b->count;
|
|
|
|
w = &b->waiters[b->count];
|
|
w->ev = ev;
|
|
w->req = req;
|
|
b->count += 1;
|
|
|
|
talloc_set_destructor(state, tevent_barrier_wait_state_destructor);
|
|
|
|
if (b->count < talloc_array_length(b->waiters)) {
|
|
return req;
|
|
}
|
|
|
|
im = tevent_create_immediate(req);
|
|
if (tevent_req_nomem(im, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
tevent_schedule_immediate(im, ev, tevent_barrier_release_trigger, b);
|
|
return req;
|
|
}
|
|
|
|
static int tevent_barrier_wait_state_destructor(
|
|
struct tevent_barrier_wait_state *s)
|
|
{
|
|
struct tevent_barrier *b = s->b;
|
|
b->waiters[s->index].req = b->waiters[b->count-1].req;
|
|
b->count -= 1;
|
|
return 0;
|
|
}
|
|
|
|
static void tevent_barrier_release_trigger(struct tevent_context *ctx,
|
|
struct tevent_immediate *im,
|
|
void *private_data)
|
|
{
|
|
struct tevent_barrier *b = talloc_get_type_abort(
|
|
private_data, struct tevent_barrier);
|
|
tevent_barrier_release(b);
|
|
}
|
|
|
|
int tevent_barrier_wait_recv(struct tevent_req *req)
|
|
{
|
|
return tevent_req_simple_recv_unix(req);
|
|
}
|