Skip to content

Commit e1c2bf9

Browse files
authored
Merge branch 'master' into pdfload-add-page-box
2 parents e6622ee + cc5e049 commit e1c2bf9

File tree

11 files changed

+95
-85
lines changed

11 files changed

+95
-85
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ master
44
using libraw [lxsameer]
55
- add magickload_source: load from a source with imagemagick
66
- pdfload: control region to be rendered via `page_box` [lovell]
7+
- add vips__worker_exit(): enables fast threadpool shutdown
8+
- larger mmap windows on 64-bit machines improve random access mode for many
9+
file formats
710

811
7/7/25 8.17.1
912

libvips/conversion/subsample.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include <stdlib.h>
5454

5555
#include <vips/vips.h>
56+
#include <vips/internal.h>
5657

5758
#include "pconversion.h"
5859

@@ -102,7 +103,10 @@ vips_subsample_line_gen(VipsRegion *out_region,
102103
VipsPel *q = VIPS_REGION_ADDR(out_region, le, y);
103104
VipsPel *p;
104105

105-
/* Loop across the region, in owidth sized pieces.
106+
if (vips__worker_exit())
107+
return 0;
108+
109+
/* Loop across the region, in owidth-sized pieces.
106110
*/
107111
for (x = le; x < ri; x += owidth) {
108112
/* How many pixels do we make this time?
@@ -165,20 +169,17 @@ vips_subsample_point_gen(VipsRegion *out_region,
165169
VipsPel *q = VIPS_REGION_ADDR(out_region, le, y);
166170
VipsPel *p;
167171

168-
/* Loop across the region, in owidth sized pieces.
169-
*/
172+
if (vips__worker_exit())
173+
return 0;
174+
170175
for (x = le; x < ri; x++) {
171-
/* Ask for input.
172-
*/
173176
s.left = x * subsample->xfac;
174177
s.top = y * subsample->yfac;
175178
s.width = 1;
176179
s.height = 1;
177180
if (vips_region_prepare(ir, &s))
178181
return -1;
179182

180-
/* Append new pels to output.
181-
*/
182183
p = VIPS_REGION_ADDR(ir, s.left, s.top);
183184
for (k = 0; k < ps; k++)
184185
q[k] = p[k];

libvips/foreign/foreign.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -357,19 +357,19 @@ static GQuark vips__foreign_load_operation = 0;
357357
*
358358
* Some hints about the image loader.
359359
*
360-
* [flags@Vips.ForeignFlags.PARTIAL] means that the image can be read directly from the
361-
* file without needing to be unpacked to a temporary image first.
360+
* [flags@Vips.ForeignFlags.PARTIAL] means that the image can be read directly
361+
* from the file without needing to be unpacked to a temporary image first.
362362
*
363-
* [flags@Vips.ForeignFlags.SEQUENTIAL] means that the loader supports lazy reading, but
364-
* only top-to-bottom (sequential) access. Formats like PNG can read sets of
365-
* scanlines, for example, but only in order.
363+
* [flags@Vips.ForeignFlags.SEQUENTIAL] means that the loader supports lazy
364+
* reading, but only top-to-bottom (sequential) access. Formats like PNG can
365+
* read sets of scanlines, for example, but only in order.
366366
*
367367
* If neither PARTIAL or SEQUENTIAL is set, the loader only supports whole
368368
* image read. Setting both PARTIAL and SEQUENTIAL is an error.
369369
*
370-
* [flags@Vips.ForeignFlags.BIGENDIAN] means that image pixels are most-significant byte
371-
* first. Depending on the native byte order of the host machine, you may
372-
* need to swap bytes. See [method@Image.copy].
370+
* [flags@Vips.ForeignFlags.BIGENDIAN] means that image pixels are
371+
* most-significant byte first. Depending on the native byte order of the
372+
* host machine, you may need to swap bytes. See [method@Image.copy].
373373
*/
374374

375375
G_DEFINE_ABSTRACT_TYPE(VipsForeign, vips_foreign, VIPS_TYPE_OPERATION);

libvips/include/vips/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ void vips_threadset_free(VipsThreadset *set);
166166

167167
VIPS_API void vips__worker_lock(GMutex *mutex);
168168
VIPS_API void vips__worker_cond_wait(GCond *cond, GMutex *mutex);
169+
gboolean vips__worker_exit(void);
169170

170171
void vips__cache_init(void);
171172

libvips/include/vips/private.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,6 @@ extern "C" {
4444

4545
#define VIPS_SPARE (8)
4646

47-
/* Private to iofuncs: the minimum number of scanlines we add above and below
48-
* the window as a margin for slop.
49-
*/
50-
#define VIPS__WINDOW_MARGIN_PIXELS (128)
51-
52-
/* Private to iofuncs: add at least this many bytes above and below the window.
53-
* There's no point mapping just a few KB of a small image.
54-
*/
55-
#define VIPS__WINDOW_MARGIN_BYTES (1024 * 1024 * 10)
56-
5747
/* sizeof() a VIPS header on disc.
5848
*/
5949
#define VIPS_SIZEOF_HEADER (64)

libvips/include/vips/threadpool.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ typedef struct _VipsThreadState {
9696
* debugging race conditions.
9797
*/
9898
gboolean stall;
99-
10099
} VipsThreadState;
101100

102101
typedef struct _VipsThreadStateClass {

libvips/iofuncs/image.c

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,6 @@ vips_image_build(VipsObject *object)
832832
*/
833833
switch (mode[0]) {
834834
case 'v':
835-
/* Used by 'r' for native open of vips, see below. Also by
836-
* vips_image_rewind_output().
837-
*/
838835
if (vips_image_open_input(image))
839836
return -1;
840837

@@ -857,8 +854,7 @@ vips_image_build(VipsObject *object)
857854
/* Open the image in t, then byteswap to this
858855
* image.
859856
*/
860-
if (!(t = vips_image_new_mode(filename,
861-
"v")))
857+
if (!(t = vips_image_new_mode(filename, "v")))
862858
return -1;
863859

864860
if (vips_byteswap(t, &t2, NULL)) {
@@ -918,9 +914,8 @@ vips_image_build(VipsObject *object)
918914
image->dtype = VIPS_IMAGE_OPENOUT;
919915
else {
920916
image->dtype = VIPS_IMAGE_PARTIAL;
921-
g_signal_connect(image, "written",
922-
G_CALLBACK(vips_image_save_cb),
923-
NULL);
917+
g_signal_connect(image,
918+
"written", G_CALLBACK(vips_image_save_cb), NULL);
924919
}
925920
} break;
926921

@@ -958,17 +953,15 @@ vips_image_build(VipsObject *object)
958953
image->sizeof_header;
959954
if (image->file_length < sizeof_image) {
960955
vips_error("VipsImage",
961-
_("unable to open \"%s\", file too short"),
962-
image->filename);
956+
_("unable to open \"%s\", file too short"), image->filename);
963957
return -1;
964958
}
965959

966960
/* Just weird. Only print a warning for this, since we should
967961
* still be able to process it without coredumps.
968962
*/
969963
if (image->file_length > sizeof_image)
970-
g_warning("%s is longer than expected",
971-
image->filename);
964+
g_warning("%s is longer than expected", image->filename);
972965
break;
973966

974967
case 'm':
@@ -986,7 +979,6 @@ vips_image_build(VipsObject *object)
986979

987980
default:
988981
vips_error("VipsImage", _("bad mode \"%s\""), mode);
989-
990982
return -1;
991983
}
992984

@@ -1759,8 +1751,8 @@ vips_image_new_mode(const char *filename, const char *mode)
17591751
/**
17601752
* vips_image_new_memory: (skip)
17611753
*
1762-
* [ctor@Image.new_memory] creates a new [class@Image] which, when written to, will
1763-
* create a memory image.
1754+
* [ctor@Image.new_memory] creates a new [class@Image] which, when written to,
1755+
* will create a memory image.
17641756
*
17651757
* ::: seealso
17661758
* [ctor@Image.new].
@@ -3309,8 +3301,7 @@ vips_image_rewind_output(VipsImage *image)
33093301
NULL);
33103302
if (vips_object_build(VIPS_OBJECT(image))) {
33113303
vips_error("VipsImage",
3312-
_("auto-rewind for %s failed"),
3313-
image->filename);
3304+
_("auto-rewind for %s failed"), image->filename);
33143305
return -1;
33153306
}
33163307

@@ -3657,8 +3648,7 @@ vips_image_pio_input(VipsImage *image)
36573648
/* Should have been written to.
36583649
*/
36593650
if (!image->data) {
3660-
vips_error("vips_image_pio_input",
3661-
"%s", _("no image data"));
3651+
vips_error("vips_image_pio_input", "%s", _("no image data"));
36623652
return -1;
36633653
}
36643654

@@ -3683,7 +3673,6 @@ vips_image_pio_input(VipsImage *image)
36833673
break;
36843674

36853675
case VIPS_IMAGE_OPENOUT:
3686-
36873676
/* Free any resources the image holds and reset to a base
36883677
* state.
36893678
*/
@@ -3693,8 +3682,7 @@ vips_image_pio_input(VipsImage *image)
36933682
break;
36943683

36953684
default:
3696-
vips_error("vips_image_pio_input",
3697-
"%s", _("image not readable"));
3685+
vips_error("vips_image_pio_input", "%s", _("image not readable"));
36983686
return -1;
36993687
}
37003688

libvips/iofuncs/sinkscreen.c

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ typedef struct _Render {
115115

116116
/* Parameters.
117117
*/
118-
VipsImage *in; /* Image we render */
119-
VipsImage *out; /* Write tiles here on demand */
120-
VipsImage *mask; /* Set valid pixels here */
121-
int tile_width; /* Tile size */
118+
VipsImage *in; /* Image we render */
119+
VipsImage *out; /* Write tiles here on demand */
120+
VipsImage *mask; /* Set valid pixels here */
121+
int tile_width; /* Tile size */
122122
int tile_height;
123123
int max_tiles; /* Maximum number of tiles */
124124
int priority; /* Larger numbers done sooner */
@@ -139,9 +139,9 @@ typedef struct _Render {
139139

140140
/* Tile cache.
141141
*/
142-
GSList *all; /* All our tiles */
143-
int ntiles; /* Number of tiles */
144-
int ticks; /* Inc. on each access ... used for LRU */
142+
GSList *all; /* All our tiles */
143+
int ntiles; /* Number of tiles */
144+
int ticks; /* Inc. on each access ... used for LRU */
145145

146146
/* List of dirty tiles. Most recent at the front.
147147
*/
@@ -194,6 +194,18 @@ static VipsSemaphore n_render_dirty_sem;
194194
*/
195195
static gboolean render_reschedule = FALSE;
196196

197+
/* Set this GPrivate to link a thread back to its Render struct.
198+
*/
199+
static GPrivate render_worker_key;
200+
201+
gboolean
202+
vips__worker_exit(void)
203+
{
204+
Render *render = (Render *) g_private_get(&render_worker_key);
205+
206+
return render && render->shutdown;
207+
}
208+
197209
static void
198210
render_thread_state_class_init(RenderThreadStateClass *class)
199211
{
@@ -269,6 +281,7 @@ render_free(Render *render)
269281

270282
#ifdef VIPS_DEBUG_AMBER
271283
render_num_renders -= 1;
284+
printf("%d active renders\n", render_num_renders);
272285
#endif /*VIPS_DEBUG_AMBER*/
273286

274287
return 0;
@@ -295,7 +308,7 @@ render_ref(Render *render)
295308
static int
296309
render_unref(Render *render)
297310
{
298-
int kill;
311+
gboolean kill;
299312

300313
#if GLIB_CHECK_VERSION(2, 58, 0)
301314
g_assert(!g_atomic_ref_count_compare(&render->ref_count, 0));
@@ -426,10 +439,16 @@ render_work(VipsThreadState *state, void *a)
426439
VIPS_DEBUG_MSG("calculating tile %p %dx%d\n",
427440
tile, tile->area.left, tile->area.top);
428441

442+
/* vips__worker_exit() uses this to find the render to check for
443+
* shutdown.
444+
*/
445+
g_private_set(&render_worker_key, render);
446+
429447
if (vips_region_prepare_to(state->reg, tile->region,
430448
&tile->area, tile->area.left, tile->area.top)) {
431449
VIPS_DEBUG_MSG_RED("render_work: vips_region_prepare_to() failed: %s\n",
432450
vips_error_buffer());
451+
g_private_set(&render_worker_key, NULL);
433452
return -1;
434453
}
435454
tile->painted = TRUE;
@@ -438,6 +457,8 @@ render_work(VipsThreadState *state, void *a)
438457
render->notify)
439458
render->notify(render->out, &tile->area, render->a);
440459

460+
g_private_set(&render_worker_key, NULL);
461+
441462
return 0;
442463
}
443464

@@ -620,6 +641,7 @@ render_new(VipsImage *in, VipsImage *out, VipsImage *mask,
620641

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

625647
return render;
@@ -1094,6 +1116,11 @@ render_work_private(void *data, void *null)
10941116

10951117
Render *render = (Render *) data;
10961118

1119+
/* vips__worker_exit() uses this to find the render to check for
1120+
* shutdown.
1121+
*/
1122+
g_private_set(&render_worker_key, render);
1123+
10971124
// this will quit on ->shutdown == TRUE
10981125
if (vips_threadpool_run(render->in,
10991126
render_thread_state_new,
@@ -1103,6 +1130,8 @@ render_work_private(void *data, void *null)
11031130
render))
11041131
VIPS_DEBUG_MSG_RED("render_work_private: threadpool_run failed\n");
11051132

1133+
g_private_set(&render_worker_key, NULL);
1134+
11061135
render_unref(render);
11071136

11081137
VIPS_DEBUG_MSG_AMBER("render_work_private: stop\n");
@@ -1144,11 +1173,11 @@ vips__sink_screen_once(void *data)
11441173
* uchar image and has 255 for pixels which are currently in cache and 0
11451174
* for uncalculated pixels.
11461175
*
1147-
* Renders with a positive priority are assumed to be large, gh-priority,
1176+
* Renders with a positive priority are assumed to be large, high-priority,
11481177
* foreground images. Although there can be many of these, only one is ever
11491178
* active, to avoid overcommitting threads.
11501179
*
1151-
* Renders with a negative priority are assumed to be small, thumbnail images
1180+
* Renders with a negative priority are assumed to be small, thumbnail images,
11521181
* consisting of a single tile. Single tile images are effectively
11531182
* single-threaded, so all these renders are evaluated together.
11541183
*

libvips/iofuncs/threadpool.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,6 @@ vips_thread_main_loop(void *a, void *b)
379379
VipsWorker *worker = (VipsWorker *) a;
380380
VipsThreadpool *pool = worker->pool;
381381

382-
g_assert(pool == worker->pool);
383-
384382
VIPS_GATE_START("vips_thread_main_loop: thread");
385383

386384
g_private_set(&worker_key, worker);
@@ -481,9 +479,6 @@ vips_threadpool_wait(VipsThreadpool *pool)
481479
static void
482480
vips_threadpool_free(VipsThreadpool *pool)
483481
{
484-
VIPS_DEBUG_MSG("vips_threadpool_free: \"%s\" (%p)\n",
485-
pool->im->filename, pool);
486-
487482
vips_threadpool_wait(pool);
488483

489484
g_mutex_clear(&pool->allocate_lock);
@@ -532,9 +527,6 @@ vips_threadpool_new(VipsImage *im)
532527
*/
533528
pool->max_workers = vips_image_get_concurrency(im, pool->max_workers);
534529

535-
VIPS_DEBUG_MSG("vips_threadpool_new: \"%s\" (%p), with %d threads\n",
536-
im->filename, pool, pool->max_workers);
537-
538530
return pool;
539531
}
540532

0 commit comments

Comments
 (0)