diff options
author | Kazunori Asayama <asayama@sm.sony.co.jp> | 2009-02-05 18:31:08 -0800 |
---|---|---|
committer | Yuji Mano <yuji.mano@am.sony.com> | 2009-02-11 11:03:55 -0800 |
commit | eef565c951c86501740861d02fe46b2fbbce10ea (patch) | |
tree | 97a98b8452154d5c833e19b875c74b3b51aedd28 | |
parent | 89b797929373d0cf832a257fe25832f082eb8ee6 (diff) | |
download | mars-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.h | 10 | ||||
-rw-r--r-- | base/src/host/lib/mutex_cell.c | 35 | ||||
-rw-r--r-- | base/src/mpu/lib/mutex.c | 78 |
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; } |