Skip to content
Merged
2 changes: 2 additions & 0 deletions .github/workflows/Linux-libretro-common-samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ jobs:
rpng_roundtrip_test
word_wrap_overflow_test
task_queue_title_error_test
tpool_wait_test
fifo_queue_bounds_test
)

# Per-binary run command (overrides ./<binary> if present).
Expand Down
36 changes: 31 additions & 5 deletions gfx/common/x11_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,31 @@ static bool xss_screensaver_inhibit(Display *dpy, bool enable)
return true;
}
#else
static bool xss_screensaver_inhibit(Display *dpy, bool enable)
{
(void) dpy;
return false;
}
static bool xss_screensaver_inhibit(Display *dpy, bool enable) { return false; }
#endif

/* Probe once for xdg-screensaver and its xset backend dependency.
* xdg-screensaver's "X11" backend shells out to xset; if xset is missing
* (common on minimal installs / containers / some WMs without
* x11-xserver-utils), invoking xdg-screensaver spams stderr with
* "xset: not found" and "Illegal number" without us ever knowing why.
* Check up front so we can silently no-op instead. */
static bool xdg_screensaver_probe(void)
{
/* Both are needed: xdg-screensaver itself, and xset which it execs.
* `command -v` is a POSIX shell builtin so this works under /bin/sh
* on every platform that has system(). Redirecting both streams
* keeps the probe silent. */
int ret = system("command -v xdg-screensaver >/dev/null 2>&1 && "
"command -v xset >/dev/null 2>&1");
if (ret == -1 || WEXITSTATUS(ret) != 0)
{
RARCH_LOG("[X11] xdg-screensaver or xset not available; screensaver suspension disabled.\n");
return false;
}
return true;
}

static void xdg_screensaver_inhibit(Window wnd)
{
int ret;
Expand Down Expand Up @@ -312,6 +330,14 @@ bool x11_suspend_screensaver(void *data, bool enable)
{
if (xdg_screensaver_available)
{
static bool probed = false;
if (!probed)
{
xdg_screensaver_available = xdg_screensaver_probe();
probed = true;
}
if (!xdg_screensaver_available)
return true;
xdg_screensaver_inhibit(wnd);
return xdg_screensaver_available;
}
Expand Down
4 changes: 4 additions & 0 deletions intl/msg_hash_ga.h
Original file line number Diff line number Diff line change
Expand Up @@ -2530,6 +2530,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SCANLINE_SYNC,
"Sioncrónú Scanline"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_SCANLINE_SYNC,
"Sioncrónaigh cur i láthair físe le suíomh na líne scanadh. Laghdaíonn sé moill ar chostas riosca níos airde stróiceadh. Ní mór VSync a dhíchumasú."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY,
"Moill Fráma"
Expand Down
4 changes: 4 additions & 0 deletions intl/msg_hash_ko.h
Original file line number Diff line number Diff line change
Expand Up @@ -2554,6 +2554,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SCANLINE_SYNC,
"스캔라인 동기화"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_SCANLINE_SYNC,
"동영상 출력을 스캔라인 위치에 맞춰 동기화합니다. 지연 시간이 줄어들지만 티어링 증상이 발생할 확률이 높아집니다. 수직 동기화가 비활성화되어야 합니다."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY,
"프레임 지연"
Expand Down
12 changes: 12 additions & 0 deletions intl/msg_hash_sk.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,14 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_PASSWORD,
"Heslo"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ACCESS_KEY_ID,
"ID prístupového kľúča"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SECRET_ACCESS_KEY,
"Tajný prístupový kľúč"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS,
"Záznam"
Expand Down Expand Up @@ -2253,6 +2261,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_TURBO_MODE_SINGLEBUTTON_HOLD,
"Jedno tlačidlo (držať)"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_TURBO_BUTTON,
"Tlačidlo Turbo"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS,
"Rýchlo streľba"
Expand Down
20 changes: 20 additions & 0 deletions intl/msg_hash_sv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,26 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_CLOUD_SYNC_PASSWORD,
"Ditt lösenord för ditt molnlagringskonto."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ACCESS_KEY_ID,
"Åtkomstnyckel-ID"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CLOUD_SYNC_ACCESS_KEY_ID,
"Ditt åtkomstnyckel-ID för ditt molnlagringskonto."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SECRET_ACCESS_KEY,
"Hemlig åtkomstnyckel"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CLOUD_SYNC_SECRET_ACCESS_KEY,
"Din hemliga åtkomstnyckel för ditt molnlagringskonto."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CLOUD_SYNC_S3_URL,
"Din S3-slutpunkts-URL för molnlagring."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS,
"Loggning"
Expand Down
4 changes: 2 additions & 2 deletions intl/progress.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
#define LANGUAGE_PROGRESS_FRENCH_APPROVED 100

/* Irish */
#define LANGUAGE_PROGRESS_IRISH_TRANSLATED 99
#define LANGUAGE_PROGRESS_IRISH_TRANSLATED 100
#define LANGUAGE_PROGRESS_IRISH_APPROVED 0

/* Galician */
Expand Down Expand Up @@ -95,7 +95,7 @@
#define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0

/* Korean */
#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99
#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100
#define LANGUAGE_PROGRESS_KOREAN_APPROVED 0

/* Dutch */
Expand Down
12 changes: 12 additions & 0 deletions libretro-common/include/queues/fifo_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ static INLINE void fifo_clear(fifo_buffer_t *buffer)
/**
* Writes \c size bytes to the given queue.
*
* \c size is silently capped at \c FIFO_WRITE_AVAIL(buffer) --
* the call writes at most that many bytes and discards any
* excess. Callers that need to be sure all bytes are queued
* must gate on \c FIFO_WRITE_AVAIL beforehand. Behaviour is
* undefined if \c buffer is \c NULL.
*
* @param buffer The FIFO queue to write to.
* @param in_buf The buffer to read bytes from.
* @param size The length of \c in_buf, in bytes.
Expand All @@ -135,6 +141,12 @@ void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len);
/**
* Reads \c size bytes from the given queue.
*
* \c size is silently capped at \c FIFO_READ_AVAIL(buffer) --
* the call returns at most that many bytes and leaves the
* trailing portion of \c in_buf untouched. Callers that need
* exactly \c size bytes must gate on \c FIFO_READ_AVAIL
* beforehand. Behaviour is undefined if \c buffer is \c NULL.
*
* @param buffer The FIFO queue to read from.
* @param in_buf The buffer to store the read bytes in.
* @param size The length of \c in_buf, in bytes.
Expand Down
57 changes: 54 additions & 3 deletions libretro-common/queues/fifo_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,21 @@

static bool fifo_initialize_internal(fifo_buffer_t *buf, size_t len)
{
uint8_t *buffer = (uint8_t*)calloc(1, len + 1);
uint8_t *buffer;

/* The ring reserves one slot to distinguish empty from full,
* so the actual allocation is (len + 1) bytes. Reject @len
* values that would wrap that addition: SIZE_MAX would
* compute (size_t)0, which calloc(1, 0) is allowed to satisfy
* with a non-NULL pointer to a zero-byte allocation. Letting
* that succeed would leave buf->size == 0 and the next
* fifo_write would divide by zero at the `% buffer->size`
* step. No current caller asks for SIZE_MAX, so the rejection
* is purely defensive. */
if (len >= SIZE_MAX)
return false;

buffer = (uint8_t*)calloc(1, len + 1);

if (!buffer)
return false;
Expand Down Expand Up @@ -91,8 +105,31 @@ fifo_buffer_t *fifo_new(size_t len)

void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len)
{
size_t first_write = len;
size_t first_write;
size_t rest_write = 0;
size_t avail;

/* Cap @len at the available space. Existing callers all
* gate on FIFO_WRITE_AVAIL before invoking us, so this is
* a no-op for them; for any caller that doesn't, the
* unbounded branch below would walk off the end of
* @buffer->buffer (the wrap-around copy at line `memcpy(
* buffer->buffer, ..., rest_write)` would write up to
* len - first_write bytes into a buffer of @buffer->size
* total, overrunning by len - size). Worse, the original
* `buffer->end + len > buffer->size` test wraps in size_t
* for huge @len and silently misclassifies the request as
* "fits in one chunk", taking the corrupting first memcpy
* down a path with no wrap-around bound at all. Capping
* here closes both windows. */
avail = FIFO_WRITE_AVAIL(buffer);
if (len > avail)
len = avail;

if (!len)
return;

first_write = len;

if (buffer->end + len > buffer->size)
{
Expand All @@ -109,8 +146,22 @@ void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len)

void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len)
{
size_t first_read = len;
size_t first_read;
size_t rest_read = 0;
size_t avail;

/* Same rationale as fifo_write: cap @len at what's actually
* available to avoid out-of-buffer copies on a caller that
* forgot to gate on FIFO_READ_AVAIL. Existing callers all
* gate first; this is defensive. */
avail = FIFO_READ_AVAIL(buffer);
if (len > avail)
len = avail;

if (!len)
return;

first_read = len;

if (buffer->first + len > buffer->size)
{
Expand Down
11 changes: 9 additions & 2 deletions libretro-common/rthreads/tpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,15 @@ void tpool_wait(tpool_t *tp)
{
/* working_cond is dual use. It signals when we're not stopping but the
* working_cnt is 0 indicating there isn't any work processing. If we
* are stopping it will trigger when there aren't any threads running. */
if ((!tp->stop && tp->working_cnt != 0) || (tp->stop && tp->thread_cnt != 0))
* are stopping it will trigger when there aren't any threads running.
*
* The non-stopping branch must also wait while work_first is non-NULL:
* a tpool_wait racing tpool_add_work would otherwise return before any
* worker has dequeued the just-added work (working_cnt still 0). The
* worker's completion path signals working_cond only when both
* working_cnt == 0 and work_first == NULL, so this predicate matches
* the signal exactly. */
if ((!tp->stop && (tp->work_first || tp->working_cnt != 0)) || (tp->stop && tp->thread_cnt != 0))
scond_wait(tp->working_cond, tp->work_mutex);
else
break;
Expand Down
29 changes: 29 additions & 0 deletions libretro-common/samples/queues/fifo_queue_bounds_test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
TARGET := fifo_queue_bounds_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
fifo_queue_bounds_test.c \
$(LIBRETRO_COMM_DIR)/queues/fifo_queue.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -O0 -I$(LIBRETRO_COMM_DIR)/include

ifneq ($(SANITIZER),)
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
endif

all: $(TARGET)

%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)

clean:
rm -f $(TARGET) $(OBJS)

.PHONY: clean
Loading
Loading