Skip to content

Commit

Permalink
Refactor cache line unlock
Browse files Browse the repository at this point in the history
Instead of a single loop for handling all cases expand the code so each section
has a clear intention

Signed-off-by: Michal Mielewczyk <michal.mielewczyk@huawei.com>
  • Loading branch information
mmichal10 committed Oct 16, 2024
1 parent 1e088c7 commit c487b24
Showing 1 changed file with 117 additions and 66 deletions.
183 changes: 117 additions & 66 deletions src/utils/utils_alock.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,25 +313,23 @@ static inline void ocf_alock_unlock_entry_rd(struct ocf_alock *alock,
env_atomic_dec(access);
}

static inline bool ocf_alock_trylock_entry_wr2wr(struct ocf_alock *alock,
static inline void ocf_alock_lock_entry_wr2wr(struct ocf_alock *alock,
ocf_cache_line_t entry)
{
env_atomic *access = &alock->access[entry];
int v = env_atomic_read(access);

ENV_BUG_ON(v != OCF_CACHE_LINE_ACCESS_WR);
return true;
}

static inline bool ocf_alock_trylock_entry_wr2rd(struct ocf_alock *alock,
static inline void ocf_alock_lock_entry_wr2rd(struct ocf_alock *alock,
ocf_cache_line_t entry)
{
env_atomic *access = &alock->access[entry];
int v = env_atomic_read(access);

ENV_BUG_ON(v != OCF_CACHE_LINE_ACCESS_WR);
env_atomic_set(access, OCF_CACHE_LINE_ACCESS_ONE_RD);
return true;
}

static inline bool ocf_alock_trylock_entry_rd2wr(struct ocf_alock *alock,
Expand Down Expand Up @@ -498,9 +496,9 @@ bool ocf_alock_lock_one_rd(struct ocf_alock *alock,
static inline void ocf_alock_unlock_one_rd_common(struct ocf_alock *alock,
const ocf_cache_line_t entry)
{
bool locked = false;
bool exchanged = false;
bool locked = false, no_waiters = true;

int rw;
uint32_t idx = _WAITERS_LIST_ITEM(entry);
struct ocf_alock_waiters_list *lst = &alock->waiters_lsts[idx];
struct ocf_alock_waiter *waiter;
Expand All @@ -510,49 +508,77 @@ static inline void ocf_alock_unlock_one_rd_common(struct ocf_alock *alock,
/*
* Lock exchange scenario
* 1. RD -> IDLE
* 2. RD -> RD
* 3. RD -> WR
* 2. RD -> WR
* 3. RD -> RD
* 4. RD -> Multiple RD
*/

/* Check is requested page is on the list */
/* Check is requested cache line is on the waiter list */
list_for_each_safe(iter, next, &lst->head) {
waiter = list_entry(iter, struct ocf_alock_waiter, item);
if (entry == waiter->entry) {
no_waiters = false;
break;
}
}

/* RD -> IDLE */
if (no_waiters) {
ocf_alock_unlock_entry_rd(alock, entry);
return;
}

ENV_BUG_ON(waiter->rw != OCF_READ && waiter->rw != OCF_WRITE);

/* RD -> WR/RD */
if (waiter->rw == OCF_WRITE) {
locked = ocf_alock_trylock_entry_rd2wr(alock, entry);
} else if (waiter->rw == OCF_READ) {
locked = ocf_alock_trylock_entry_rd2rd(alock, entry);
}

if (!locked)
return;

rw = waiter->rw;

list_del(iter);

ocf_alock_mark_index_locked(alock, waiter->req, waiter->idx, true);
ocf_alock_entry_locked(alock, waiter->req, waiter->cmpl);

env_allocator_del(alock->allocator, waiter);

/* If we upgraded to write lock, the read reaquests won't be able to
* lock the cache line anyways
*/
if (rw == OCF_WRITE)
return;

iter = next;

/* RD -> Multiple RD */
list_for_each_safe_from(iter, next, &lst->head) {
waiter = list_entry(iter, struct ocf_alock_waiter, item);

if (entry != waiter->entry)
continue;

ENV_BUG_ON(waiter->rw != OCF_READ && waiter->rw != OCF_WRITE);

if (!exchanged) {
if (waiter->rw == OCF_WRITE)
locked = ocf_alock_trylock_entry_rd2wr(alock, entry);
else if (waiter->rw == OCF_READ)
locked = ocf_alock_trylock_entry_rd2rd(alock, entry);
} else {
if (waiter->rw == OCF_WRITE)
locked = ocf_alock_trylock_entry_wr(alock, entry);
else if (waiter->rw == OCF_READ)
locked = ocf_alock_trylock_entry_rd(alock, entry);
}
if (waiter->rw == OCF_WRITE)
return;

if (locked) {
exchanged = true;
list_del(iter);
locked = ocf_alock_trylock_entry_rd(alock, entry);
if (!locked)
return;

ocf_alock_mark_index_locked(alock, waiter->req, waiter->idx, true);
ocf_alock_entry_locked(alock, waiter->req, waiter->cmpl);
list_del(iter);

env_allocator_del(alock->allocator, waiter);
} else {
break;
}
}
ocf_alock_mark_index_locked(alock, waiter->req, waiter->idx, true);
ocf_alock_entry_locked(alock, waiter->req, waiter->cmpl);

if (!exchanged) {
/* No exchange, no waiters on the list, unlock and return
* WR -> IDLE
*/
ocf_alock_unlock_entry_rd(alock, entry);
env_allocator_del(alock->allocator, waiter);
}
}

Expand Down Expand Up @@ -583,8 +609,8 @@ void ocf_alock_unlock_one_rd(struct ocf_alock *alock,
static inline void ocf_alock_unlock_one_wr_common(struct ocf_alock *alock,
const ocf_cache_line_t entry)
{
bool locked = false;
bool exchanged = false;
bool locked = false, no_waiters = true;
int rw;

uint32_t idx = _WAITERS_LIST_ITEM(entry);
struct ocf_alock_waiters_list *lst = &alock->waiters_lsts[idx];
Expand All @@ -595,49 +621,74 @@ static inline void ocf_alock_unlock_one_wr_common(struct ocf_alock *alock,
/*
* Lock exchange scenario
* 1. WR -> IDLE
* 2. WR -> RD
* 3. WR -> WR
* 2. WR -> WR
* 3. WR -> RD
* 4. WR -> Multiple RD
*/

/* Check is requested page is on the list */
/* Check is requested cache line is on the waiter list */
list_for_each_safe(iter, next, &lst->head) {
waiter = list_entry(iter, struct ocf_alock_waiter, item);
if (entry == waiter->entry) {
no_waiters = false;
break;
}
}

/* WR -> IDLE */
if (no_waiters) {
ocf_alock_unlock_entry_wr(alock, entry);
return;
}

ENV_BUG_ON(waiter->rw != OCF_READ && waiter->rw != OCF_WRITE);

/* WR -> WR/RD */
if (waiter->rw == OCF_WRITE) {
ocf_alock_lock_entry_wr2wr(alock, entry);
} else if (waiter->rw == OCF_READ) {
ocf_alock_lock_entry_wr2rd(alock, entry);
}

rw = waiter->rw;

list_del(iter);

ocf_alock_mark_index_locked(alock, waiter->req, waiter->idx, true);
ocf_alock_entry_locked(alock, waiter->req, waiter->cmpl);

env_allocator_del(alock->allocator, waiter);

/* If we passed the write lock, the read reaquests won't be able to lock
* the cache line anyways
*/
if (rw == OCF_WRITE)
return;

iter = next;

/* WR -> Multiple RD */
list_for_each_safe_from(iter, next, &lst->head) {
waiter = list_entry(iter, struct ocf_alock_waiter, item);

if (entry != waiter->entry)
continue;

ENV_BUG_ON(waiter->rw != OCF_READ && waiter->rw != OCF_WRITE);

if (!exchanged) {
if (waiter->rw == OCF_WRITE)
locked = ocf_alock_trylock_entry_wr2wr(alock, entry);
else if (waiter->rw == OCF_READ)
locked = ocf_alock_trylock_entry_wr2rd(alock, entry);
} else {
if (waiter->rw == OCF_WRITE)
locked = ocf_alock_trylock_entry_wr(alock, entry);
else if (waiter->rw == OCF_READ)
locked = ocf_alock_trylock_entry_rd(alock, entry);
}
if (waiter->rw == OCF_WRITE)
return;

if (locked) {
exchanged = true;
list_del(iter);
locked = ocf_alock_trylock_entry_rd(alock, entry);
if (!locked)
return;

ocf_alock_mark_index_locked(alock, waiter->req, waiter->idx, true);
ocf_alock_entry_locked(alock, waiter->req, waiter->cmpl);
list_del(iter);

env_allocator_del(alock->allocator, waiter);
} else {
break;
}
}
ocf_alock_mark_index_locked(alock, waiter->req, waiter->idx, true);
ocf_alock_entry_locked(alock, waiter->req, waiter->cmpl);

if (!exchanged) {
/* No exchange, no waiters on the list, unlock and return
* WR -> IDLE
*/
ocf_alock_unlock_entry_wr(alock, entry);
env_allocator_del(alock->allocator, waiter);
}
}

Expand Down

0 comments on commit c487b24

Please sign in to comment.