[asterisk-commits] russell: branch russell/events r84324 - /team/russell/events/res/ais/lck.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Oct 1 17:22:57 CDT 2007


Author: russell
Date: Mon Oct  1 17:22:56 2007
New Revision: 84324

URL: http://svn.digium.com/view/asterisk?view=rev&rev=84324
Log:
Add some more of the code for acquiring locks

Modified:
    team/russell/events/res/ais/lck.c

Modified: team/russell/events/res/ais/lck.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/res/ais/lck.c?view=diff&rev=84324&r1=84323&r2=84324
==============================================================================
--- team/russell/events/res/ais/lck.c (original)
+++ team/russell/events/res/ais/lck.c Mon Oct  1 17:22:56 2007
@@ -81,7 +81,8 @@
 static struct ao2_container *lock_resources;
 
 struct lock_resource {
-	SaLckResourceHandleT *handle;
+	SaLckResourceHandleT handle;
+	SaLckLockIdT id;
 	SaNameT ais_name;
 	struct ast_str *name;
 };
@@ -94,10 +95,22 @@
 		ast_free(lock->name);
 }
 
+static inline struct lock_resource *lock_ref(struct lock_resource *lock)
+{
+	ao2_ref(lock, +1);
+	return lock;
+}
+
 static inline struct lock_resource *lock_unref(struct lock_resource *lock)
 {
 	ao2_ref(lock, -1);
 	return NULL;
+}
+
+static void lock_unref_cb(void *data)
+{
+	struct lock_resource *lock = data;
+	lock_unref(lock);
 }
 
 static struct lock_resource *find_lock(const char *name)
@@ -106,12 +119,15 @@
 	struct lock_resource *lock, tmp_lock = {
 		.name = lock_name,
 	};
+	SaAisErrorT ais_res;
 
 	ast_str_set(&lock_name, 0, name);
 
+	/* Return the lock if it has already been opened on this node */
 	if ((lock = ao2_find(lock_resources, &tmp_lock, OBJ_POINTER)))
 		return lock;
 
+	/* Allocate and open the lock */
 	if (!(lock = ao2_alloc(sizeof(*lock), lock_destructor)))
 		return NULL;
 
@@ -122,9 +138,93 @@
 	if (!lock->name)
 		return lock_unref(lock);
 
-	// XXX open the dlock
+	/* Map the name into the SaNameT for convenience */
+	ast_copy_string((char *) lock->ais_name.value, lock->name->str,
+		sizeof(lock->ais_name.value));
+	lock->ais_name.length = lock->name->used;
+
+	ais_res = saLckResourceOpen(lck_handle, &lock->ais_name,
+		SA_LCK_RESOURCE_CREATE, SA_TIME_ONE_SECOND * 3, &lock->handle);
+	if (ais_res != SA_AIS_OK) {
+		ast_log(LOG_ERROR, "Failed to open lock: %s\n", ais_err2str(ais_res));
+		return lock_unref(lock);
+	}
 
 	return lock;
+}
+
+const struct ast_datastore_info dlock_datastore_info = {
+	.type = "DLOCK",
+	.destroy = lock_unref_cb,
+};
+
+static void add_lock_to_chan(struct ast_channel *chan, struct lock_resource *lock,
+	enum lock_type lock_type, double timeout, char *buf, size_t len)
+{
+	struct ast_datastore *datastore;
+	SaAisErrorT ais_res;
+	SaLckLockModeT mode;
+	SaLckLockFlagsT flags;
+	SaLckLockStatusT status;
+
+	ast_channel_lock(chan);
+	datastore = ast_channel_datastore_find(chan, &dlock_datastore_info, lock->name->str);
+
+	if (datastore) {
+		ast_log(LOG_ERROR, "The DLOCk '%s' is already locked by channel '%s'\n",
+			lock->name->str, chan->name);
+		ast_channel_unlock(chan);
+		ast_copy_string(buf, "FAILURE", len);
+		return;
+	}
+	ast_channel_unlock(chan);
+
+	switch (lock_type) {
+	case TRY_RDLOCK:
+		flags = SA_LCK_LOCK_NO_QUEUE;
+	case RDLOCK:
+		mode = SA_LCK_PR_LOCK_MODE;
+		break;
+	case TRY_WRLOCK:
+		flags = SA_LCK_LOCK_NO_QUEUE;
+	case WRLOCK:
+		mode = SA_LCK_EX_LOCK_MODE;
+	}
+
+	/* Actually acquire the lock now */
+	ais_res = saLckResourceLock(lock->handle, &lock->id, mode, flags, 0,
+		(SaTimeT) timeout * SA_TIME_ONE_SECOND, &status);
+	if (ais_res != SA_AIS_OK) {
+		ast_log(LOG_ERROR, "Problem acquiring lock '%s': %s\n",
+			lock->name->str, ais_err2str(ais_res));
+		return;
+	}
+
+	switch (status) {
+	case SA_LCK_LOCK_GRANTED:
+		ast_copy_string(buf, "SUCCESS", len);
+		break;
+	/*! XXX \todo Need to look at handling these other cases in a different way */
+	case SA_LCK_LOCK_DEADLOCK:
+	case SA_LCK_LOCK_NOT_QUEUED:
+	case SA_LCK_LOCK_ORPHANED:
+	case SA_LCK_LOCK_NO_MORE:
+	case SA_LCK_LOCK_DUPLICATE_EX:
+		ast_copy_string(buf, "FAILURE", len);
+		return;
+	}
+
+	if (!(datastore = ast_channel_datastore_alloc(&dlock_datastore_info, 
+		lock->name->str))) {
+		ast_copy_string(buf, "FAILURE", len);
+		return;
+	}
+
+	datastore->data = lock_ref(lock);
+
+	ast_channel_lock(chan);
+	ast_channel_datastore_add(chan, datastore);
+	ast_channel_unlock(chan);
 }
 
 static int handle_lock(struct ast_channel *chan, enum lock_type lock_type,
@@ -136,7 +236,7 @@
 	);
 	int res = 0;
 	double timeout = 3;
-	struct lock_resource *lock;
+	struct lock_resource *lock = NULL;
 
 	ast_autoservice_start(chan);
 
@@ -170,7 +270,9 @@
 		goto return_cleanup;
 	}
 
-	// XXX
+	add_lock_to_chan(chan, lock, lock_type, timeout, buf, len);
+
+	lock = lock_unref(lock);
 
 return_cleanup:
 	ast_autoservice_stop(chan);




More information about the asterisk-commits mailing list