[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