Use atomic functions in more places
lehoangquyen lquyen@bbmtek.com
Mon, 17 Dec 2018 14:14:21 +0800
3 files changed,
33 insertions(+),
10 deletions(-)
M
include/mgba-util/common.h
→
include/mgba-util/common.h
@@ -81,6 +81,7 @@ #if !defined(_MSC_VER) && (defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
#define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE) #define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE) #define ATOMIC_ADD(DST, OP) __atomic_add_fetch(&DST, OP, __ATOMIC_RELEASE) +#define ATOMIC_SUB(DST, OP) __atomic_sub_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_OR(DST, OP) __atomic_or_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_AND(DST, OP) __atomic_and_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) __atomic_compare_exchange_n(&DST, &EXPECTED, SRC, true,__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)@@ -89,6 +90,7 @@ // TODO
#define ATOMIC_STORE(DST, SRC) DST = SRC #define ATOMIC_LOAD(DST, SRC) DST = SRC #define ATOMIC_ADD(DST, OP) DST += OP +#define ATOMIC_SUB(DST, OP) DST -= OP #define ATOMIC_OR(DST, OP) DST |= OP #define ATOMIC_AND(DST, OP) DST &= OP #define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false)
M
src/gb/sio/lockstep.c
→
src/gb/sio/lockstep.c
@@ -236,6 +236,8 @@ node->p->d.transferCycles = GBSIOCyclesPerTransfer[(value >> 1) & 1];
mTimingDeschedule(&driver->p->p->timing, &driver->p->event); mTimingDeschedule(&driver->p->p->timing, &node->event); mTimingSchedule(&driver->p->p->timing, &node->event, 0); + } else { + mLOG(GB_SIO, FATAL, "GBSIOLockstepNodeWriteSC() failed to write to masterClaimed\n"); } } return value;
M
src/gba/sio/lockstep.c
→
src/gba/sio/lockstep.c
@@ -93,7 +93,7 @@ switch (node->mode) {
case SIO_MULTI: node->d.writeRegister = GBASIOLockstepNodeMultiWriteRegister; node->d.p->rcnt |= 3; - ++node->p->attachedMulti; + ATOMIC_ADD(node->p->attachedMulti, 1); node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached; if (node->id) { node->d.p->rcnt |= 4;@@ -118,7 +118,7 @@ struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
node->mode = driver->p->mode; switch (node->mode) { case SIO_MULTI: - --node->p->attachedMulti; + ATOMIC_SUB(node->p->attachedMulti, 1); break; default: break;@@ -132,11 +132,15 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; if (address == REG_SIOCNT) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); - if (value & 0x0080 && node->p->d.transferActive == TRANSFER_IDLE) { + + enum mLockstepPhase transferActive; + ATOMIC_LOAD(transferActive, node->p->d.transferActive); + + if (value & 0x0080 && transferActive == TRANSFER_IDLE) { if (!node->id && node->d.p->multiplayerControl.ready) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id); - node->p->d.transferActive = TRANSFER_STARTING; - node->p->d.transferCycles = GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->d.attached - 1]; + ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING); + ATOMIC_STORE(node->p->d.transferCycles, GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->d.attached - 1]); mTimingDeschedule(&driver->p->p->timing, &node->event); mTimingSchedule(&driver->p->p->timing, &node->event, 0); } else {@@ -209,11 +213,19 @@
static int32_t _masterUpdate(struct GBASIOLockstepNode* node) { bool needsToWait = false; int i; - switch (node->p->d.transferActive) { + + enum mLockstepPhase transferActive; + int attachedMulti, attached; + + ATOMIC_LOAD(transferActive, node->p->d.transferActive); + ATOMIC_LOAD(attachedMulti, node->p->attachedMulti); + ATOMIC_LOAD(attached, node->p->d.attached); + + switch (transferActive) { case TRANSFER_IDLE: // If the master hasn't initiated a transfer, it can keep going. node->nextEvent += LOCKSTEP_INCREMENT; - node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached; + node->d.p->multiplayerControl.ready = attachedMulti == attached; break; case TRANSFER_STARTING: // Start the transfer, but wait for the other GBAs to catch up@@ -276,9 +288,16 @@ return node->nextEvent;
} static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) { - node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached; + enum mLockstepPhase transferActive; + int attachedMulti, attached; + + ATOMIC_LOAD(transferActive, node->p->d.transferActive); + ATOMIC_LOAD(attachedMulti, node->p->attachedMulti); + ATOMIC_LOAD(attached, node->p->d.attached); + + node->d.p->multiplayerControl.ready = attachedMulti == attached; bool signal = false; - switch (node->p->d.transferActive) { + switch (transferActive) { case TRANSFER_IDLE: if (!node->d.p->multiplayerControl.ready) { node->p->d.addCycles(&node->p->d, node->id, LOCKSTEP_INCREMENT);@@ -368,7 +387,7 @@ }
if (value & 0x0080 && !node->id) { // Internal shift clock if (value & 1) { - node->p->d.transferActive = TRANSFER_STARTING; + ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING); } // Frequency if (value & 2) {