Skip to content
Draft
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
3 changes: 2 additions & 1 deletion src/bz-application.c
Original file line number Diff line number Diff line change
Expand Up @@ -1472,7 +1472,8 @@ enumerate_disk_entries_fiber (GWeakRef *wr)
io_data->cache = g_object_ref (self->cache);

entries = dex_await_boxed (
dex_scheduler_spawn (
dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) enumerate_disk_io_fiber,
Expand Down
111 changes: 2 additions & 109 deletions src/bz-async-texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

#define G_LOG_DOMAIN "BAZAAR::ASYNC-TEXTURE"

#define MAX_CONCURRENT_IO 8
#define MAX_CONCURRENT_GLYCIN 32
#define CACHE_INVALID_AGE (G_TIME_SPAN_DAY * 1)
#define HTTP_TIMEOUT_SECONDS 5
#define MAX_LOAD_RETRIES 3
Expand Down Expand Up @@ -565,7 +563,8 @@ maybe_load (BzAsyncTexture *self)
data->retries = self->retries;
g_weak_ref_init (&data->self, self);

future = dex_scheduler_spawn (
future = dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) load_fiber_work,
Expand All @@ -580,18 +579,6 @@ maybe_load (BzAsyncTexture *self)
static DexFuture *
load_fiber_work (LoadData *data)
{
static GMutex queueing_mutex = { 0 };

static guint concurrent_io = MAX_CONCURRENT_IO;
static guint io_queued[MAX_CONCURRENT_IO] = { 0 };
static BzGuard *io_gates[MAX_CONCURRENT_IO] = { 0 };
static GMutex io_mutexes[MAX_CONCURRENT_IO] = { 0 };

static guint concurrent_glycin = 0;
static guint glycin_queued[MAX_CONCURRENT_GLYCIN] = { 0 };
static BzGuard *glycin_gates[MAX_CONCURRENT_GLYCIN] = { 0 };
static GMutex glycin_mutexes[MAX_CONCURRENT_GLYCIN] = { 0 };

GFile *source = data->source;
char *source_uri = data->source_uri;
GFile *cache_into = data->cache_into;
Expand All @@ -601,77 +588,13 @@ load_fiber_work (LoadData *data)
g_autoptr (GError) local_error = NULL;
g_autoptr (GMutexLocker) locker = NULL;
g_autoptr (BzGuard) slot_guard = NULL;
guint slot_queued = G_MAXUINT;
gboolean is_http = FALSE;
g_autoptr (GDateTime) now = NULL;
g_autofree char *async_tex_data_path = NULL;
g_autoptr (GFile) async_tex_data_file = NULL;
g_autoptr (GdkTexture) texture = NULL;
g_autoptr (GlyFrame) frame = NULL;

locker = g_mutex_locker_new (&queueing_mutex);
if (concurrent_glycin == 0)
{
/* Ensure we don't overload the system with work; aim for # of logical
processors divided by 2

See:
https://github.com/bazaar-org/bazaar/issues/497
https://docs.gtk.org/glib/func.get_num_processors.html

Eva Thu, 23 Oct 2025 14:19:44 -0700
*/
concurrent_glycin = MIN (
MAX_CONCURRENT_GLYCIN,
MAX (1, g_get_num_processors () / 2));

g_debug ("Allowing %d concurrent texture glycin", concurrent_glycin);
}
g_clear_pointer (&locker, g_mutex_locker_free);

#define FIND_LOCK(name, _idx) \
G_STMT_START \
{ \
locker = g_mutex_locker_new (&queueing_mutex); \
\
for (guint i = 0; i < concurrent_##name; i++) \
{ \
if (name##_queued[i] < slot_queued) \
{ \
slot_queued = name##_queued[i]; \
(_idx) = i; \
} \
} \
\
name##_queued[(_idx)]++; \
g_clear_pointer (&locker, g_mutex_locker_free); \
} \
G_STMT_END

#define FINISH_LOCK(name, _idx) \
G_STMT_START \
{ \
locker = g_mutex_locker_new (&queueing_mutex); \
name##_queued[(_idx)]--; \
g_clear_pointer (&locker, g_mutex_locker_free); \
} \
G_STMT_END

#define RATE_LIMIT_BEGIN(name) \
G_STMT_START \
{ \
guint _slot_index = 0; \
\
FIND_LOCK (name, _slot_index); \
BZ_BEGIN_GUARD_WITH_CONTEXT (&slot_guard, \
&name##_mutexes[_slot_index], \
&name##_gates[_slot_index]); \
FINISH_LOCK (name, _slot_index); \
} \
G_STMT_END

#define RATE_LIMIT_END() bz_clear_guard (&slot_guard)

is_http = g_str_has_prefix (source_uri, "http");
now = g_date_time_new_now_utc ();
if (cache_into != NULL)
Expand All @@ -682,8 +605,6 @@ load_fiber_work (LoadData *data)

if (cache_into != NULL)
{
RATE_LIMIT_BEGIN (io);

if (g_file_query_exists (cache_into, NULL) &&
g_file_query_exists (async_tex_data_file, NULL))
{
Expand Down Expand Up @@ -717,9 +638,6 @@ load_fiber_work (LoadData *data)
{
if (age_span < CACHE_INVALID_AGE)
{
RATE_LIMIT_END ();
RATE_LIMIT_BEGIN (glycin);

loader = gly_loader_new (cache_into);
/* We assume we exported this file, so uhhh it is safe to
not use sandboxing, since it is faster :-) */
Expand All @@ -728,9 +646,6 @@ load_fiber_work (LoadData *data)
image = gly_loader_load (loader, &local_error);
if (image != NULL)
frame = gly_image_next_frame (image, &local_error);

RATE_LIMIT_END ();
RATE_LIMIT_BEGIN (io);
}
else
g_debug ("Metadata file %s for cached texture at %s indicates this resource is too old (GTimeSpan: %zu), "
Expand Down Expand Up @@ -763,8 +678,6 @@ load_fiber_work (LoadData *data)
}
}
}

RATE_LIMIT_END ();
}

if (frame == NULL)
Expand All @@ -780,8 +693,6 @@ load_fiber_work (LoadData *data)

parent = g_file_get_parent (cache_into);

RATE_LIMIT_BEGIN (io);

if (g_file_query_exists (parent, NULL))
{
GFileType parent_type = G_FILE_TYPE_UNKNOWN;
Expand Down Expand Up @@ -811,8 +722,6 @@ load_fiber_work (LoadData *data)
return dex_future_new_for_error (g_steal_pointer (&local_error));
}
}

RATE_LIMIT_END ();
}

if (is_http)
Expand All @@ -825,16 +734,12 @@ load_fiber_work (LoadData *data)
g_autofree char *tmpl = NULL;
g_autoptr (GFileIOStream) io = NULL;

RATE_LIMIT_BEGIN (io);

basename = g_file_get_basename (source);
tmpl = g_strdup_printf ("XXXXXX-%s", basename);
load_file = g_file_new_tmp (tmpl, &io, &local_error);
if (load_file == NULL)
return dex_future_new_for_error (g_steal_pointer (&local_error));
g_io_stream_close (G_IO_STREAM (io), NULL, NULL);

RATE_LIMIT_END ();
}

result = dex_await (
Expand All @@ -853,25 +758,19 @@ load_fiber_work (LoadData *data)
{
if (cache_into != NULL)
{
RATE_LIMIT_BEGIN (io);

result = g_file_copy (
source, cache_into,
G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA,
cancellable, NULL, NULL, &local_error);
if (!result)
return dex_future_new_for_error (g_steal_pointer (&local_error));

RATE_LIMIT_END ();

load_file = g_object_ref (cache_into);
}
else
load_file = g_object_ref (source);
}

RATE_LIMIT_BEGIN (glycin);

loader = gly_loader_new (load_file);
#ifdef SANDBOXED_LIBFLATPAK
gly_loader_set_sandbox_selector (loader, GLY_SANDBOX_SELECTOR_NOT_SANDBOXED);
Expand All @@ -888,8 +787,6 @@ load_fiber_work (LoadData *data)
if (frame == NULL)
return dex_future_new_for_error (g_steal_pointer (&local_error));

RATE_LIMIT_END ();

if (async_tex_data_file != NULL)
{
g_autoptr (GVariantBuilder) builder = NULL;
Expand All @@ -907,8 +804,6 @@ load_fiber_work (LoadData *data)
variant = g_variant_builder_end (builder);
bytes = g_variant_get_data_as_bytes (variant);

RATE_LIMIT_BEGIN (io);

output = g_file_replace (
async_tex_data_file,
NULL,
Expand All @@ -925,8 +820,6 @@ load_fiber_work (LoadData *data)
g_output_stream_close (G_OUTPUT_STREAM (output), NULL, &local_error);
}

RATE_LIMIT_END ();

if (local_error != NULL)
g_warning ("Failed to write async-tex cache metadata to %s ;"
"The image will be fully reloaded next time: %s",
Expand Down
6 changes: 4 additions & 2 deletions src/bz-content-provider.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,8 @@ input_files_changed (BzContentProvider *self,
init_data = input_init_data_new ();
init_data->file = g_object_ref (additions[i]);

future = dex_scheduler_spawn (
future = dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) input_init_fiber,
Expand Down Expand Up @@ -616,7 +617,8 @@ commence_reload (InputTrackingData *data)
load_data->file = g_file_new_for_path (data->path);
load_data->parser = g_object_ref (self->parser);

future = dex_scheduler_spawn (
future = dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) input_load_fiber,
Expand Down
29 changes: 23 additions & 6 deletions src/bz-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ bz_get_io_scheduler (void)
return scheduler;
}

DexLimiter *
bz_get_io_limiter (void)
{
static DexLimiter *limiter = NULL;

if (g_once_init_enter_pointer (&limiter))
g_once_init_leave_pointer (&limiter, dex_limiter_new (16));

return limiter;
}

void
bz_reap_file (GFile *file)
{
Expand Down Expand Up @@ -220,7 +231,8 @@ DexFuture *
bz_reap_file_dex (GFile *file)
{
dex_return_error_if_fail (G_IS_FILE (file));
return dex_scheduler_spawn (
return dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) reap_file_fiber,
Expand All @@ -231,7 +243,8 @@ DexFuture *
bz_reap_path_dex (const char *path)
{
dex_return_error_if_fail (path != NULL);
return dex_scheduler_spawn (
return dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) reap_path_fiber,
Expand All @@ -242,7 +255,8 @@ DexFuture *
bz_reap_user_data_dex (const char *app_id)
{
dex_return_error_if_fail (app_id != NULL);
return dex_scheduler_spawn (
return dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) reap_user_data_fiber,
Expand All @@ -253,7 +267,8 @@ DexFuture *
bz_reap_user_cache_dex (const char *app_id)
{
dex_return_error_if_fail (app_id != NULL);
return dex_scheduler_spawn (
return dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) reap_user_cache_fiber,
Expand All @@ -264,7 +279,8 @@ DexFuture *
bz_get_user_sizes_dex (const char *app_id)
{
dex_return_error_if_fail (app_id != NULL);
return dex_scheduler_spawn (
return dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) get_user_sizes_fiber,
Expand All @@ -274,7 +290,8 @@ bz_get_user_sizes_dex (const char *app_id)
DexFuture *
bz_get_user_data_ids_dex (void)
{
return dex_scheduler_spawn (
return dex_limiter_run (
bz_get_io_limiter (),
bz_get_io_scheduler (),
bz_get_dex_stack_size (),
(DexFiberFunc) get_all_user_data_ids_fiber,
Expand Down
3 changes: 3 additions & 0 deletions src/bz-io.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ bz_dup_user_cache_path (const char *app_id);
DexScheduler *
bz_get_io_scheduler (void);

DexLimiter *
bz_get_io_limiter (void);

void
bz_reap_file (GFile *file);

Expand Down
2 changes: 1 addition & 1 deletion src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ xmllint = find_program('xmllint', required: true)

gtk_dep = dependency('gtk4', version: '>= 4.22.1')
libadwaita_dep = dependency('libadwaita-1', version: '>= 1.8')
libdex_dep = dependency('libdex-1', version: '>= 1.0.0')
libdex_dep = dependency('libdex-1', version: '>= 1.2')
flatpak_dep = dependency('flatpak', version: '>= 1.9')
appstream_dep = dependency('appstream', version: '>= 1.0')
xmlb_dep = dependency('xmlb', version: '>= 0.3.4')
Expand Down
1 change: 1 addition & 0 deletions subprojects/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
libdex/
Empty file added subprojects/.wraplock
Empty file.
10 changes: 10 additions & 0 deletions subprojects/libdex.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[wrap-git]
directory=libdex
url=https://gitlab.gnome.org/GNOME/libdex.git
push-url=ssh://git@ssh.gitlab.gnome.org:GNOME/libdex.git
revision=1.2.alpha
depth=1

[provide]
dependency_names=libdex-1
libdex-1=libdex_dep
Loading