Skip to content

add vips__worker_exit #4601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 11, 2025
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 ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ master
- add dcrawload, dcrawload_source, dcrawload_buffer: load raw camera files
using libraw [lxsameer]
- add magickload_source: load from a source with imagemagick
- add vips__worker_exit(): enables fast threadpool shutdown
- larger mmap windows on 64-bit machines improve random access mode for many
file formats

Expand Down
15 changes: 8 additions & 7 deletions libvips/conversion/subsample.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <stdlib.h>

#include <vips/vips.h>
#include <vips/internal.h>

#include "pconversion.h"

Expand Down Expand Up @@ -102,7 +103,10 @@ vips_subsample_line_gen(VipsRegion *out_region,
VipsPel *q = VIPS_REGION_ADDR(out_region, le, y);
VipsPel *p;

/* Loop across the region, in owidth sized pieces.
if (vips__worker_exit())
return 0;

/* Loop across the region, in owidth-sized pieces.
*/
for (x = le; x < ri; x += owidth) {
/* How many pixels do we make this time?
Expand Down Expand Up @@ -165,20 +169,17 @@ vips_subsample_point_gen(VipsRegion *out_region,
VipsPel *q = VIPS_REGION_ADDR(out_region, le, y);
VipsPel *p;

/* Loop across the region, in owidth sized pieces.
*/
if (vips__worker_exit())
return 0;

for (x = le; x < ri; x++) {
/* Ask for input.
*/
s.left = x * subsample->xfac;
s.top = y * subsample->yfac;
s.width = 1;
s.height = 1;
if (vips_region_prepare(ir, &s))
return -1;

/* Append new pels to output.
*/
p = VIPS_REGION_ADDR(ir, s.left, s.top);
for (k = 0; k < ps; k++)
q[k] = p[k];
Expand Down
1 change: 1 addition & 0 deletions libvips/include/vips/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ void vips_threadset_free(VipsThreadset *set);

VIPS_API void vips__worker_lock(GMutex *mutex);
VIPS_API void vips__worker_cond_wait(GCond *cond, GMutex *mutex);
gboolean vips__worker_exit(void);

void vips__cache_init(void);

Expand Down
1 change: 0 additions & 1 deletion libvips/include/vips/threadpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ typedef struct _VipsThreadState {
* debugging race conditions.
*/
gboolean stall;

} VipsThreadState;

typedef struct _VipsThreadStateClass {
Expand Down
49 changes: 39 additions & 10 deletions libvips/iofuncs/sinkscreen.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/* asynchronous screen sink
*
* 1/1/10
Expand Down Expand Up @@ -115,10 +115,10 @@

/* Parameters.
*/
VipsImage *in; /* Image we render */
VipsImage *out; /* Write tiles here on demand */
VipsImage *mask; /* Set valid pixels here */
int tile_width; /* Tile size */
VipsImage *in; /* Image we render */
VipsImage *out; /* Write tiles here on demand */
VipsImage *mask; /* Set valid pixels here */
int tile_width; /* Tile size */
int tile_height;
int max_tiles; /* Maximum number of tiles */
int priority; /* Larger numbers done sooner */
Expand All @@ -139,9 +139,9 @@

/* Tile cache.
*/
GSList *all; /* All our tiles */
int ntiles; /* Number of tiles */
int ticks; /* Inc. on each access ... used for LRU */
GSList *all; /* All our tiles */
int ntiles; /* Number of tiles */
int ticks; /* Inc. on each access ... used for LRU */

/* List of dirty tiles. Most recent at the front.
*/
Expand Down Expand Up @@ -194,6 +194,18 @@
*/
static gboolean render_reschedule = FALSE;

/* Set this GPrivate to link a thread back to its Render struct.
*/
static GPrivate render_worker_key;

gboolean
vips__worker_exit(void)
{
Render *render = (Render *) g_private_get(&render_worker_key);

return render && render->shutdown;
}

static void
render_thread_state_class_init(RenderThreadStateClass *class)
{
Expand Down Expand Up @@ -269,6 +281,7 @@

#ifdef VIPS_DEBUG_AMBER
render_num_renders -= 1;
printf("%d active renders\n", render_num_renders);
#endif /*VIPS_DEBUG_AMBER*/

return 0;
Expand All @@ -295,7 +308,7 @@
static int
render_unref(Render *render)
{
int kill;
gboolean kill;

#if GLIB_CHECK_VERSION(2, 58, 0)
g_assert(!g_atomic_ref_count_compare(&render->ref_count, 0));
Expand Down Expand Up @@ -426,10 +439,16 @@
VIPS_DEBUG_MSG("calculating tile %p %dx%d\n",
tile, tile->area.left, tile->area.top);

/* vips__worker_exit() uses this to find the render to check for
* shutdown.
*/
g_private_set(&render_worker_key, render);

if (vips_region_prepare_to(state->reg, tile->region,
&tile->area, tile->area.left, tile->area.top)) {
VIPS_DEBUG_MSG_RED("render_work: vips_region_prepare_to() failed: %s\n",
vips_error_buffer());
g_private_set(&render_worker_key, NULL);
return -1;
}
tile->painted = TRUE;
Expand All @@ -438,6 +457,8 @@
render->notify)
render->notify(render->out, &tile->area, render->a);

g_private_set(&render_worker_key, NULL);

return 0;
}

Expand Down Expand Up @@ -620,6 +641,7 @@

#ifdef VIPS_DEBUG_AMBER
render_num_renders += 1;
printf("%d active renders\n", render_num_renders);
#endif /*VIPS_DEBUG_AMBER*/

return render;
Expand Down Expand Up @@ -1094,6 +1116,11 @@

Render *render = (Render *) data;

/* vips__worker_exit() uses this to find the render to check for
* shutdown.
*/
g_private_set(&render_worker_key, render);

// this will quit on ->shutdown == TRUE
if (vips_threadpool_run(render->in,
render_thread_state_new,
Expand All @@ -1103,6 +1130,8 @@
render))
VIPS_DEBUG_MSG_RED("render_work_private: threadpool_run failed\n");

g_private_set(&render_worker_key, NULL);

render_unref(render);

VIPS_DEBUG_MSG_AMBER("render_work_private: stop\n");
Expand Down Expand Up @@ -1144,11 +1173,11 @@
* uchar image and has 255 for pixels which are currently in cache and 0
* for uncalculated pixels.
*
* Renders with a positive priority are assumed to be large, gh-priority,
* Renders with a positive priority are assumed to be large, high-priority,
* foreground images. Although there can be many of these, only one is ever
* active, to avoid overcommitting threads.
*
* Renders with a negative priority are assumed to be small, thumbnail images
* Renders with a negative priority are assumed to be small, thumbnail images,
* consisting of a single tile. Single tile images are effectively
* single-threaded, so all these renders are evaluated together.
*
Expand Down
8 changes: 0 additions & 8 deletions libvips/iofuncs/threadpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,6 @@ vips_thread_main_loop(void *a, void *b)
VipsWorker *worker = (VipsWorker *) a;
VipsThreadpool *pool = worker->pool;

g_assert(pool == worker->pool);

VIPS_GATE_START("vips_thread_main_loop: thread");

g_private_set(&worker_key, worker);
Expand Down Expand Up @@ -481,9 +479,6 @@ vips_threadpool_wait(VipsThreadpool *pool)
static void
vips_threadpool_free(VipsThreadpool *pool)
{
VIPS_DEBUG_MSG("vips_threadpool_free: \"%s\" (%p)\n",
pool->im->filename, pool);

vips_threadpool_wait(pool);

g_mutex_clear(&pool->allocate_lock);
Expand Down Expand Up @@ -532,9 +527,6 @@ vips_threadpool_new(VipsImage *im)
*/
pool->max_workers = vips_image_get_concurrency(im, pool->max_workers);

VIPS_DEBUG_MSG("vips_threadpool_new: \"%s\" (%p), with %d threads\n",
im->filename, pool, pool->max_workers);

return pool;
}

Expand Down
Loading