Compare commits
6 Commits
threadwait
...
threadwait
Author | SHA1 | Date | |
---|---|---|---|
eb10385a2b | |||
3603939475 | |||
d76c7c3029 | |||
f2f032a494 | |||
728b976aae | |||
ff583bdde8 |
@ -23,7 +23,7 @@ fps_counter_init(struct fps_counter *counter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
counter->thread = NULL;
|
counter->thread = NULL;
|
||||||
SDL_AtomicSet(&counter->started, 0);
|
atomic_init(&counter->started, 0);
|
||||||
// no need to initialize the other fields, they are unused until started
|
// no need to initialize the other fields, they are unused until started
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -35,6 +35,16 @@ fps_counter_destroy(struct fps_counter *counter) {
|
|||||||
SDL_DestroyMutex(counter->mutex);
|
SDL_DestroyMutex(counter->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_started(struct fps_counter *counter) {
|
||||||
|
return atomic_load_explicit(&counter->started, memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
set_started(struct fps_counter *counter, bool started) {
|
||||||
|
atomic_store_explicit(&counter->started, started, memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
// must be called with mutex locked
|
// must be called with mutex locked
|
||||||
static void
|
static void
|
||||||
display_fps(struct fps_counter *counter) {
|
display_fps(struct fps_counter *counter) {
|
||||||
@ -70,10 +80,10 @@ run_fps_counter(void *data) {
|
|||||||
|
|
||||||
mutex_lock(counter->mutex);
|
mutex_lock(counter->mutex);
|
||||||
while (!counter->interrupted) {
|
while (!counter->interrupted) {
|
||||||
while (!counter->interrupted && !SDL_AtomicGet(&counter->started)) {
|
while (!counter->interrupted && !is_started(counter)) {
|
||||||
cond_wait(counter->state_cond, counter->mutex);
|
cond_wait(counter->state_cond, counter->mutex);
|
||||||
}
|
}
|
||||||
while (!counter->interrupted && SDL_AtomicGet(&counter->started)) {
|
while (!counter->interrupted && is_started(counter)) {
|
||||||
uint32_t now = SDL_GetTicks();
|
uint32_t now = SDL_GetTicks();
|
||||||
check_interval_expired(counter, now);
|
check_interval_expired(counter, now);
|
||||||
|
|
||||||
@ -96,7 +106,7 @@ fps_counter_start(struct fps_counter *counter) {
|
|||||||
counter->nr_skipped = 0;
|
counter->nr_skipped = 0;
|
||||||
mutex_unlock(counter->mutex);
|
mutex_unlock(counter->mutex);
|
||||||
|
|
||||||
SDL_AtomicSet(&counter->started, 1);
|
set_started(counter, true);
|
||||||
cond_signal(counter->state_cond);
|
cond_signal(counter->state_cond);
|
||||||
|
|
||||||
// counter->thread is always accessed from the same thread, no need to lock
|
// counter->thread is always accessed from the same thread, no need to lock
|
||||||
@ -114,13 +124,13 @@ fps_counter_start(struct fps_counter *counter) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_stop(struct fps_counter *counter) {
|
fps_counter_stop(struct fps_counter *counter) {
|
||||||
SDL_AtomicSet(&counter->started, 0);
|
set_started(counter, false);
|
||||||
cond_signal(counter->state_cond);
|
cond_signal(counter->state_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
fps_counter_is_started(struct fps_counter *counter) {
|
fps_counter_is_started(struct fps_counter *counter) {
|
||||||
return SDL_AtomicGet(&counter->started);
|
return is_started(counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -145,7 +155,7 @@ fps_counter_join(struct fps_counter *counter) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
||||||
if (!SDL_AtomicGet(&counter->started)) {
|
if (!is_started(counter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +168,7 @@ fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_add_skipped_frame(struct fps_counter *counter) {
|
fps_counter_add_skipped_frame(struct fps_counter *counter) {
|
||||||
if (!SDL_AtomicGet(&counter->started)) {
|
if (!is_started(counter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#ifndef FPSCOUNTER_H
|
#ifndef FPSCOUNTER_H
|
||||||
#define FPSCOUNTER_H
|
#define FPSCOUNTER_H
|
||||||
|
|
||||||
|
#include <stdatomic.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <SDL2/SDL_atomic.h>
|
|
||||||
#include <SDL2/SDL_mutex.h>
|
#include <SDL2/SDL_mutex.h>
|
||||||
#include <SDL2/SDL_thread.h>
|
#include <SDL2/SDL_thread.h>
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ struct fps_counter {
|
|||||||
|
|
||||||
// atomic so that we can check without locking the mutex
|
// atomic so that we can check without locking the mutex
|
||||||
// if the FPS counter is disabled, we don't want to lock unnecessarily
|
// if the FPS counter is disabled, we don't want to lock unnecessarily
|
||||||
SDL_atomic_t started;
|
atomic_bool started;
|
||||||
|
|
||||||
// the following fields are protected by the mutex
|
// the following fields are protected by the mutex
|
||||||
bool interrupted;
|
bool interrupted;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <SDL2/SDL_thread.h>
|
||||||
#include <SDL2/SDL_timer.h>
|
#include <SDL2/SDL_timer.h>
|
||||||
#include <SDL2/SDL_platform.h>
|
#include <SDL2/SDL_platform.h>
|
||||||
|
|
||||||
@ -317,14 +318,12 @@ connect_to_server(uint16_t port, uint32_t attempts, uint32_t delay) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
close_socket(socket_t *socket) {
|
close_socket(socket_t socket) {
|
||||||
assert(*socket != INVALID_SOCKET);
|
assert(socket != INVALID_SOCKET);
|
||||||
net_shutdown(*socket, SHUT_RDWR);
|
net_shutdown(socket, SHUT_RDWR);
|
||||||
if (!net_close(*socket)) {
|
if (!net_close(socket)) {
|
||||||
LOGW("Could not close socket");
|
LOGW("Could not close socket");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
*socket = INVALID_SOCKET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -332,6 +331,22 @@ server_init(struct server *server) {
|
|||||||
*server = (struct server) SERVER_INITIALIZER;
|
*server = (struct server) SERVER_INITIALIZER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run_wait_server(void *data) {
|
||||||
|
struct server *server = data;
|
||||||
|
cmd_simple_wait(server->process, NULL); // ignore exit code
|
||||||
|
// no need for synchronization, server_socket is initialized before this
|
||||||
|
// thread was created
|
||||||
|
if (server->server_socket != INVALID_SOCKET
|
||||||
|
&& !atomic_flag_test_and_set(&server->server_socket_closed)) {
|
||||||
|
// On Linux, accept() is unblocked by shutdown(), but on Windows, it is
|
||||||
|
// unblocked by closesocket(). Therefore, call both (close_socket()).
|
||||||
|
close_socket(server->server_socket);
|
||||||
|
}
|
||||||
|
LOGD("Server terminated");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
server_start(struct server *server, const char *serial,
|
server_start(struct server *server, const char *serial,
|
||||||
const struct server_params *params) {
|
const struct server_params *params) {
|
||||||
@ -345,30 +360,49 @@ server_start(struct server *server, const char *serial,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!push_server(serial)) {
|
if (!push_server(serial)) {
|
||||||
SDL_free(server->serial);
|
goto error1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enable_tunnel_any_port(server, params->port_range)) {
|
if (!enable_tunnel_any_port(server, params->port_range)) {
|
||||||
SDL_free(server->serial);
|
goto error1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// server will connect to our server socket
|
// server will connect to our server socket
|
||||||
server->process = execute_server(server, params);
|
server->process = execute_server(server, params);
|
||||||
|
|
||||||
if (server->process == PROCESS_NONE) {
|
if (server->process == PROCESS_NONE) {
|
||||||
if (!server->tunnel_forward) {
|
goto error2;
|
||||||
close_socket(&server->server_socket);
|
|
||||||
}
|
}
|
||||||
disable_tunnel(server);
|
|
||||||
SDL_free(server->serial);
|
// If the server process dies before connecting to the server socket, then
|
||||||
return false;
|
// the client will be stuck forever on accept(). To avoid the problem, we
|
||||||
|
// must be able to wake up the accept() call when the server dies. To keep
|
||||||
|
// things simple and multiplatform, just spawn a new thread waiting for the
|
||||||
|
// server process and calling shutdown()/close() on the server socket if
|
||||||
|
// necessary to wake up any accept() blocking call.
|
||||||
|
server->wait_server_thread =
|
||||||
|
SDL_CreateThread(run_wait_server, "wait-server", server);
|
||||||
|
if (!server->wait_server_thread) {
|
||||||
|
cmd_terminate(server->process);
|
||||||
|
cmd_simple_wait(server->process, NULL); // ignore exit code
|
||||||
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->tunnel_enabled = true;
|
server->tunnel_enabled = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error2:
|
||||||
|
if (!server->tunnel_forward) {
|
||||||
|
bool was_closed =
|
||||||
|
atomic_flag_test_and_set(&server->server_socket_closed);
|
||||||
|
// the thread is not started, the flag could not be already set
|
||||||
|
assert(!was_closed);
|
||||||
|
close_socket(server->server_socket);
|
||||||
|
}
|
||||||
|
disable_tunnel(server);
|
||||||
|
error1:
|
||||||
|
SDL_free(server->serial);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -386,7 +420,11 @@ server_connect_to(struct server *server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we don't need the server socket anymore
|
// we don't need the server socket anymore
|
||||||
close_socket(&server->server_socket);
|
if (!atomic_flag_test_and_set(&server->server_socket_closed)) {
|
||||||
|
// close it from here
|
||||||
|
close_socket(server->server_socket);
|
||||||
|
// otherwise, it is closed by run_wait_server()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t attempts = 100;
|
uint32_t attempts = 100;
|
||||||
uint32_t delay = 100; // ms
|
uint32_t delay = 100; // ms
|
||||||
@ -413,29 +451,27 @@ server_connect_to(struct server *server) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
server_stop(struct server *server) {
|
server_stop(struct server *server) {
|
||||||
if (server->server_socket != INVALID_SOCKET) {
|
if (server->server_socket != INVALID_SOCKET
|
||||||
close_socket(&server->server_socket);
|
&& !atomic_flag_test_and_set(&server->server_socket_closed)) {
|
||||||
|
close_socket(server->server_socket);
|
||||||
}
|
}
|
||||||
if (server->video_socket != INVALID_SOCKET) {
|
if (server->video_socket != INVALID_SOCKET) {
|
||||||
close_socket(&server->video_socket);
|
close_socket(server->video_socket);
|
||||||
}
|
}
|
||||||
if (server->control_socket != INVALID_SOCKET) {
|
if (server->control_socket != INVALID_SOCKET) {
|
||||||
close_socket(&server->control_socket);
|
close_socket(server->control_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(server->process != PROCESS_NONE);
|
assert(server->process != PROCESS_NONE);
|
||||||
|
|
||||||
if (!cmd_terminate(server->process)) {
|
cmd_terminate(server->process);
|
||||||
LOGW("Could not terminate server");
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_simple_wait(server->process, NULL); // ignore exit code
|
|
||||||
LOGD("Server terminated");
|
|
||||||
|
|
||||||
if (server->tunnel_enabled) {
|
if (server->tunnel_enabled) {
|
||||||
// ignore failure
|
// ignore failure
|
||||||
disable_tunnel(server);
|
disable_tunnel(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_WaitThread(server->wait_server_thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#ifndef SERVER_H
|
#ifndef SERVER_H
|
||||||
#define SERVER_H
|
#define SERVER_H
|
||||||
|
|
||||||
|
#include <stdatomic.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <SDL2/SDL_thread.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
@ -12,6 +14,8 @@
|
|||||||
struct server {
|
struct server {
|
||||||
char *serial;
|
char *serial;
|
||||||
process_t process;
|
process_t process;
|
||||||
|
SDL_Thread *wait_server_thread;
|
||||||
|
atomic_flag server_socket_closed;
|
||||||
socket_t server_socket; // only used if !tunnel_forward
|
socket_t server_socket; // only used if !tunnel_forward
|
||||||
socket_t video_socket;
|
socket_t video_socket;
|
||||||
socket_t control_socket;
|
socket_t control_socket;
|
||||||
@ -24,6 +28,8 @@ struct server {
|
|||||||
#define SERVER_INITIALIZER { \
|
#define SERVER_INITIALIZER { \
|
||||||
.serial = NULL, \
|
.serial = NULL, \
|
||||||
.process = PROCESS_NONE, \
|
.process = PROCESS_NONE, \
|
||||||
|
.wait_server_thread = NULL, \
|
||||||
|
.server_socket_closed = ATOMIC_FLAG_INIT, \
|
||||||
.server_socket = INVALID_SOCKET, \
|
.server_socket = INVALID_SOCKET, \
|
||||||
.video_socket = INVALID_SOCKET, \
|
.video_socket = INVALID_SOCKET, \
|
||||||
.control_socket = INVALID_SOCKET, \
|
.control_socket = INVALID_SOCKET, \
|
||||||
|
@ -163,9 +163,11 @@ public final class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setClipboardText(String text) {
|
public void setClipboardText(String text) {
|
||||||
serviceManager.getClipboardManager().setText(text);
|
boolean ok = serviceManager.getClipboardManager().setText(text);
|
||||||
|
if (ok) {
|
||||||
Ln.i("Device clipboard set");
|
Ln.i("Device clipboard set");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mode one of the {@code SCREEN_POWER_MODE_*} constants
|
* @param mode one of the {@code SCREEN_POWER_MODE_*} constants
|
||||||
@ -176,9 +178,11 @@ public final class Device {
|
|||||||
Ln.e("Could not get built-in display");
|
Ln.e("Could not get built-in display");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SurfaceControl.setDisplayPowerMode(d, mode);
|
boolean ok = SurfaceControl.setDisplayPowerMode(d, mode);
|
||||||
|
if (ok) {
|
||||||
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable auto-rotation (if enabled), set the screen rotation and re-enable auto-rotation (if it was enabled).
|
* Disable auto-rotation (if enabled), set the screen rotation and re-enable auto-rotation (if it was enabled).
|
||||||
|
@ -74,13 +74,15 @@ public class ClipboardManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(CharSequence text) {
|
public boolean setText(CharSequence text) {
|
||||||
try {
|
try {
|
||||||
Method method = getSetPrimaryClipMethod();
|
Method method = getSetPrimaryClipMethod();
|
||||||
ClipData clipData = ClipData.newPlainText(null, text);
|
ClipData clipData = ClipData.newPlainText(null, text);
|
||||||
setPrimaryClip(method, manager, clipData);
|
setPrimaryClip(method, manager, clipData);
|
||||||
|
return true;
|
||||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
Ln.e("Could not invoke method", e);
|
Ln.e("Could not invoke method", e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,12 +121,14 @@ public final class SurfaceControl {
|
|||||||
return setDisplayPowerModeMethod;
|
return setDisplayPowerModeMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDisplayPowerMode(IBinder displayToken, int mode) {
|
public static boolean setDisplayPowerMode(IBinder displayToken, int mode) {
|
||||||
try {
|
try {
|
||||||
Method method = getSetDisplayPowerModeMethod();
|
Method method = getSetDisplayPowerModeMethod();
|
||||||
method.invoke(null, displayToken, mode);
|
method.invoke(null, displayToken, mode);
|
||||||
|
return true;
|
||||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
Ln.e("Could not invoke method", e);
|
Ln.e("Could not invoke method", e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user