Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/mgba/core/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ enum mCoreThreadRequest {
mTHREAD_REQ_WAIT = 2, // Core-set pause
mTHREAD_REQ_RESET = 4,
mTHREAD_REQ_RUN_ON = 8,
mTHREAD_REQ_CRASHED = 16,
};

struct mCoreThreadInternal {
Expand Down
12 changes: 7 additions & 5 deletions src/core/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
}

impl->requested &= ~pendingRequests | mTHREAD_REQ_PAUSE | mTHREAD_REQ_WAIT;
impl->requested &= ~pendingRequests | mTHREAD_REQ_PAUSE | mTHREAD_REQ_WAIT | mTHREAD_REQ_CRASHED;
pendingRequests = impl->requested;

if (impl->state == mTHREAD_REQUEST) {
Expand All @@ -345,6 +345,9 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
if (pendingRequests & mTHREAD_REQ_WAIT) {
_changeState(impl, mTHREAD_PAUSED);
}
if (pendingRequests & mTHREAD_REQ_CRASHED) {
_changeState(impl, mTHREAD_CRASHED);
}
} else {
_changeState(impl, mTHREAD_RUNNING);
}
Expand Down Expand Up @@ -494,16 +497,14 @@ bool mCoreThreadHasCrashed(struct mCoreThread* threadContext) {

void mCoreThreadMarkCrashed(struct mCoreThread* threadContext) {
MutexLock(&threadContext->impl->stateMutex);
threadContext->impl->requested |= mTHREAD_REQ_CRASHED;
_changeState(threadContext->impl, mTHREAD_CRASHED);
MutexUnlock(&threadContext->impl->stateMutex);
}

void mCoreThreadClearCrashed(struct mCoreThread* threadContext) {
MutexLock(&threadContext->impl->stateMutex);
if (threadContext->impl->state == mTHREAD_CRASHED) {
threadContext->impl->state = mTHREAD_REQUEST;
ConditionWake(&threadContext->impl->stateOnThreadCond);
}
_cancelRequest(threadContext->impl, mTHREAD_REQ_CRASHED);
MutexUnlock(&threadContext->impl->stateMutex);
}

Expand Down Expand Up @@ -532,6 +533,7 @@ void mCoreThreadEnd(struct mCoreThread* threadContext) {
void mCoreThreadReset(struct mCoreThread* threadContext) {
MutexLock(&threadContext->impl->stateMutex);
_waitOnInterrupt(threadContext->impl);
_cancelRequest(threadContext->impl, mTHREAD_REQ_CRASHED);
_sendRequest(threadContext->impl, mTHREAD_REQ_RESET);
_waitOnRequest(threadContext->impl, mTHREAD_REQ_RESET);
MutexUnlock(&threadContext->impl->stateMutex);
Expand Down
40 changes: 38 additions & 2 deletions src/gba/sio/lockstep.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,22 @@ static void _verifyAwake(struct GBASIOLockstepCoordinator* coordinator) {
#endif
}

static void _abortTransfer(struct GBASIOLockstepCoordinator* coordinator, struct GBASIOLockstepPlayer* player) {
mLOG(GBA_SIO, DEBUG, "Aborting in-progress transfer");
// TODO: Do we need to clean this up better?
coordinator->transferActive = false;
coordinator->waiting = 0;

if (player->playerId != 0) {
struct GBASIOLockstepPlayer* runner = TableLookup(&coordinator->players, coordinator->attachedPlayers[0]);
if (runner) {
GBASIOLockstepPlayerWake(runner);
}
} else {
GBASIOLockstepCoordinatorWakePlayers(coordinator);
}
}

void GBASIOLockstepDriverCreate(struct GBASIOLockstepDriver* driver, struct mLockstepUser* user) {
memset(driver, 0, sizeof(*driver));
driver->d.init = GBASIOLockstepDriverInit;
Expand Down Expand Up @@ -216,10 +232,23 @@ static void GBASIOLockstepDriverReset(struct GBASIODriver* driver) {
_enqueueEvent(coordinator, &event, TARGET_ALL & ~TARGET(player->playerId));
}
} else {
MutexLock(&coordinator->mutex);
player = TableLookup(&coordinator->players, lockstep->lockstepId);
player->cycleOffset = mTimingCurrentTime(&driver->p->p->timing) - coordinator->cycle;
}

if (coordinator->transferActive) {
_abortTransfer(coordinator, player);
player->asleep = false;
}
if (player->playerId == 0 && coordinator->nAttached > 1) {
coordinator->waiting = 0;
// We will immediately go back to sleep when the initial mode gets set,
// so we need to clear this here to avoid triggering an assert later.
player->asleep = false;
GBASIOLockstepCoordinatorWakePlayers(coordinator);
}

if (mTimingIsScheduled(&lockstep->d.p->p->timing, &lockstep->event)) {
MutexUnlock(&coordinator->mutex);
return;
Expand Down Expand Up @@ -458,7 +487,6 @@ static void GBASIOLockstepDriverSetMode(struct GBASIODriver* driver, enum GBASIO
.mode = mode,
};
if (player->playerId == 0) {
mASSERT_DEBUG(!coordinator->transferActive); // TODO
coordinator->transferMode = mode;
GBASIOLockstepCoordinatorWaitOnPlayers(coordinator, player);
}
Expand Down Expand Up @@ -517,7 +545,11 @@ static bool GBASIOLockstepDriverStart(struct GBASIODriver* driver) {
bool ret = false;
MutexLock(&coordinator->mutex);
if (coordinator->transferActive) {
mLOG(GBA_SIO, ERROR, "Transfer restarted unexpectedly");
mLOG(GBA_SIO, GAME_ERROR, "Transfer restarted unexpectedly");
goto out;
}
if (coordinator->nAttached < 2) {
mLOG(GBA_SIO, DEBUG, "Attempted to start transfer with no secondary players");
goto out;
}
struct GBASIOLockstepPlayer* player = TableLookup(&coordinator->players, lockstep->lockstepId);
Expand Down Expand Up @@ -938,6 +970,10 @@ void _lockstepEvent(struct mTiming* timing, void* context, uint32_t cyclesLate)
GBASIOLockstepCoordinatorAckPlayer(coordinator, player);
break;
case SIO_EV_MODE_SET:
if (coordinator->transferActive && player->mode != event->mode) {
mLOG(GBA_SIO, DEBUG, "Switching modes while transfer is active");
_abortTransfer(coordinator, player);
}
_setReady(coordinator, player, event->playerId, event->mode);
if (event->playerId == 0) {
GBASIOLockstepCoordinatorAckPlayer(coordinator, player);
Expand Down