rmagick 7.1.7 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,13 +2,15 @@
2
2
  #define _RMAGICK_GVL_H_
3
3
 
4
4
  #include "ruby/thread.h"
5
+ #include "ruby/fiber/scheduler.h"
5
6
 
6
7
  typedef void *(gvl_function_t)(void *);
7
8
 
8
9
  #define GVL_FUNC(name) name##_gvl
9
10
  #define GVL_STRUCT_TYPE(name) name##_args_t
10
- #define CALL_FUNC_WITHOUT_GVL(fp, args) \
11
- rb_thread_call_without_gvl(fp, args, RUBY_UBF_PROCESS, NULL)
11
+ #if defined(RB_NOGVL_OFFLOAD_SAFE) && defined(HAVE_RB_FIBER_SCHEDULER_BLOCKING_OPERATION_EXTRACT)
12
+ #define RMAGICK_OFFLOAD_SAFE 1
13
+ #endif
12
14
 
13
15
 
14
16
  #define DEFINE_GVL_STRUCT1(name, type1) \
@@ -0,0 +1,100 @@
1
+ #ifndef _RMAGICK_GVL_HPP_
2
+ #define _RMAGICK_GVL_HPP_
3
+
4
+ extern void rm_gvl_init(void);
5
+ extern void rm_gvl_check_readable(const void *);
6
+ extern void rm_gvl_check_writable(const void *);
7
+ extern bool rm_gvl_in_use(const void *);
8
+
9
+ /**
10
+ * A call to an ImageMagick function without the GVL, which a Fiber scheduler
11
+ * with a worker pool may run on a worker thread. Register the Ruby objects the
12
+ * call uses and what the caller releases after it, then call run().
13
+ */
14
+ class rm_gvl_call
15
+ {
16
+ public:
17
+ rm_gvl_call(gvl_function_t *fp, void *args);
18
+
19
+ rm_gvl_call &read(VALUE obj);
20
+ rm_gvl_call &read(const void *ptr);
21
+ rm_gvl_call &update(VALUE obj);
22
+ rm_gvl_call &update(const void *ptr);
23
+ rm_gvl_call &read_each(VALUE ary);
24
+ rm_gvl_call &update_each(VALUE ary);
25
+ rm_gvl_call &release(ExceptionInfo *exception);
26
+ rm_gvl_call &release(ImageInfo *info);
27
+ rm_gvl_call &release(DrawInfo *draw_info);
28
+ rm_gvl_call &release(KernelInfo *kernel);
29
+ rm_gvl_call &destroy(Image *image);
30
+ rm_gvl_call &split(Image *images);
31
+ #if defined(IMAGEMAGICK_7)
32
+ rm_gvl_call &restore_mask(Image *image, ChannelType channel_mask);
33
+ #endif
34
+ rm_gvl_call &free_buffer(void *buffer);
35
+ rm_gvl_call &relinquish(void *memory);
36
+ rm_gvl_call &free_result();
37
+ rm_gvl_call &keep_thread(bool keep = true);
38
+ rm_gvl_call &cleanup(void (*release)(void *, intptr_t), void *ptr, intptr_t arg = 0);
39
+ rm_gvl_call &restore(void (*release)(void *, intptr_t), void *ptr, intptr_t arg = 0, size_t size = 0);
40
+
41
+ template <typename T> T run();
42
+
43
+ private:
44
+ enum ResultType { ResultIgnored, ResultImage, ResultMemory };
45
+ enum { MaxObjects = 4, MaxCleanups = 4 };
46
+
47
+ typedef struct
48
+ {
49
+ VALUE obj;
50
+ const void *ptr;
51
+ bool update;
52
+ bool each;
53
+ } object_t;
54
+
55
+ typedef struct
56
+ {
57
+ void (*release)(void *, intptr_t);
58
+ void *ptr;
59
+ intptr_t arg;
60
+ size_t size;
61
+ bool restore;
62
+ } cleanup_t;
63
+
64
+ gvl_function_t *fp;
65
+ void *args;
66
+ object_t objects[MaxObjects];
67
+ int nobjects;
68
+ cleanup_t cleanups[MaxCleanups];
69
+ int ncleanups;
70
+ ResultType result_type;
71
+ bool keep;
72
+
73
+ rm_gvl_call &add_object(VALUE obj, const void *ptr, bool update, bool each);
74
+ rm_gvl_call &add_cleanup(void (*release)(void *, intptr_t), void *ptr, intptr_t arg, size_t size, bool restore);
75
+ void *call(ResultType type);
76
+ void *call_here(ResultType type);
77
+ void unwind(ResultType type, void *result, bool abandoned = false);
78
+ };
79
+
80
+ template <typename T>
81
+ T
82
+ rm_gvl_call::run()
83
+ {
84
+ return (T)(uintptr_t)call(result_type);
85
+ }
86
+
87
+ template <> Image *rm_gvl_call::run<Image *>();
88
+ template <> void rm_gvl_call::run<void>();
89
+
90
+ //! declare the arguments of the GVL stub of name and an rm_gvl_call named var that calls it
91
+ #define DECLARE_GVL_CALL(var, name, ...) \
92
+ GVL_STRUCT_TYPE(name) var##_args = { __VA_ARGS__ }; \
93
+ rm_gvl_call var(GVL_FUNC(name), &var##_args)
94
+
95
+ //! declare the arguments of type and an rm_gvl_call named var that calls fp with them
96
+ #define DECLARE_GVL_CALL_FP(var, type, fp, ...) \
97
+ GVL_STRUCT_TYPE(type) var##_args = { __VA_ARGS__ }; \
98
+ rm_gvl_call var(fp, &var##_args)
99
+
100
+ #endif
@@ -74,6 +74,28 @@ get_draw(VALUE self)
74
74
  }
75
75
 
76
76
 
77
+ /**
78
+ * Get the Draw struct of a Draw object for a method that changes it.
79
+ *
80
+ * No Ruby usage (internal function)
81
+ *
82
+ * @param self the Draw object
83
+ * @return the initialized Draw struct
84
+ * @throw FrozenError if the Draw object is frozen
85
+ * @throw RuntimeError if an offloaded call is using the Draw object
86
+ */
87
+ static Draw *
88
+ get_writable_draw(VALUE self)
89
+ {
90
+ Draw *draw;
91
+
92
+ rb_check_frozen(self);
93
+ draw = get_draw(self);
94
+ rm_gvl_check_writable(draw);
95
+ return draw;
96
+ }
97
+
98
+
77
99
  /**
78
100
  * Set the affine matrix from an {Magick::AffineMatrix}.
79
101
  *
@@ -85,8 +107,7 @@ Draw_affine_eq(VALUE self, VALUE matrix)
85
107
  {
86
108
  Draw *draw;
87
109
 
88
- rb_check_frozen(self);
89
- draw = get_draw(self);
110
+ draw = get_writable_draw(self);
90
111
  Export_AffineMatrix(&draw->info->affine, matrix);
91
112
  return matrix;
92
113
  }
@@ -103,8 +124,7 @@ Draw_align_eq(VALUE self, VALUE align)
103
124
  {
104
125
  Draw *draw;
105
126
 
106
- rb_check_frozen(self);
107
- draw = get_draw(self);
127
+ draw = get_writable_draw(self);
108
128
  VALUE_TO_ENUM(align, draw->info->align, AlignType);
109
129
  return align;
110
130
  }
@@ -121,8 +141,7 @@ Draw_decorate_eq(VALUE self, VALUE decorate)
121
141
  {
122
142
  Draw *draw;
123
143
 
124
- rb_check_frozen(self);
125
- draw = get_draw(self);
144
+ draw = get_writable_draw(self);
126
145
  VALUE_TO_ENUM(decorate, draw->info->decorate, DecorationType);
127
146
  return decorate;
128
147
  }
@@ -139,8 +158,7 @@ Draw_density_eq(VALUE self, VALUE density)
139
158
  {
140
159
  Draw *draw;
141
160
 
142
- rb_check_frozen(self);
143
- draw = get_draw(self);
161
+ draw = get_writable_draw(self);
144
162
  magick_clone_string(&draw->info->density, StringValueCStr(density));
145
163
 
146
164
  return density;
@@ -158,8 +176,7 @@ Draw_encoding_eq(VALUE self, VALUE encoding)
158
176
  {
159
177
  Draw *draw;
160
178
 
161
- rb_check_frozen(self);
162
- draw = get_draw(self);
179
+ draw = get_writable_draw(self);
163
180
  magick_clone_string(&draw->info->encoding, StringValueCStr(encoding));
164
181
 
165
182
  return encoding;
@@ -177,8 +194,7 @@ Draw_fill_eq(VALUE self, VALUE fill)
177
194
  {
178
195
  Draw *draw;
179
196
 
180
- rb_check_frozen(self);
181
- draw = get_draw(self);
197
+ draw = get_writable_draw(self);
182
198
  Color_to_PixelColor(&draw->info->fill, fill);
183
199
  return fill;
184
200
  }
@@ -198,8 +214,7 @@ Draw_fill_pattern_eq(VALUE self, VALUE pattern)
198
214
  {
199
215
  Draw *draw;
200
216
 
201
- rb_check_frozen(self);
202
- draw = get_draw(self);
217
+ draw = get_writable_draw(self);
203
218
 
204
219
  if (draw->info->fill_pattern != NULL)
205
220
  {
@@ -213,7 +228,7 @@ Draw_fill_pattern_eq(VALUE self, VALUE pattern)
213
228
  Image *image;
214
229
 
215
230
  pattern = rm_cur_image(pattern);
216
- image = rm_check_destroyed(pattern);
231
+ image = rm_check_readable(pattern);
217
232
  // Do not trace creation
218
233
  draw->info->fill_pattern = rm_clone_image(image);
219
234
  }
@@ -233,8 +248,7 @@ Draw_font_eq(VALUE self, VALUE font)
233
248
  {
234
249
  Draw *draw;
235
250
 
236
- rb_check_frozen(self);
237
- draw = get_draw(self);
251
+ draw = get_writable_draw(self);
238
252
  magick_clone_string(&draw->info->font, StringValueCStr(font));
239
253
 
240
254
  return font;
@@ -252,8 +266,7 @@ Draw_font_family_eq(VALUE self, VALUE family)
252
266
  {
253
267
  Draw *draw;
254
268
 
255
- rb_check_frozen(self);
256
- draw = get_draw(self);
269
+ draw = get_writable_draw(self);
257
270
  magick_clone_string(&draw->info->family, StringValueCStr(family));
258
271
 
259
272
  return family;
@@ -271,8 +284,7 @@ Draw_font_stretch_eq(VALUE self, VALUE stretch)
271
284
  {
272
285
  Draw *draw;
273
286
 
274
- rb_check_frozen(self);
275
- draw = get_draw(self);
287
+ draw = get_writable_draw(self);
276
288
  VALUE_TO_ENUM(stretch, draw->info->stretch, StretchType);
277
289
  return stretch;
278
290
  }
@@ -289,8 +301,7 @@ Draw_font_style_eq(VALUE self, VALUE style)
289
301
  {
290
302
  Draw *draw;
291
303
 
292
- rb_check_frozen(self);
293
- draw = get_draw(self);
304
+ draw = get_writable_draw(self);
294
305
  VALUE_TO_ENUM(style, draw->info->style, StyleType);
295
306
  return style;
296
307
  }
@@ -309,8 +320,7 @@ Draw_font_weight_eq(VALUE self, VALUE weight)
309
320
  Draw *draw;
310
321
  size_t w;
311
322
 
312
- rb_check_frozen(self);
313
- draw = get_draw(self);
323
+ draw = get_writable_draw(self);
314
324
 
315
325
  if (FIXNUM_P(weight))
316
326
  {
@@ -375,8 +385,7 @@ Draw_gravity_eq(VALUE self, VALUE grav)
375
385
  {
376
386
  Draw *draw;
377
387
 
378
- rb_check_frozen(self);
379
- draw = get_draw(self);
388
+ draw = get_writable_draw(self);
380
389
  VALUE_TO_ENUM(grav, draw->info->gravity, GravityType);
381
390
 
382
391
  return grav;
@@ -394,8 +403,7 @@ Draw_kerning_eq(VALUE self, VALUE kerning)
394
403
  {
395
404
  Draw *draw;
396
405
 
397
- rb_check_frozen(self);
398
- draw = get_draw(self);
406
+ draw = get_writable_draw(self);
399
407
  draw->info->kerning = NUM2DBL(kerning);
400
408
  return kerning;
401
409
  }
@@ -412,8 +420,7 @@ Draw_interline_spacing_eq(VALUE self, VALUE spacing)
412
420
  {
413
421
  Draw *draw;
414
422
 
415
- rb_check_frozen(self);
416
- draw = get_draw(self);
423
+ draw = get_writable_draw(self);
417
424
  draw->info->interline_spacing = NUM2DBL(spacing);
418
425
  return spacing;
419
426
  }
@@ -430,8 +437,7 @@ Draw_interword_spacing_eq(VALUE self, VALUE spacing)
430
437
  {
431
438
  Draw *draw;
432
439
 
433
- rb_check_frozen(self);
434
- draw = get_draw(self);
440
+ draw = get_writable_draw(self);
435
441
  draw->info->interword_spacing = NUM2DBL(spacing);
436
442
  return spacing;
437
443
  }
@@ -463,8 +469,8 @@ image_to_str(Image *image)
463
469
 
464
470
  info = CloneImageInfo(NULL);
465
471
  exception = AcquireExceptionInfo();
466
- GVL_STRUCT_TYPE(ImageToBlob) args = { info, image, &length, exception };
467
- blob = (unsigned char *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(ImageToBlob), &args);
472
+ DECLARE_GVL_CALL(call, ImageToBlob, info, image, &length, exception);
473
+ blob = call.keep_thread().run<unsigned char *>();
468
474
  DestroyImageInfo(info);
469
475
  CHECK_EXCEPTION();
470
476
  DestroyExceptionInfo(exception);
@@ -504,8 +510,8 @@ Image *str_to_image(VALUE str)
504
510
 
505
511
  info = CloneImageInfo(NULL);
506
512
  exception = AcquireExceptionInfo();
507
- GVL_STRUCT_TYPE(BlobToImage) args = { info, RSTRING_PTR(str), (size_t)RSTRING_LEN(str), exception };
508
- image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(BlobToImage), &args);
513
+ DECLARE_GVL_CALL(call, BlobToImage, info, RSTRING_PTR(str), (size_t)RSTRING_LEN(str), exception);
514
+ image = call.keep_thread().run<Image *>();
509
515
  DestroyImageInfo(info);
510
516
  CHECK_EXCEPTION();
511
517
  DestroyExceptionInfo(exception);
@@ -668,8 +674,7 @@ Draw_pointsize_eq(VALUE self, VALUE pointsize)
668
674
  {
669
675
  Draw *draw;
670
676
 
671
- rb_check_frozen(self);
672
- draw = get_draw(self);
677
+ draw = get_writable_draw(self);
673
678
  draw->info->pointsize = NUM2DBL(pointsize);
674
679
  return pointsize;
675
680
  }
@@ -688,8 +693,7 @@ Draw_rotation_eq(VALUE self, VALUE deg)
688
693
  double degrees;
689
694
  AffineMatrix affine, current;
690
695
 
691
- rb_check_frozen(self);
692
- draw = get_draw(self);
696
+ draw = get_writable_draw(self);
693
697
 
694
698
  degrees = NUM2DBL(deg);
695
699
  if (fabs(degrees) > DBL_EPSILON)
@@ -724,8 +728,7 @@ Draw_stroke_eq(VALUE self, VALUE stroke)
724
728
  {
725
729
  Draw *draw;
726
730
 
727
- rb_check_frozen(self);
728
- draw = get_draw(self);
731
+ draw = get_writable_draw(self);
729
732
  Color_to_PixelColor(&draw->info->stroke, stroke);
730
733
  return stroke;
731
734
  }
@@ -744,8 +747,7 @@ Draw_stroke_pattern_eq(VALUE self, VALUE pattern)
744
747
  {
745
748
  Draw *draw;
746
749
 
747
- rb_check_frozen(self);
748
- draw = get_draw(self);
750
+ draw = get_writable_draw(self);
749
751
 
750
752
  if (draw->info->stroke_pattern != NULL)
751
753
  {
@@ -760,7 +762,7 @@ Draw_stroke_pattern_eq(VALUE self, VALUE pattern)
760
762
 
761
763
  // DestroyDrawInfo destroys the clone
762
764
  pattern = rm_cur_image(pattern);
763
- image = rm_check_destroyed(pattern);
765
+ image = rm_check_readable(pattern);
764
766
  // Do not trace creation
765
767
  draw->info->stroke_pattern = rm_clone_image(image);
766
768
  }
@@ -780,8 +782,7 @@ Draw_stroke_width_eq(VALUE self, VALUE stroke_width)
780
782
  {
781
783
  Draw *draw;
782
784
 
783
- rb_check_frozen(self);
784
- draw = get_draw(self);
785
+ draw = get_writable_draw(self);
785
786
  draw->info->stroke_width = NUM2DBL(stroke_width);
786
787
  return stroke_width;
787
788
  }
@@ -798,8 +799,7 @@ Draw_text_antialias_eq(VALUE self, VALUE text_antialias)
798
799
  {
799
800
  Draw *draw;
800
801
 
801
- rb_check_frozen(self);
802
- draw = get_draw(self);
802
+ draw = get_writable_draw(self);
803
803
  draw->info->text_antialias = (MagickBooleanType) RTEST(text_antialias);
804
804
  return text_antialias;
805
805
  }
@@ -829,8 +829,7 @@ Draw_undercolor_eq(VALUE self, VALUE undercolor)
829
829
  {
830
830
  Draw *draw;
831
831
 
832
- rb_check_frozen(self);
833
- draw = get_draw(self);
832
+ draw = get_writable_draw(self);
834
833
  Color_to_PixelColor(&draw->info->undercolor, undercolor);
835
834
  return undercolor;
836
835
  }
@@ -868,9 +867,12 @@ annotate_ensure(VALUE arg)
868
867
  struct Draw_annotate_args *annotate = (struct Draw_annotate_args *)arg;
869
868
  Draw *draw = annotate->draw;
870
869
 
871
- magick_free(draw->info->text);
872
- draw->info->text = NULL;
873
- draw->info->affine = annotate->keep;
870
+ if (!rm_gvl_in_use(draw))
871
+ {
872
+ magick_free(draw->info->text);
873
+ draw->info->text = NULL;
874
+ draw->info->affine = annotate->keep;
875
+ }
874
876
 
875
877
  #if defined(IMAGEMAGICK_7)
876
878
  if (annotate->exception)
@@ -930,23 +932,24 @@ annotate_body(VALUE arg)
930
932
  snprintf(geometry_str, sizeof(geometry_str), "%lux%lu%+ld%+ld", width, height, x, y);
931
933
  }
932
934
 
933
- magick_clone_string(&draw->info->geometry, geometry_str);
934
-
935
935
  // Store in Draw structure. The text is drawn as given: it is not run
936
936
  // through InterpretImageProperties(), so a `%[...]` or `%x` escape in it is
937
937
  // not expanded. Everything those escapes provide is available directly from
938
938
  // Ruby -- Image#columns, Image#filename, Image#artifact and so on.
939
939
  embed_text = StringValueCStr(annotate->text);
940
940
  image = rm_check_frozen(annotate->image_arg);
941
+ rm_gvl_check_writable(draw);
942
+
943
+ magick_clone_string(&draw->info->geometry, geometry_str);
941
944
  draw->info->text = ConstantString(embed_text);
942
945
 
943
946
  #if defined(IMAGEMAGICK_7)
944
947
  annotate->exception = AcquireExceptionInfo();
945
- GVL_STRUCT_TYPE(AnnotateImage) args = { image, draw->info, annotate->exception };
948
+ DECLARE_GVL_CALL(call, AnnotateImage, image, draw->info, annotate->exception);
946
949
  #else
947
- GVL_STRUCT_TYPE(AnnotateImage) args = { image, draw->info };
950
+ DECLARE_GVL_CALL(call, AnnotateImage, image, draw->info);
948
951
  #endif
949
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(AnnotateImage), &args);
952
+ call.update(annotate->image_arg).update(annotate->self).run<void>();
950
953
 
951
954
  #if defined(IMAGEMAGICK_7)
952
955
  exception = annotate->exception;
@@ -991,6 +994,7 @@ VALUE Draw_annotate(
991
994
  // Save the affine matrix in case it is modified by
992
995
  // Draw#rotation=
993
996
  annotate.draw = get_draw(self);
997
+ rm_gvl_check_writable(annotate.draw);
994
998
  annotate.keep = annotate.draw->info->affine;
995
999
 
996
1000
  annotate.self = self;
@@ -1057,7 +1061,7 @@ Draw_composite(int argc, VALUE *argv, VALUE self)
1057
1061
 
1058
1062
  // Retrieve the image to composite
1059
1063
  image = rm_cur_image(argv[4]);
1060
- comp_img = rm_check_destroyed(image);
1064
+ comp_img = rm_check_readable(image);
1061
1065
 
1062
1066
  x = NUM2DBL(argv[0]);
1063
1067
  y = NUM2DBL(argv[1]);
@@ -1102,6 +1106,26 @@ Draw_composite(int argc, VALUE *argv, VALUE self)
1102
1106
  }
1103
1107
 
1104
1108
 
1109
+ // Release what Draw#draw and get_type_metrics() set on the DrawInfo for one call
1110
+ static void
1111
+ free_primitive(void *ptr, intptr_t arg ATTRIBUTE_UNUSED)
1112
+ {
1113
+ Draw *draw = (Draw *)ptr;
1114
+
1115
+ magick_free(draw->info->primitive);
1116
+ draw->info->primitive = NULL;
1117
+ }
1118
+
1119
+ static void
1120
+ free_text(void *ptr, intptr_t arg ATTRIBUTE_UNUSED)
1121
+ {
1122
+ Draw *draw = (Draw *)ptr;
1123
+
1124
+ magick_free(draw->info->text);
1125
+ draw->info->text = NULL;
1126
+ }
1127
+
1128
+
1105
1129
  /**
1106
1130
  * Execute the stored drawing primitives on the current image.
1107
1131
  *
@@ -1122,6 +1146,7 @@ Draw_draw(VALUE self, VALUE image_arg)
1122
1146
  image = rm_check_frozen(image_arg);
1123
1147
 
1124
1148
  draw = get_draw(self);
1149
+ rm_gvl_check_writable(draw);
1125
1150
  if (draw->primitives == 0)
1126
1151
  {
1127
1152
  rb_raise(rb_eArgError, "nothing to draw");
@@ -1132,11 +1157,12 @@ Draw_draw(VALUE self, VALUE image_arg)
1132
1157
 
1133
1158
  #if defined(IMAGEMAGICK_7)
1134
1159
  exception = AcquireExceptionInfo();
1135
- GVL_STRUCT_TYPE(DrawImage) args = { image, draw->info, exception };
1160
+ DECLARE_GVL_CALL(call, DrawImage, image, draw->info, exception);
1161
+ call.release(exception);
1136
1162
  #else
1137
- GVL_STRUCT_TYPE(DrawImage) args = { image, draw->info };
1163
+ DECLARE_GVL_CALL(call, DrawImage, image, draw->info);
1138
1164
  #endif
1139
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(DrawImage), &args);
1165
+ call.update(image_arg).update(self).restore(free_primitive, draw).run<void>();
1140
1166
 
1141
1167
  magick_free(draw->info->primitive);
1142
1168
  draw->info->primitive = NULL;
@@ -1576,8 +1602,7 @@ PolaroidOptions_border_color_eq(VALUE self, VALUE border)
1576
1602
  {
1577
1603
  Draw *draw;
1578
1604
 
1579
- rb_check_frozen(self);
1580
- draw = get_draw(self);
1605
+ draw = get_writable_draw(self);
1581
1606
  Color_to_PixelColor(&draw->info->border_color, border);
1582
1607
  return border;
1583
1608
  }
@@ -1669,7 +1694,7 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1669
1694
  break;
1670
1695
  case 2:
1671
1696
  t = rm_cur_image(argv[0]);
1672
- image = rm_check_destroyed(t);
1697
+ image = rm_check_readable(t);
1673
1698
  text_arg = argv[1];
1674
1699
  text = rm_str2cstr(&text_arg, &text_l);
1675
1700
  break; // okay
@@ -1684,16 +1709,22 @@ get_type_metrics(int argc, VALUE *argv, VALUE self, gvl_function_t fp)
1684
1709
  }
1685
1710
 
1686
1711
  draw = get_draw(self);
1712
+ rm_gvl_check_writable(draw);
1687
1713
  // Measured as given: see the comment in Draw_annotate().
1688
1714
  draw->info->text = ConstantString(text);
1689
1715
 
1690
1716
  #if defined(IMAGEMAGICK_7)
1691
1717
  exception = AcquireExceptionInfo();
1692
- GVL_STRUCT_TYPE(get_type_metrics) args = { image, draw->info, &metrics, exception };
1718
+ DECLARE_GVL_CALL_FP(call, get_type_metrics, fp, image, draw->info, &metrics, exception);
1719
+ call.release(exception);
1693
1720
  #else
1694
- GVL_STRUCT_TYPE(get_type_metrics) args = { image, draw->info, &metrics };
1721
+ DECLARE_GVL_CALL_FP(call, get_type_metrics, fp, image, draw->info, &metrics);
1695
1722
  #endif
1696
- void *ret = CALL_FUNC_WITHOUT_GVL(fp, &args);
1723
+ if (argc == 2)
1724
+ {
1725
+ call.read(t);
1726
+ }
1727
+ void *ret = call.update(self).restore(free_text, draw).run<void *>();
1697
1728
  okay = static_cast<MagickBooleanType>(reinterpret_cast<intptr_t &>(ret));
1698
1729
 
1699
1730
  magick_free(draw->info->text);
@@ -191,8 +191,8 @@ point_fill(
191
191
  #endif
192
192
  }
193
193
 
194
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
195
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
194
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
195
+ call.keep_thread().run<void>();
196
196
  CHECK_EXCEPTION();
197
197
  }
198
198
 
@@ -261,8 +261,8 @@ vertical_fill(
261
261
  row_pixels += GetPixelChannels(image);
262
262
  }
263
263
 
264
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
265
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
264
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
265
+ call.keep_thread().run<void>();
266
266
  CHECK_EXCEPTION();
267
267
  }
268
268
 
@@ -295,8 +295,8 @@ vertical_fill(
295
295
 
296
296
  memcpy(row_pixels, master, image->columns * sizeof(PixelPacket));
297
297
 
298
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
299
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
298
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
299
+ call.keep_thread().run<void>();
300
300
  if (rm_should_raise_exception(exception, RetainExceptionRetention))
301
301
  {
302
302
  xfree((void *)master);
@@ -369,8 +369,8 @@ horizontal_fill(
369
369
  row_pixels += GetPixelChannels(image);
370
370
  }
371
371
 
372
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
373
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
372
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
373
+ call.keep_thread().run<void>();
374
374
  CHECK_EXCEPTION();
375
375
  }
376
376
 
@@ -402,8 +402,8 @@ horizontal_fill(
402
402
 
403
403
  memcpy(col_pixels, master, image->rows * sizeof(PixelPacket));
404
404
 
405
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
406
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
405
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
406
+ call.keep_thread().run<void>();
407
407
  if (rm_should_raise_exception(exception, RetainExceptionRetention))
408
408
  {
409
409
  xfree((void *)master);
@@ -514,8 +514,8 @@ v_diagonal_fill(
514
514
  #endif
515
515
  }
516
516
 
517
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
518
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
517
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
518
+ call.keep_thread().run<void>();
519
519
  CHECK_EXCEPTION();
520
520
  }
521
521
 
@@ -621,8 +621,8 @@ h_diagonal_fill(
621
621
  #endif
622
622
  }
623
623
 
624
- GVL_STRUCT_TYPE(SyncAuthenticPixels) args = { image, exception };
625
- CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args);
624
+ DECLARE_GVL_CALL(call, SyncAuthenticPixels, image, exception);
625
+ call.keep_thread().run<void>();
626
626
  CHECK_EXCEPTION();
627
627
  }
628
628
 
@@ -645,7 +645,7 @@ GradientFill_fill(VALUE self, VALUE image_obj)
645
645
  double x1, y1, x2, y2; // points on the line
646
646
 
647
647
  TypedData_Get_Struct(self, rm_GradientFill, &rm_gradient_fill_data_type, fill);
648
- image = rm_check_destroyed(rm_cur_image(image_obj));
648
+ image = rm_check_writable(rm_cur_image(image_obj));
649
649
 
650
650
  x1 = fill->x1;
651
651
  y1 = fill->y1;
@@ -765,7 +765,7 @@ TextureFill_initialize(VALUE self, VALUE texture_arg)
765
765
  texture_image = rm_cur_image(texture_arg);
766
766
 
767
767
  // Bump the reference count on the texture image.
768
- texture = rm_check_destroyed(texture_image);
768
+ texture = rm_check_readable(texture_image);
769
769
  ReferenceImage(texture);
770
770
 
771
771
  fill->texture = texture;
@@ -791,7 +791,7 @@ TextureFill_fill(VALUE self, VALUE image_obj)
791
791
  ExceptionInfo *exception;
792
792
  #endif
793
793
 
794
- image = rm_check_destroyed(rm_cur_image(image_obj));
794
+ image = rm_check_writable(rm_cur_image(image_obj));
795
795
  TypedData_Get_Struct(self, rm_TextureFill, &rm_texture_fill_data_type, fill);
796
796
 
797
797
  #if defined(IMAGEMAGICK_7)