Skip to content

Commit

Permalink
Wait for the BGB timestamp
Browse files Browse the repository at this point in the history
Also making sure to check mobile_action periodically
  • Loading branch information
mid-kid committed Mar 8, 2023
1 parent 065f491 commit 7fd57b6
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 65 deletions.
38 changes: 26 additions & 12 deletions source/bgblink.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ bool bgb_init(struct bgb_state *state, int socket, bgb_transfer_cb callback_tran
state->callback_timestamp = callback_timestamp;
state->transfer_last = 0xD2;
state->timestamp_last = 0;
state->set_status = false;
state->timestamp_init = false;

// Handshake
memcpy(&packet, &handshake, sizeof(packet));
Expand All @@ -97,6 +97,20 @@ bool bgb_init(struct bgb_state *state, int socket, bgb_transfer_cb callback_tran
packet.timestamp = 0;
if (!bgb_send(socket, &packet)) return false;

// Expect a status packet back
if (!bgb_recv(socket, &packet)) return false;
if (packet.cmd != BGB_CMD_STATUS) {
fprintf(stderr, "bgb_init: unexpected packet (1)\n");
return false;
}

// Unpause the emulator
packet.cmd = BGB_CMD_STATUS;
packet.b2 = BGB_STATUS_RUNNING | BGB_STATUS_SUPPORTRECONNECT;
packet.b3 = 0;
packet.b4 = 0;
if (!bgb_send(socket, &packet)) return false;

return true;
}

Expand All @@ -122,8 +136,10 @@ bool bgb_loop(struct bgb_state *state)
packet.b4 = 0;
packet.timestamp = 0;
if (!bgb_send(state->socket, &packet)) return false;
state->transfer_last =
state->callback_transfer(state->user, transfer_cur);
if (state->callback_transfer) {
state->transfer_last =
state->callback_transfer(state->user, transfer_cur);
}
break;

case BGB_CMD_SYNC2:
Expand All @@ -138,15 +154,7 @@ bool bgb_loop(struct bgb_state *state)
break;

case BGB_CMD_STATUS:
if (!state->set_status) {
packet.cmd = BGB_CMD_STATUS;
packet.b2 = BGB_STATUS_RUNNING | BGB_STATUS_SUPPORTRECONNECT;
packet.b3 = 0;
packet.b4 = 0;
packet.timestamp = 0;
if (!bgb_send(state->socket, &packet)) return false;
state->set_status = true;
}
// Ignore, we've already sent a status packet
break;

default:
Expand All @@ -156,6 +164,12 @@ bool bgb_loop(struct bgb_state *state)
}

if (state->callback_timestamp) {
if (!state->timestamp_init) {
state->callback_timestamp(state->user, timestamp_cur);
state->timestamp_last = timestamp_cur;
state->timestamp_init = true;
}

// Attempt to detect the clock going back in time
// This is probably a BGB bug, caused by enabling some options,
// such as the "break on ld d,d" option.
Expand Down
2 changes: 1 addition & 1 deletion source/bgblink.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct bgb_state {
// private
unsigned char transfer_last;
uint32_t timestamp_last;
bool set_status;
bool timestamp_init;
};

void socket_perror(const char *func);
Expand Down
136 changes: 90 additions & 46 deletions source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ struct mobile_user {
struct mobile_adapter *adapter;
enum mobile_action action;
FILE *config;
_Atomic uint32_t bgb_clock;
_Atomic uint32_t bgb_clock_latch[MOBILE_MAX_TIMERS];
uint32_t bgb_clock;
uint32_t bgb_clock_init;
uint32_t bgb_clock_latch[MOBILE_MAX_TIMERS];
int sockets[MOBILE_MAX_CONNECTIONS];
char number_user[MOBILE_MAX_NUMBER_SIZE + 1];
char number_peer[MOBILE_MAX_NUMBER_SIZE + 1];
Expand Down Expand Up @@ -321,8 +322,8 @@ static int impl_sock_recv(void *user, unsigned conn, void *data, unsigned size,
// zero-length datagrams.
int sock_type = 0;
socklen_t sock_type_len = sizeof(sock_type);
getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&sock_type,
&sock_type_len);
assert(getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&sock_type,
&sock_type_len) == 0);
if (sock_type == SOCK_STREAM) return -2;
}

Expand Down Expand Up @@ -397,6 +398,24 @@ static void impl_update_number(void *user, enum mobile_number type, const char *
update_title(mobile);
}

static volatile bool signal_int_trig = false;
static void signal_int(int signo)
{
(void)signo;
signal_int_trig = true;
}
#ifdef __WIN32__
static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
if (fdwCtrlType == CTRL_C_EVENT ||
fdwCtrlType == CTRL_CLOSE_EVENT) {
signal_int(SIGINT);
return TRUE;
}
return FALSE;
}
#endif

static enum mobile_action filter_actions(enum mobile_action action)
{
// Turns actions that aren't relevant to the emulator into
Expand All @@ -415,21 +434,45 @@ static enum mobile_action filter_actions(enum mobile_action action)
static void *thread_mobile_loop(void *user)
{
struct mobile_user *mobile = (struct mobile_user *)user;
for (;;) {
// Implicitly unlocks mutex_cond while waiting
pthread_cond_wait(&mobile->cond, &mobile->mutex_cond);
struct timespec now;
while (!signal_int_trig) {
// Get current time
clock_gettime(CLOCK_MONOTONIC, &now);

if (mobile->action == MOBILE_ACTION_NONE) {
struct timespec to = now;
to.tv_nsec += 100000000; // 100ms
if (to.tv_nsec > 1000000000) {
to.tv_nsec -= 1000000000;
to.tv_sec += 1;
}

// Process actions until we run out
while (mobile->action != MOBILE_ACTION_NONE) {
// Implicitly unlocks mutex_cond while waiting
pthread_cond_timedwait(&mobile->cond, &mobile->mutex_cond, &to);
}

// Fetch action if none exists
if (mobile->action == MOBILE_ACTION_NONE) {
mobile->action =
filter_actions(mobile_action_get(mobile->adapter));
}

// Process action
if (mobile->action != MOBILE_ACTION_NONE) {
mobile_action_process(mobile->adapter, mobile->action);
fflush(stdout);

mobile->action = filter_actions(
mobile_action_get(mobile->adapter));
if (mobile->action != MOBILE_ACTION_NONE) {
// Sleep 10ms to avoid busylooping too hard
nanosleep(&(struct timespec){.tv_nsec = 10000000}, NULL);
// Sleep 10ms to avoid busylooping too hard
struct timespec to = now;
to.tv_nsec += 10000000; // 10ms
if (to.tv_nsec > 1000000000) {
to.tv_nsec -= 1000000000;
to.tv_sec += 1;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, NULL);

// Fetch next action
mobile->action =
filter_actions(mobile_action_get(mobile->adapter));
}
}
return NULL;
Expand All @@ -443,13 +486,10 @@ static void bgb_loop_action(struct mobile_user *mobile)
// If the thread isn't doing anything, queue up the next action.
if (pthread_mutex_trylock(&mobile->mutex_cond) != 0) return;
if (mobile->action == MOBILE_ACTION_NONE) {
enum mobile_action action = filter_actions(
mobile_action_get(mobile->adapter));

if (action != MOBILE_ACTION_NONE) {
mobile->action = action;
pthread_cond_signal(&mobile->cond);
}
mobile->action = filter_actions(mobile_action_get(mobile->adapter));
}
if (mobile->action != MOBILE_ACTION_NONE) {
pthread_cond_broadcast(&mobile->cond);
}
pthread_mutex_unlock(&mobile->mutex_cond);
}
Expand All @@ -473,23 +513,13 @@ static void bgb_loop_timestamp(void *user, uint32_t t)
bgb_loop_action(mobile);
}

static bool signal_int_trig = false;
static void signal_int(int signo)
static void bgb_loop_timestamp_init(void *user, uint32_t t)
{
(void)signo;
signal_int_trig = true;
}
#ifdef __WIN32__
static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
if (fdwCtrlType == CTRL_C_EVENT ||
fdwCtrlType == CTRL_CLOSE_EVENT) {
signal_int(SIGINT);
return TRUE;
}
return FALSE;
// Initialize the clock
struct mobile_user *mobile = (struct mobile_user *)user;
mobile->bgb_clock = t;
mobile->bgb_clock_init = true;
}
#endif

static char *program_name;

Expand Down Expand Up @@ -710,15 +740,21 @@ int main(int argc, char *argv[])
}
mobile->mutex_serial = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
mobile->mutex_cond = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
mobile->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
mobile->action = MOBILE_ACTION_NONE;
mobile->config = config;
mobile->bgb_clock = 0;
mobile->bgb_clock_init = false;
for (int i = 0; i < MOBILE_MAX_TIMERS; i++) mobile->bgb_clock_latch[i] = 0;
for (int i = 0; i < MOBILE_MAX_CONNECTIONS; i++) mobile->sockets[i] = -1;
mobile->number_user[0] = '\0';
mobile->number_peer[0] = '\0';

// Initialize condition with attributes
pthread_condattr_t cond_attr;
assert(pthread_condattr_init(&cond_attr) == 0);
assert(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0);
assert(pthread_cond_init(&mobile->cond, &cond_attr) == 0);

pthread_mutex_lock(&mobile->mutex_cond);
pthread_mutex_lock(&mobile->mutex_serial);

Expand Down Expand Up @@ -788,6 +824,18 @@ int main(int argc, char *argv[])
#endif
update_title(mobile);

// Connect to the emulator
struct bgb_state bgb_state;
if (!bgb_init(&bgb_state, bgb_sock, bgb_loop_transfer, bgb_loop_timestamp,
mobile)) {
goto error;
}

// Wait for the timestamp to be initialized
bgb_state.callback_timestamp = bgb_loop_timestamp_init;
while (!mobile->bgb_clock_init) if (!bgb_loop(&bgb_state)) goto error;
bgb_state.callback_timestamp = bgb_loop_timestamp;

// Start main mobile thread
mobile_start(mobile->adapter);
pthread_t mobile_thread;
Expand All @@ -798,15 +846,11 @@ int main(int argc, char *argv[])
goto error;
}

// Handle the emulator connection
struct bgb_state bgb_state;
if (bgb_init(&bgb_state, bgb_sock, bgb_loop_transfer, bgb_loop_timestamp,
mobile)) {
while (!signal_int_trig) if (!bgb_loop(&bgb_state)) break;
}
while (!signal_int_trig) if (!bgb_loop(&bgb_state)) break;
signal_int_trig = true;

// Stop the main mobile thread
pthread_cancel(mobile_thread);
// Wait for the mobile thread to finish
pthread_cond_broadcast(&mobile->cond);
pthread_join(mobile_thread, NULL);
mobile_stop(mobile->adapter);

Expand Down
2 changes: 1 addition & 1 deletion subprojects/libmobile
Submodule libmobile updated 12 files
+1 −0 Makefile.am
+2 −0 commands.c
+0 −8 commands.h
+8 −1 config.c
+1 −0 config.h
+40 −0 global.h
+1 −0 meson.build
+83 −9 mobile.c
+4 −2 mobile.h
+1 −13 mobile_data.h
+28 −6 relay.c
+1 −0 relay.h
10 changes: 10 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ def accept(self):
self.sock = None
self.conn = conn

# Expect handshake
pack = self.recv()

# Send handshake
ver = {
"cmd": BGBMaster.BGB_CMD_VERSION,
"b2": 1,
Expand All @@ -92,6 +95,13 @@ def accept(self):
return False
self.send(ver)

# Send status
stat = {
"cmd": BGBMaster.BGB_CMD_STATUS,
"b2": 1,
}
self.send(stat)

def handle(self):
pack = self.recv()
if not pack:
Expand Down
4 changes: 2 additions & 2 deletions tools/flags-debug-nosanit.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
export CPPFLAGS="-UNDEBUG"
export CFLAGS="-Og -ggdb"
export CPPFLAGS="-UNDEBUG $CPPFLAGS"
export CFLAGS="-Og -ggdb $CFLAGS"
test "$(basename "$0")" = 'flags-debug-nosanit.sh' && exec "$@" || true
4 changes: 2 additions & 2 deletions tools/flags-debug.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
export CPPFLAGS="-UNDEBUG"
export CFLAGS="-Og -ggdb -fsanitize=address -fsanitize=leak -fsanitize=undefined"
export CPPFLAGS="-UNDEBUG $CPPFLAGS"
export CFLAGS="-Og -ggdb -fsanitize=address -fsanitize=leak -fsanitize=undefined $CFLAGS"
test "$(basename "$0")" = 'flags-debug.sh' && exec "$@" || true
2 changes: 1 addition & 1 deletion tools/flags-release.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/sh
export CFLAGS="-Os -flto -fuse-linker-plugin"
export CFLAGS="-Os -flto -fuse-linker-plugin $CFLAGS"
test "$(basename "$0")" = 'flags-release.sh' && exec "$@" || true

0 comments on commit 7fd57b6

Please sign in to comment.