Commit c7ddf09b authored by Shane Snyder's avatar Shane Snyder

more group join logic added

parent b089f5da
......@@ -3,7 +3,6 @@ ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS =
bin_SCRIPTS =
noinst_LTLIBRARIES =
noinst_PROGRAMS =
TESTS =
XFAIL_TESTS =
......@@ -13,22 +12,24 @@ CLEANFILES = $(bin_SCRIPTS)
MAINTAINERCLEANFILES =
EXTRA_DIST =
BUILT_SOURCES =
src_libssg_la_SOURCES =
include_HEADERS = include/ssg.h
if SSG_HAVE_MPI
include_HEADERS += include/ssg-mpi.h
endif
noinst_HEADERS = ssg-config.h
lib_LTLIBRARIES = src/libssg.la
TESTS_ENVIRONMENT =
EXTRA_DIST += prepare.sh
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src
AM_CFLAGS =
AM_LIBS =
lib_LTLIBRARIES = src/libssg.la
src_libssg_la_SOURCES =
LDADD = src/libssg.la
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = maint/ssg.pc
......@@ -36,5 +37,4 @@ include Make.rules
include $(top_srcdir)/src/Makefile.subdir
include $(top_srcdir)/src/swim-fd/Makefile.subdir
include $(top_srcdir)/tests/Makefile.subdir
......@@ -34,6 +34,28 @@ dnl
PKG_PROG_PKG_CONFIG
PKG_CONFIG="pkg-config --static"
# coreutils checks for OSX
AC_ARG_VAR([TIMEOUT], timeout program)
AC_ARG_VAR([MKTEMP], mktemp program)
if test -z "$TIMEOUT" ; then
AC_CHECK_PROGS(TIMEOUT, [timeout gtimeout])
if test -z "$TIMEOUT" ; then
AC_MSG_ERROR([Could not find timeout command (can optionally provide via the TIMEOUT variable)])
fi
else
AC_SUBST([TIMEOUT], ["$TIMEOUT"])
fi
if test -z "$MKTEMP" ; then
AC_CHECK_PROGS(MKTEMP, [mktemp gmktemp])
if test -z "$MKTEMP" ; then
AC_MSG_ERROR([Could not find mktemp command (can optionally provide via the MKTEMP variable)])
fi
else
AC_SUBST([MKTEMP], ["$MKTEMP"])
fi
check_mpi=auto
AC_ARG_ENABLE([mpi],
[ --enable-mpi enable MPI (default: dynamic check)],
......
......@@ -26,7 +26,7 @@ extern "C" {
* @param[in] comm MPI communicator containing group members
* @param[in] update_cb Callback function executed on group membership changes
* @param[in] update_cb_dat User data pointer passed to membership update callback
* @returns SSG group identifier on success, SSG_GROUP_ID_NULL otherwise
* @returns SSG group identifier for created group on success, SSG_GROUP_ID_NULL otherwise
*/
ssg_group_id_t ssg_group_create_mpi(
const char * group_name,
......
......@@ -88,7 +88,7 @@ int ssg_finalize(
* @param[in] group_size Number of group members
* @param[in] update_cb Callback function executed on group membership changes
* @param[in] update_cb_dat User data pointer passed to membership update callback
* @returns SSG group identifier on success, SSG_GROUP_ID_NULL otherwise
* @returns SSG group identifier for created group on success, SSG_GROUP_ID_NULL otherwise
*
* NOTE: The HG address string of the caller of this function must be present in
* the list of address strings given in 'group_addr_strs'. That is, the caller
......@@ -110,7 +110,7 @@ ssg_group_id_t ssg_group_create(
* HG address strings for this group
* @param[in] update_cb Callback function executed on group membership changes
* @param[in] update_cb_dat User data pointer passed to membership update callback
* @returns SSG group identifier on success, SSG_GROUP_ID_NULL otherwise
* @returns SSG group identifier for created group on success, SSG_GROUP_ID_NULL otherwise
*
*
* NOTE: The HG address string of the caller of this function must be present in
......@@ -132,6 +132,30 @@ ssg_group_id_t ssg_group_create_config(
int ssg_group_destroy(
ssg_group_id_t group_id);
/**
* Adds the calling process to an SSG group.
*
* @param[in] in_group_id Input SSG group ID
* @param[in] update_cb Callback function executed on group membership changes
* @param[in] update_cb_dat User data pointer passed to membership update callback
* @returns SSG group identifier for joined group on success, SSG_GROUP_ID_NULL otherwise
*
* NOTE: XXX in and out group ids
*/
ssg_group_id_t ssg_group_join(
ssg_group_id_t in_group_id,
ssg_membership_update_cb update_cb,
void * update_cb_dat);
/**
* Removes the calling process from an SSG group.
*
* @param[in] group_id SSG group ID
* @returns SSG_SUCCESS on success, SSG error code otherwise
*/
int ssg_group_leave(
ssg_group_id_t group_id);
/**
* Attaches a client to an SSG group.
*
......
......@@ -65,19 +65,25 @@ typedef struct ssg_group_view
{
unsigned int size;
ssg_member_state_t *member_map;
ABT_rwlock lock;
} ssg_group_view_t;
typedef struct ssg_group_target_list
{
ssg_member_state_t **targets;
unsigned int nslots;
unsigned int len;
unsigned int dping_ndx;
} ssg_group_target_list_t;
typedef struct ssg_group
{
char *name;
ssg_member_id_t self_id;
ssg_group_view_t view;
ssg_member_state_t **nondead_member_list;
unsigned int nondead_member_list_nslots;
unsigned int dping_target_ndx;
ssg_group_target_list_t target_list;
ssg_group_descriptor_t *descriptor;
swim_context_t *swim_ctx;
ABT_rwlock lock;
ssg_membership_update_cb update_cb;
void *update_cb_dat;
UT_hash_handle hh;
......@@ -86,8 +92,9 @@ typedef struct ssg_group
typedef struct ssg_attached_group
{
char *name;
ssg_group_descriptor_t *descriptor;
ssg_group_view_t view;
ssg_group_descriptor_t *descriptor;
ABT_rwlock lock;
UT_hash_handle hh;
} ssg_attached_group_t;
......@@ -120,6 +127,11 @@ static inline uint64_t ssg_hash64_str(const char * str)
void ssg_register_rpcs(
void);
int ssg_group_join_send(
ssg_group_descriptor_t * group_descriptor,
char ** group_name,
int * group_size,
void ** view_buf);
int ssg_group_attach_send(
ssg_group_descriptor_t * group_descriptor,
char ** group_name,
......
......@@ -20,12 +20,28 @@
/* SSG RPC types and (de)serialization routines */
/* TODO join and attach are nearly identical -- refactor */
/* NOTE: keep in sync with ssg_group_descriptor_t definition in ssg-internal.h */
MERCURY_GEN_STRUCT_PROC(ssg_group_descriptor_t, \
((uint64_t) (magic_nr)) \
((uint64_t) (name_hash)) \
((hg_string_t) (addr_str)));
MERCURY_GEN_PROC(ssg_group_join_request_t, \
((ssg_group_descriptor_t) (group_descriptor))
((hg_bulk_t) (bulk_handle)));
MERCURY_GEN_PROC(ssg_group_join_response_t, \
((hg_string_t) (group_name)) \
((uint32_t) (group_size)) \
((hg_size_t) (view_buf_size)));
#if 0
MERCURY_GEN_PROC(ssg_group_leave_request_t, \
((ssg_group_descriptor_t) (group_descriptor)));
#endif
MERCURY_GEN_PROC(ssg_group_attach_request_t, \
((ssg_group_descriptor_t) (group_descriptor))
((hg_bulk_t) (bulk_handle)));
......@@ -36,6 +52,10 @@ MERCURY_GEN_PROC(ssg_group_attach_response_t, \
((hg_size_t) (view_buf_size)));
/* SSG RPC handler prototypes */
DECLARE_MARGO_RPC_HANDLER(ssg_group_join_recv_ult)
#if 0
DECLARE_MARGO_RPC_HANDLER(ssg_group_leave_recv_ult)
#endif
DECLARE_MARGO_RPC_HANDLER(ssg_group_attach_recv_ult)
/* internal helper routine prototypes */
......@@ -43,6 +63,10 @@ static int ssg_group_view_serialize(
ssg_group_view_t *view, void **buf, hg_size_t *buf_size);
/* SSG RPC IDs */
static hg_id_t ssg_group_join_rpc_id;
#if 0
static hg_id_t ssg_group_leave_rpc_id;
#endif
static hg_id_t ssg_group_attach_rpc_id;
/* ssg_register_rpcs
......@@ -52,6 +76,16 @@ static hg_id_t ssg_group_attach_rpc_id;
void ssg_register_rpcs()
{
/* register HG RPCs for SSG */
ssg_group_join_rpc_id =
MARGO_REGISTER(ssg_inst->mid, "ssg_group_join",
ssg_group_join_request_t, ssg_group_join_response_t,
ssg_group_join_recv_ult);
#if 0
ssg_group_leave_rpc_id =
MARGO_REGISTER(ssg_inst->mid, "ssg_group_leave",
ssg_group_leave_request_t, void,
ssg_group_leave_recv_ult);
#endif
ssg_group_attach_rpc_id =
MARGO_REGISTER(ssg_inst->mid, "ssg_group_attach",
ssg_group_attach_request_t, ssg_group_attach_response_t,
......@@ -60,6 +94,215 @@ void ssg_register_rpcs()
return;
}
/* ssg_group_join_send
*
*
*/
int ssg_group_join_send(
ssg_group_descriptor_t * group_descriptor,
char ** group_name,
int * group_size,
void ** view_buf)
{
hg_addr_t member_addr = HG_ADDR_NULL;
hg_handle_t handle = HG_HANDLE_NULL;
hg_bulk_t bulk_handle = HG_BULK_NULL;
void *tmp_view_buf = NULL, *b;
hg_size_t tmp_view_buf_size = SSG_VIEW_BUF_DEF_SIZE;
ssg_group_join_request_t join_req;
ssg_group_join_response_t join_resp;
hg_return_t hret;
int sret = SSG_FAILURE;
*group_name = NULL;
*group_size = 0;
*view_buf = NULL;
/* lookup the address of the given group member */
hret = margo_addr_lookup(ssg_inst->mid, group_descriptor->addr_str,
&member_addr);
if (hret != HG_SUCCESS) goto fini;
hret = margo_create(ssg_inst->mid, member_addr,
ssg_group_join_rpc_id, &handle);
if (hret != HG_SUCCESS) goto fini;
/* allocate a buffer to try to store the group view in */
/* NOTE: We don't know if this buffer is big enough to store the complete
* view. If the buffer is not large enough, the group member we are
* attaching too will send a NACK indicating the necessary buffer size
*/
tmp_view_buf = malloc(tmp_view_buf_size);
if (!tmp_view_buf) goto fini;
hret = margo_bulk_create(ssg_inst->mid, 1, &tmp_view_buf, &tmp_view_buf_size,
HG_BULK_WRITE_ONLY, &bulk_handle);
if (hret != HG_SUCCESS) goto fini;
/* send a join request to the given group member address */
memcpy(&join_req.group_descriptor, group_descriptor, sizeof(*group_descriptor));
join_req.bulk_handle = bulk_handle;
hret = margo_forward(handle, &join_req);
if (hret != HG_SUCCESS) goto fini;
hret = margo_get_output(handle, &join_resp);
if (hret != HG_SUCCESS) goto fini;
/* if our initial buffer is too small, reallocate to the exact size & rejoin */
if (join_resp.view_buf_size > tmp_view_buf_size)
{
b = realloc(tmp_view_buf, join_resp.view_buf_size);
if(!b)
{
margo_free_output(handle, &join_resp);
goto fini;
}
tmp_view_buf = b;
tmp_view_buf_size = join_resp.view_buf_size;
margo_free_output(handle, &join_resp);
/* free old bulk handle and recreate it */
margo_bulk_free(bulk_handle);
hret = margo_bulk_create(ssg_inst->mid, 1, &tmp_view_buf, &tmp_view_buf_size,
HG_BULK_WRITE_ONLY, &bulk_handle);
if (hret != HG_SUCCESS) goto fini;
join_req.bulk_handle = bulk_handle;
hret = margo_forward(handle, &join_req);
if (hret != HG_SUCCESS) goto fini;
hret = margo_get_output(handle, &join_resp);
if (hret != HG_SUCCESS) goto fini;
}
/* readjust view buf size if initial guess was too large */
if (join_resp.view_buf_size < tmp_view_buf_size)
{
b = realloc(tmp_view_buf, join_resp.view_buf_size);
if(!b)
{
HG_Free_output(handle, &join_resp);
goto fini;
}
tmp_view_buf = b;
}
/* set output pointers according to the returned view parameters */
*group_name = strdup(join_resp.group_name);
*group_size = (int)join_resp.group_size;
*view_buf = tmp_view_buf;
margo_free_output(handle, &join_resp);
tmp_view_buf = NULL;
sret = SSG_SUCCESS;
fini:
if (member_addr != HG_ADDR_NULL) margo_addr_free(ssg_inst->mid, member_addr);
if (handle != HG_HANDLE_NULL) margo_destroy(handle);
if (bulk_handle != HG_BULK_NULL) margo_bulk_free(bulk_handle);
free(tmp_view_buf);
return sret;
}
static void ssg_group_join_recv_ult(
hg_handle_t handle)
{
const struct hg_info *hgi = NULL;
ssg_group_t *g = NULL;
ssg_group_join_request_t join_req;
ssg_group_join_response_t join_resp;
hg_size_t view_size_requested;
void *view_buf = NULL;
hg_size_t view_buf_size;
hg_bulk_t bulk_handle = HG_BULK_NULL;
int sret;
hg_return_t hret;
if (!ssg_inst) goto fini;
hgi = margo_get_info(handle);
if (!hgi) goto fini;
hret = margo_get_input(handle, &join_req);
if (hret != HG_SUCCESS) goto fini;
view_size_requested = margo_bulk_get_size(join_req.bulk_handle);
/* look for the given group in my local table of groups */
HASH_FIND(hh, ssg_inst->group_table, &join_req.group_descriptor.name_hash,
sizeof(uint64_t), g);
if (!g)
{
margo_free_input(handle, &join_req);
goto fini;
}
sret = ssg_group_view_serialize(&g->view, &view_buf, &view_buf_size);
if (sret != SSG_SUCCESS)
{
margo_free_input(handle, &join_req);
goto fini;
}
if (view_size_requested >= view_buf_size)
{
/* if attacher's buf is large enough, transfer the view */
hret = margo_bulk_create(ssg_inst->mid, 1, &view_buf, &view_buf_size,
HG_BULK_READ_ONLY, &bulk_handle);
if (hret != HG_SUCCESS)
{
margo_free_input(handle, &join_req);
goto fini;
}
hret = margo_bulk_transfer(ssg_inst->mid, HG_BULK_PUSH, hgi->addr,
join_req.bulk_handle, 0, bulk_handle, 0, view_buf_size);
if (hret != HG_SUCCESS)
{
margo_free_input(handle, &join_req);
goto fini;
}
}
/* XXX what else? need to add to view/target list */
printf("***SDS: received JOINNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN REQUESTTTTTTTTTTTTTT\n");
/* set the response and send back */
join_resp.group_name = g->name;
join_resp.group_size = (int)g->view.size;
join_resp.view_buf_size = view_buf_size;
margo_respond(handle, &join_resp);
margo_free_input(handle, &join_req);
fini:
free(view_buf);
if (handle != HG_HANDLE_NULL) margo_destroy(handle);
if (bulk_handle != HG_BULK_NULL) margo_bulk_free(bulk_handle);
return;
}
DEFINE_MARGO_RPC_HANDLER(ssg_group_join_recv_ult)
#if 0
/* ssg_group_leave_send
*
*
*/
int ssg_group_leave_send(
ssg_group_descriptor_t * group_descriptor,
char ** group_name,
int * group_size,
void ** view_buf)
{
hg_class_t *hgcl = NULL;
hg_addr_t member_addr = HG_ADDR_NULL;
hg_handle_t handle = HG_HANDLE_NULL;
/* send a join request to the given group member address */
return SSG_SUCCESS;
}
#endif
/* ssg_group_attach_send
*
*
......@@ -93,7 +336,7 @@ int ssg_group_attach_send(
ssg_group_attach_rpc_id, &handle);
if (hret != HG_SUCCESS) goto fini;
/* allocate a buffer of the given size to try to store the group view in */
/* allocate a buffer to try to store the group view in */
/* NOTE: We don't know if this buffer is big enough to store the complete
* view. If the buffer is not large enough, the group member we are
* attaching too will send a NACK indicating the necessary buffer size
......@@ -125,6 +368,7 @@ int ssg_group_attach_send(
}
tmp_view_buf = b;
tmp_view_buf_size = attach_resp.view_buf_size;
margo_free_output(handle, &attach_resp);
/* free old bulk handle and recreate it */
margo_bulk_free(bulk_handle);
......@@ -136,7 +380,6 @@ int ssg_group_attach_send(
hret = margo_forward(handle, &attach_req);
if (hret != HG_SUCCESS) goto fini;
margo_free_output(handle, &attach_resp);
hret = margo_get_output(handle, &attach_resp);
if (hret != HG_SUCCESS) goto fini;
}
......@@ -237,7 +480,7 @@ static void ssg_group_attach_recv_ult(
margo_free_input(handle, &attach_req);
fini:
free(view_buf); /* TODO: cache this */
free(view_buf);
if (handle != HG_HANDLE_NULL) margo_destroy(handle);
if (bulk_handle != HG_BULK_NULL) margo_bulk_free(bulk_handle);
......
......@@ -34,31 +34,61 @@ struct ssg_group_lookup_ult_args
{
ssg_group_view_t *view;
ssg_member_state_t *member_state;
ABT_rwlock lock;
hg_return_t out;
};
static void ssg_group_lookup_ult(void * arg);
/* SSG helper routine prototypes */
static ssg_group_t * ssg_group_create_internal(
const char * group_name, const char * const group_addr_strs[],
int group_size, ssg_membership_update_cb update_cb, void *update_cb_dat);
static int ssg_group_view_create(
const char * const group_addr_strs[], int group_size,
const char * self_addr_str, ABT_rwlock view_lock,
ssg_group_view_t * view, ssg_member_id_t * self_id);
static ssg_group_descriptor_t * ssg_group_descriptor_create(
uint64_t name_hash, const char * leader_addr_str, int owner_status);
static ssg_group_descriptor_t * ssg_group_descriptor_dup(
ssg_group_descriptor_t * descriptor);
static void ssg_group_descriptor_free(
ssg_group_descriptor_t * descriptor);
static int ssg_group_view_create(
const char * const group_addr_strs[], int group_size,
hg_addr_t self_addr, ssg_member_id_t * self_id,
ssg_group_view_t * view);
static ssg_member_id_t ssg_gen_member_id(
const char * addr_str);
static void ssg_group_view_destroy(
ssg_group_view_t * view);
static void ssg_group_destroy_internal(
ssg_group_t * g);
static void ssg_attached_group_destroy(
ssg_attached_group_t * ag);
static void ssg_group_view_destroy(
ssg_group_view_t * view);
static void ssg_group_descriptor_free(
ssg_group_descriptor_t * descriptor);
static ssg_member_id_t ssg_gen_member_id(
const char * addr_str);
static const char ** ssg_addr_str_buf_to_list(
const char * buf, int num_addrs);
static void ssg_shuffle_member_list(
ssg_group_target_list_t *list);
/* SWIM group management routine prototypes */
static int ssg_get_swim_dping_target(
void *group_data,
swim_member_id_t *target_id,
swim_member_inc_nr_t *target_inc_nr,
hg_addr_t *target_addr);
static int ssg_get_swim_iping_targets(
void *group_data,
swim_member_id_t dping_target_id,
int *num_targets,
swim_member_id_t *target_ids,
hg_addr_t *target_addrs);
static void ssg_get_swim_member_addr(
void *group_data,
swim_member_id_t id,
hg_addr_t *target_addr);
static void ssg_get_swim_member_state(
void *group_data,
swim_member_id_t id,
swim_member_state_t **state);
static void ssg_apply_swim_member_update(
void *group_data,
swim_member_update_t update);
/* XXX: i think we ultimately need per-mid ssg instances rather than 1 global? */
ssg_instance_t *ssg_inst = NULL;
......@@ -123,477 +153,257 @@ int ssg_finalize()
*** SSG group management routines ***
*************************************/
static int ssg_get_swim_dping_target(
void *group_data,
swim_member_id_t *target_id,
swim_member_inc_nr_t *target_inc_nr,
hg_addr_t *target_addr);
static int ssg_get_swim_iping_targets(
void *group_data,
swim_member_id_t dping_target_id,
int *num_targets,
swim_member_id_t *target_ids,
hg_addr_t *target_addrs);
static void ssg_get_swim_member_addr(
void *group_data,
swim_member_id_t id,
hg_addr_t *target_addr);
static void ssg_get_swim_member_state(
void *group_data,
swim_member_id_t id,
swim_member_state_t **state);
static void ssg_apply_swim_member_update(
void *group_data,
swim_member_update_t update);
static void ssg_shuffle_member_list(
ssg_member_state_t **list,
unsigned int len);
void print_nondead_list(ssg_group_t *g, char *tag)
ssg_group_id_t ssg_group_create(
const char * group_name,
const char * const group_addr_strs[],
int group_size,
ssg_membership_update_cb update_cb,
void * update_cb_dat)
{
unsigned int i = 0;
printf("***SDS %s nondead_member_list [%lu]: ", tag, g->self_id);
ssg_group_t *g;
ssg_group_id_t g_id = SSG_GROUP_ID_NULL;
for (i = 0; i < g->view.size; i++)
g = ssg_group_create_internal(group_name, group_addr_strs,
group_size, update_cb, update_cb_dat);
if (g)
{
printf("%p\t", g->nondead_member_list[i]);
/* on successful creation, dup the group descriptor and return
* it for the caller to hold on to
*/
g_id = (ssg_group_id_t)ssg_group_descriptor_dup(g->descriptor);
if (g_id == SSG_GROUP_ID_NULL)
ssg_group_destroy_internal(g);
}
printf("\n");
return g_id;
}
static int ssg_get_swim_dping_target(
void *group_data,
swim_member_id_t *target_id,
swim_member_inc_nr_t *target_inc_nr,
hg_addr_t *target_addr)
ssg_group_id_t ssg_group_create_config(
const char * group_name,
const char * file_name,
ssg_membership_update_cb update_cb,
void * update_cb_dat)
{
ssg_group_t *g = (ssg_group_t *)group_data;
ssg_member_state_t *dping_target_ms;
unsigned int nondead_list_len;
assert(g != NULL);
int fd;
struct stat st;
char *rd_buf = NULL;
ssize_t rd_buf_size;
char *tok;
void *addr_str_buf = NULL;
int addr_str_buf_len = 0, num_addrs = 0;
int ret;
const char **addr_strs = NULL;
ssg_group_id_t group_id = SSG_GROUP_ID_NULL;
ABT_rwlock_rdlock(g->view.lock);
/* open config file for reading */
fd = open(file_name, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error: SSG unable to open config file %s for group %s\n",
file_name, group_name);
goto fini;
}
nondead_list_len = g->view.size;
if (nondead_list_len == 0)
/* get file size and allocate a buffer to store it */
ret = fstat(fd, &st);
if (ret == -1)
{
ABT_rwlock_unlock(g->view.lock);
return -1; /* no targets */
fprintf(stderr, "Error: SSG unable to stat config file %s for group %s\n",
file_name, group_name);
goto fini;
}
rd_buf = malloc(st.st_size+1);
if (rd_buf == NULL) goto fini;
/* reshuffle member list after a complete traversal */
if (g->dping_target_ndx == nondead_list_len)
/* load it all in one fell swoop */
rd_buf_size = read(fd, rd_buf, st.st_size);
if (rd_buf_size != st.st_size)
{
ssg_shuffle_member_list(g->nondead_member_list, g->view.size);
g->dping_target_ndx = 0;
fprintf(stderr, "Error: SSG unable to read config file %s for group %s\n",
file_name, group_name);
goto fini;
}
rd_buf[rd_buf_size]='\0';
/* strtok the result - each space-delimited address is assumed to be
* a unique mercury address
*/
tok = strtok(rd_buf, "\r\n\t ");
if (tok == NULL) goto fini;
/* pull next dping target using saved state */
dping_target_ms = g->nondead_member_list[g->dping_target_ndx];
/* build up the address buffer */
addr_str_buf = malloc(rd_buf_size);
if (addr_str_buf == NULL) goto fini;
do
{
int tok_size = strlen(tok);
memcpy((char*)addr_str_buf + addr_str_buf_len, tok, tok_size+1);
addr_str_buf_len += tok_size+1;
num_addrs++;
tok = strtok(NULL, "\r\n\t ");
} while (tok != NULL);
if (addr_str_buf_len != rd_buf_size)
{
/* adjust buffer size if our initial guess was wrong */
void *tmp = realloc(addr_str_buf, addr_str_buf_len);
if (tmp == NULL) goto fini;
addr_str_buf = tmp;
}
*target_id = (swim_member_id_t)dping_target_ms->id;
*target_inc_nr = dping_target_ms->swim_state.inc_nr;
*target_addr = dping_target_ms->addr;
/* set up address string array for group members */
addr_strs = ssg_addr_str_buf_to_list(addr_str_buf, num_addrs);
if (!addr_strs) goto fini;
/* increment dping target index for next iteration */
g->dping_target_ndx++;
/* invoke the generic group create routine using our list of addrs */
group_id = ssg_group_create(group_name, addr_strs, num_addrs,
update_cb, update_cb_dat);
ABT_rwlock_unlock(g->view.lock);
fini:
/* cleanup before returning */
if (fd != -1) close(fd);
free(rd_buf);