This commit is contained in:
Nekotekina 2015-03-10 22:16:31 +03:00
parent 11b409907e
commit a62eeaaecc
3 changed files with 27 additions and 30 deletions

View File

@ -211,9 +211,9 @@ template<typename T> inline static typename std::enable_if<std::is_arithmetic<T>
template<typename T> inline static typename std::enable_if<std::is_arithmetic<T>::value, T>::type operator --(_atomic_base<be_t<T>>& left, int)
{
u64 result;
T result;
left.atomic_op([&result](be_t<u64>& value)
left.atomic_op([&result](be_t<T>& value)
{
result = value--;
});

View File

@ -25,13 +25,13 @@ s32 syncMutexInitialize(vm::ptr<CellSyncMutex> mutex)
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.addr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
// prx: set zero and sync
mutex->data.exchange({});
mutex->sync_var.exchange({});
return CELL_OK;
}
@ -51,26 +51,22 @@ s32 cellSyncMutexLock(vm::ptr<CellSyncMutex> mutex)
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.addr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
// prx: increase m_acq and remember its old value
be_t<u16> order;
mutex->data.atomic_op([&order](CellSyncMutex::data_t& mutex)
{
order = mutex.m_acq++;
});
// prx: increase acquire_count and remember its old value
const be_t<u16> order = be_t<u16>::make(mutex->acquire_count++);
// prx: wait until this old value is equal to m_rel
// prx: wait until release_count is equal to old acquire_count
g_sync_mutex_wm.wait_op(mutex.addr(), [mutex, order]()
{
return order == mutex->data.read_relaxed().m_rel;
return order == mutex->release_count.read_relaxed();
});
// prx: sync
mutex->data.read_sync();
mutex->sync_var.read_sync();
return CELL_OK;
}
@ -83,19 +79,16 @@ s32 cellSyncMutexTryLock(vm::ptr<CellSyncMutex> mutex)
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.addr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
// prx: exit if m_acq and m_rel are not equal, increase m_acq
return mutex->data.atomic_op(CELL_OK, [](CellSyncMutex::data_t& mutex) -> s32
// prx: lock only if acquire_count and release_count are equal
return mutex->sync_var.atomic_op(CELL_OK, [](CellSyncMutex::sync_t& mutex) -> s32
{
if (mutex.m_acq++ != mutex.m_rel)
{
return CELL_SYNC_ERROR_BUSY;
}
return CELL_OK;
return (mutex.acquire_count++ != mutex.release_count) ? CELL_SYNC_ERROR_BUSY : CELL_OK;
});
}
@ -112,10 +105,8 @@ s32 cellSyncMutexUnlock(vm::ptr<CellSyncMutex> mutex)
return CELL_SYNC_ERROR_ALIGN;
}
mutex->data.atomic_op_sync([](CellSyncMutex::data_t& mutex)
{
mutex.m_rel++;
});
// prx: increase release count
mutex->release_count++;
g_sync_mutex_wm.notify(mutex.addr());

View File

@ -29,15 +29,21 @@ enum
CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, // ???
};
struct CellSyncMutex
union CellSyncMutex
{
struct data_t
struct sync_t
{
be_t<u16> m_rel; // release order (increased when mutex is unlocked)
be_t<u16> m_acq; // acquire order (increased when mutex is locked)
be_t<u16> release_count; // increased when mutex is unlocked
be_t<u16> acquire_count; // increased when mutex is locked
};
atomic_t<data_t> data;
struct
{
atomic_t<u16> release_count;
atomic_t<u16> acquire_count;
};
atomic_t<sync_t> sync_var;
};
static_assert(sizeof(CellSyncMutex) == 4, "CellSyncMutex: wrong size");