[Cbe-oss-dev] [PATCH 08/28]MARS/base: avoid mutex lock contention

Yuji Mano yuji.mano at am.sony.com
Fri Feb 6 13:31:08 EST 2009


From: Kazunori Asayama <asayama at sm.sony.co.jp>

Avoid lock contention in mutex

This patch avoids contention in mutex by using a waiting queue

Signed-off-by: Kazunori Asayama <asayama at sm.sony.co.jp>
---
 base/include/common/mars/mutex_types.h |   10 +++-
 base/src/host/lib/mutex_cell.c         |   35 +++++++++++---
 base/src/mpu/lib/mutex.c               |   78 +++++++++++++++++++++++++++------
 3 files changed, 101 insertions(+), 22 deletions(-)

--- a/base/include/common/mars/mutex_types.h
+++ b/base/include/common/mars/mutex_types.h
@@ -58,8 +58,16 @@
  *
  * An instance of this structure must be created when using the MARS Mutex API.
  */
+
+struct mars_mutex_status {
+	uint8_t lock;
+	uint8_t pad;
+	uint8_t current_id;
+	uint8_t next_id;
+};
+
 struct mars_mutex {
-	uint32_t lock;
+	struct mars_mutex_status status;
 	uint8_t pad[124];
 } __attribute__((aligned(MARS_MUTEX_ALIGN)));
 
--- a/base/src/host/lib/mutex_cell.c
+++ b/base/src/host/lib/mutex_cell.c
@@ -43,6 +43,13 @@
 #include "mars/error.h"
 #include "mars/mutex.h"
 
+static void init_status(struct mars_mutex_status *status)
+{
+	status->lock = MARS_MUTEX_UNLOCKED;
+	status->current_id = 0;
+	status->next_id = 0;
+}
+
 int mars_mutex_create(uint64_t *mutex_ea_ret)
 {
 	struct mars_mutex *mutex;
@@ -58,7 +65,7 @@ int mars_mutex_create(uint64_t *mutex_ea
 
 	mutex = mars_ea_to_ptr(mutex_ea);
 
-	mutex->lock = MARS_MUTEX_UNLOCKED;
+	init_status(&mutex->status);
 	__lwsync();
 
 	*mutex_ea_ret = mutex_ea;
@@ -83,7 +90,7 @@ int mars_mutex_reset(uint64_t mutex_ea)
 	if (!mutex_ea)
 		return MARS_ERROR_NULL;
 
-	mutex->lock = MARS_MUTEX_UNLOCKED;
+	init_status(&mutex->status);
 	__lwsync();
 
 	return MARS_SUCCESS;
@@ -92,6 +99,8 @@ int mars_mutex_reset(uint64_t mutex_ea)
 int mars_mutex_lock(uint64_t mutex_ea)
 {
 	struct mars_mutex *mutex = mars_ea_to_ptr(mutex_ea);
+	struct mars_mutex_status status;
+	uint32_t value;
 
 	if (!mutex_ea) {
 		return MARS_ERROR_NULL;
@@ -99,8 +108,12 @@ int mars_mutex_lock(uint64_t mutex_ea)
 
 	do {
 		do {
-		} while (__lwarx(&mutex->lock) == MARS_MUTEX_LOCKED);
-	} while (!__stwcx(&mutex->lock, MARS_MUTEX_LOCKED));
+			value = __lwarx(&mutex->status);
+			status = *(struct mars_mutex_status *)&value;
+		} while (status.lock == MARS_MUTEX_LOCKED);
+		status.lock = MARS_MUTEX_LOCKED;
+		value = *(uint32_t *)&status;
+	} while (!__stwcx(&mutex->status, value));
 
 	__isync();
 
@@ -110,14 +123,22 @@ int mars_mutex_lock(uint64_t mutex_ea)
 int mars_mutex_unlock(uint64_t mutex_ea)
 {
 	struct mars_mutex *mutex = mars_ea_to_ptr(mutex_ea);
+	struct mars_mutex_status status;
+	uint32_t value;
 
 	if (!mutex_ea)
 		return MARS_ERROR_NULL;
-	if (mutex->lock != MARS_MUTEX_LOCKED)
+	if (mutex->status.lock != MARS_MUTEX_LOCKED)
 		return MARS_ERROR_STATE;
 
 	__lwsync();
-	mutex->lock = MARS_MUTEX_UNLOCKED;
+
+	do {
+		value = __lwarx(&mutex->status);
+		status = *(struct mars_mutex_status *)&value;
+		status.lock = MARS_MUTEX_UNLOCKED;
+		value = *(uint32_t *)&status;
+	} while (!__stwcx(&mutex->status, value));
 
 	return MARS_SUCCESS;
 }
@@ -146,7 +167,7 @@ int mars_mutex_unlock_put(uint64_t mutex
 		mutex->pad, sizeof(mutex->pad));
 	ret = mars_mutex_unlock(mutex_ea);
 	if (ret == MARS_SUCCESS)
-		mutex->lock = MARS_MUTEX_UNLOCKED;
+		mutex->status.lock = MARS_MUTEX_UNLOCKED;
 	return ret;
 #else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */
 	(void)mutex; /* ignored */
--- a/base/src/mpu/lib/mutex.c
+++ b/base/src/mpu/lib/mutex.c
@@ -42,9 +42,12 @@
 #include "mars/error.h"
 #include "mars/mutex.h"
 
+static struct mars_mutex mutex_buffer;
+
 int mars_mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex)
 {
-	int status, mask;
+	int status, mask, done = 0;
+	uint8_t id = 0;
 
 	/* check function params */
 	if (!mutex_ea)
@@ -62,21 +65,48 @@ int mars_mutex_lock_get(uint64_t mutex_e
 	/* set event mask for the lost event */
 	spu_write_event_mask(MFC_LLR_LOST_EVENT);
 
+	/* update waiting state */
 	do {
 		mfc_getllar(mutex, mutex_ea, 0, 0);
 		mfc_read_atomic_status();
 
-		if (mutex->lock == MARS_MUTEX_LOCKED) {
+		if (mutex->status.lock == MARS_MUTEX_UNLOCKED &&
+		    mutex->status.current_id == mutex->status.next_id) {
+			/* no other thread waiting for mutex so get lock now */
+			mutex->status.lock = MARS_MUTEX_LOCKED;
+			done = 1;
+		}
+		else {
+			/* otherwise update waiting state */
+			id = mutex->status.next_id++;
+			done = 0;
+		}
+
+		spu_dsync();
+		mfc_putllc(mutex, mutex_ea, 0, 0);
+		status = mfc_read_atomic_status() & MFC_PUTLLC_STATUS;
+	} while (status);
+
+	while (!done) {
+		mfc_getllar(mutex, mutex_ea, 0, 0);
+		mfc_read_atomic_status();
+
+		if (mutex->status.lock == MARS_MUTEX_LOCKED ||
+		    mutex->status.current_id != id) {
+			/* wait until mutex is released */
 			spu_read_event_status();
 			spu_write_event_ack(MFC_LLR_LOST_EVENT);
-			status = MFC_PUTLLC_STATUS;
-		} else {
-			mutex->lock = MARS_MUTEX_LOCKED;
+		}
+		else {
+			/* get lock */
+			mutex->status.lock = MARS_MUTEX_LOCKED;
+			mutex->status.current_id++;
+
 			spu_dsync();
 			mfc_putllc(mutex, mutex_ea, 0, 0);
-			status = mfc_read_atomic_status() & MFC_PUTLLC_STATUS;
+			done = !(mfc_read_atomic_status() & MFC_PUTLLC_STATUS);
 		}
-	} while (status);
+	}
 
 	/* restore event mask */
 	spu_write_event_mask(mask);
@@ -89,6 +119,8 @@ int mars_mutex_lock_get(uint64_t mutex_e
 
 int mars_mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex)
 {
+	int status, mask;
+
 	/* check function params */
 	if (!mutex_ea)
 		return MARS_ERROR_NULL;
@@ -98,16 +130,34 @@ int mars_mutex_unlock_put(uint64_t mutex
 		return MARS_ERROR_ALIGN;
 	if ((uintptr_t)mutex & MARS_MUTEX_ALIGN_MASK)
 		return MARS_ERROR_ALIGN;
-	if (mutex->lock != MARS_MUTEX_LOCKED)
+	if (mutex->status.lock != MARS_MUTEX_LOCKED)
 		return MARS_ERROR_STATE;
 
-	mutex->lock = MARS_MUTEX_UNLOCKED;
-
 	mfc_sync(0);
-	mfc_put(mutex, mutex_ea, sizeof(struct mars_mutex), 0, 0, 0);
-	mfc_write_tag_mask(1 << 0);
-	mfc_write_tag_update_all();
-	mfc_read_tag_status();
+
+	/* save event mask */
+	mask = spu_read_event_mask();
+
+	/* set event mask for the lost event */
+	spu_write_event_mask(MFC_LLR_LOST_EVENT);
+
+	do {
+		mfc_getllar(&mutex_buffer, mutex_ea, 0, 0);
+		mfc_read_atomic_status();
+
+		mutex->status = mutex_buffer.status;
+		mutex->status.lock = MARS_MUTEX_UNLOCKED;
+
+		spu_dsync();
+		mfc_putllc(mutex, mutex_ea, 0, 0);
+		status = mfc_read_atomic_status() & MFC_PUTLLC_STATUS;
+	} while (status);
+
+	/* restore event mask */
+	spu_write_event_mask(mask);
+
+	/* clear any remnant lost event */
+	spu_write_event_ack(MFC_LLR_LOST_EVENT);
 
 	return MARS_SUCCESS;
 }







More information about the cbe-oss-dev mailing list