aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazunori Asayama <asayama@sm.sony.co.jp>2009-02-05 18:31:08 -0800
committerYuji Mano <yuji.mano@am.sony.com>2009-02-11 11:03:55 -0800
commiteef565c951c86501740861d02fe46b2fbbce10ea (patch)
tree97a98b8452154d5c833e19b875c74b3b51aedd28
parent89b797929373d0cf832a257fe25832f082eb8ee6 (diff)
downloadmars-src-eef565c951c86501740861d02fe46b2fbbce10ea.tar.gz
base: Avoid mutex lock contention
Avoid lock contention in mutex This patch avoids contention in mutex by using a waiting queue Signed-off-by: Kazunori Asayama <asayama@sm.sony.co.jp> Signed-off-by: Yuji Mano <yuji.mano@am.sony.com>
-rw-r--r--base/include/common/mars/mutex_types.h10
-rw-r--r--base/src/host/lib/mutex_cell.c35
-rw-r--r--base/src/mpu/lib/mutex.c78
3 files changed, 101 insertions, 22 deletions
diff --git a/base/include/common/mars/mutex_types.h b/base/include/common/mars/mutex_types.h
index 96ce9e2..70b7201 100644
--- 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)));
diff --git a/base/src/host/lib/mutex_cell.c b/base/src/host/lib/mutex_cell.c
index 989be65..fd0170c 100644
--- 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_ret)
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_ea, struct mars_mutex *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 */
diff --git a/base/src/mpu/lib/mutex.c b/base/src/mpu/lib/mutex.c
index fd02ab3..4ef507f 100644
--- 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_ea, struct mars_mutex *mutex)
/* 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_ea, struct mars_mutex *mutex)
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_ea, struct mars_mutex *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;
}