Quellcode durchsuchen

Merge trunk revision 2399:
Implementation of cpg_iteration functions

This functions allows iterate available cpg groups
and their members. API is modelled like ckpt iteration
functions.



git-svn-id: http://svn.fedorahosted.org/svn/corosync/branches/flatiron@2492 fd59a12c-fef9-0310-b244-a6a79926bd2f

Steven Dake vor 16 Jahren
Ursprung
Commit
835a6e14ca
6 geänderte Dateien mit 653 neuen und 7 gelöschten Zeilen
  1. 5 0
      configure.ac
  2. 31 0
      include/corosync/cpg.h
  3. 52 1
      include/corosync/ipc_cpg.h
  4. 19 1
      lib/Makefile.am
  5. 233 3
      lib/cpg.c
  6. 313 2
      services/cpg.c

+ 5 - 0
configure.ac

@@ -171,6 +171,9 @@ SOMAJOR="4"
 SOMINOR="0"
 SOMICRO="0"
 SONAME="${SOMAJOR}.${SOMINOR}.${SOMICRO}"
+# Special for libcpg
+CPG_SOMICRO="1"
+CPG_SONAME="${SOMAJOR}.${SOMINOR}.${CPG_SOMICRO}"
 
 # local options
 AC_ARG_ENABLE([ansi],
@@ -382,6 +385,7 @@ AC_SUBST([SOMAJOR])
 AC_SUBST([SOMINOR])
 AC_SUBST([SOMICRO])
 AC_SUBST([SONAME])
+AC_SUBST([CPG_SONAME])
 
 AC_SUBST([OS_DYFLAGS])
 
@@ -427,6 +431,7 @@ AC_MSG_RESULT([  Features                 =${PACKAGE_FEATURES}])
 AC_MSG_RESULT([])
 AC_MSG_RESULT([$PACKAGE build info:])
 AC_MSG_RESULT([  Library SONAME           = ${SONAME}])
+AC_MSG_RESULT([  CPG Library SONAME       = ${CPG_SONAME}])
 AC_MSG_RESULT([  Default optimization     = ${OPT_CFLAGS}])
 AC_MSG_RESULT([  Default debug options    = ${GDB_CFLAGS}])
 AC_MSG_RESULT([  Extra compiler warnings  = ${EXTRA_WARNING}])

+ 31 - 0
include/corosync/cpg.h

@@ -4,6 +4,7 @@
  * All rights reserved.
  *
  * Author: Christine Caulfield (ccaulfi@redhat.com)
+ * Author: Jan Friesse (jfriesse@redhat.com)
  *
  * This software licensed under BSD license, the text of which follows:
  *
@@ -48,6 +49,8 @@ extern "C" {
  */
 typedef uint64_t cpg_handle_t;
 
+typedef uint64_t cpg_iteration_handle_t;
+
 typedef enum {
 	CPG_TYPE_UNORDERED, /* not implemented */
 	CPG_TYPE_FIFO,		/* same as agreed */
@@ -69,6 +72,12 @@ typedef enum {
 	CPG_REASON_PROCDOWN = 5
 } cpg_reason_t;
 
+typedef enum {
+	CPG_ITERATION_NAME_ONLY = 1,
+	CPG_ITERATION_ONE_GROUP = 2,
+	CPG_ITERATION_ALL = 3,
+} cpg_iteration_type_t;
+
 struct cpg_address {
 	uint32_t nodeid;
 	uint32_t pid;
@@ -83,6 +92,12 @@ struct cpg_name {
 
 #define CPG_MEMBERS_MAX 128
 
+struct cpg_iteration_description_t {
+	struct cpg_name group;
+	uint32_t nodeid;
+	uint32_t pid;
+};
+
 typedef void (*cpg_deliver_fn_t) (
 	cpg_handle_t handle,
 	const struct cpg_name *group_name,
@@ -209,6 +224,22 @@ cs_error_t cpg_zcb_mcast_joined (
 	void *msg,
 	size_t msg_len);
 
+/*
+ * Iteration
+ */
+cs_error_t cpg_iteration_initialize(
+	cpg_handle_t handle,
+	cpg_iteration_type_t iteration_type,
+	const struct cpg_name *group,
+	cpg_iteration_handle_t *cpg_iteration_handle);
+
+cs_error_t cpg_iteration_next(
+	cpg_iteration_handle_t handle,
+	struct cpg_iteration_description_t *description);
+
+cs_error_t cpg_iteration_finalize (
+	cpg_iteration_handle_t handle);
+
 #ifdef __cplusplus
 }
 #endif

+ 52 - 1
include/corosync/ipc_cpg.h

@@ -45,6 +45,9 @@ enum req_cpg_types {
 	MESSAGE_REQ_CPG_MCAST = 2,
 	MESSAGE_REQ_CPG_MEMBERSHIP = 3,
 	MESSAGE_REQ_CPG_LOCAL_GET = 4,
+	MESSAGE_REQ_CPG_ITERATIONINITIALIZE = 5,
+	MESSAGE_REQ_CPG_ITERATIONNEXT = 6,
+	MESSAGE_REQ_CPG_ITERATIONFINALIZE = 7
 };
 
 enum res_cpg_types {
@@ -56,7 +59,10 @@ enum res_cpg_types {
 	MESSAGE_RES_CPG_DELIVER_CALLBACK = 5,
 	MESSAGE_RES_CPG_FLOW_CONTROL_STATE_SET = 6,
 	MESSAGE_RES_CPG_LOCAL_GET = 7,
-	MESSAGE_RES_CPG_FLOWCONTROL_CALLBACK = 8
+	MESSAGE_RES_CPG_FLOWCONTROL_CALLBACK = 8,
+	MESSAGE_RES_CPG_ITERATIONINITIALIZE = 9,
+	MESSAGE_RES_CPG_ITERATIONNEXT = 10,
+	MESSAGE_RES_CPG_ITERATIONFINALIZE = 11,
 };
 
 enum lib_cpg_confchg_reason {
@@ -126,6 +132,21 @@ static inline int mar_name_compare (
 		g1->length - g2->length);
 }
 
+typedef struct {
+	mar_cpg_name_t group;
+	mar_uint32_t nodeid;
+	mar_uint32_t pid;
+} mar_cpg_iteration_description_t;
+
+static inline void marshall_from_mar_cpg_iteration_description_t(
+	struct cpg_iteration_description_t *dest,
+	const mar_cpg_iteration_description_t *src)
+{
+	dest->nodeid = src->nodeid;
+	dest->pid = src->pid;
+	marshall_from_mar_cpg_name_t (&dest->group, &src->group);
+};
+
 struct req_lib_cpg_join {
 	coroipc_request_header_t header __attribute__((aligned(8)));
 	mar_cpg_name_t group_name __attribute__((aligned(8)));
@@ -217,4 +238,34 @@ struct res_lib_cpg_leave {
 	coroipc_response_header_t header __attribute__((aligned(8)));
 };
 
+struct req_lib_cpg_iterationinitialize {
+	coroipc_request_header_t header __attribute__((aligned(8)));
+	mar_cpg_name_t group_name __attribute__((aligned(8)));
+	mar_uint32_t iteration_type __attribute__((aligned(8)));
+};
+
+struct res_lib_cpg_iterationinitialize {
+	coroipc_response_header_t header __attribute__((aligned(8)));
+	hdb_handle_t iteration_handle __attribute__((aligned(8)));
+};
+
+struct req_lib_cpg_iterationnext {
+	coroipc_request_header_t header __attribute__((aligned(8)));
+	hdb_handle_t iteration_handle __attribute__((aligned(8)));
+};
+
+struct res_lib_cpg_iterationnext {
+	coroipc_response_header_t header __attribute__((aligned(8)));
+	mar_cpg_iteration_description_t description __attribute__((aligned(8)));
+};
+
+struct req_lib_cpg_iterationfinalize {
+	coroipc_request_header_t header __attribute__((aligned(8)));
+	hdb_handle_t iteration_handle __attribute__((aligned(8)));
+};
+
+struct res_lib_cpg_iterationfinalize {
+	coroipc_response_header_t header __attribute__((aligned(8)));
+};
+
 #endif /* IPC_CPG_H_DEFINED */

+ 19 - 1
lib/Makefile.am

@@ -40,7 +40,7 @@ INCLUDES		= -I$(top_builddir)/include -I$(top_srcdir)/include
 
 lib_LIBRARIES		= libcpg.a libconfdb.a libevs.a libcfg.a libquorum.a \
 			  libvotequorum.a libpload.a libcoroipcc.a
-SHARED_LIBS		= $(lib_LIBRARIES:%.a=%.so.$(SONAME))
+SHARED_LIBS		= $(filter-out libcpg.so.$(SONAME), $(lib_LIBRARIES:%.a=%.so.$(SONAME))) libcpg.so.$(CPG_SONAME)
 SHARED_LIBS_SO		= $(lib_LIBRARIES:%.a=%.so)
 SHARED_LIBS_SO_TWO	= $(lib_LIBRARIES:%.a=%.so.$(SOMAJOR))
 
@@ -75,6 +75,11 @@ libconfdb.so.$(SONAME): confdb.o sa-confdb.o libcoroipcc.so.$(SONAME)
 	ln -sf libconfdb.so.$(SONAME) libconfdb.so
 	ln -sf libconfdb.so.$(SONAME) libconfdb.so.$(SOMAJOR)
 
+libcpg.so.$(CPG_SONAME): cpg.o libcoroipcc.so.$(SONAME)
+	$(CC) $(DARWIN_OPTS) $^ -o $@
+	ln -sf $@ libcpg.so
+	ln -sf $@ libcpg.so.$(SOMAJOR)
+
 lib%.so.$(SONAME): %.o libcoroipcc.so.$(SONAME)
 	$(CC) $(DARWIN_OPTS) $^ -o $@
 	ln -sf lib$*.so.$(SONAME) lib$*.so
@@ -95,6 +100,11 @@ libconfdb.so.$(SONAME): confdb.o sa-confdb.o libcoroipcc.so.$(SONAME)
 	ln -sf libconfdb.so.$(SONAME) libconfdb.so
 	ln -sf libconfdb.so.$(SONAME) libconfdb.so.$(SOMAJOR)
 
+libcpg.so.$(CPG_SONAME): cpg.o libcoroipcc.so.$(SONAME)
+	$(LD) $(SOLARIS_OPTS) -G $^ -o $@
+	ln -sf $@ libcpg.so
+	ln -sf $@ libcpg.so.$(SOMAJOR)
+
 lib%.so.$(SONAME): %.o libcoroipcc.so.$(SONAME)
 	$(LD) $(SOLARIS_OPTS) -G $^ -o $@
 	ln -sf lib$*.so.$(SONAME) lib$*.so
@@ -118,6 +128,14 @@ libconfdb.so.$(SONAME): confdb.o sa-confdb.o ../lcr/lcr_ifact.o libcoroipcc.so.$
 	ln -sf libconfdb.so.$(SONAME) libconfdb.so
 	ln -sf libconfdb.so.$(SONAME) libconfdb.so.$(SOMAJOR)
 
+libcpg.so.$(CPG_SONAME): cpg.o libcoroipcc.so.$(SONAME)
+	$(CC) -shared -o $@ \
+		-Wl,-soname=libcpg.so.$(SOMAJOR) \
+		-Wl,-version-script=$(srcdir)/libcpg.versions \
+		$^ $(LDFLAGS) $(AM_LDFLAGS)
+	ln -sf $@ libcpg.so
+	ln -sf $@ libcpg.so.$(SOMAJOR)
+
 lib%.so.$(SONAME): %.o libcoroipcc.so.$(SONAME)
 	$(CC) -shared -o $@ \
 		-Wl,-soname=lib$*.so.$(SOMAJOR) \

+ 233 - 3
lib/cpg.c

@@ -5,7 +5,8 @@
  *
  * All rights reserved.
  *
- * Author: Patrick Caulfield (pcaulfie@redhat.com)
+ * Author: Christine Caulfield (ccaulfi@redhat.com)
+ * Author: Jan Friesse (jfriesse@redhat.com)
  *
  * This software licensed under BSD license, the text of which follows:
  *
@@ -51,6 +52,7 @@
 #include <corosync/coroipcc.h>
 #include <corosync/corodefs.h>
 #include <corosync/hdb.h>
+#include <corosync/list.h>
 
 #include <corosync/cpg.h>
 #include <corosync/ipc_cpg.h>
@@ -62,10 +64,49 @@ struct cpg_inst {
 	int finalize;
 	cpg_callbacks_t callbacks;
 	void *context;
+	struct list_head iteration_list_head;
 };
 
 DECLARE_HDB_DATABASE(cpg_handle_t_db,NULL);
 
+struct cpg_iteration_instance_t {
+	cpg_iteration_handle_t cpg_iteration_handle;
+	hdb_handle_t conn_handle;
+	hdb_handle_t executive_iteration_handle;
+	struct list_head list;
+};
+
+DECLARE_HDB_DATABASE(cpg_iteration_handle_t_db,NULL);
+
+
+/*
+ * Internal (not visible by API) functions
+ */
+
+static void cpg_iteration_instance_finalize (struct cpg_iteration_instance_t *cpg_iteration_instance)
+{
+	list_del (&cpg_iteration_instance->list);
+	hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
+}
+
+static void cpg_inst_finalize (struct cpg_inst *cpg_inst, hdb_handle_t handle)
+{
+	struct list_head *iter, *iter_next;
+	struct cpg_iteration_instance_t *cpg_iteration_instance;
+
+	/*
+	 * Traverse thru iteration instances and delete them
+	 */
+	for (iter = cpg_inst->iteration_list_head.next;	iter != &cpg_inst->iteration_list_head;iter = iter_next) {
+		iter_next = iter->next;
+
+		cpg_iteration_instance = list_entry (iter, struct cpg_iteration_instance_t, list);
+
+		cpg_iteration_instance_finalize (cpg_iteration_instance);
+	}
+	hdb_handle_destroy (&cpg_handle_t_db, handle);
+}
+
 /**
  * @defgroup cpg_coroipcc The closed process group API
  * @ingroup coroipcc
@@ -105,6 +146,8 @@ cs_error_t cpg_initialize (
 		memcpy (&cpg_inst->callbacks, callbacks, sizeof (cpg_callbacks_t));
 	}
 
+	list_init(&cpg_inst->iteration_list_head);
+
 	hdb_handle_put (&cpg_handle_t_db, *handle);
 
 	return (CS_OK);
@@ -140,8 +183,7 @@ cs_error_t cpg_finalize (
 
 	coroipcc_service_disconnect (cpg_inst->handle);
 
-	hdb_handle_destroy (&cpg_handle_t_db, handle);
-
+	cpg_inst_finalize (cpg_inst, handle);
 	hdb_handle_put (&cpg_handle_t_db, handle);
 
 	return (CPG_OK);
@@ -685,4 +727,192 @@ error_exit:
 
 	return (error);
 }
+
+cs_error_t cpg_iteration_initialize(
+	cpg_handle_t handle,
+	cpg_iteration_type_t iteration_type,
+	const struct cpg_name *group,
+	cpg_iteration_handle_t *cpg_iteration_handle)
+{
+	cs_error_t error;
+	struct iovec iov;
+	struct cpg_inst *cpg_inst;
+	struct cpg_iteration_instance_t *cpg_iteration_instance;
+	struct req_lib_cpg_iterationinitialize req_lib_cpg_iterationinitialize;
+	struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize;
+
+	if (cpg_iteration_handle == NULL) {
+		return (CS_ERR_INVALID_PARAM);
+	}
+
+	if ((iteration_type == CPG_ITERATION_ONE_GROUP && group == NULL) ||
+		(iteration_type != CPG_ITERATION_ONE_GROUP && group != NULL)) {
+		return (CS_ERR_INVALID_PARAM);
+	}
+
+	if (iteration_type != CPG_ITERATION_NAME_ONLY && iteration_type != CPG_ITERATION_ONE_GROUP &&
+	    iteration_type != CPG_ITERATION_ALL) {
+
+		return (CS_ERR_INVALID_PARAM);
+	}
+
+	error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+	if (error != CS_OK) {
+		return (error);
+	}
+
+	error = hdb_error_to_cs (hdb_handle_create (&cpg_iteration_handle_t_db,
+		sizeof (struct cpg_iteration_instance_t), cpg_iteration_handle));
+	if (error != CS_OK) {
+		goto error_put_cpg_db;
+	}
+
+	error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, *cpg_iteration_handle,
+		(void *)&cpg_iteration_instance));
+	if (error != CS_OK) {
+		goto error_destroy;
+	}
+
+	cpg_iteration_instance->conn_handle = cpg_inst->handle;
+
+	list_init (&cpg_iteration_instance->list);
+
+	req_lib_cpg_iterationinitialize.header.size = sizeof (struct req_lib_cpg_iterationinitialize);
+	req_lib_cpg_iterationinitialize.header.id = MESSAGE_REQ_CPG_ITERATIONINITIALIZE;
+	req_lib_cpg_iterationinitialize.iteration_type = iteration_type;
+	if (group) {
+		marshall_to_mar_cpg_name_t (&req_lib_cpg_iterationinitialize.group_name, group);
+	}
+
+	iov.iov_base = (void *)&req_lib_cpg_iterationinitialize;
+	iov.iov_len = sizeof (struct req_lib_cpg_iterationinitialize);
+
+	error = coroipcc_msg_send_reply_receive (cpg_inst->handle,
+		&iov,
+		1,
+		&res_lib_cpg_iterationinitialize,
+		sizeof (struct res_lib_cpg_iterationinitialize));
+
+	if (error != CS_OK) {
+		goto error_put_destroy;
+	}
+
+	cpg_iteration_instance->executive_iteration_handle =
+		res_lib_cpg_iterationinitialize.iteration_handle;
+	cpg_iteration_instance->cpg_iteration_handle = *cpg_iteration_handle;
+
+	list_add (&cpg_iteration_instance->list, &cpg_inst->iteration_list_head);
+
+	hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
+	hdb_handle_put (&cpg_handle_t_db, handle);
+
+	return (res_lib_cpg_iterationinitialize.header.error);
+
+error_put_destroy:
+	hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
+error_destroy:
+	hdb_handle_destroy (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
+error_put_cpg_db:
+	hdb_handle_put (&cpg_handle_t_db, handle);
+
+	return (error);
+}
+
+cs_error_t cpg_iteration_next(
+	cpg_iteration_handle_t handle,
+	struct cpg_iteration_description_t *description)
+{
+	cs_error_t error;
+	struct cpg_iteration_instance_t *cpg_iteration_instance;
+	struct req_lib_cpg_iterationnext req_lib_cpg_iterationnext;
+	struct res_lib_cpg_iterationnext *res_lib_cpg_iterationnext;
+	struct iovec iov;
+	void *return_address;
+
+	if (description == NULL) {
+		return CS_ERR_INVALID_PARAM;
+	}
+
+	error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
+		(void *)&cpg_iteration_instance));
+	if (error != CS_OK) {
+		goto error_exit;
+	}
+
+	req_lib_cpg_iterationnext.header.size = sizeof (struct req_lib_cpg_iterationnext);
+	req_lib_cpg_iterationnext.header.id = MESSAGE_REQ_CPG_ITERATIONNEXT;
+	req_lib_cpg_iterationnext.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
+
+	iov.iov_base = (void *)&req_lib_cpg_iterationnext;
+	iov.iov_len = sizeof (struct req_lib_cpg_iterationnext);
+
+	error = coroipcc_msg_send_reply_receive_in_buf_get (cpg_iteration_instance->conn_handle,
+		&iov,
+		1,
+		&return_address);
+	res_lib_cpg_iterationnext = return_address;
+
+	if (error != CS_OK) {
+		goto error_put;
+	}
+
+	marshall_from_mar_cpg_iteration_description_t(
+			description,
+			&res_lib_cpg_iterationnext->description);
+
+	error = (error == CS_OK ? res_lib_cpg_iterationnext->header.error : error);
+
+	coroipcc_msg_send_reply_receive_in_buf_put(
+			cpg_iteration_instance->conn_handle);
+
+error_put:
+	hdb_handle_put (&cpg_iteration_handle_t_db, handle);
+
+error_exit:
+	return (error);
+}
+
+cs_error_t cpg_iteration_finalize (
+	cpg_iteration_handle_t handle)
+{
+	cs_error_t error;
+	struct iovec iov;
+	struct cpg_iteration_instance_t *cpg_iteration_instance;
+	struct req_lib_cpg_iterationfinalize req_lib_cpg_iterationfinalize;
+	struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize;
+
+	error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
+		(void *)&cpg_iteration_instance));
+	if (error != CS_OK) {
+		goto error_exit;
+	}
+
+	req_lib_cpg_iterationfinalize.header.size = sizeof (struct req_lib_cpg_iterationfinalize);
+	req_lib_cpg_iterationfinalize.header.id = MESSAGE_REQ_CPG_ITERATIONFINALIZE;
+	req_lib_cpg_iterationfinalize.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
+
+	iov.iov_base = (void *)&req_lib_cpg_iterationfinalize;
+	iov.iov_len = sizeof (struct req_lib_cpg_iterationfinalize);
+
+	error = coroipcc_msg_send_reply_receive (cpg_iteration_instance->conn_handle,
+		&iov,
+		1,
+		&res_lib_cpg_iterationfinalize,
+		sizeof (struct req_lib_cpg_iterationfinalize));
+
+	if (error != CS_OK) {
+		goto error_put;
+	}
+
+	cpg_iteration_instance_finalize (cpg_iteration_instance);
+	hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
+
+	return (res_lib_cpg_iterationfinalize.header.error);
+
+error_put:
+	hdb_handle_put (&cpg_iteration_handle_t_db, handle);
+error_exit:
+	return (error);
+}
+
 /** @} */

+ 313 - 2
services/cpg.c

@@ -134,8 +134,18 @@ struct cpg_pd {
 	uint32_t pid;
 	enum cpd_state cpd_state;
 	struct list_head list;
+	struct list_head iteration_instance_list_head;
 };
 
+struct cpg_iteration_instance {
+	hdb_handle_t handle;
+	struct list_head list;
+	struct list_head items_list_head; /* List of process_info */
+	struct list_head *current_pointer;
+};
+
+DECLARE_HDB_DATABASE(cpg_iteration_handle_t_db,NULL);
+
 DECLARE_LIST_INIT(cpg_pd_list_head);
 
 static unsigned int my_member_list[PROCESSOR_COUNT_MAX];
@@ -212,6 +222,18 @@ static void message_handler_req_lib_cpg_membership (void *conn,
 static void message_handler_req_lib_cpg_local_get (void *conn,
 						   const void *message);
 
+static void message_handler_req_lib_cpg_iteration_initialize (
+	void *conn,
+	const void *message);
+
+static void message_handler_req_lib_cpg_iteration_next (
+	void *conn,
+	const void *message);
+
+static void message_handler_req_lib_cpg_iteration_finalize (
+	void *conn,
+	const void *message);
+
 static int cpg_node_joinleave_send (unsigned int pid, const mar_cpg_name_t *group_name, int fn, int reason);
 
 static int cpg_exec_send_downlist(void);
@@ -253,7 +275,19 @@ static struct corosync_lib_handler cpg_lib_engine[] =
 	{ /* 4 */
 		.lib_handler_fn				= message_handler_req_lib_cpg_local_get,
 		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
-	}
+	},
+	{ /* 5 */
+		.lib_handler_fn				= message_handler_req_lib_cpg_iteration_initialize,
+		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+	},
+	{ /* 6 */
+		.lib_handler_fn				= message_handler_req_lib_cpg_iteration_next,
+		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+	},
+	{ /* 7 */
+		.lib_handler_fn				= message_handler_req_lib_cpg_iteration_finalize,
+		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+	},
 };
 
 static struct corosync_exec_handler cpg_exec_engine[] =
@@ -572,6 +606,45 @@ static int cpg_exec_init_fn (struct corosync_api_v1 *corosync_api)
 	return (0);
 }
 
+static void cpg_iteration_instance_finalize (struct cpg_iteration_instance *cpg_iteration_instance)
+{
+	struct list_head *iter, *iter_next;
+	struct process_info *pi;
+
+	for (iter = cpg_iteration_instance->items_list_head.next;
+		iter != &cpg_iteration_instance->items_list_head;
+		iter = iter_next) {
+
+		iter_next = iter->next;
+
+		pi = list_entry (iter, struct process_info, list);
+		list_del (&pi->list);
+		free (pi);
+	}
+
+	list_del (&cpg_iteration_instance->list);
+	hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_instance->handle);
+}
+
+static void cpg_pd_finalize (struct cpg_pd *cpd)
+{
+	struct list_head *iter, *iter_next;
+	struct cpg_iteration_instance *cpii;
+
+	for (iter = cpd->iteration_instance_list_head.next;
+		iter != &cpd->iteration_instance_list_head;
+		iter = iter_next) {
+
+		iter_next = iter->next;
+
+		cpii = list_entry (iter, struct cpg_iteration_instance, list);
+
+		cpg_iteration_instance_finalize (cpii);
+	}
+
+	list_del (&cpd->list);
+}
+
 static int cpg_lib_exit_fn (void *conn)
 {
 	struct cpg_pd *cpd = (struct cpg_pd *)api->ipc_private_data_get (conn);
@@ -582,7 +655,9 @@ static int cpg_lib_exit_fn (void *conn)
 		cpg_node_joinleave_send (cpd->pid, &cpd->group_name,
 				MESSAGE_REQ_EXEC_CPG_PROCLEAVE, CONFCHG_CPG_REASON_LEAVE);
 	}
-	list_del (&cpd->list);
+
+	cpg_pd_finalize (cpd);
+
 	api->ipc_refcnt_dec (conn);
 	return (0);
 }
@@ -958,6 +1033,8 @@ static int cpg_lib_init_fn (void *conn)
 	cpd->conn = conn;
 	list_add (&cpd->list, &cpg_pd_list_head);
 
+	list_init (&cpd->iteration_instance_list_head);
+
 	api->ipc_refcnt_inc (conn);
 	log_printf(LOGSYS_LEVEL_DEBUG, "lib_init_fn: conn=%p, cpd=%p\n", conn, cpd);
 	return (0);
@@ -1157,3 +1234,237 @@ static void message_handler_req_lib_cpg_local_get (void *conn,
 	api->ipc_response_send (conn, &res_lib_cpg_local_get,
 		sizeof (res_lib_cpg_local_get));
 }
+
+static void message_handler_req_lib_cpg_iteration_initialize (
+	void *conn,
+	const void *message)
+{
+	const struct req_lib_cpg_iterationinitialize *req_lib_cpg_iterationinitialize = message;
+	struct cpg_pd *cpd = (struct cpg_pd *)api->ipc_private_data_get (conn);
+	hdb_handle_t cpg_iteration_handle;
+
+	struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize;
+	struct list_head *iter, *iter2;
+	struct cpg_iteration_instance *cpg_iteration_instance;
+	cs_error_t error = CS_OK;
+	int res;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "cpg iteration initialize\n");
+
+	/* Because between calling this function and *next can be some operations which will
+	 * change list, we must do full copy.
+	 */
+
+	/*
+	 * Create new iteration instance
+	 */
+	res = hdb_handle_create (&cpg_iteration_handle_t_db, sizeof (struct cpg_iteration_instance),
+			&cpg_iteration_handle);
+
+	if (res != 0) {
+		error = CS_ERR_NO_MEMORY;
+		goto response_send;
+	}
+
+	res = hdb_handle_get (&cpg_iteration_handle_t_db, cpg_iteration_handle, (void *)&cpg_iteration_instance);
+
+	if (res != 0) {
+		error = CS_ERR_BAD_HANDLE;
+		goto error_destroy;
+	}
+
+	list_init (&cpg_iteration_instance->items_list_head);
+	cpg_iteration_instance->handle = cpg_iteration_handle;
+
+	/*
+	 * Create copy of process_info list "grouped by" group name
+	 */
+	for (iter = process_info_list_head.next; iter != &process_info_list_head; iter = iter->next) {
+		struct process_info *pi = list_entry (iter, struct process_info, list);
+		struct process_info *new_pi;
+
+		if (req_lib_cpg_iterationinitialize->iteration_type == CPG_ITERATION_NAME_ONLY) {
+			/*
+			 * Try to find processed group name in our list new list
+			 */
+			int found = 0;
+
+			for (iter2 = cpg_iteration_instance->items_list_head.next;
+			     iter2 != &cpg_iteration_instance->items_list_head;
+			     iter2 = iter2->next) {
+				 struct process_info *pi2 = list_entry (iter2, struct process_info, list);
+
+				 if (mar_name_compare (&pi2->group, &pi->group) == 0) {
+					found = 1;
+					break;
+				 }
+			}
+
+			if (found) {
+				/*
+				 * We have this name in list -> don't add
+				 */
+				continue ;
+			}
+		} else if (req_lib_cpg_iterationinitialize->iteration_type == CPG_ITERATION_ONE_GROUP) {
+			/*
+			 * Test pi group name with request
+			 */
+			if (mar_name_compare (&pi->group, &req_lib_cpg_iterationinitialize->group_name) != 0)
+				/*
+				 * Not same -> don't add
+				 */
+				continue ;
+		}
+
+		new_pi = malloc (sizeof (struct process_info));
+		if (!new_pi) {
+			log_printf(LOGSYS_LEVEL_WARNING, "Unable to allocate process_info struct");
+
+			error = CS_ERR_NO_MEMORY;
+
+			goto error_put_destroy;
+		}
+
+		memcpy (new_pi, pi, sizeof (struct process_info));
+		list_init (&new_pi->list);
+
+		if (req_lib_cpg_iterationinitialize->iteration_type == CPG_ITERATION_NAME_ONLY) {
+			/*
+			 * pid and nodeid -> undefined
+			 */
+			new_pi->pid = new_pi->nodeid = 0;
+		}
+
+		/*
+		 * We will return list "grouped" by "group name", so try to find right place to add
+		 */
+		for (iter2 = cpg_iteration_instance->items_list_head.next;
+		     iter2 != &cpg_iteration_instance->items_list_head;
+		     iter2 = iter2->next) {
+			 struct process_info *pi2 = list_entry (iter2, struct process_info, list);
+
+			 if (mar_name_compare (&pi2->group, &pi->group) == 0) {
+				break;
+			 }
+		}
+
+		list_add (&new_pi->list, iter2);
+	}
+
+	/*
+	 * Now we have a full "grouped by" copy of process_info list
+	 */
+
+	/*
+	 * Add instance to current cpd list
+	 */
+	list_init (&cpg_iteration_instance->list);
+	list_add (&cpg_iteration_instance->list, &cpd->iteration_instance_list_head);
+
+	cpg_iteration_instance->current_pointer = &cpg_iteration_instance->items_list_head;
+
+error_put_destroy:
+	hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_handle);
+error_destroy:
+	if (error != CS_OK) {
+		hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_handle);
+	}
+
+response_send:
+	res_lib_cpg_iterationinitialize.header.size = sizeof (res_lib_cpg_iterationinitialize);
+	res_lib_cpg_iterationinitialize.header.id = MESSAGE_RES_CPG_ITERATIONINITIALIZE;
+	res_lib_cpg_iterationinitialize.header.error = error;
+	res_lib_cpg_iterationinitialize.iteration_handle = cpg_iteration_handle;
+
+	api->ipc_response_send (conn, &res_lib_cpg_iterationinitialize,
+		sizeof (res_lib_cpg_iterationinitialize));
+}
+
+static void message_handler_req_lib_cpg_iteration_next (
+	void *conn,
+	const void *message)
+{
+	const struct req_lib_cpg_iterationnext *req_lib_cpg_iterationnext = message;
+	struct res_lib_cpg_iterationnext res_lib_cpg_iterationnext;
+	struct cpg_iteration_instance *cpg_iteration_instance;
+	cs_error_t error = CS_OK;
+	int res;
+	struct process_info *pi;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "cpg iteration next\n");
+
+	res = hdb_handle_get (&cpg_iteration_handle_t_db,
+			req_lib_cpg_iterationnext->iteration_handle,
+			(void *)&cpg_iteration_instance);
+
+	if (res != 0) {
+		error = CS_ERR_LIBRARY;
+		goto error_exit;
+	}
+
+	assert (cpg_iteration_instance);
+
+	cpg_iteration_instance->current_pointer = cpg_iteration_instance->current_pointer->next;
+
+	if (cpg_iteration_instance->current_pointer == &cpg_iteration_instance->items_list_head) {
+		error = CS_ERR_NO_SECTIONS;
+		goto error_put;
+	}
+
+	pi = list_entry (cpg_iteration_instance->current_pointer, struct process_info, list);
+
+	/*
+	 * Copy iteration data
+	 */
+	res_lib_cpg_iterationnext.description.nodeid = pi->nodeid;
+	res_lib_cpg_iterationnext.description.pid = pi->pid;
+	memcpy (&res_lib_cpg_iterationnext.description.group,
+			&pi->group,
+			sizeof (mar_cpg_name_t));
+
+error_put:
+	hdb_handle_put (&cpg_iteration_handle_t_db, req_lib_cpg_iterationnext->iteration_handle);
+error_exit:
+	res_lib_cpg_iterationnext.header.size = sizeof (res_lib_cpg_iterationnext);
+	res_lib_cpg_iterationnext.header.id = MESSAGE_RES_CPG_ITERATIONNEXT;
+	res_lib_cpg_iterationnext.header.error = error;
+
+	api->ipc_response_send (conn, &res_lib_cpg_iterationnext,
+		sizeof (res_lib_cpg_iterationnext));
+}
+
+static void message_handler_req_lib_cpg_iteration_finalize (
+	void *conn,
+	const void *message)
+{
+	const struct req_lib_cpg_iterationfinalize *req_lib_cpg_iterationfinalize = message;
+	struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize;
+	struct cpg_iteration_instance *cpg_iteration_instance;
+	cs_error_t error = CS_OK;
+	int res;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "cpg iteration finalize\n");
+
+	res = hdb_handle_get (&cpg_iteration_handle_t_db,
+			req_lib_cpg_iterationfinalize->iteration_handle,
+			(void *)&cpg_iteration_instance);
+
+	if (res != 0) {
+		error = CS_ERR_LIBRARY;
+		goto error_exit;
+	}
+
+	assert (cpg_iteration_instance);
+
+	cpg_iteration_instance_finalize (cpg_iteration_instance);
+	hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->handle);
+
+error_exit:
+	res_lib_cpg_iterationfinalize.header.size = sizeof (res_lib_cpg_iterationfinalize);
+	res_lib_cpg_iterationfinalize.header.id = MESSAGE_RES_CPG_ITERATIONFINALIZE;
+	res_lib_cpg_iterationfinalize.header.error = error;
+
+	api->ipc_response_send (conn, &res_lib_cpg_iterationfinalize,
+		sizeof (res_lib_cpg_iterationfinalize));
+}