Просмотр исходного кода

defect 903
First cut at a distributed locking service.


git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@829 fd59a12c-fef9-0310-b244-a6a79926bd2f

Steven Dake 20 лет назад
Родитель
Сommit
52fc4efc54
16 измененных файлов с 3353 добавлено и 26 удалено
  1. 6 6
      exec/Makefile
  2. 1483 0
      exec/lck.c
  3. 49 0
      exec/lck.h
  4. 5 3
      exec/main.c
  5. 9 5
      exec/main.h
  6. 1 0
      exec/print.c
  7. 3 2
      exec/print.h
  8. 9 2
      include/ipc_gen.h
  9. 162 0
      include/ipc_lck.h
  10. 16 0
      include/list.h
  11. 182 0
      include/saLck.h
  12. 14 5
      lib/Makefile
  13. 1149 0
      lib/lck.c
  14. 24 0
      lib/libSaLck.versions
  15. 6 3
      test/Makefile
  16. 235 0
      test/testlck.c

+ 6 - 6
exec/Makefile

@@ -29,13 +29,13 @@
 # THE POSSIBILITY OF SUCH DAMAGE.
 
 # Production mode flags
-CFLAGS = -O3 -Wall -fomit-frame-pointer
-LDFLAGS = -lpthread
+#CFLAGS = -O3 -Wall -fomit-frame-pointer
+#LDFLAGS = -lpthread
 
 # Debug mode flags
-#CFLAGS = -g -Wall
+CFLAGS = -g -Wall
 ##-DDEBUG
-#LDFLAGS = -g -lpthread
+LDFLAGS = -g -lpthread
 
 # Profile mode flags
 #CFLAGS = -O3 -pg
@@ -48,9 +48,9 @@ LDFLAGS = -lpthread
 TOTEM_SRC = aispoll.c totemnet.c totemrrp.c totemsrp.c totemmrp.c totempg.c totemconfig.c tlist.c hdb.c crypto.c wthread.c
 TOTEM_OBJS = aispoll.o totemnet.o totemrrp.o totemsrp.o totemmrp.o totempg.o totemconfig.o tlist.o hdb.o crypto.o wthread.o
 
-EXEC_SRC = main.c clm.c amf.c ckpt.c evt.c evs.c mainparse.c print.c mempool.c \
+EXEC_SRC = main.c clm.c amf.c ckpt.c evt.c lck.c evs.c mainparse.c print.c mempool.c \
 		util.c sync.c
-EXEC_OBJS = main.o clm.o amf.o ckpt.o evt.o evs.o mainparse.o print.o mempool.o \
+EXEC_OBJS = main.o clm.o amf.o ckpt.o evt.o lck.o evs.o mainparse.o print.o mempool.o \
 		util.o sync.o
 EXEC_LIBS = libtotem_pg.a
 

+ 1483 - 0
exec/lck.c

@@ -0,0 +1,1483 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <arpa/inet.h>
+
+#include "../include/saAis.h"
+#include "../include/saLck.h"
+#include "../include/ipc_lck.h"
+#include "../include/list.h"
+#include "../include/queue.h"
+#include "aispoll.h"
+#include "mempool.h"
+#include "util.h"
+#include "main.h"
+#include "totempg.h"
+
+#define LOG_SERVICE LOG_SERVICE_LCK
+#include "print.h"
+
+struct resource;
+struct resource_lock {
+	SaLckLockModeT lock_mode;
+	SaLckLockIdT lock_id;
+	SaLckLockFlagsT lock_flags;
+	SaLckWaiterSignalT waiter_signal;
+	SaLckLockStatusT lock_status;
+	SaTimeT timeout;
+	struct resource *resource;
+	int async_call;
+	SaInvocationT invocation;
+	struct message_source callback_source;
+	struct message_source response_source;
+	struct list_head list; /* locked resource lock list */
+	struct list_head resource_list; /* resource locks on a resource */
+	struct list_head resource_cleanup_list; /* cleanup data for resource locks */
+};
+
+struct resource {
+	SaNameT name;
+	int refcount;
+	struct list_head list;
+	struct list_head resource_lock_list_head;
+	struct list_head pr_granted_list_head;
+	struct list_head pr_pending_list_head;
+	struct list_head ex_pending_list_head;
+	struct resource_lock *ex_granted;
+};
+
+struct resource_cleanup {
+	struct resource *resource;
+	SaLckResourceHandleT resource_handle;
+	struct list_head resource_lock_list_head;
+	struct list_head list;
+};
+
+DECLARE_LIST_INIT(resource_list_head);
+
+static int lck_exec_init_fn (struct openais_config *);
+
+static int lck_exit_fn (struct conn_info *conn_info);
+
+static int lck_init_two_fn (struct conn_info *conn_info);
+
+static int message_handler_req_exec_lck_resourceopen (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required);
+
+static int message_handler_req_exec_lck_resourceclose (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required);
+
+static int message_handler_req_exec_lck_resourcelock (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required);
+
+static int message_handler_req_exec_lck_resourceunlock (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required);
+
+static int message_handler_req_exec_lck_resourcelockorphan (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required);
+
+static int message_handler_req_exec_lck_lockpurge (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required);
+
+static int message_handler_req_lib_lck_resourceopen (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_resourceopenasync (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_resourceclose (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_resourcelock (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_resourcelockasync (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_resourceunlock (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_resourceunlockasync (
+	struct conn_info *conn_info,
+	void *message);
+
+static int message_handler_req_lib_lck_lockpurge (
+	struct conn_info *conn_info,
+	void *message);
+
+static void lck_recovery_activate (void);
+static void lck_recovery_initialize (void);
+static int  lck_recovery_process (void);
+static void lck_recovery_finalize();
+static void lck_recovery_abort(void);
+
+void resource_release (struct resource *resource);
+
+/*
+static struct list_head *recovery_lck_next = 0;
+static struct list_head *recovery_lck_section_next = 0;
+static int recovery_section_data_offset = 0;
+static int recovery_section_send_flag = 0;
+static int recovery_abort = 0;
+*/
+
+static struct memb_ring_id saved_ring_id;
+
+static int lck_confchg_fn (
+		enum totem_configuration_type configuration_type,
+		struct in_addr *member_list, int member_list_entries,
+		struct in_addr *left_list, int left_list_entries,
+		struct in_addr *joined_list, int joined_list_entries,
+		struct memb_ring_id *ring_id);
+
+/*
+ * Executive Handler Definition
+ */
+struct libais_handler lck_libais_handlers[] =
+{
+	{ /* 0 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourceopen,
+		.response_size		= sizeof (struct res_lib_lck_resourceopen),
+		.response_id		= MESSAGE_RES_LCK_RESOURCEOPEN,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 1 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourceopenasync,
+		.response_size		= sizeof (struct res_lib_lck_resourceopenasync),
+		.response_id		= MESSAGE_RES_LCK_RESOURCEOPENASYNC,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 2 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourceclose,
+		.response_size		= sizeof (struct res_lib_lck_resourceclose),
+		.response_id		= MESSAGE_RES_LCK_RESOURCECLOSE,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 3 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourcelock,
+		.response_size		= sizeof (struct res_lib_lck_resourcelock),
+		.response_id		= MESSAGE_RES_LCK_RESOURCELOCK,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 4 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourcelockasync,
+		.response_size		= sizeof (struct res_lib_lck_resourcelockasync),
+		.response_id		= MESSAGE_RES_LCK_RESOURCELOCKASYNC,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 5 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourceunlock,
+		.response_size		= sizeof (struct res_lib_lck_resourceunlock),
+		.response_id		= MESSAGE_RES_LCK_RESOURCELOCK,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 6 */
+		.libais_handler_fn	= message_handler_req_lib_lck_resourceunlockasync,
+		.response_size		= sizeof (struct res_lib_lck_resourceunlock),
+		.response_id		= MESSAGE_RES_LCK_RESOURCEUNLOCKASYNC,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	},
+	{ /* 7 */
+		.libais_handler_fn	= message_handler_req_lib_lck_lockpurge,
+		.response_size		= sizeof (struct res_lib_lck_lockpurge),
+		.response_id		= MESSAGE_RES_LCK_LOCKPURGE,
+		.flow_control		= FLOW_CONTROL_REQUIRED
+	}
+};
+
+
+static int (*lck_aisexec_handler_fns[]) (void *msg, struct in_addr source_addr, int endian_conversion_required) = {
+	message_handler_req_exec_lck_resourceopen,
+	message_handler_req_exec_lck_resourceclose,
+	message_handler_req_exec_lck_resourcelock,
+	message_handler_req_exec_lck_resourceunlock,
+	message_handler_req_exec_lck_resourcelockorphan,
+	message_handler_req_exec_lck_lockpurge,
+};
+
+struct service_handler lck_service_handler = {
+	.libais_handlers		= lck_libais_handlers,
+	.libais_handlers_count		= sizeof (lck_libais_handlers) / sizeof (struct libais_handler),
+	.aisexec_handler_fns		= lck_aisexec_handler_fns,
+	.aisexec_handler_fns_count	= sizeof (lck_aisexec_handler_fns) / sizeof (int (*)),
+	.confchg_fn			= lck_confchg_fn,
+	.libais_init_two_fn		= lck_init_two_fn,
+	.libais_exit_fn			= lck_exit_fn,
+	.exec_init_fn			= lck_exec_init_fn,
+	.exec_dump_fn			= 0,
+	.sync_init			= lck_recovery_initialize,
+	.sync_process			= lck_recovery_process,
+	.sync_activate			= lck_recovery_activate,
+	.sync_abort			= lck_recovery_abort,
+};
+
+/*
+ * All data types used for executive messages
+ */
+struct req_exec_lck_resourceopen {
+	struct req_header header;
+	struct message_source source;
+	SaNameT resource_name;
+	SaLckResourceHandleT resource_handle;
+	SaInvocationT invocation;
+	SaTimeT timeout;
+	SaLckResourceOpenFlagsT open_flags;
+	int async_call;
+	SaAisErrorT fail_with_error;
+};
+
+struct req_exec_lck_resourceclose {
+	struct req_header header;
+	struct message_source source;
+	SaNameT lockResourceName;
+	SaLckResourceHandleT resource_handle;
+};
+
+struct req_exec_lck_resourcelock {
+	struct req_header header;
+	SaLckResourceHandleT resource_handle;
+	SaInvocationT invocation;
+	int async_call;
+	SaAisErrorT fail_with_error;
+	struct message_source source;
+	struct req_lib_lck_resourcelock req_lib_lck_resourcelock;
+};
+
+struct req_exec_lck_resourceunlock {
+	struct req_header header;
+	struct message_source source;
+	SaNameT resource_name;
+	SaLckLockIdT lock_id;
+	SaInvocationT invocation;
+	SaTimeT timeout;
+	int async_call;
+};
+
+struct req_exec_lck_resourcelockorphan {
+	struct req_header header;
+	struct message_source source;
+	SaNameT resource_name;
+	SaLckLockIdT lock_id;
+};
+
+struct req_exec_lck_lockpurge {
+	struct req_header header;
+	struct message_source source;
+	struct req_lib_lck_lockpurge req_lib_lck_lockpurge;
+};
+
+static void lck_recovery_initialize (void) 
+{
+	return;
+}
+
+static int lck_recovery_process (void) 
+{
+	return (0);
+}
+
+static void lck_recovery_finalize () 
+{
+	return;
+	
+}
+
+static void lck_recovery_activate (void) 
+{		
+ 	return;
+}
+
+static void lck_recovery_abort (void) 
+{
+	return;
+}
+
+static int lck_confchg_fn (
+	enum totem_configuration_type configuration_type,
+	struct in_addr *member_list, int member_list_entries,
+	struct in_addr *left_list, int left_list_entries,
+	struct in_addr *joined_list, int joined_list_entries,
+	struct memb_ring_id *ring_id) 
+{
+	return (0);
+}
+
+static struct resource *resource_find (SaNameT *name)
+{
+	struct list_head *resource_list;
+	struct resource *resource;
+
+   for (resource_list = resource_list_head.next;
+        resource_list != &resource_list_head;
+        resource_list = resource_list->next) {
+
+        resource = list_entry (resource_list,
+            struct resource, list);
+
+		if (name_match (name, &resource->name)) {
+			return (resource);
+		}
+	}
+	return (0);
+}
+
+static struct resource_lock *resource_lock_find (
+	struct resource *resource,
+	struct message_source *source,
+	SaLckLockIdT lock_id)
+{
+	struct list_head *list;
+	struct resource_lock *resource_lock;
+
+	for (list = resource->resource_lock_list_head.next;
+		list != &resource->resource_lock_list_head;
+		list = list->next) {
+
+printf ("%x next %x prev %x\n", list, list->next, list->prev);
+printf ("next resource\n");
+		resource_lock = list_entry (list, struct resource_lock, resource_list);
+
+printf ("lock id %llx\n", resource_lock->lock_id);
+		if ((memcmp (&resource_lock->callback_source,
+			source, sizeof (struct message_source)) == 0) &&
+			(lock_id == resource_lock->lock_id)) {
+
+			return (resource_lock);
+		}
+	}
+	return (0);
+}
+
+struct resource_cleanup *lck_resource_cleanup_find (
+	struct conn_info *conn_info,
+	SaLckResourceHandleT resource_handle)
+{
+	
+	struct list_head *list;
+	struct resource_cleanup *resource_cleanup;
+
+   for (list = conn_info->ais_ci.u.liblck_ci.resource_cleanup_list.next;
+		list != &conn_info->ais_ci.u.liblck_ci.resource_cleanup_list;
+        list = list->next) {
+
+		resource_cleanup = list_entry (list, struct resource_cleanup, list);
+		if (resource_cleanup->resource_handle == resource_handle) {
+			return (resource_cleanup);
+		}
+	}
+	return (0);
+}
+	
+
+int lck_resource_close (struct resource *resource)
+{
+	struct req_exec_lck_resourceclose req_exec_lck_resourceclose;
+	struct iovec iovec;
+
+	req_exec_lck_resourceclose.header.size =
+		sizeof (struct req_exec_lck_resourceclose);
+	req_exec_lck_resourceclose.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCECLOSE;
+
+	memcpy (&req_exec_lck_resourceclose.lockResourceName,
+		&resource->name, sizeof (SaNameT));
+
+	iovec.iov_base = (char *)&req_exec_lck_resourceclose;
+	iovec.iov_len = sizeof (req_exec_lck_resourceclose);
+
+	if (totempg_send_ok (sizeof (struct req_exec_lck_resourceclose))) {
+		assert (totempg_mcast (&iovec, 1, TOTEMPG_AGREED) == 0);
+		return (0);
+	}
+
+	return (-1);
+}
+
+void resource_lock_orphan (struct resource_lock *resource_lock)
+{
+	struct req_exec_lck_resourcelockorphan req_exec_lck_resourcelockorphan;
+	struct iovec iovec;
+
+	req_exec_lck_resourcelockorphan.header.size =
+		sizeof (struct req_exec_lck_resourcelockorphan);
+	req_exec_lck_resourcelockorphan.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCELOCKORPHAN;
+
+	memcpy (&req_exec_lck_resourcelockorphan.source,
+		&resource_lock->callback_source,
+		sizeof (struct message_source));
+
+	memcpy (&req_exec_lck_resourcelockorphan.resource_name,
+		&resource_lock->resource->name,
+		sizeof (SaNameT));
+		
+	req_exec_lck_resourcelockorphan.lock_id = resource_lock->lock_id;
+	
+	iovec.iov_base = (char *)&req_exec_lck_resourcelockorphan;
+	iovec.iov_len = sizeof (req_exec_lck_resourcelockorphan);
+
+	assert (totempg_mcast (&iovec, 1, TOTEMPG_AGREED) == 0);
+
+	// AAA
+}
+
+void lck_resource_cleanup_lock_remove (
+	struct resource_cleanup *resource_cleanup)
+{
+	struct list_head *list;
+	struct resource_lock *resource_lock;
+
+	for (list = resource_cleanup->resource_lock_list_head.next;
+		list != &resource_cleanup->resource_lock_list_head;
+		list = list->next) {
+
+		resource_lock = list_entry (list, struct resource_lock, resource_cleanup_list);
+		printf ("Found another lock resource to unlock\n");
+		resource_lock_orphan (resource_lock);
+	}
+}
+
+void lck_resource_cleanup_remove (
+	struct conn_info *conn_info,
+	SaLckResourceHandleT resource_handle)
+{
+	
+	struct list_head *list;
+	struct resource_cleanup *resource_cleanup;
+
+	for (list = conn_info->ais_ci.u.liblck_ci.resource_cleanup_list.next;
+		list != &conn_info->ais_ci.u.liblck_ci.resource_cleanup_list;
+		list = list->next) {
+
+		resource_cleanup = list_entry (list, struct resource_cleanup, list);
+		if (resource_cleanup->resource_handle == resource_handle) {
+			list_del (&resource_cleanup->list);
+			free (resource_cleanup);
+			return;
+		}
+	}
+}
+
+
+static int lck_exec_init_fn (struct openais_config *openais_config)
+{
+	/*
+	 *  Initialize the saved ring ID.
+	 */
+	saved_ring_id.seq = 0;
+	saved_ring_id.rep.s_addr = this_ip->sin_addr.s_addr;		
+	
+	return (0);
+}
+
+static int lck_exit_fn (struct conn_info *conn_info)
+{
+	struct resource_cleanup *resource_cleanup;
+	struct list_head *list;
+	
+printf ("exit_fn\n");
+	if (conn_info->conn_info_partner->service != LCK_SERVICE) {
+		return 0;
+	}
+
+	log_printf(LOG_LEVEL_NOTICE, "lck_exit_fn conn_info = %#x, with fd = %d\n", conn_info, conn_info->fd);
+	
+	/*
+	 * close all resources opened on this fd
+	 */
+	list = conn_info->conn_info_partner->ais_ci.u.liblck_ci.resource_cleanup_list.next;	
+	while (!list_empty(&conn_info->conn_info_partner->ais_ci.u.liblck_ci.resource_cleanup_list)) {
+		
+		resource_cleanup = list_entry (list, struct resource_cleanup, list);
+		
+printf ("resource to cleanup\n");
+		if (resource_cleanup->resource->name.length > 0)	{
+			lck_resource_cleanup_lock_remove (resource_cleanup);
+			lck_resource_close (resource_cleanup->resource);
+		}
+		
+printf ("resource cleanup %x\n", resource_cleanup);
+		list_del (&resource_cleanup->list);	
+		free (resource_cleanup);
+                
+		list = conn_info->conn_info_partner->ais_ci.u.liblck_ci.resource_cleanup_list.next;
+	}
+
+	return (0);
+}
+
+static int lck_init_two_fn (struct conn_info *conn_info)
+{
+	list_init (&conn_info->conn_info_partner->ais_ci.u.liblck_ci.resource_list);
+	list_init (&conn_info->conn_info_partner->ais_ci.u.liblck_ci.resource_cleanup_list);
+
+	return (0);
+
+}
+
+static int message_handler_req_exec_lck_resourceopen (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required)
+{
+	struct req_exec_lck_resourceopen *req_exec_lck_resourceopen = (struct req_exec_lck_resourceopen *)message;
+	struct res_lib_lck_resourceopen res_lib_lck_resourceopen;
+	struct res_lib_lck_resourceopenasync res_lib_lck_resourceopenasync;
+	struct resource *resource;
+	struct resource_cleanup *resource_cleanup;
+	SaErrorT error = SA_AIS_OK;
+
+	log_printf (LOG_LEVEL_NOTICE, "EXEC request: saLckResourceOpen %s\n",
+		getSaNameT (&req_exec_lck_resourceopen->resource_name));
+	
+	if (req_exec_lck_resourceopen->fail_with_error != SA_AIS_OK) {
+		error = req_exec_lck_resourceopen->fail_with_error;
+		goto error_exit;
+	}
+
+	resource = resource_find (&req_exec_lck_resourceopen->resource_name);
+
+	/*
+	 * If resource doesn't exist, create one
+	 */
+	if (resource == 0) {
+		if ((req_exec_lck_resourceopen->open_flags & SA_LCK_RESOURCE_CREATE) == 0) {
+			error = SA_AIS_ERR_NOT_EXIST;
+			goto error_exit;
+		}
+		resource = malloc (sizeof (struct resource));
+		if (resource == 0) {
+			error = SA_AIS_ERR_NO_MEMORY;
+			goto error_exit;
+		}
+		memset (resource, 0, sizeof (struct resource));
+
+		memcpy (&resource->name,
+			&req_exec_lck_resourceopen->resource_name,
+			sizeof (SaNameT));
+		list_init (&resource->list);
+		list_init (&resource->resource_lock_list_head);
+		list_add (&resource->list, &resource_list_head);
+		list_init (&resource->pr_granted_list_head);
+		list_init (&resource->pr_pending_list_head);
+		list_init (&resource->ex_pending_list_head);
+		resource->refcount = 0;
+		resource->ex_granted = NULL;
+	}
+
+	/*
+	 * Setup connection information and mark resource as referenced
+	 */
+	log_printf (LOG_LEVEL_DEBUG, "Lock resource opened is %p\n", resource);
+	resource_cleanup = malloc (sizeof (struct resource_cleanup));
+	if (resource_cleanup == 0) {
+		free (resource);
+		error = SA_AIS_ERR_NO_MEMORY;
+	} else {
+		list_init (&resource_cleanup->list);
+		list_init (&resource_cleanup->resource_lock_list_head);
+		resource_cleanup->resource = resource;
+		resource_cleanup->resource_handle = req_exec_lck_resourceopen->resource_handle;
+		list_add (
+			&resource_cleanup->list,
+			&req_exec_lck_resourceopen->source.conn_info->ais_ci.u.liblck_ci.resource_cleanup_list);
+	}
+	resource->refcount += 1;
+printf ("refcount == %d\n", resource->refcount);
+	
+	
+	/*
+	 * Send error result to LCK library
+	 */
+error_exit:
+	/*
+	 * If this node was the source of the message, respond to this node
+	 */
+	if (message_source_is_local (&req_exec_lck_resourceopen->source)) {
+		/*
+		 * If its an async call respond with the invocation and handle
+		 */
+		if (req_exec_lck_resourceopen->async_call) {
+			res_lib_lck_resourceopenasync.header.size = sizeof (struct res_lib_lck_resourceopenasync);
+			res_lib_lck_resourceopenasync.header.id = MESSAGE_RES_LCK_RESOURCEOPENASYNC;
+			res_lib_lck_resourceopenasync.header.error = error;
+			res_lib_lck_resourceopenasync.resourceHandle = req_exec_lck_resourceopen->resource_handle;
+			res_lib_lck_resourceopenasync.invocation = req_exec_lck_resourceopen->invocation;
+			memcpy (&res_lib_lck_resourceopenasync.source,
+				&req_exec_lck_resourceopen->source,
+				sizeof (struct message_source));
+
+			libais_send_response (
+				req_exec_lck_resourceopen->source.conn_info,
+				&res_lib_lck_resourceopenasync,
+				sizeof (struct res_lib_lck_resourceopenasync));
+			libais_send_response (
+				req_exec_lck_resourceopen->source.conn_info->conn_info_partner,
+				&res_lib_lck_resourceopenasync,
+				sizeof (struct res_lib_lck_resourceopenasync));
+		} else {
+			/*
+			 * otherwise respond with the normal resourceopen response
+			 */
+			res_lib_lck_resourceopen.header.size = sizeof (struct res_lib_lck_resourceopen);
+			res_lib_lck_resourceopen.header.id = MESSAGE_RES_LCK_RESOURCEOPEN;
+			res_lib_lck_resourceopen.header.error = error;
+			memcpy (&res_lib_lck_resourceopen.source,
+				&req_exec_lck_resourceopen->source,
+				sizeof (struct message_source));
+
+			libais_send_response (req_exec_lck_resourceopen->source.conn_info, &res_lib_lck_resourceopen,
+				sizeof (struct res_lib_lck_resourceopen));
+		}
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_lck_resourceclose (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required)
+{
+	struct req_exec_lck_resourceclose *req_exec_lck_resourceclose = (struct req_exec_lck_resourceclose *)message;
+	struct res_lib_lck_resourceclose res_lib_lck_resourceclose;
+	struct resource *resource = 0;
+	SaAisErrorT error = SA_AIS_OK;
+
+	log_printf (LOG_LEVEL_NOTICE, "EXEC request: saLckResourceClose %s\n",
+		getSaNameT (&req_exec_lck_resourceclose->lockResourceName));
+
+	resource = resource_find (&req_exec_lck_resourceclose->lockResourceName);
+	if (resource == 0) {
+		goto error_exit;
+	}
+		
+	resource->refcount -= 1;
+printf ("refcount %d\n", resource->refcount);
+	if (resource->refcount == 0) {
+		printf ("should free resource\n");
+	}
+error_exit:
+	if (message_source_is_local(&req_exec_lck_resourceclose->source)) {
+		lck_resource_cleanup_remove (
+			req_exec_lck_resourceclose->source.conn_info,
+			req_exec_lck_resourceclose->resource_handle);
+
+		res_lib_lck_resourceclose.header.size = sizeof (struct res_lib_lck_resourceclose);
+		res_lib_lck_resourceclose.header.id = MESSAGE_RES_LCK_RESOURCECLOSE;
+		res_lib_lck_resourceclose.header.error = error;
+		libais_send_response (req_exec_lck_resourceclose->source.conn_info,
+			&res_lib_lck_resourceclose, sizeof (struct res_lib_lck_resourceclose));
+	}
+	return (0);
+}
+
+void waiter_notification_send (struct resource_lock *resource_lock)
+{
+	struct res_lib_lck_lockwaitercallback res_lib_lck_lockwaitercallback;
+
+	if (message_source_is_local (&resource_lock->callback_source) == 0) {
+		return;
+	}
+
+	res_lib_lck_lockwaitercallback.header.size = sizeof (struct res_lib_lck_lockwaitercallback);
+	res_lib_lck_lockwaitercallback.header.id = MESSAGE_RES_LCK_LOCKWAITERCALLBACK;
+	res_lib_lck_lockwaitercallback.header.error = SA_AIS_OK;
+	res_lib_lck_lockwaitercallback.waiter_signal = resource_lock->waiter_signal;
+	res_lib_lck_lockwaitercallback.lock_id = resource_lock->lock_id;
+	res_lib_lck_lockwaitercallback.mode_requested = resource_lock->lock_mode;
+
+	if (resource_lock->resource->ex_granted) {
+		res_lib_lck_lockwaitercallback.mode_held = SA_LCK_EX_LOCK_MODE;
+	} else {
+		res_lib_lck_lockwaitercallback.mode_held = SA_LCK_PR_LOCK_MODE;
+	}
+
+	libais_send_response (
+		resource_lock->callback_source.conn_info->conn_info_partner,
+		&res_lib_lck_lockwaitercallback,
+		sizeof (struct res_lib_lck_lockwaitercallback));
+}
+
+void waiter_notification_list_send (struct list_head *list_notify_head)
+{
+	struct list_head *list;
+	struct resource_lock *resource_lock;
+
+	printf ("sending waiter notification to resource_lock list\n");
+	for (list = list_notify_head->next;
+		list != list_notify_head;
+		list = list->next) {
+
+		resource_lock = list_entry (list, struct resource_lock, list);
+		waiter_notification_send (resource_lock);
+	}
+}
+
+void resource_lock_async_deliver (
+	struct message_source *source,
+	struct resource_lock *resource_lock,
+	SaAisErrorT error)
+{
+	struct res_lib_lck_resourcelockasync res_lib_lck_resourcelockasync;
+
+	if (source && message_source_is_local(source)) {
+		if (resource_lock->async_call) {
+printf ("resource lock async deliver\n");
+			res_lib_lck_resourcelockasync.header.size = sizeof (struct res_lib_lck_resourcelockasync);
+			res_lib_lck_resourcelockasync.header.id = MESSAGE_RES_LCK_RESOURCELOCKASYNC;
+			res_lib_lck_resourcelockasync.header.error = error;
+			res_lib_lck_resourcelockasync.resource_lock = (void *)resource_lock;
+			res_lib_lck_resourcelockasync.lockStatus = resource_lock->lock_status;
+			res_lib_lck_resourcelockasync.invocation = resource_lock->invocation;
+			res_lib_lck_resourcelockasync.lockId = resource_lock->lock_id;
+			libais_send_response (source->conn_info->conn_info_partner,
+				&res_lib_lck_resourcelockasync,
+				sizeof (struct res_lib_lck_resourcelockasync));
+		}
+	}
+}
+
+void lock_response_deliver (
+	struct message_source *source,
+	struct resource_lock *resource_lock,
+	SaAisErrorT error)
+{
+	struct res_lib_lck_resourcelock res_lib_lck_resourcelock;
+
+	printf ("deliver\n");
+	if (source && message_source_is_local(source)) {
+		if (resource_lock->async_call) {
+			resource_lock_async_deliver (&resource_lock->callback_source, resource_lock, error);
+		} else {
+			res_lib_lck_resourcelock.header.size = sizeof (struct res_lib_lck_resourcelock);
+			res_lib_lck_resourcelock.header.id = MESSAGE_RES_LCK_RESOURCELOCK;
+			res_lib_lck_resourcelock.header.error = error;
+			res_lib_lck_resourcelock.resource_lock = (void *)resource_lock;
+			res_lib_lck_resourcelock.lockStatus = resource_lock->lock_status;
+			libais_send_response (source->conn_info,
+				&res_lib_lck_resourcelock,
+				sizeof (struct res_lib_lck_resourcelock));
+		}
+	}
+}
+
+
+/*
+ * Queue a lock if resource flags allow it
+ */
+void lock_queue (
+	struct resource *resource,
+	struct resource_lock *resource_lock)
+{
+	if ((resource_lock->lock_flags & SA_LCK_LOCK_NO_QUEUE) == 0) {
+		/*
+		 * Add lock to the list
+		 */
+		if (resource_lock->lock_mode == SA_LCK_PR_LOCK_MODE) {
+			list_add_tail (&resource_lock->list, 
+				&resource->pr_pending_list_head);
+				waiter_notification_send (resource->ex_granted);
+		} else
+		if (resource_lock->lock_mode == SA_LCK_EX_LOCK_MODE) {
+			list_add_tail (&resource_lock->list, 
+				&resource->ex_pending_list_head);
+				waiter_notification_list_send (&resource->pr_granted_list_head);
+		}
+	} else {
+		resource_lock->lock_status = SA_LCK_LOCK_NOT_QUEUED;
+	}
+}
+
+/*
+The algorithm:
+
+if ex lock granted
+	if ex pending list has locks
+		send waiter notification to ex lock granted 
+else
+	if ex pending list has locks
+		if pr granted list has locks
+			send waiter notification to all pr granted locks
+		else
+			grant ex lock from pending to granted
+	else
+		grant all pr pending locks to pr granted list
+*/
+#define SA_LCK_LOCK_NO_STATUS 0
+void lock_algorithm (
+	struct resource *resource,
+	struct resource_lock *resource_lock)
+{
+	resource_lock->lock_status = SA_LCK_LOCK_NO_STATUS; /* no status */
+	if (resource->ex_granted) {
+		/*
+		 * Exclusive lock granted
+		 */
+		if (resource_lock->lock_mode == SA_LCK_PR_LOCK_MODE) {
+			lock_queue (resource, resource_lock);
+		}
+	} else {
+		/*
+		 * Exclusive lock not granted
+		 */
+		if (resource_lock->lock_mode == SA_LCK_EX_LOCK_MODE) {
+			if (list_empty (&resource->pr_granted_list_head) == 0) {
+				lock_queue (resource, resource_lock);
+			} else {
+				/*
+				 * grant ex lock from pending to granted
+				 */
+				resource->ex_granted = resource_lock;
+				resource_lock->lock_status = SA_LCK_LOCK_GRANTED;
+			}
+		} else {
+			/*
+			 * grant all pr pending locks to pr granted list
+			 */
+			list_add (&resource_lock->list,
+				&resource->pr_granted_list_head);
+			resource_lock->lock_status = SA_LCK_LOCK_GRANTED;
+		}
+	}
+}
+
+/*
+ * 	if lock in ex, set ex to null
+ *	delete resource lock from list
+ * 
+ *	 if ex lock not granted
+ * 		if ex pending list has locks
+ *			grant first ex pending list lock to ex lock
+ * 	if ex lock not granted
+ *		if pr pending list has locks
+ *			assign all pr pending locks to pr granted lock list
+ */
+void unlock_algorithm (
+	struct resource *resource,
+	struct resource_lock *resource_lock)
+{
+	struct resource_lock *resource_lock_grant;
+	struct list_head *list;
+	struct list_head *list_p;
+
+	printf ("unlock\n");
+	/*
+	 * If unlocking the ex lock, reset ex granted
+	 */
+	if (resource_lock == resource->ex_granted) {
+		resource->ex_granted = 0;
+	}
+
+	/*
+	 * Delete resource lock from whichever list it is on
+	 */
+	list_del (&resource_lock->list);
+
+	/*
+	 * Check if EX locks are available, if so assign one
+	 */
+	if (resource->ex_granted == 0) {
+		if (list_empty (&resource->ex_pending_list_head) == 0) {
+			/*
+			 * grant first ex pending list lock to ex lock
+			 */
+			resource_lock_grant = list_entry (
+				resource->ex_pending_list_head.next,
+				struct resource_lock, list);
+
+			list_del (&resource_lock_grant->list);
+			resource->ex_granted = resource_lock_grant;
+
+			resource_lock_grant->lock_status = SA_LCK_LOCK_GRANTED;
+			lock_response_deliver (
+				&resource_lock_grant->response_source,
+				resource_lock_grant,
+				SA_AIS_OK);
+		}
+	}
+
+	/*
+	 * Couldn't assign EX lock, so assign any pending PR locks
+	 */
+	if (resource->ex_granted == 0) {
+		if (list_empty (&resource->pr_pending_list_head) == 0) {
+ 			/*
+			 * assign all pr pending locks to pr granted lock list
+			 */
+
+		   for (list = resource->pr_pending_list_head.next;
+				list != &resource->pr_pending_list_head;
+				list = list->next) {
+
+				resource_lock_grant = list_entry (list, struct resource_lock, list);
+				resource_lock_grant->lock_status = SA_LCK_LOCK_GRANTED;
+
+				lock_response_deliver (
+					&resource_lock_grant->response_source,
+					resource_lock_grant,
+					SA_AIS_OK);
+			}
+
+			/*
+			 * Add pending locks to granted list
+			 */
+		   	list_p = &resource->pr_pending_list_head.next;
+			list_del (&resource->pr_pending_list_head);
+			list_add_tail (list_p,
+				&resource->pr_granted_list_head);
+		}
+	}
+}
+
+static int message_handler_req_exec_lck_resourcelock (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required)
+{
+	struct req_exec_lck_resourcelock *req_exec_lck_resourcelock = (struct req_exec_lck_resourcelock *)message;
+	struct resource *resource = 0;
+	struct resource_lock *resource_lock = 0;
+	struct resource_cleanup *resource_cleanup = 0;
+
+	log_printf (LOG_LEVEL_NOTICE, "EXEC request: saLckResourceLock %s\n",
+		getSaNameT (&req_exec_lck_resourcelock->req_lib_lck_resourcelock.lockResourceName));
+
+	resource = resource_find (&req_exec_lck_resourcelock->req_lib_lck_resourcelock.lockResourceName);
+	if (resource == 0) {
+		goto error_exit;
+	}
+	resource->refcount += 1;
+
+	resource_lock = malloc (sizeof (struct resource_lock));
+	if (resource_lock == 0) {
+		lock_response_deliver (&req_exec_lck_resourcelock->source,
+			resource_lock,
+			SA_AIS_ERR_NO_MEMORY);
+		goto error_exit;
+	}
+
+	/*
+	 * Build resource lock structure
+	 */
+	memset (resource_lock, 0, sizeof (struct resource_lock));
+
+	list_init (&resource_lock->list);
+	list_init (&resource_lock->resource_list);
+	list_init (&resource_lock->resource_cleanup_list);
+
+	list_add (&resource_lock->resource_list, &resource->resource_lock_list_head);
+
+	resource_lock->resource = resource;
+
+	resource_lock->lock_mode =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.lockMode;
+	resource_lock->lock_flags =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.lockFlags;
+	resource_lock->waiter_signal =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.waiterSignal;
+	resource_lock->timeout =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.timeout;
+	resource_lock->lock_id =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.lockId;
+	resource_lock->async_call =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.async_call;
+	resource_lock->invocation =
+		req_exec_lck_resourcelock->req_lib_lck_resourcelock.invocation;
+	
+	/*
+	 * Waiter callback source
+	 */
+	memcpy (&resource_lock->callback_source,
+		&req_exec_lck_resourcelock->req_lib_lck_resourcelock.source,
+		sizeof (struct message_source));
+
+	lock_algorithm (resource, resource_lock);
+
+	/*
+	 * Add resource lock to cleanup handler for this api resource instance
+	 */
+	resource_cleanup = lck_resource_cleanup_find (
+		resource_lock->callback_source.conn_info,
+		req_exec_lck_resourcelock->resource_handle);
+
+	assert (resource_cleanup);
+		
+	list_add (&resource_lock->resource_cleanup_list,
+		&resource_cleanup->resource_lock_list_head);
+
+	/*
+	 * If lock queued by lock algorithm, dont send response to library now
+	 */
+	if (resource_lock->lock_status != SA_LCK_LOCK_NO_STATUS) {
+		/*
+		 * If lock granted or denied, deliver callback or 
+		 * response to library for non-async calls
+		 */
+		lock_response_deliver (
+			&req_exec_lck_resourcelock->source,
+			resource_lock,
+			SA_AIS_OK);
+	} else {
+		memcpy (&resource_lock->response_source,
+			&req_exec_lck_resourcelock->source,
+			sizeof (struct message_source));
+	}
+
+	/*
+	 * Deliver async response to library
+	 */
+	req_exec_lck_resourcelock->source.conn_info =
+		req_exec_lck_resourcelock->source.conn_info->conn_info_partner;
+	resource_lock_async_deliver (
+		&req_exec_lck_resourcelock->source,
+		resource_lock,
+		SA_AIS_OK);
+	req_exec_lck_resourcelock->source.conn_info =
+		req_exec_lck_resourcelock->source.conn_info->conn_info_partner;
+
+error_exit:
+	return (0);
+}
+
+static int message_handler_req_exec_lck_resourceunlock (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required)
+{
+	struct req_exec_lck_resourceunlock *req_exec_lck_resourceunlock = (struct req_exec_lck_resourceunlock *)message;
+	struct res_lib_lck_resourceunlock res_lib_lck_resourceunlock;
+	struct res_lib_lck_resourceunlockasync res_lib_lck_resourceunlockasync;
+	struct resource *resource = 0;
+	struct resource_lock *resource_lock = 0;
+	SaAisErrorT error = SA_AIS_OK;
+
+	log_printf (LOG_LEVEL_NOTICE, "EXEC request: saLckResourceUnlock %s\n",
+		getSaNameT (&req_exec_lck_resourceunlock->resource_name));
+
+	resource = resource_find (&req_exec_lck_resourceunlock->resource_name);
+	if (resource == 0) {
+		goto error_exit;
+	}
+printf ("resource %x\n", resource);
+	resource->refcount -= 1;
+
+	resource_lock = resource_lock_find (resource,
+		&req_exec_lck_resourceunlock->source,
+		req_exec_lck_resourceunlock->lock_id);
+	assert (resource_lock);
+
+	list_del (&resource_lock->resource_cleanup_list);
+	unlock_algorithm (resource, resource_lock);
+
+error_exit:
+	if (message_source_is_local(&req_exec_lck_resourceunlock->source)) {
+		if (req_exec_lck_resourceunlock->async_call) {
+			res_lib_lck_resourceunlockasync.header.size = sizeof (struct res_lib_lck_resourceunlockasync);
+			res_lib_lck_resourceunlockasync.header.id = MESSAGE_RES_LCK_RESOURCEUNLOCKASYNC;
+			res_lib_lck_resourceunlockasync.header.error = error;
+			res_lib_lck_resourceunlockasync.invocation =
+				req_exec_lck_resourceunlock->invocation;
+
+			libais_send_response (
+				req_exec_lck_resourceunlock->source.conn_info,
+				&res_lib_lck_resourceunlockasync,
+				sizeof (struct res_lib_lck_resourceunlockasync));
+			libais_send_response (
+				resource_lock->callback_source.conn_info,
+				&res_lib_lck_resourceunlockasync,
+				sizeof (struct res_lib_lck_resourceunlockasync));
+		} else {
+			res_lib_lck_resourceunlock.header.size = sizeof (struct res_lib_lck_resourceunlock);
+			res_lib_lck_resourceunlock.header.id = MESSAGE_RES_LCK_RESOURCEUNLOCK;
+			res_lib_lck_resourceunlock.header.error = error;
+			libais_send_response (req_exec_lck_resourceunlock->source.conn_info,
+				&res_lib_lck_resourceunlock, sizeof (struct res_lib_lck_resourceunlock));
+		}
+	}
+	return (0);
+}
+
+static int message_handler_req_exec_lck_resourcelockorphan (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required)
+{
+	struct req_exec_lck_resourcelockorphan *req_exec_lck_resourcelockorphan = (struct req_exec_lck_resourcelockorphan *)message;
+	struct resource *resource = 0;
+	struct resource_lock *resource_lock = 0;
+
+	log_printf (LOG_LEVEL_NOTICE, "EXEC request: Orphan resource locks for resource %s\n",
+		getSaNameT (&req_exec_lck_resourcelockorphan->resource_name));
+
+	resource = resource_find (&req_exec_lck_resourcelockorphan->resource_name);
+	if (resource == 0) {
+		assert (0);
+		goto error_exit;
+	}
+	resource->refcount -= 1;
+
+	resource_lock = resource_lock_find (resource,
+		&req_exec_lck_resourcelockorphan->source,
+		req_exec_lck_resourcelockorphan->lock_id);
+	assert (resource_lock);
+
+	list_del (&resource_lock->resource_cleanup_list);
+	unlock_algorithm (resource, resource_lock);
+error_exit:
+}
+
+static int message_handler_req_exec_lck_lockpurge (
+	void *message,
+	struct in_addr source_addr,
+	int endian_conversion_required)
+{
+	struct req_exec_lck_lockpurge *req_exec_lck_lockpurge = (struct req_exec_lck_lockpurge *)message;
+	struct res_lib_lck_lockpurge res_lib_lck_lockpurge;
+	struct resource *resource = 0;
+	SaAisErrorT error = SA_AIS_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "EXEC request: saLckLockPurge %s\n",
+		getSaNameT (&req_exec_lck_lockpurge->req_lib_lck_lockpurge.lockResourceName));
+
+	resource = resource_find (&req_exec_lck_lockpurge->req_lib_lck_lockpurge.lockResourceName);
+	if (resource == 0) {
+		goto error_exit;
+	}
+		
+error_exit:
+	if (message_source_is_local(&req_exec_lck_lockpurge->source)) {
+//		lck_resource_cleanup_remove (req_exec_lck_lockpurge->source.conn_info,
+//			resource);
+
+		res_lib_lck_lockpurge.header.size = sizeof (struct res_lib_lck_lockpurge);
+		res_lib_lck_lockpurge.header.id = MESSAGE_RES_LCK_LOCKPURGE;
+		res_lib_lck_lockpurge.header.error = error;
+		libais_send_response (req_exec_lck_lockpurge->source.conn_info,
+			&res_lib_lck_lockpurge, sizeof (struct res_lib_lck_lockpurge));
+	}
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourceopen (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_resourceopen *req_lib_lck_resourceopen = (struct req_lib_lck_resourceopen *)message;
+	struct req_exec_lck_resourceopen req_exec_lck_resourceopen;
+	struct iovec iovec;
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceOpen %s\n",
+		getSaNameT (&req_lib_lck_resourceopen->lockResourceName));
+
+	req_exec_lck_resourceopen.header.size =
+		sizeof (struct req_exec_lck_resourceopen);
+	req_exec_lck_resourceopen.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCEOPEN;
+
+	message_source_set (&req_exec_lck_resourceopen.source, conn_info);
+
+	memcpy (&req_exec_lck_resourceopen.resource_name,
+		&req_lib_lck_resourceopen->lockResourceName,
+		sizeof (SaNameT));
+	
+	req_exec_lck_resourceopen.open_flags = req_lib_lck_resourceopen->resourceOpenFlags;
+	req_exec_lck_resourceopen.async_call = 0;
+	req_exec_lck_resourceopen.invocation = 0;
+	req_exec_lck_resourceopen.resource_handle = req_lib_lck_resourceopen->resourceHandle;
+printf ("lib open handle %llx\n", req_exec_lck_resourceopen.resource_handle);
+	req_exec_lck_resourceopen.fail_with_error = SA_AIS_OK;
+
+	iovec.iov_base = (char *)&req_exec_lck_resourceopen;
+	iovec.iov_len = sizeof (req_exec_lck_resourceopen);
+
+	assert (totempg_mcast (&iovec, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourceopenasync (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_resourceopen *req_lib_lck_resourceopen = (struct req_lib_lck_resourceopen *)message;
+	struct req_exec_lck_resourceopen req_exec_lck_resourceopen;
+	struct iovec iovec;
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceOpenAsync %s\n",
+		getSaNameT (&req_lib_lck_resourceopen->lockResourceName));
+
+	req_exec_lck_resourceopen.header.size =
+		sizeof (struct req_exec_lck_resourceopen);
+	req_exec_lck_resourceopen.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCEOPEN;
+
+	message_source_set (&req_exec_lck_resourceopen.source, conn_info);
+
+	memcpy (&req_exec_lck_resourceopen.resource_name,
+		&req_lib_lck_resourceopen->lockResourceName,
+		sizeof (SaNameT));
+	
+	req_exec_lck_resourceopen.resource_handle = req_lib_lck_resourceopen->resourceHandle;
+printf ("lib open handle %llx\n", req_exec_lck_resourceopen.resource_handle);
+	req_exec_lck_resourceopen.invocation = req_lib_lck_resourceopen->invocation;
+	req_exec_lck_resourceopen.open_flags = req_lib_lck_resourceopen->resourceOpenFlags;
+	req_exec_lck_resourceopen.timeout = 0;
+	req_exec_lck_resourceopen.async_call = 1;
+
+	iovec.iov_base = (char *)&req_exec_lck_resourceopen;
+	iovec.iov_len = sizeof (req_exec_lck_resourceopen);
+
+	assert (totempg_mcast (&iovec, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourceclose (struct conn_info *conn_info, void *message) {
+	struct req_lib_lck_resourceclose *req_lib_lck_resourceclose = (struct req_lib_lck_resourceclose *)message;
+	struct req_exec_lck_resourceclose req_exec_lck_resourceclose;
+	struct iovec iovecs[2];
+	struct resource *resource;
+	struct res_lib_lck_resourceclose res_lib_lck_resourceclose;
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceClose %s\n",
+		getSaNameT (&req_lib_lck_resourceclose->lockResourceName));
+
+	resource = resource_find (&req_lib_lck_resourceclose->lockResourceName);
+	if (resource) {
+		req_exec_lck_resourceclose.header.size =
+			sizeof (struct req_exec_lck_resourceclose);
+		req_exec_lck_resourceclose.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCECLOSE;
+
+		message_source_set (&req_exec_lck_resourceclose.source, conn_info);
+
+		memcpy (&req_exec_lck_resourceclose.lockResourceName,
+			&req_lib_lck_resourceclose->lockResourceName, sizeof (SaNameT));
+
+		req_exec_lck_resourceclose.resource_handle = req_lib_lck_resourceclose->resourceHandle;
+		iovecs[0].iov_base = (char *)&req_exec_lck_resourceclose;
+		iovecs[0].iov_len = sizeof (req_exec_lck_resourceclose);
+
+		if (totempg_send_ok (sizeof (struct req_exec_lck_resourceclose))) {
+			assert (totempg_mcast (iovecs, 1, TOTEMPG_AGREED) == 0);
+		}
+	}
+	else {
+		log_printf (LOG_LEVEL_ERROR, "#### LCK: Could Not Find the Checkpoint to close so Returning Error. ####\n");
+
+		res_lib_lck_resourceclose.header.size = sizeof (struct res_lib_lck_resourceclose);
+		res_lib_lck_resourceclose.header.id = MESSAGE_RES_LCK_RESOURCECLOSE;
+		res_lib_lck_resourceclose.header.error = SA_AIS_ERR_NOT_EXIST;
+
+		libais_send_response (conn_info,
+			&res_lib_lck_resourceclose,
+			sizeof (struct res_lib_lck_resourceclose));
+	}
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourcelock (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_resourcelock *req_lib_lck_resourcelock = (struct req_lib_lck_resourcelock *)message;
+	struct req_exec_lck_resourcelock req_exec_lck_resourcelock;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceLock %s\n",
+		getSaNameT (&req_lib_lck_resourcelock->lockResourceName));
+
+	req_exec_lck_resourcelock.header.size =
+		sizeof (struct req_exec_lck_resourcelock);
+	req_exec_lck_resourcelock.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCELOCK;
+
+	message_source_set (&req_exec_lck_resourcelock.source, conn_info);
+
+	memcpy (&req_exec_lck_resourcelock.req_lib_lck_resourcelock,
+		req_lib_lck_resourcelock,
+		sizeof (struct req_lib_lck_resourcelock));
+	
+	req_exec_lck_resourcelock.resource_handle = req_lib_lck_resourcelock->resourceHandle;
+	req_exec_lck_resourcelock.async_call = 0;
+	req_exec_lck_resourcelock.invocation = 0;
+	req_exec_lck_resourcelock.fail_with_error = SA_AIS_OK;
+
+printf ("handle %d\n", req_exec_lck_resourcelock.resource_handle);
+	iovecs[0].iov_base = (char *)&req_exec_lck_resourcelock;
+	iovecs[0].iov_len = sizeof (req_exec_lck_resourcelock);
+
+	assert (totempg_mcast (iovecs, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourcelockasync (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_resourcelock *req_lib_lck_resourcelock = (struct req_lib_lck_resourcelock *)message;
+	struct req_exec_lck_resourcelock req_exec_lck_resourcelock;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceLockAsync %s\n",
+		getSaNameT (&req_lib_lck_resourcelock->lockResourceName));
+
+	req_exec_lck_resourcelock.header.size =
+		sizeof (struct req_exec_lck_resourcelock);
+	req_exec_lck_resourcelock.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCELOCK;
+
+	message_source_set (&req_exec_lck_resourcelock.source, conn_info);
+
+	memcpy (&req_exec_lck_resourcelock.req_lib_lck_resourcelock,
+		req_lib_lck_resourcelock,
+		sizeof (struct req_lib_lck_resourcelock));
+	
+	req_exec_lck_resourcelock.resource_handle = req_lib_lck_resourcelock->resourceHandle;
+	req_exec_lck_resourcelock.async_call = 1;
+	req_exec_lck_resourcelock.invocation = req_lib_lck_resourcelock->invocation;
+
+	iovecs[0].iov_base = (char *)&req_exec_lck_resourcelock;
+	iovecs[0].iov_len = sizeof (req_exec_lck_resourcelock);
+
+	assert (totempg_mcast (iovecs, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourceunlock (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_resourceunlock *req_lib_lck_resourceunlock = (struct req_lib_lck_resourceunlock *)message;
+	struct req_exec_lck_resourceunlock req_exec_lck_resourceunlock;
+	struct iovec iovec;
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceUnlock %s\n",
+		getSaNameT (&req_lib_lck_resourceunlock->lockResourceName));
+
+	req_exec_lck_resourceunlock.header.size =
+		sizeof (struct req_exec_lck_resourceunlock);
+	req_exec_lck_resourceunlock.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCEUNLOCK;
+
+	message_source_set (&req_exec_lck_resourceunlock.source, conn_info);
+
+	memcpy (&req_exec_lck_resourceunlock.resource_name,
+		&req_lib_lck_resourceunlock->lockResourceName,
+		sizeof (SaNameT));
+		
+	req_exec_lck_resourceunlock.lock_id = req_lib_lck_resourceunlock->lockId;
+	req_exec_lck_resourceunlock.async_call = 0;
+	req_exec_lck_resourceunlock.invocation = 0;
+	
+	iovec.iov_base = (char *)&req_exec_lck_resourceunlock;
+	iovec.iov_len = sizeof (req_exec_lck_resourceunlock);
+
+	assert (totempg_mcast (&iovec, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+
+static int message_handler_req_lib_lck_resourceunlockasync (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_resourceunlock *req_lib_lck_resourceunlock = (struct req_lib_lck_resourceunlock *)message;
+	struct req_exec_lck_resourceunlock req_exec_lck_resourceunlock;
+	struct iovec iovec;
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceUnlockAsync %s\n",
+		getSaNameT (&req_lib_lck_resourceunlock->lockResourceName));
+
+	req_exec_lck_resourceunlock.header.size =
+		sizeof (struct req_exec_lck_resourceunlock);
+	req_exec_lck_resourceunlock.header.id = MESSAGE_REQ_EXEC_LCK_RESOURCEUNLOCK;
+
+	message_source_set (&req_exec_lck_resourceunlock.source, conn_info);
+
+	memcpy (&req_exec_lck_resourceunlock.resource_name,
+		&req_lib_lck_resourceunlock->lockResourceName,
+		sizeof (SaNameT));
+		
+	req_exec_lck_resourceunlock.lock_id = req_lib_lck_resourceunlock->lockId;
+	req_exec_lck_resourceunlock.invocation = req_lib_lck_resourceunlock->invocation;
+	req_exec_lck_resourceunlock.async_call = 1;
+	
+	iovec.iov_base = (char *)&req_exec_lck_resourceunlock;
+	iovec.iov_len = sizeof (req_exec_lck_resourceunlock);
+
+	assert (totempg_mcast (&iovec, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+
+static int message_handler_req_lib_lck_lockpurge (struct conn_info *conn_info, void *message)
+{
+	struct req_lib_lck_lockpurge *req_lib_lck_lockpurge = (struct req_lib_lck_lockpurge *)message;
+	struct req_exec_lck_lockpurge req_exec_lck_lockpurge;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_NOTICE, "LIB request: saLckResourceLockPurge %s\n",
+		getSaNameT (&req_lib_lck_lockpurge->lockResourceName));
+
+	req_exec_lck_lockpurge.header.size =
+		sizeof (struct req_exec_lck_lockpurge);
+	req_exec_lck_lockpurge.header.id = MESSAGE_REQ_EXEC_LCK_LOCKPURGE;
+
+	message_source_set (&req_exec_lck_lockpurge.source, conn_info);
+
+	memcpy (&req_exec_lck_lockpurge.req_lib_lck_lockpurge,
+		req_lib_lck_lockpurge,
+		sizeof (struct req_lib_lck_lockpurge));
+	
+	iovecs[0].iov_base = (char *)&req_exec_lck_lockpurge;
+	iovecs[0].iov_len = sizeof (req_exec_lck_lockpurge);
+
+	assert (totempg_mcast (iovecs, 1, TOTEMPG_AGREED) == 0);
+
+	return (0);
+}
+

+ 49 - 0
exec/lck.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2005 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../include/saAis.h"
+#include "../include/saCkpt.h"
+#include "aispoll.h"
+#include "totemsrp.h"
+
+#ifndef LCK_H_DEFINED
+#define LCK_H_DEFINED
+
+struct liblck_ci {
+	struct list_head resource_list;
+	struct list_head resource_cleanup_list;
+};
+
+extern struct service_handler lck_service_handler;
+
+#endif /* CKPT_H_DEFINED */

+ 5 - 3
exec/main.c

@@ -73,6 +73,7 @@
 #include "amf.h"
 #include "ckpt.h"
 #include "evt.h"
+#include "lck.h"
 #include "swab.h"
 
 #define LOG_SERVICE LOG_SERVICE_MAIN
@@ -91,7 +92,8 @@ struct service_handler *ais_service_handlers[] = {
     &clm_service_handler,
     &amf_service_handler,
     &ckpt_service_handler,
-    &evt_service_handler
+    &evt_service_handler,
+    &lck_service_handler
 };
 
 struct sync_callbacks sync_callbacks[5];
@@ -100,8 +102,8 @@ int sync_callback_count;
 
 totemsrp_handle totemsrp_handle_in;
 
-#define AIS_SERVICE_HANDLERS_COUNT 5
-#define AIS_SERVICE_HANDLER_AISEXEC_FUNCTIONS_MAX 40
+#define AIS_SERVICE_HANDLERS_COUNT 6
+#define AIS_SERVICE_HANDLER_AISEXEC_FUNCTIONS_MAX 50
 
  /*
   * IPC Initializers

+ 9 - 5
exec/main.h

@@ -43,6 +43,7 @@
 #include "amf.h"
 #include "ckpt.h"
 #include "evt.h"
+#include "lck.h"
 
 #ifndef AIS_EXEC_H_DEFINED
 #define AIS_EXEC_H_DEFINED
@@ -75,6 +76,7 @@ struct ais_ci {
 		struct libamf_ci libamf_ci;
 		struct libckpt_ci libckpt_ci;
 		struct libevt_ci libevt_ci;
+		struct liblck_ci liblck_ci;
 	} u;
 };
 
@@ -135,13 +137,15 @@ enum nodeexec_message_types {
 	MESSAGE_REQ_EXEC_CKPT_SYNCHRONIZESECTION = 21,
 	MESSAGE_REQ_EXEC_EVT_EVENTDATA = 22,
 	MESSAGE_REQ_EXEC_EVT_CHANCMD = 23,
-	MESSAGE_REQ_EXEC_EVT_RECOVERY_EVENTDATA = 24
+	MESSAGE_REQ_EXEC_EVT_RECOVERY_EVENTDATA = 24,
+	MESSAGE_REQ_EXEC_LCK_RESOURCEOPEN = 25,
+	MESSAGE_REQ_EXEC_LCK_RESOURCECLOSE = 26,
+	MESSAGE_REQ_EXEC_LCK_RESOURCELOCK = 27,
+	MESSAGE_REQ_EXEC_LCK_RESOURCEUNLOCK = 28,
+	MESSAGE_REQ_EXEC_LCK_RESOURCELOCKORPHAN = 29,
+	MESSAGE_REQ_EXEC_LCK_LOCKPURGE = 30
 };
 
-struct message_source {
-    struct conn_info *conn_info;
-    struct in_addr in_addr;
-} __attribute__((packed));
 extern struct sockaddr_in *this_ip;
 
 poll_handle aisexec_poll_handle;

+ 1 - 0
exec/print.c

@@ -65,6 +65,7 @@ static char *log_services[] = {
 	"[AMF  ]",
 	"[CKPT ]",
 	"[EVT  ]",
+	"[LCK  ]",
 	"[EVS  ]",
 	"[SYNC ]"
 };

+ 3 - 2
exec/print.h

@@ -61,8 +61,9 @@
 #define LOG_SERVICE_AMF		4
 #define LOG_SERVICE_CKPT	5
 #define LOG_SERVICE_EVT		6
-#define LOG_SERVICE_EVS		7
-#define LOG_SERVICE_SYNC	8
+#define LOG_SERVICE_LCK		7
+#define LOG_SERVICE_EVS		8
+#define LOG_SERVICE_SYNC	9
 
 extern void internal_log_printf (int logclass, char *format, ...);
 

+ 9 - 2
include/ipc_gen.h

@@ -34,12 +34,15 @@
 #ifndef IPC_GEN_H_DEFINED
 #define IPC_GEN_H_DEFINED
 
+#include <netinet/in.h>
+
 enum service_types {
 	EVS_SERVICE = 0,
 	CLM_SERVICE = 1,
 	AMF_SERVICE = 2,
 	CKPT_SERVICE = 3,
-	EVT_SERVICE = 4
+	EVT_SERVICE = 4,
+	LCK_SERVICE = 5
 };
 
 enum req_init_types {
@@ -90,7 +93,6 @@ struct req_lib_dispatch_init {
 	unsigned long conn_info;
 };
 
-	
 struct req_lib_init {
 	struct res_header header;
 };
@@ -107,4 +109,9 @@ struct res_lib_response_init {
 struct res_lib_dispatch_init {
 	struct res_header header;
 };
+struct message_source {
+	struct conn_info *conn_info;
+	struct in_addr in_addr;
+} __attribute__((packed));
+
 #endif /* IPC_GEN_H_DEFINED */

+ 162 - 0
include/ipc_lck.h

@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2002-2005 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IPC_LCK_H_DEFINED
+#define IPC_LCK_H_DEFINED
+
+#include "saAis.h"
+#include "saLck.h"
+#include "ipc_gen.h"
+
+enum req_lib_lck_resource_types {
+	MESSAGE_REQ_LCK_RESOURCEOPEN = 0,
+	MESSAGE_REQ_LCK_RESOURCEOPENASYNC = 1,
+	MESSAGE_REQ_LCK_RESOURCECLOSE = 2,
+	MESSAGE_REQ_LCK_RESOURCELOCK = 3,
+	MESSAGE_REQ_LCK_RESOURCELOCKASYNC = 4,
+	MESSAGE_REQ_LCK_RESOURCEUNLOCK = 5,
+	MESSAGE_REQ_LCK_RESOURCEUNLOCKASYNC = 6,
+	MESSAGE_REQ_LCK_LOCKPURGE = 7,
+};
+
+enum res_lib_lck_resource_types {
+	MESSAGE_RES_LCK_RESOURCEOPEN = 0,
+	MESSAGE_RES_LCK_RESOURCEOPENASYNC = 1,
+	MESSAGE_RES_LCK_RESOURCECLOSE = 2,
+	MESSAGE_RES_LCK_RESOURCELOCK = 3,
+	MESSAGE_RES_LCK_RESOURCELOCKASYNC = 4,
+	MESSAGE_RES_LCK_RESOURCEUNLOCK = 5,
+	MESSAGE_RES_LCK_RESOURCEUNLOCKASYNC = 6,
+	MESSAGE_RES_LCK_LOCKPURGE = 7,
+	MESSAGE_RES_LCK_LOCKWAITERCALLBACK = 8
+};
+
+struct req_lib_lck_resourceopen {
+	struct req_header header;
+	SaInvocationT invocation;
+	SaNameT lockResourceName;
+	SaLckResourceOpenFlagsT resourceOpenFlags;
+	SaLckResourceHandleT resourceHandle;
+	SaTimeT timeout;
+	int async_call;
+};
+
+struct res_lib_lck_resourceopen {
+	struct res_header header;
+	SaLckResourceHandleT resourceHandle;
+	struct message_source source;
+};
+
+struct res_lib_lck_resourceopenasync {
+	struct res_header header;
+	SaInvocationT invocation;
+	SaLckResourceHandleT resourceHandle;
+	struct message_source source;
+};
+
+struct req_lib_lck_resourceclose {
+	struct req_header header;
+	SaNameT lockResourceName;
+	SaLckResourceHandleT resourceHandle;
+};
+
+struct res_lib_lck_resourceclose {
+	struct res_header header;
+};
+
+struct req_lib_lck_resourcelock {
+	struct req_header header;
+	SaNameT lockResourceName;
+	SaInvocationT invocation;
+	SaLckLockModeT lockMode;
+	SaLckLockFlagsT lockFlags;
+	SaLckWaiterSignalT waiterSignal;
+	SaTimeT timeout;
+	SaLckLockIdT lockId;
+	int async_call;
+	struct message_source source;
+	SaLckResourceHandleT resourceHandle;
+};
+
+struct res_lib_lck_resourcelock {
+	struct res_header header;
+	SaLckLockStatusT lockStatus;
+	void *resource_lock;
+};
+
+struct res_lib_lck_resourcelockasync {
+	struct res_header header;
+	SaLckLockStatusT lockStatus;
+	SaLckLockIdT lockId;
+	void *resource_lock;
+	SaInvocationT invocation;
+	SaLckResourceHandleT resourceHandle;
+};
+
+struct req_lib_lck_resourceunlock {
+	struct req_header header;
+	SaNameT lockResourceName;
+	SaLckLockIdT lockId;
+	SaInvocationT invocation;
+	SaTimeT timeout;
+	int async_call;
+	void *resource_lock;
+};
+
+struct res_lib_lck_resourceunlock {
+	struct res_header header;
+};
+
+struct res_lib_lck_resourceunlockasync {
+	struct res_header header;
+	SaInvocationT invocation;
+};
+
+struct req_lib_lck_lockpurge {
+	struct req_header header;
+	SaNameT lockResourceName;
+};
+
+struct res_lib_lck_lockpurge {
+	struct res_header header;
+};
+
+struct res_lib_lck_lockwaitercallback {
+	struct res_header header;
+	SaLckWaiterSignalT waiter_signal;
+	SaLckLockIdT lock_id;
+	SaLckLockModeT mode_held;
+	SaLckLockModeT mode_requested;
+};
+
+#endif /* IPC_LCK_H_DEFINED */

+ 16 - 0
include/list.h

@@ -84,4 +84,20 @@ static inline int list_empty(struct list_head *l)
 	return l->next == l;
 }
 
+static inline void list_splice (struct list_head *list, struct list_head *head)
+{
+	struct list_head *first;
+	struct list_head *last;
+	struct list_head *current;
+
+	first = list->next;
+	last = list->prev;
+	current = head->next;
+
+	first->prev = head;
+	head->next = first;
+	last->next = current;
+	current->prev = last;
+}
+
 #endif /* LIST_H_DEFINED */

+ 182 - 0
include/saLck.h

@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2005 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SALCK_H_DEFINED
+#define SALCK_H_DEFINED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef SaUint64T SaLckHandleT;
+
+typedef SaUint64T SaLckLockIdT;
+
+typedef SaUint64T SaLckResourceHandleT;
+
+#define SA_LCK_LOCK_NO_QUEUE 0x1
+#define SA_LCK_LOCK_ORPHAN 0x2
+
+typedef SaUint32T SaLckLockFlagsT;
+
+#define SA_LCK_RESOURCE_CREATE 0x1
+
+typedef SaUint32T SaLckResourceOpenFlagsT;
+
+typedef enum {
+	SA_LCK_LOCK_GRANTED = 1,
+	SA_LCK_LOCK_DEADLOCK = 2,
+	SA_LCK_LOCK_NOT_QUEUED = 3,
+	SA_LCK_LOCK_ORPHANED = 4,
+	SA_LCK_LOCK_NO_MORE = 5,
+	SA_LCK_LOCK_DUPLICATE_EX = 6
+} SaLckLockStatusT;
+
+typedef enum {
+	SA_LCK_PR_LOCK_MODE = 1,
+	SA_LCK_EX_LOCK_MODE = 2
+} SaLckLockModeT;
+
+#define SA_LCK_OPT_ORPHAN_LOCKS 0x1
+#define SA_LCK_OPT_DEADLOCK_DETECTION 0x2
+
+typedef SaUint32T SaLckOptionsT;
+
+typedef SaUint64T SaLckWaiterSignalT;
+
+typedef void (*SaLckResourceOpenCallbackT) (
+	SaInvocationT invocation,
+	SaLckResourceHandleT lockResourceHandle,
+	SaAisErrorT error);
+
+typedef void (*SaLckLockGrantcallbackT) (
+	SaInvocationT invocation,
+	SaLckLockStatusT lockStatus,
+	SaAisErrorT error);
+
+typedef void (*SaLckLockWaiterCallbackT) (
+	SaLckWaiterSignalT waiterSignal,
+	SaLckLockIdT lockId,
+	SaLckLockModeT modeHeld,
+	SaLckLockModeT modeRequested);
+
+typedef void (*SaLckResourceUnlockCallbackT) (
+	SaInvocationT invocation,
+	SaAisErrorT error);
+
+typedef struct {
+	SaLckResourceOpenCallbackT saLckResourceOpenCallback;
+	SaLckLockGrantcallbackT saLckLockGrantCallback;
+	SaLckLockWaiterCallbackT saLckLockWaiterCallback;
+	SaLckResourceUnlockCallbackT saLckResourceUnlockCallback;
+} SaLckCallbacksT;
+
+SaAisErrorT
+saLckInitialize (
+	SaLckHandleT *lckHandle,
+	const SaLckCallbacksT *lckCallbacks,
+	SaVersionT *version);
+
+SaAisErrorT
+saLckSelectionObjectGet (
+	SaLckHandleT lckHandle,
+	SaSelectionObjectT *selectionObject);
+
+SaAisErrorT
+saLckOptionCheck (
+	SaLckHandleT lckHandle,
+	SaLckOptionsT *lckOptions);
+
+SaAisErrorT
+saLckDispatch (
+	SaLckHandleT lckHandle,
+	SaDispatchFlagsT dispatchFlags);
+
+SaAisErrorT
+saLckFinalize (
+	SaLckHandleT lckHandle);
+
+SaAisErrorT
+saLckResourceOpen (
+	SaLckHandleT lckHandle,
+	const SaNameT *lockResourceName,
+	SaLckResourceOpenFlagsT resourceFlags,
+	SaTimeT timeout,
+	SaLckResourceHandleT *lockResourceHandle);
+
+SaAisErrorT
+saLckResourceOpenAsync (
+	SaLckHandleT lckHandle,
+	SaInvocationT invocation,
+	const SaNameT *lockResourceName,
+	SaLckResourceOpenFlagsT resourceFlags);
+
+SaAisErrorT
+saLckResourceClose (
+	SaLckResourceHandleT lockResourceHandle);
+
+SaAisErrorT
+saLckResourceLock (
+	SaLckResourceHandleT lockResourceHandle,
+	SaLckLockIdT *lockId,
+	SaLckLockModeT lockMode,
+	SaLckLockFlagsT lockFlags,
+	SaLckWaiterSignalT waiterSignal,	
+	SaTimeT timeout,
+	SaLckLockStatusT *lockStatus);
+
+SaAisErrorT
+SaLckResourceLockAsync (
+	SaLckResourceHandleT lockResourceHandle,
+	SaInvocationT invocation,
+	SaLckLockIdT *lockId,
+	SaLckLockModeT lockMode,
+	SaLckLockFlagsT lockFlags,
+	SaLckWaiterSignalT waiterSignal);
+
+SaAisErrorT
+saLckResourceUnlock (
+	SaLckLockIdT lockId,
+	SaTimeT timeout);
+
+SaAisErrorT
+saLckResourceUnlockAsync (
+	SaInvocationT invocation,	
+	SaLckLockIdT lockId);
+
+SaAisErrorT
+saLckLockPurge (
+	SaLckResourceHandleT lockResourceHandle);
+
+#endif /* SALCK_H_DEFINED */

+ 14 - 5
lib/Makefile

@@ -44,8 +44,8 @@ LDFLAGS = -g
 #LDFLAGS = -g
 
 all:libSaClm.a libSaClm.so.1.0 libSaAmf.a libSaAmf.so.1.0 libSaCkpt.a \
-	libSaCkpt.so.1.0 libSaEvt.a libSaEvt.so.1.0 libais.a libais.so.1.0 libevs.a \
-	libevs.so.1.0
+	libSaCkpt.so.1.0 libSaEvt.a libSaEvt.so.1.0 libSaLck.a libSaLck.so.1.0 \
+	libais.a libais.so.1.0 libevs.a libevs.so.1.0
 
 LIBAIS_SRC = util.c amf.c clm.c ckpt.c evt.c
 
@@ -87,10 +87,19 @@ libSaEvt.so.1.0: util.o evt.o
 	ln -s libSaEvt.so.1.0 libSaEvt.so.1
 	ln -s libSaEvt.so.1.0 libSaEvt.so
 
+libSaLck.a: util.o lck.o
+	$(AR) -rc libSaLck.a util.o lck.o
+
+libSaLck.so.1.0: util.o lck.o
+	$(CC) -shared -Wl,-soname,libSaLCK.so.1,-version-script=libSaLck.versions util.o lck.o -o $@
+	rm -f libSaLck.so.1 libSaLck.so
+	ln -s libSaLck.so.1.0 libSaLck.so.1
+	ln -s libSaLck.so.1.0 libSaLck.so
+
 libais.a: util.o amf.o clm.o ckpt.o evt.o
 	$(AR) -rc libais.a util.o amf.o clm.o ckpt.o evt.o
 
-libais.so.1.0: util.o amf.o clm.o ckpt.o evt.o
+libais.so.1.0: util.o amf.o clm.o ckpt.o evt.o lck.o
 	$(CC) -shared -Wl,-soname,libais.so.1,-version-script=libSaAis.versions util.o amf.o clm.o ckpt.o \
 								evt.o -o $@
 	rm -f libais.so.1 libais.so
@@ -108,8 +117,8 @@ libevs.so.1.0: util.o evs.o
 
 clean:
 	rm -f *.o libais.so* libais.a libSaClm.so* libSaClm.a* libSaAmf.so* libSaAmf.a \
-		libSaCkpt.so* libSaCkpt.a* libSaEvt.so* libSaEvt.a libevs.so* libevs.a \
-		*.da *.bb *.bbg
+		libSaCkpt.so* libSaCkpt.a* libSaEvt.so* libSaEvt.a libSaLck.so libSaLck.a \
+		libevs.so* libevs.a *.da *.bb *.bbg
  
 # -fPIC rules required for all libraries
 %.o: %.c

+ 1149 - 0
lib/lck.c

@@ -0,0 +1,1149 @@
+/*
+ * Copyright (c) 2005 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "../include/saAis.h"
+#include "../include/list.h"
+#include "../include/saLck.h"
+#include "../include/ipc_gen.h"
+#include "../include/ipc_lck.h"
+
+#include "util.h"
+
+struct message_overlay {
+	struct res_header header;
+	char data[4096];
+};
+
+/*
+ * Data structure for instance data
+ */
+struct lckInstance {
+	int response_fd;
+	int dispatch_fd;
+	SaLckCallbacksT callbacks;
+	int finalize;
+	SaLckHandleT lckHandle;
+	struct list_head resource_list;
+	pthread_mutex_t response_mutex;
+	pthread_mutex_t dispatch_mutex;
+};
+
+struct lckResourceInstance {
+	int response_fd;
+	SaLckHandleT lckHandle;
+	SaLckResourceHandleT lckResourceHandle;
+	SaLckResourceOpenFlagsT resourceOpenFlags;
+	SaNameT lockResourceName;
+	struct list_head list;
+	struct message_source source;
+	pthread_mutex_t *response_mutex;
+};
+
+struct lckLockIdInstance {
+	int response_fd;
+	SaLckResourceHandleT lckResourceHandle;
+	struct list_head list;
+	void *resource_lock;
+	pthread_mutex_t *response_mutex;
+};
+
+void lckHandleInstanceDestructor (void *instance);
+void lckResourceHandleInstanceDestructor (void *instance);
+void lckResourceHandleLockIdInstanceDestructor (void *instance);
+
+/*
+ * All LCK instances in this database
+ */
+static struct saHandleDatabase lckHandleDatabase = {
+	.handleCount			= 0,
+	.handles			= 0,
+	.mutex				= PTHREAD_MUTEX_INITIALIZER,
+	.handleInstanceDestructor	= lckHandleInstanceDestructor
+};
+
+/*
+ *  All Resource instances in this database
+ */
+static struct saHandleDatabase lckResourceHandleDatabase = {
+	.handleCount			= 0,
+	.handles			= 0,
+	.mutex				= PTHREAD_MUTEX_INITIALIZER,
+	.handleInstanceDestructor	= lckResourceHandleInstanceDestructor
+};
+
+/*
+ *  All Resource Lock Identifier instances in this database
+ */
+static struct saHandleDatabase lckLockIdHandleDatabase = {
+	.handleCount			= 0,
+	.handles			= 0,
+	.mutex				= PTHREAD_MUTEX_INITIALIZER,
+	.handleInstanceDestructor	= lckResourceHandleLockIdInstanceDestructor
+};
+
+/*
+ * Versions supported
+ */
+static SaVersionT lckVersionsSupported[] = {
+	{ 'B', 1, 1 }
+};
+
+static struct saVersionDatabase lckVersionDatabase = {
+	sizeof (lckVersionsSupported) / sizeof (SaVersionT),
+	lckVersionsSupported
+};
+
+
+/*
+ * Implementation
+ */
+void lckHandleInstanceDestructor (void *instance)
+{
+}
+
+void lckResourceHandleInstanceDestructor (void *instance)
+{
+	return;
+}
+
+void lckResourceHandleLockIdInstanceDestructor (void *instance)
+{
+}
+
+#ifdef NOT_DONE
+static void lckSectionIterationInstanceFinalize (struct lckSectionIterationInstance *lckSectionIterationInstance)
+{
+	struct iteratorSectionIdListEntry *iteratorSectionIdListEntry;
+	struct list_head *sectionIdIterationList;
+	struct list_head *sectionIdIterationListNext;
+	/*
+	 * iterate list of section ids for this iterator to free the allocated memory
+	 * be careful to cache next pointer because free removes memory from use
+	 */
+	for (sectionIdIterationList = lckSectionIterationInstance->sectionIdListHead.next,
+		sectionIdIterationListNext = sectionIdIterationList->next;
+		sectionIdIterationList != &lckSectionIterationInstance->sectionIdListHead;
+		sectionIdIterationList = sectionIdIterationListNext,
+		sectionIdIterationListNext = sectionIdIterationList->next) {
+
+		iteratorSectionIdListEntry = list_entry (sectionIdIterationList,
+			struct iteratorSectionIdListEntry, list);
+
+		free (iteratorSectionIdListEntry);
+	}
+
+	list_del (&lckSectionIterationInstance->list);
+
+	saHandleDestroy (&lckSectionIterationHandleDatabase,
+		lckSectionIterationInstance->sectionIterationHandle);
+}
+
+static void lckResourceInstanceFinalize (struct lckResourceInstance *lckResourceInstance)
+{
+	struct lckSectionIterationInstance *sectionIterationInstance;
+	struct list_head *sectionIterationList;
+	struct list_head *sectionIterationListNext;
+
+	for (sectionIterationList = lckResourceInstance->section_iteration_list_head.next,
+		sectionIterationListNext = sectionIterationList->next;
+		sectionIterationList != &lckResourceInstance->section_iteration_list_head;
+		sectionIterationList = sectionIterationListNext,
+		sectionIterationListNext = sectionIterationList->next) {
+
+		sectionIterationInstance = list_entry (sectionIterationList,
+			struct lckSectionIterationInstance, list);
+
+		lckSectionIterationInstanceFinalize (sectionIterationInstance);
+	}
+
+	list_del (&lckResourceInstance->list);
+
+	saHandleDestroy (&lckResourceHandleDatabase, lckResourceInstance->lckResourceHandle);
+}
+
+static void lckInstanceFinalize (struct lckInstance *lckInstance)
+{
+	struct lckResourceInstance *lckResourceInstance;
+	struct list_head *resourceInstanceList;
+	struct list_head *resourceInstanceListNext;
+
+	for (resourceInstanceList = lckInstance->resource_list.next,
+		resourceInstanceListNext = resourceInstanceList->next;
+		resourceInstanceList != &lckInstance->resource_list;
+		resourceInstanceList = resourceInstanceListNext,
+		resourceInstanceListNext = resourceInstanceList->next) {
+
+		lckResourceInstance = list_entry (resourceInstanceList,
+			struct lckResourceInstance, list);
+
+		lckResourceInstanceFinalize (lckResourceInstance);
+	}
+
+	saHandleDestroy (&lckHandleDatabase, lckInstance->lckHandle);
+}
+
+#endif
+
+SaAisErrorT
+saLckInitialize (
+	SaLckHandleT *lckHandle,
+	const SaLckCallbacksT *callbacks,
+	SaVersionT *version)
+{
+	struct lckInstance *lckInstance;
+	SaAisErrorT error = SA_AIS_OK;
+
+	if (lckHandle == NULL) {
+		return (SA_AIS_ERR_INVALID_PARAM);
+	}
+
+	error = saVersionVerify (&lckVersionDatabase, version);
+	if (error != SA_AIS_OK) {
+		goto error_no_destroy;
+	}
+
+	error = saHandleCreate (&lckHandleDatabase, sizeof (struct lckInstance),
+		lckHandle);
+	if (error != SA_AIS_OK) {
+		goto error_no_destroy;
+	}
+
+	error = saHandleInstanceGet (&lckHandleDatabase, *lckHandle,
+		(void *)&lckInstance);
+	if (error != SA_AIS_OK) {
+		goto error_destroy;
+	}
+
+	lckInstance->response_fd = -1;
+
+	error = saServiceConnectTwo (&lckInstance->response_fd,
+		&lckInstance->dispatch_fd, LCK_SERVICE);
+	if (error != SA_AIS_OK) {
+		goto error_put_destroy;
+	}
+
+	if (callbacks) {
+		memcpy (&lckInstance->callbacks, callbacks, sizeof (SaLckCallbacksT));
+	} else {
+		memset (&lckInstance->callbacks, 0, sizeof (SaLckCallbacksT));
+	}
+
+	list_init (&lckInstance->resource_list);
+
+	lckInstance->lckHandle = *lckHandle;
+
+	pthread_mutex_init (&lckInstance->response_mutex, NULL);
+
+
+	saHandleInstancePut (&lckHandleDatabase, *lckHandle);
+
+	return (SA_AIS_OK);
+
+error_put_destroy:
+	saHandleInstancePut (&lckHandleDatabase, *lckHandle);
+error_destroy:
+	saHandleDestroy (&lckHandleDatabase, *lckHandle);
+error_no_destroy:
+	return (error);
+}
+
+SaAisErrorT
+saLckSelectionObjectGet (
+	const SaLckHandleT lckHandle,
+	SaSelectionObjectT *selectionObject)
+{
+	struct lckInstance *lckInstance;
+	SaAisErrorT error;
+
+	if (selectionObject == NULL) {
+		return (SA_AIS_ERR_INVALID_PARAM);
+	}
+	error = saHandleInstanceGet (&lckHandleDatabase, lckHandle, (void *)&lckInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	*selectionObject = lckInstance->dispatch_fd;
+
+	saHandleInstancePut (&lckHandleDatabase, lckHandle);
+
+	return (SA_AIS_OK);
+}
+
+SaAisErrorT
+saLckOptionCheck (
+	SaLckHandleT lckHandle,
+	SaLckOptionsT *lckOptions)
+{
+	return (SA_AIS_OK);
+}
+
+SaAisErrorT
+saLckDispatch (
+	const SaLckHandleT lckHandle,
+	SaDispatchFlagsT dispatchFlags)
+{
+	struct pollfd ufds;
+	int poll_fd;
+	int timeout = 1;
+	SaLckCallbacksT callbacks;
+	SaAisErrorT error;
+	int dispatch_avail;
+	struct lckInstance *lckInstance;
+	struct lckResourceInstance *lckResourceInstance;
+	struct lckLockIdInstance *lckLockIdInstance;
+	int cont = 1; /* always continue do loop except when set to 0 */
+	struct message_overlay dispatch_data;
+	struct res_lib_lck_lockwaitercallback *res_lib_lck_lockwaitercallback;
+	struct res_lib_lck_resourceopenasync *res_lib_lck_resourceopenasync;
+	struct res_lib_lck_resourcelockasync *res_lib_lck_resourcelockasync;
+	struct res_lib_lck_resourceunlockasync *res_lib_lck_resourceunlockasync;
+
+
+	if (dispatchFlags != SA_DISPATCH_ONE &&
+		dispatchFlags != SA_DISPATCH_ALL &&
+		dispatchFlags != SA_DISPATCH_BLOCKING) {
+
+		return (SA_AIS_ERR_INVALID_PARAM);
+	}
+
+	error = saHandleInstanceGet (&lckHandleDatabase, lckHandle,
+		(void *)&lckInstance);
+	if (error != SA_AIS_OK) {
+		goto error_exit;
+	}
+
+	/*
+	 * Timeout instantly for SA_DISPATCH_ALL
+	 */
+	if (dispatchFlags == SA_DISPATCH_ALL) {
+		timeout = 0;
+	}
+
+	do {
+		/*
+		 * Read data directly from socket
+		 */
+		poll_fd = lckInstance->dispatch_fd;
+		ufds.fd = poll_fd;
+		ufds.events = POLLIN;
+		ufds.revents = 0;
+
+		error = saPollRetry(&ufds, 1, timeout);
+		if (error != SA_AIS_OK) {
+			goto error_put;
+		}
+		pthread_mutex_lock(&lckInstance->dispatch_mutex);
+
+		if (lckInstance->finalize == 1) {
+			error = SA_AIS_OK;
+			goto error_unlock;
+		}
+
+		if ((ufds.revents & (POLLERR|POLLHUP|POLLNVAL)) != 0) {
+				error = SA_AIS_ERR_BAD_HANDLE;
+				goto error_unlock;
+		}
+		
+		dispatch_avail = (ufds.revents & POLLIN);
+
+		if (dispatch_avail == 0 && dispatchFlags == SA_DISPATCH_ALL) {
+			pthread_mutex_unlock(&lckInstance->dispatch_mutex);
+			break; /* exit do while cont is 1 loop */
+		} else
+		if (dispatch_avail == 0) {
+			pthread_mutex_unlock(&lckInstance->dispatch_mutex);
+			continue;
+		}
+		
+		memset(&dispatch_data,0, sizeof(struct message_overlay));
+		error = saRecvRetry (lckInstance->dispatch_fd, &dispatch_data.header, sizeof (struct res_header), MSG_WAITALL | MSG_NOSIGNAL);
+		if (error != SA_AIS_OK) {
+			goto error_unlock;
+		}
+		if (dispatch_data.header.size > sizeof (struct res_header)) {
+			error = saRecvRetry (lckInstance->dispatch_fd, &dispatch_data.data,
+				dispatch_data.header.size - sizeof (struct res_header),
+				MSG_WAITALL | MSG_NOSIGNAL);
+			if (error != SA_AIS_OK) {
+				goto error_unlock;
+			}
+		}
+
+		/*
+		* Make copy of callbacks, message data, unlock instance,
+		* and call callback. A risk of this dispatch method is that
+		* the callback routines may operate at the same time that
+		* LckFinalize has been called in another thread.
+		*/
+		memcpy(&callbacks,&lckInstance->callbacks, sizeof(lckInstance->callbacks));
+		pthread_mutex_unlock(&lckInstance->dispatch_mutex);
+		/*
+		 * Dispatch incoming response
+		 */
+		switch (dispatch_data.header.id) {
+		case MESSAGE_RES_LCK_LOCKWAITERCALLBACK:
+			if (callbacks.saLckResourceOpenCallback == NULL) {
+				continue;
+			}
+			res_lib_lck_lockwaitercallback = (struct res_lib_lck_lockwaitercallback *)&dispatch_data;
+			callbacks.saLckLockWaiterCallback (
+				res_lib_lck_lockwaitercallback->waiter_signal,
+				res_lib_lck_lockwaitercallback->lock_id,
+				res_lib_lck_lockwaitercallback->mode_held,
+				res_lib_lck_lockwaitercallback->mode_requested);
+			break;
+
+		case MESSAGE_RES_LCK_RESOURCEOPENASYNC:
+			if (callbacks.saLckLockWaiterCallback == NULL) {
+				continue;
+			}
+			res_lib_lck_resourceopenasync = (struct res_lib_lck_resourceopenasync *)&dispatch_data;
+			/*
+			 * This instance get/listadd/put required so that close
+			 * later has the proper list of resources
+			 */
+			if (res_lib_lck_resourceopenasync->header.error == SA_AIS_OK) {
+				error = saHandleInstanceGet (&lckResourceHandleDatabase,
+					res_lib_lck_resourceopenasync->resourceHandle,
+					(void *)&lckResourceInstance);
+
+					assert (error == SA_AIS_OK); /* should only be valid handles here */
+				/*
+				 * open succeeded without error
+				 */
+
+				callbacks.saLckResourceOpenCallback(
+					res_lib_lck_resourceopenasync->invocation,
+					res_lib_lck_resourceopenasync->resourceHandle,
+					res_lib_lck_resourceopenasync->header.error);
+				saHandleInstancePut (&lckResourceHandleDatabase,
+					res_lib_lck_resourceopenasync->resourceHandle);
+			} else {
+				/*
+				 * open failed with error
+				 */
+				callbacks.saLckResourceOpenCallback(
+					res_lib_lck_resourceopenasync->invocation,
+					-1,
+					res_lib_lck_resourceopenasync->header.error);
+			}
+			break;
+		case MESSAGE_RES_LCK_RESOURCELOCKASYNC:
+printf ("grant\n");
+			if (callbacks.saLckLockGrantCallback == NULL) {
+				continue;
+			}
+			res_lib_lck_resourcelockasync = (struct res_lib_lck_resourcelockasync *)&dispatch_data;
+			/*
+			 * This instance get/listadd/put required so that close
+			 * later has the proper list of resources
+			 */
+			if (res_lib_lck_resourcelockasync->header.error == SA_AIS_OK) {
+				error = saHandleInstanceGet (&lckLockIdHandleDatabase,
+					res_lib_lck_resourcelockasync->lockId,
+					(void *)&lckLockIdInstance);
+
+					assert (error == SA_AIS_OK); /* should only be valid handles here */
+				/*
+				 * open succeeded without error
+				 */
+				lckLockIdInstance->resource_lock = res_lib_lck_resourcelockasync->resource_lock;
+
+				callbacks.saLckLockGrantCallback(
+					res_lib_lck_resourcelockasync->invocation,
+					res_lib_lck_resourcelockasync->lockStatus,
+					res_lib_lck_resourcelockasync->header.error);
+				saHandleInstancePut (&lckLockIdHandleDatabase,
+					res_lib_lck_resourcelockasync->lockId);
+			} else {
+				/*
+				 * open failed with error
+				 */
+				callbacks.saLckLockGrantCallback (
+					res_lib_lck_resourceopenasync->invocation,
+					-1,
+					res_lib_lck_resourceopenasync->header.error);
+			}
+			break;
+
+
+		case MESSAGE_RES_LCK_RESOURCEUNLOCKASYNC:
+			if (callbacks.saLckResourceUnlockCallback == NULL) {
+				continue;
+			}
+			res_lib_lck_resourceunlockasync = (struct res_lib_lck_resourceunlockasync *)&dispatch_data;
+			callbacks.saLckResourceUnlockCallback (
+				res_lib_lck_resourceunlockasync->invocation,
+				res_lib_lck_resourceunlockasync->header.error);
+			break;
+#ifdef NOT_DONE_YET
+
+		case MESSAGE_RES_LCK_RESOURCESYNCHRONIZEASYNC:
+			if (callbacks.saLckResourceSynchronizeCallback == NULL) {
+				continue;
+			}
+
+			res_lib_lck_resourcesynchronizeasync = (struct res_lib_lck_resourcesynchronizeasync *) &dispatch_data;
+
+			callbacks.saLckResourceSynchronizeCallback(
+				res_lib_lck_resourcesynchronizeasync->invocation,
+				res_lib_lck_resourcesynchronizeasync->header.error);
+			break;
+#endif
+
+		default:
+			/* TODO */
+			break;
+		}
+		/*
+		 * Determine if more messages should be processed
+		 */
+		switch (dispatchFlags) {
+		case SA_DISPATCH_ONE:
+				cont = 0;
+			break;
+		case SA_DISPATCH_ALL:
+			break;
+		case SA_DISPATCH_BLOCKING:
+			break;
+		}
+	} while (cont);
+error_unlock:
+	pthread_mutex_unlock(&lckInstance->dispatch_mutex);
+error_put:
+	saHandleInstancePut(&lckHandleDatabase, lckHandle);
+error_exit:
+	return (error);
+}
+
+SaAisErrorT
+saLckFinalize (
+	const SaLckHandleT lckHandle)
+{
+	struct lckInstance *lckInstance;
+	SaAisErrorT error;
+
+	error = saHandleInstanceGet (&lckHandleDatabase, lckHandle,
+		(void *)&lckInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	pthread_mutex_lock (&lckInstance->response_mutex);
+
+	/*
+	 * Another thread has already started finalizing
+	 */
+	if (lckInstance->finalize) {
+		pthread_mutex_unlock (&lckInstance->response_mutex);
+		saHandleInstancePut (&lckHandleDatabase, lckHandle);
+		return (SA_AIS_ERR_BAD_HANDLE);
+	}
+
+	lckInstance->finalize = 1;
+
+	pthread_mutex_unlock (&lckInstance->response_mutex);
+
+// TODO	lckInstanceFinalize (lckInstance);
+
+	if (lckInstance->response_fd != -1) {
+		shutdown (lckInstance->response_fd, 0);
+		close (lckInstance->response_fd);
+	}
+
+	if (lckInstance->dispatch_fd != -1) {
+		shutdown (lckInstance->dispatch_fd, 0);
+		close (lckInstance->dispatch_fd);
+	}
+
+	saHandleInstancePut (&lckHandleDatabase, lckHandle);
+
+	return (SA_AIS_OK);
+}
+
+SaAisErrorT
+saLckResourceOpen (
+	SaLckHandleT lckHandle,
+	const SaNameT *lockResourceName,
+	SaLckResourceOpenFlagsT resourceOpenFlags,
+	SaTimeT timeout,
+	SaLckResourceHandleT *lckResourceHandle)
+{
+	SaAisErrorT error;
+	struct lckResourceInstance *lckResourceInstance;
+	struct lckInstance *lckInstance;
+	struct req_lib_lck_resourceopen req_lib_lck_resourceopen;
+	struct res_lib_lck_resourceopen res_lib_lck_resourceopen;
+
+	if (lckResourceHandle == NULL) {
+		return (SA_AIS_ERR_INVALID_PARAM);
+	}
+
+	if (lockResourceName == NULL) {
+		return (SA_AIS_ERR_INVALID_PARAM);
+	}
+
+	error = saHandleInstanceGet (&lckHandleDatabase, lckHandle,
+		(void *)&lckInstance);
+	if (error != SA_AIS_OK) {
+		goto error_exit;
+	}
+
+	error = saHandleCreate (&lckResourceHandleDatabase,
+		sizeof (struct lckResourceInstance), lckResourceHandle);
+	if (error != SA_AIS_OK) {
+		goto error_put_lck;
+	}
+
+	error = saHandleInstanceGet (&lckResourceHandleDatabase,
+		*lckResourceHandle, (void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		goto error_destroy;
+	}
+
+	lckResourceInstance->response_fd = lckInstance->response_fd;
+
+	lckResourceInstance->lckHandle = lckHandle;
+	lckResourceInstance->lckResourceHandle = *lckResourceHandle;
+	lckResourceInstance->response_mutex = &lckInstance->response_mutex;
+
+	req_lib_lck_resourceopen.header.size = sizeof (struct req_lib_lck_resourceopen);
+	req_lib_lck_resourceopen.header.id = MESSAGE_REQ_LCK_RESOURCEOPEN;
+
+	memcpy (&req_lib_lck_resourceopen.lockResourceName, lockResourceName, sizeof (SaNameT));
+
+	memcpy (&lckResourceInstance->lockResourceName, lockResourceName, sizeof (SaNameT));
+	req_lib_lck_resourceopen.resourceOpenFlags = resourceOpenFlags;
+	req_lib_lck_resourceopen.resourceHandle = *lckResourceHandle;
+	req_lib_lck_resourceopen.async_call = 0;
+
+	pthread_mutex_lock (&lckInstance->response_mutex);
+
+	error = saSendReceiveReply (lckResourceInstance->response_fd, 
+		&req_lib_lck_resourceopen,
+		sizeof (struct req_lib_lck_resourceopen),
+		&res_lib_lck_resourceopen,
+		sizeof (struct res_lib_lck_resourceopen));
+	
+	pthread_mutex_unlock (&lckInstance->response_mutex);
+
+	if (res_lib_lck_resourceopen.header.error != SA_AIS_OK) {
+		error = res_lib_lck_resourceopen.header.error;
+		goto error_put_destroy;
+	}
+
+	memcpy (&lckResourceInstance->source,
+		&res_lib_lck_resourceopen.source,
+		sizeof (struct message_source));
+
+	saHandleInstancePut (&lckResourceHandleDatabase, *lckResourceHandle);
+
+	saHandleInstancePut (&lckHandleDatabase, lckHandle);
+
+	list_init (&lckResourceInstance->list);
+
+	list_add (&lckResourceInstance->list, &lckInstance->resource_list);
+	return (error);
+
+error_put_destroy:
+	saHandleInstancePut (&lckResourceHandleDatabase, *lckResourceHandle);
+error_destroy:
+	saHandleDestroy (&lckResourceHandleDatabase, *lckResourceHandle);
+error_put_lck:
+	saHandleInstancePut (&lckHandleDatabase, lckHandle);
+error_exit:
+	return (error);
+}
+
+SaAisErrorT
+saLckResourceOpenAsync (
+	SaLckHandleT lckHandle,
+	SaInvocationT invocation,
+	const SaNameT *lockResourceName,
+	SaLckResourceOpenFlagsT resourceOpenFlags)
+{
+	struct lckResourceInstance *lckResourceInstance;
+	struct lckInstance *lckInstance;
+	SaLckResourceHandleT lckResourceHandle;
+	SaAisErrorT error;
+	struct req_lib_lck_resourceopen req_lib_lck_resourceopen;
+	struct res_lib_lck_resourceopen res_lib_lck_resourceopen;
+
+	error = saHandleInstanceGet (&lckHandleDatabase, lckHandle,
+		(void *)&lckInstance);
+	if (error != SA_AIS_OK) {
+		goto error_exit;
+	}
+
+	if (lckInstance->callbacks.saLckResourceOpenCallback == NULL) {
+		error = SA_AIS_ERR_INIT;
+		goto error_put_lck;
+	}
+
+	error = saHandleCreate (&lckResourceHandleDatabase,
+		sizeof (struct lckResourceInstance), &lckResourceHandle);
+	if (error != SA_AIS_OK) {
+		goto error_put_lck;
+	}
+
+	error = saHandleInstanceGet (&lckResourceHandleDatabase, lckResourceHandle,
+		(void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		goto error_destroy;
+	}
+
+	lckResourceInstance->response_fd = lckInstance->response_fd;
+	lckResourceInstance->response_mutex = &lckInstance->response_mutex;
+	lckResourceInstance->lckHandle = lckHandle;
+	lckResourceInstance->lckResourceHandle = lckResourceHandle;
+	lckResourceInstance->resourceOpenFlags = resourceOpenFlags;
+
+	req_lib_lck_resourceopen.header.size = sizeof (struct req_lib_lck_resourceopen);
+	req_lib_lck_resourceopen.header.id = MESSAGE_REQ_LCK_RESOURCEOPENASYNC;
+	req_lib_lck_resourceopen.invocation = invocation;
+	req_lib_lck_resourceopen.resourceOpenFlags = resourceOpenFlags;
+	req_lib_lck_resourceopen.resourceHandle = lckResourceHandle;
+	req_lib_lck_resourceopen.async_call = 1;
+
+	pthread_mutex_lock (&lckInstance->response_mutex);
+
+	error = saSendReceiveReply (lckResourceInstance->response_fd, 
+		&req_lib_lck_resourceopen,
+		sizeof (struct req_lib_lck_resourceopen),
+		&res_lib_lck_resourceopen,
+		sizeof (struct res_lib_lck_resourceopen));
+
+	pthread_mutex_unlock (&lckInstance->response_mutex);
+
+	if (error == SA_AIS_OK) {
+		saHandleInstancePut (&lckResourceHandleDatabase,
+			lckResourceHandle);
+		saHandleInstancePut (&lckHandleDatabase, lckHandle);
+		return (res_lib_lck_resourceopen.header.error);
+	}
+
+	saHandleInstancePut (&lckResourceHandleDatabase, lckResourceHandle);
+error_destroy:
+	saHandleDestroy (&lckResourceHandleDatabase, lckResourceHandle);
+error_put_lck:
+	saHandleInstancePut (&lckHandleDatabase, lckHandle);
+error_exit:
+	return (error);
+}
+
+SaAisErrorT
+saLckResourceClose (
+	SaLckResourceHandleT lckResourceHandle)
+{
+	struct req_lib_lck_resourceclose req_lib_lck_resourceclose;
+	struct res_lib_lck_resourceclose res_lib_lck_resourceclose;
+	SaAisErrorT error;
+	struct lckResourceInstance *lckResourceInstance;
+
+	error = saHandleInstanceGet (&lckResourceHandleDatabase, lckResourceHandle,
+		(void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	req_lib_lck_resourceclose.header.size = sizeof (struct req_lib_lck_resourceclose);
+	req_lib_lck_resourceclose.header.id = MESSAGE_REQ_LCK_RESOURCECLOSE;
+	memcpy (&req_lib_lck_resourceclose.lockResourceName,
+		&lckResourceInstance->lockResourceName, sizeof (SaNameT));
+	req_lib_lck_resourceclose.resourceHandle = lckResourceHandle;
+
+	pthread_mutex_lock (lckResourceInstance->response_mutex);
+
+	error = saSendReceiveReply (lckResourceInstance->response_fd, 
+		&req_lib_lck_resourceclose,
+		sizeof (struct req_lib_lck_resourceclose),
+		&res_lib_lck_resourceclose,
+		sizeof (struct res_lib_lck_resourceclose));
+
+	pthread_mutex_unlock (lckResourceInstance->response_mutex);
+
+	saHandleInstancePut (&lckResourceHandleDatabase, lckResourceHandle);
+
+	saHandleDestroy (&lckResourceHandleDatabase, lckResourceHandle);
+
+	return (error == SA_AIS_OK ? res_lib_lck_resourceclose.header.error : error);
+}
+
+SaAisErrorT
+saLckResourceLock (
+	SaLckResourceHandleT lckResourceHandle,
+	SaLckLockIdT *lockId,
+	SaLckLockModeT lockMode,
+	SaLckLockFlagsT lockFlags,
+	SaLckWaiterSignalT waiterSignal,	
+	SaTimeT timeout,
+	SaLckLockStatusT *lockStatus)
+{
+	struct req_lib_lck_resourcelock req_lib_lck_resourcelock;
+	struct res_lib_lck_resourcelock res_lib_lck_resourcelock;
+	SaAisErrorT error;
+	struct lckResourceInstance *lckResourceInstance;
+	struct lckLockIdInstance *lckLockIdInstance;
+	int lock_fd;
+	int dummy_fd;
+
+	error = saHandleInstanceGet (&lckResourceHandleDatabase, lckResourceHandle,
+		(void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	error = saHandleCreate (&lckLockIdHandleDatabase,
+		sizeof (struct lckLockIdInstance), lockId);
+	if (error != SA_AIS_OK) {
+		goto error_put_lck;
+	}
+
+	error = saHandleInstanceGet (&lckLockIdHandleDatabase, *lockId,
+		(void *)&lckLockIdInstance);
+	if (error != SA_AIS_OK) {
+		goto error_destroy;
+	}
+
+	error = saServiceConnectTwo (&lock_fd, &dummy_fd, LCK_SERVICE);
+	if (error != SA_AIS_OK) { // TODO error handling
+		goto error_destroy;
+	}
+
+	lckLockIdInstance->response_mutex = lckResourceInstance->response_mutex;
+	lckLockIdInstance->response_fd = lckResourceInstance->response_fd;
+	lckLockIdInstance->lckResourceHandle = lckResourceHandle;
+
+	req_lib_lck_resourcelock.header.size = sizeof (struct req_lib_lck_resourcelock);
+	req_lib_lck_resourcelock.header.id = MESSAGE_REQ_LCK_RESOURCELOCK;
+	memcpy (&req_lib_lck_resourcelock.lockResourceName,
+		&lckResourceInstance->lockResourceName, sizeof (SaNameT));
+	req_lib_lck_resourcelock.lockMode = lockMode;
+	req_lib_lck_resourcelock.lockFlags = lockFlags;
+	req_lib_lck_resourcelock.waiterSignal = waiterSignal;
+	req_lib_lck_resourcelock.lockId = *lockId;
+	req_lib_lck_resourcelock.async_call = 0;
+	req_lib_lck_resourcelock.invocation = 0;
+	req_lib_lck_resourcelock.resourceHandle = lckResourceHandle;
+
+	memcpy (&req_lib_lck_resourcelock.source,
+		&lckResourceInstance->source,
+		sizeof (struct message_source));
+
+	/*
+	 * no mutex needed here since its a new connection
+	 */
+	error = saSendReceiveReply (lock_fd, 
+		&req_lib_lck_resourcelock,
+		sizeof (struct req_lib_lck_resourcelock),
+		&res_lib_lck_resourcelock,
+		sizeof (struct res_lib_lck_resourcelock));
+
+	close (lock_fd);
+	close (dummy_fd);
+
+	if (error == SA_AIS_OK) {
+		lckLockIdInstance->resource_lock = res_lib_lck_resourcelock.resource_lock;
+		*lockStatus = res_lib_lck_resourcelock.lockStatus;
+
+		return (res_lib_lck_resourcelock.header.error);
+	}
+
+	/*
+	 * Error
+	 */
+	saHandleInstancePut (&lckLockIdHandleDatabase, *lockId);
+
+error_destroy:
+	saHandleDestroy (&lckLockIdHandleDatabase, *lockId);
+
+error_put_lck:
+	saHandleInstancePut (&lckResourceHandleDatabase, lckResourceHandle);
+	return (error);
+
+}
+
+SaAisErrorT
+SaLckResourceLockAsync (
+	SaLckResourceHandleT lckResourceHandle,
+	SaInvocationT invocation,
+	SaLckLockIdT *lockId,
+	SaLckLockModeT lockMode,
+	SaLckLockFlagsT lockFlags,
+	SaLckWaiterSignalT waiterSignal)
+{
+	struct req_lib_lck_resourcelock req_lib_lck_resourcelock;
+	struct res_lib_lck_resourcelockasync res_lib_lck_resourcelockasync;
+	SaAisErrorT error;
+	struct lckResourceInstance *lckResourceInstance;
+	struct lckLockIdInstance *lckLockIdInstance;
+	int lock_fd;
+	int dummy_fd;
+
+	error = saHandleInstanceGet (&lckResourceHandleDatabase, lckResourceHandle,
+		(void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	error = saHandleCreate (&lckLockIdHandleDatabase,
+		sizeof (struct lckLockIdInstance), lockId);
+	if (error != SA_AIS_OK) {
+		goto error_put_lck;
+	}
+
+	error = saHandleInstanceGet (&lckLockIdHandleDatabase, *lockId,
+		(void *)&lckLockIdInstance);
+	if (error != SA_AIS_OK) {
+		goto error_destroy;
+	}
+
+	error = saServiceConnectTwo (&lock_fd, &dummy_fd, LCK_SERVICE);
+	if (error != SA_AIS_OK) { // TODO error handling
+		goto error_destroy;
+	}
+
+	lckLockIdInstance->response_mutex = lckResourceInstance->response_mutex;
+	lckLockIdInstance->response_fd = lckResourceInstance->response_fd;
+	lckLockIdInstance->lckResourceHandle = lckResourceHandle;
+
+	req_lib_lck_resourcelock.header.size = sizeof (struct req_lib_lck_resourcelock);
+	req_lib_lck_resourcelock.header.id = MESSAGE_REQ_LCK_RESOURCELOCKASYNC;
+	memcpy (&req_lib_lck_resourcelock.lockResourceName,
+		&lckResourceInstance->lockResourceName, sizeof (SaNameT));
+	req_lib_lck_resourcelock.lockMode = lockMode;
+	req_lib_lck_resourcelock.lockFlags = lockFlags;
+	req_lib_lck_resourcelock.waiterSignal = waiterSignal;
+	req_lib_lck_resourcelock.lockId = *lockId;
+	req_lib_lck_resourcelock.async_call = 1;
+	req_lib_lck_resourcelock.invocation = invocation;
+	req_lib_lck_resourcelock.resourceHandle = lckResourceHandle;
+
+	memcpy (&req_lib_lck_resourcelock.source,
+		&lckResourceInstance->source,
+		sizeof (struct message_source));
+
+	/*
+	 * no mutex needed here since its a new connection
+	 */
+	error = saSendReceiveReply (lock_fd, 
+		&req_lib_lck_resourcelock,
+		sizeof (struct req_lib_lck_resourcelock),
+		&res_lib_lck_resourcelockasync,
+		sizeof (struct res_lib_lck_resourcelock));
+
+	close (lock_fd);
+	close (dummy_fd);
+
+	if (error == SA_AIS_OK) {
+		return (res_lib_lck_resourcelockasync.header.error);
+	}
+
+	/*
+	 * Error
+	 */
+	saHandleInstancePut (&lckLockIdHandleDatabase, *lockId);
+
+error_destroy:
+	saHandleDestroy (&lckLockIdHandleDatabase, *lockId);
+
+error_put_lck:
+	saHandleInstancePut (&lckResourceHandleDatabase, lckResourceHandle);
+	return (error);
+}
+
+SaAisErrorT
+saLckResourceUnlock (
+	SaLckLockIdT lockId,
+	SaTimeT timeout)
+{
+	struct req_lib_lck_resourceunlock req_lib_lck_resourceunlock;
+	struct res_lib_lck_resourceunlock res_lib_lck_resourceunlock;
+	SaAisErrorT error;
+	struct lckLockIdInstance *lckLockIdInstance;
+	struct lckResourceInstance *lckResourceInstance;
+
+	error = saHandleInstanceGet (&lckLockIdHandleDatabase, lockId,
+		(void *)&lckLockIdInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	/*
+	 * Retrieve resource name
+	 */
+	error = saHandleInstanceGet (&lckResourceHandleDatabase,
+		lckLockIdInstance->lckResourceHandle, (void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		saHandleInstancePut (&lckLockIdHandleDatabase, lockId);
+		return (error);
+	}
+
+	memcpy (&req_lib_lck_resourceunlock.lockResourceName,
+		&lckResourceInstance->lockResourceName, sizeof (SaNameT));
+
+	saHandleInstancePut (&lckResourceHandleDatabase,
+		lckLockIdInstance->lckResourceHandle);
+
+	req_lib_lck_resourceunlock.header.size = sizeof (struct req_lib_lck_resourceunlock);
+	req_lib_lck_resourceunlock.header.id = MESSAGE_REQ_LCK_RESOURCEUNLOCK;
+	req_lib_lck_resourceunlock.lockId = lockId;
+	req_lib_lck_resourceunlock.timeout = timeout;
+	req_lib_lck_resourceunlock.invocation = -1;
+	req_lib_lck_resourceunlock.async_call = 0;
+	req_lib_lck_resourceunlock.resource_lock = lckLockIdInstance->resource_lock;
+
+	pthread_mutex_lock (lckLockIdInstance->response_mutex);
+
+	error = saSendReceiveReply (lckLockIdInstance->response_fd, 
+		&req_lib_lck_resourceunlock,
+		sizeof (struct req_lib_lck_resourceunlock),
+		&res_lib_lck_resourceunlock,
+		sizeof (struct res_lib_lck_resourceunlock));
+
+	pthread_mutex_unlock (lckLockIdInstance->response_mutex);
+
+	saHandleInstancePut (&lckLockIdHandleDatabase, lockId);
+
+	saHandleDestroy (&lckLockIdHandleDatabase, lockId);
+
+	return (error == SA_AIS_OK ? res_lib_lck_resourceunlock.header.error : error);
+}
+
+SaAisErrorT
+saLckResourceUnlockAsync (
+	SaInvocationT invocation,	
+	SaLckLockIdT lockId)
+{
+	struct req_lib_lck_resourceunlock req_lib_lck_resourceunlock;
+	struct res_lib_lck_resourceunlockasync res_lib_lck_resourceunlockasync;
+	SaAisErrorT error;
+	struct lckLockIdInstance *lckLockIdInstance;
+	struct lckResourceInstance *lckResourceInstance;
+
+	error = saHandleInstanceGet (&lckLockIdHandleDatabase, lockId,
+		(void *)&lckLockIdInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	/*
+	 * Retrieve resource name
+	 */
+	error = saHandleInstanceGet (&lckResourceHandleDatabase,
+		lckLockIdInstance->lckResourceHandle, (void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		saHandleInstancePut (&lckLockIdHandleDatabase, lockId);
+		return (error);
+	}
+
+	memcpy (&req_lib_lck_resourceunlock.lockResourceName,
+		&lckResourceInstance->lockResourceName, sizeof (SaNameT));
+
+	saHandleInstancePut (&lckResourceHandleDatabase,
+		lckLockIdInstance->lckResourceHandle);
+
+
+	/*
+	 * Build and send request
+	 */
+	req_lib_lck_resourceunlock.header.size = sizeof (struct req_lib_lck_resourceunlock);
+	req_lib_lck_resourceunlock.header.id = MESSAGE_REQ_LCK_RESOURCEUNLOCKASYNC;
+	req_lib_lck_resourceunlock.invocation = invocation;
+	req_lib_lck_resourceunlock.lockId = lockId;
+	req_lib_lck_resourceunlock.async_call = 1;
+
+	pthread_mutex_lock (lckLockIdInstance->response_mutex);
+
+	error = saSendReceiveReply (lckLockIdInstance->response_fd, 
+		&req_lib_lck_resourceunlock,
+		sizeof (struct req_lib_lck_resourceunlock),
+		&res_lib_lck_resourceunlockasync,
+		sizeof (struct res_lib_lck_resourceunlockasync));
+
+	pthread_mutex_unlock (lckLockIdInstance->response_mutex);
+
+	saHandleInstancePut (&lckLockIdHandleDatabase, lockId);
+
+	return (error == SA_AIS_OK ? res_lib_lck_resourceunlockasync.header.error : error);
+}
+
+SaAisErrorT
+saLckLockPurge (
+	SaLckResourceHandleT lckResourceHandle)
+{
+	struct req_lib_lck_lockpurge req_lib_lck_lockpurge;
+	struct res_lib_lck_lockpurge res_lib_lck_lockpurge;
+	SaAisErrorT error;
+	struct lckResourceInstance *lckResourceInstance;
+
+	error = saHandleInstanceGet (&lckResourceHandleDatabase, lckResourceHandle,
+		(void *)&lckResourceInstance);
+	if (error != SA_AIS_OK) {
+		return (error);
+	}
+
+	req_lib_lck_lockpurge.header.size = sizeof (struct req_lib_lck_lockpurge);
+	req_lib_lck_lockpurge.header.id = MESSAGE_REQ_LCK_LOCKPURGE;
+	memcpy (&req_lib_lck_lockpurge.lockResourceName,
+		&lckResourceInstance->lockResourceName, sizeof (SaNameT));
+
+	pthread_mutex_lock (lckResourceInstance->response_mutex);
+
+	error = saSendReceiveReply (lckResourceInstance->response_fd, 
+		&req_lib_lck_lockpurge,
+		sizeof (struct req_lib_lck_lockpurge),
+		&res_lib_lck_lockpurge,
+		sizeof (struct res_lib_lck_lockpurge));
+
+	pthread_mutex_unlock (lckResourceInstance->response_mutex);
+
+	saHandleInstancePut (&lckResourceHandleDatabase, lckResourceHandle);
+
+	return (error == SA_AIS_OK ? res_lib_lck_lockpurge.header.error : error);
+}

+ 24 - 0
lib/libSaLck.versions

@@ -0,0 +1,24 @@
+# Version and symbol export for libSaLck.so
+
+OPENAIS_LCK_B.01.01 {
+	global:
+		saLckInitialize;
+		saLckSelectionObjectGet;
+		saLckDispatch;
+		saLckinalize;
+	local:
+		saHandleCreate;
+		saHandleDestroy;
+		saHandleInstanceGet;
+		saHandleInstancePut;
+		saPollRetry;
+		saRecvRetry;
+		saSendMsgReceiveReply;
+		saSendMsgRetry;
+		saSendReceiveReply;
+		saSendRetry;
+		saServiceConnect;
+		saServiceConnectTwo;
+		saVersionVerify;
+		clustTimeNow;
+};

+ 6 - 3
test/Makefile

@@ -28,7 +28,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
-LIBRARIES= ../lib/libSaClm.a ../lib/libSaAmf.a ../lib/libSaCkpt.a ../lib/libSaEvt.a ../lib/libevs.a
+LIBRARIES= ../lib/libSaClm.a ../lib/libSaAmf.a ../lib/libSaCkpt.a ../lib/libSaEvt.a ../lib/libSaLck.a ../lib/libevs.a
 LIBS = $(LIBRARIES) -lpthread
 
 # Production mode flags
@@ -53,12 +53,12 @@ TEST_SRC =  testclm.c testamf.c testamf1.c testamf2.c testamf3.c \
 		testckpt.c ckptstress.c ckptbench.c  \
 		ckptbenchth.c testevt.c testevs.c evsbench.c \
 		subscription.c publish.c evtbench.c \
-		sa_error.c unlink.c testclm2.c
+		sa_error.c unlink.c testclm2.c testlck.c
 
 all: testclm testamf testamf1 testamf2 testamf3 testamf4 testamf5 \
 	testamf6 testamfth testckpt ckptstress ckptbench \
 	ckptbenchth ckpt-rd ckpt-wr testevt testevs \
-	evsbench subscription publish evtbench unlink testclm2
+	evsbench subscription publish evtbench unlink testclm2 testlck
 
 testtimer: testtimer.o $(LIBRARIES)
 	$(CC) $(LDFLAGS) -o testtimer testtimer.o ../exec/timer.o
@@ -138,6 +138,9 @@ ckpt-wr: ckpt-wr.o sa_error.o $(LIBRARIES)
 testclm2: testclm2.o $(LIBRARIES)
 	$(CC) $(LDFLAGS) -o testclm2 testclm2.o $(LIBS)
 
+testlck: testlck.o $(LIBRARIES)
+	$(CC) $(LDFLAGS) -o testlck testlck.o $(LIBS)
+
 clean:
 	rm -f *.o testclm testamf testamf1 testamf2 testamf3 testamf4 \
 	testamf5 testamf6 testamfth testckpt ckptstress testtimer \

+ 235 - 0
test/testlck.c

@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2005 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "saAis.h"
+#include "saLck.h"
+
+SaNameT resource_name_async;
+SaLckResourceHandleT resource_handle_async;
+
+void testLckResourceOpenCallback (
+	SaInvocationT invocation,
+	SaLckResourceHandleT lockResourceHandle,
+	SaAisErrorT error)
+{
+	printf ("testLckResourceOpenCallback invocation %lld error %d\n",
+		invocation, error);
+	resource_handle_async = lockResourceHandle;
+}
+
+void testLckLockGrantCallback (
+	SaInvocationT invocation,
+	SaLckLockStatusT lockStatus,
+	SaAisErrorT error)
+{
+	printf ("testLckLockGrantCallback invocation %lld status %d error %d\n",
+		invocation, lockStatus, error);
+}
+
+SaLckLockIdT pr_lock_id;
+
+void testLckLockWaiterCallback (
+        SaLckWaiterSignalT waiterSignal,
+        SaLckLockIdT lockId,
+        SaLckLockModeT modeHeld,
+        SaLckLockModeT modeRequested)
+{
+	int result;
+	printf ("waiter callback mode held %d mode requested %d lock id %lld\n",
+		modeHeld,
+		modeRequested,
+		lockId);
+	printf ("pr lock id %lld\n", pr_lock_id);
+	result = saLckResourceUnlockAsync (
+		25,
+		lockId);
+	printf ("saLckResourceUnlockAsync result %d (should be 1)\n", result);
+}
+
+void testLckResourceUnlockCallback (
+        SaInvocationT invocation,
+        SaAisErrorT error)
+{
+	printf ("testLckResourceUnlockCallback async invocation %lld error %d\n", invocation, error);
+}
+
+SaLckCallbacksT callbacks = {
+	.saLckResourceOpenCallback	= testLckResourceOpenCallback,
+	.saLckLockGrantCallback		= testLckLockGrantCallback,
+	.saLckLockWaiterCallback	= testLckLockWaiterCallback,
+	.saLckResourceUnlockCallback	= testLckResourceUnlockCallback
+};
+
+SaVersionT version = { 'B', 1, 1 };
+
+void setSaNameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+void sigintr_handler (int signum) {
+	exit (0);
+}
+
+struct th_data {
+	SaLckHandleT handle;
+};
+
+void *th_dispatch (void *arg)
+{
+	struct th_data *th_data = (struct th_data *)arg;
+
+	saLckDispatch (th_data->handle, SA_DISPATCH_BLOCKING);
+	return (0);
+}
+
+int main (void) {
+	SaLckHandleT handle;
+	SaLckResourceHandleT resource_handle;
+	int result;
+	SaLckLockIdT ex_lock_id;
+	SaLckLockStatusT status;
+	SaNameT resource_name;
+	pthread_t dispatch_thread;
+	fd_set read_fds;
+	struct th_data th_data;
+
+	signal (SIGINT, sigintr_handler);
+
+	result = saLckInitialize (&handle, &callbacks, &version);
+	if (result != SA_OK) {
+		printf ("Could not initialize Lock Service API instance error %d\n", result);
+		exit (1);
+	}
+	printf ("saLckInitialize result is %d (should be 1)\n", result);
+
+	th_data.handle = handle;
+	pthread_create (&dispatch_thread, NULL, th_dispatch, &th_data);
+
+	setSaNameT (&resource_name, "test_resource");
+	setSaNameT (&resource_name_async, "test_resource_async");
+
+	result = saLckResourceOpen (
+		handle,
+		&resource_name,
+		SA_LCK_RESOURCE_CREATE,
+//		0,
+		SA_TIME_ONE_SECOND,
+		&resource_handle);
+	printf ("saLckResourceOpen %d (should be 12)\n", result);
+printf ("HANDLE %llx\n", resource_handle);
+
+	result = saLckResourceClose (resource_handle);
+	printf ("saLckResourceClose %d (should be 9)\n", result);
+
+	result = saLckResourceOpen (
+		handle,
+		&resource_name,
+		SA_LCK_RESOURCE_CREATE,
+		SA_TIME_ONE_SECOND,
+		&resource_handle);
+	printf ("saLckResourceOpen %d (should be 1)\n", result);
+
+	result = saLckResourceOpenAsync (
+		handle,
+		0x56,
+		&resource_name_async,
+		SA_LCK_RESOURCE_CREATE);
+	printf ("saLckResourceOpenAsync %d (should be 1)\n", result);
+		
+	result = saLckResourceLock (
+		resource_handle,
+		&pr_lock_id,
+		SA_LCK_PR_LOCK_MODE,
+		SA_LCK_LOCK_ORPHAN,
+		55,
+		SA_TIME_END,
+		&status);
+	printf ("saLckResourceLock PR %d (should be 1)\n", result);
+	printf ("status %d\n", status);
+
+	result = saLckResourceLock (
+		resource_handle,
+		&ex_lock_id,
+		SA_LCK_EX_LOCK_MODE,
+		0,
+		55,
+		SA_TIME_END,
+		&status);
+	printf ("saLckResourceLock EX %d (should be 1)\n", result);
+	printf ("status %d\n", status);
+		
+	result = SaLckResourceLockAsync (
+		resource_handle,
+		0x56,
+		&pr_lock_id,
+		SA_LCK_PR_LOCK_MODE,
+		0,
+		55);
+	printf ("SaLckResourceLockAsync PR %d (should be 1)\n", result);
+	printf ("status %d\n", status);
+	printf ("press the enter key to exit\n");
+	FD_ZERO (&read_fds);
+	do {
+		FD_SET (STDIN_FILENO, &read_fds);
+		result = select (STDIN_FILENO + 1, &read_fds, 0, 0, 0);
+		if (FD_ISSET (STDIN_FILENO, &read_fds)) {
+			break;
+		}
+	} while (result);
+
+	result = saLckResourceUnlock (
+		ex_lock_id,
+		SA_TIME_END);
+	printf ("saLckResourceUnlock result %d (should be 1)\n",
+		result);
+	
+	result = saLckResourceClose (resource_handle);
+	printf ("saLckResourceClose result %d (should be 1)\n", result);
+
+	result = saLckFinalize (handle);
+	printf ("saLckFinalize %d (should be 1)\n", result);
+	return (0);
+}