Codebase list ruby-fxruby / 18e5fac
Release Ruby's GVL while calls to FXImage#savePixels and #loadPixels. Lars Kanis 9 years ago
6 changed file(s) with 235 addition(s) and 2 deletion(s). Raw diff Collapse all Expand all
350350 else
351351 FileUtils.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exist?('scintilla_wrap.cpp')
352352 end
353 have_func 'rb_thread_call_without_gvl'
353354 end
354355
355356 # This directive processes the "--with-fox-include" and "--with-fox-lib"
382383 $CFLAGS += " -DRUBY_2_0" if RUBY_VERSION =~ /2\.0\./
383384
384385 # Last step: build the makefile
386 create_header
385387 create_makefile("fox16_c")
0 /*
1 * gvl_wrappers.c - Wrapper functions for locking/unlocking the Ruby GVL
2 *
3 */
4
5 #include "FXRbCommon.h"
6
7 FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_WRAPPER_STRUCT );
8 FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_SKELETON );
9 FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB );
2525
2626 extern "C" {
2727 #include "ruby.h"
28
29 #include "extconf.h"
2830
2931 #ifdef HAVE_RUBY_ENCODING_H
3032 #include "ruby/encoding.h"
9698 #include "FXScintilla.h"
9799 #endif
98100 #include "FXRuby.h"
101 #include "gvl_wrappers.h"
7272 inline void klass ## _blend(klass* self,FXColor color){ \
7373 self->klass::blend(color); \
7474 } \
75 inline bool klass ## _savePixels(const klass* self,FXStream& store){ \
75 inline bool klass ## _savePixels_gvl(const klass* self,FXStream& store){ \
7676 return self->klass::savePixels(store); \
7777 } \
78 inline bool klass ## _loadPixels(klass* self,FXStream& store){ \
78 inline bool klass ## _loadPixels_gvl(klass* self,FXStream& store){ \
7979 return self->klass::loadPixels(store); \
8080 }
8181
0 /*
1 * gvl_wrappers.h - Wrapper functions for locking/unlocking the Ruby GVL
2 *
3 * These are some obscure preprocessor directives that allow to generate
4 * drop-in replacement wrapper functions in a declarative manner.
5 * These wrapper functions ensure that ruby's GVL is released on each
6 * function call and reacquired at the end of the call or in callbacks.
7 * This way blocking functions calls don't block concurrent ruby threads.
8 *
9 * The wrapper of each function is prefixed by "gvl_".
10 *
11 * Use "gcc -E" to retrieve the generated code.
12 */
13
14 #ifndef __gvl_wrappers_h
15 #define __gvl_wrappers_h
16
17 #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
18 extern "C" void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1,
19 rb_unblock_function_t *ubf, void *data2);
20 #endif
21
22 #define DEFINE_PARAM_LIST1(type, name) \
23 name,
24
25 #define DEFINE_PARAM_LIST2(type, name) \
26 p->params.name,
27
28 #define DEFINE_PARAM_LIST3(type, name) \
29 type name,
30
31 #define DEFINE_PARAM_DECL(type, name) \
32 type name;
33
34 #define DEFINE_GVL_WRAPPER_STRUCT(name, when_non_void, rettype, lastparamtype, lastparamname) \
35 struct gvl_wrapper_##name##_params { \
36 struct { \
37 FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_DECL) \
38 lastparamtype lastparamname; \
39 } params; \
40 when_non_void( rettype retval; ) \
41 };
42
43 #define DEFINE_GVL_SKELETON(name, when_non_void, rettype, lastparamtype, lastparamname) \
44 static void * gvl_##name##_skeleton( void *data ){ \
45 struct gvl_wrapper_##name##_params *p = (struct gvl_wrapper_##name##_params*)data; \
46 when_non_void( p->retval = ) \
47 name##_gvl( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST2) p->params.lastparamname ); \
48 return NULL; \
49 }
50
51 #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
52 #define DEFINE_GVL_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
53 rettype name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
54 struct gvl_wrapper_##name##_params params = { \
55 {FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname}, when_non_void((rettype)0) \
56 }; \
57 rb_thread_call_without_gvl(gvl_##name##_skeleton, &params, RUBY_UBF_IO, 0); \
58 when_non_void( return params.retval; ) \
59 }
60 #else
61 #define DEFINE_GVL_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
62 rettype name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
63 return name##_gvl( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname ); \
64 }
65 #endif
66
67 #define DEFINE_GVL_STUB_DECL(name, when_non_void, rettype, lastparamtype, lastparamname) \
68 rettype name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname);
69
70 #define DEFINE_GVL_TARGET_DECL(name, when_non_void, rettype, lastparamtype, lastparamname) \
71 rettype name##_gvl(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname);
72
73 #define GVL_TYPE_VOID(string)
74 #define GVL_TYPE_NONVOID(string) string
75
76
77 /*
78 * Definitions of blocking functions and their parameters
79 */
80
81 #define FOR_EACH_PARAM_OF_FXImage_loadPixels(param) \
82 param(FXImage *, self)
83 #define FOR_EACH_PARAM_OF_FXImage_savePixels(param) \
84 param(const FXImage *, self)
85
86 #define FOR_EACH_PARAM_OF_FXBMPImage_loadPixels(param) \
87 param(FXBMPImage *, self)
88 #define FOR_EACH_PARAM_OF_FXBMPImage_savePixels(param) \
89 param(const FXBMPImage *, self)
90
91 #define FOR_EACH_PARAM_OF_FXJPGImage_loadPixels(param) \
92 param(FXJPGImage *, self)
93 #define FOR_EACH_PARAM_OF_FXJPGImage_savePixels(param) \
94 param(const FXJPGImage *, self)
95
96 #define FOR_EACH_PARAM_OF_FXGIFImage_loadPixels(param) \
97 param(FXGIFImage *, self)
98 #define FOR_EACH_PARAM_OF_FXGIFImage_savePixels(param) \
99 param(const FXGIFImage *, self)
100
101 #define FOR_EACH_PARAM_OF_FXICOImage_loadPixels(param) \
102 param(FXICOImage *, self)
103 #define FOR_EACH_PARAM_OF_FXICOImage_savePixels(param) \
104 param(const FXICOImage *, self)
105
106 #define FOR_EACH_PARAM_OF_FXPNGImage_loadPixels(param) \
107 param(FXPNGImage *, self)
108 #define FOR_EACH_PARAM_OF_FXPNGImage_savePixels(param) \
109 param(const FXPNGImage *, self)
110
111 #define FOR_EACH_PARAM_OF_FXPPMImage_loadPixels(param) \
112 param(FXPPMImage *, self)
113 #define FOR_EACH_PARAM_OF_FXPPMImage_savePixels(param) \
114 param(const FXPPMImage *, self)
115
116 #define FOR_EACH_PARAM_OF_FXPCXImage_loadPixels(param) \
117 param(FXPCXImage *, self)
118 #define FOR_EACH_PARAM_OF_FXPCXImage_savePixels(param) \
119 param(const FXPCXImage *, self)
120
121 #define FOR_EACH_PARAM_OF_FXRGBImage_loadPixels(param) \
122 param(FXRGBImage *, self)
123 #define FOR_EACH_PARAM_OF_FXRGBImage_savePixels(param) \
124 param(const FXRGBImage *, self)
125
126 #define FOR_EACH_PARAM_OF_FXTGAImage_loadPixels(param) \
127 param(FXTGAImage *, self)
128 #define FOR_EACH_PARAM_OF_FXTGAImage_savePixels(param) \
129 param(const FXTGAImage *, self)
130
131 #define FOR_EACH_PARAM_OF_FXTIFImage_loadPixels(param) \
132 param(FXTIFImage *, self)
133 #define FOR_EACH_PARAM_OF_FXTIFImage_savePixels(param) \
134 param(const FXTIFImage *, self)
135
136 #define FOR_EACH_PARAM_OF_FXXBMImage_loadPixels(param) \
137 param(FXXBMImage *, self)
138 #define FOR_EACH_PARAM_OF_FXXBMImage_savePixels(param) \
139 param(const FXXBMImage *, self)
140
141 #define FOR_EACH_PARAM_OF_FXXPMImage_loadPixels(param) \
142 param(FXXPMImage *, self)
143 #define FOR_EACH_PARAM_OF_FXXPMImage_savePixels(param) \
144 param(const FXXPMImage *, self)
145
146 /* function( name, void_or_nonvoid, returntype, lastparamtype, lastparamname ) */
147 #define FOR_EACH_BLOCKING_FUNCTION(function) \
148 function(FXImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
149 function(FXImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
150 function(FXBMPImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
151 function(FXBMPImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
152 function(FXJPGImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
153 function(FXJPGImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
154 function(FXGIFImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
155 function(FXGIFImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
156 function(FXICOImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
157 function(FXICOImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
158 function(FXPNGImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
159 function(FXPNGImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
160 function(FXPPMImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
161 function(FXPPMImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
162 function(FXPCXImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
163 function(FXPCXImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
164 function(FXRGBImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
165 function(FXRGBImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
166 function(FXTGAImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
167 function(FXTGAImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
168 function(FXTIFImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
169 function(FXTIFImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
170 function(FXXBMImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
171 function(FXXBMImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
172 function(FXXPMImage_loadPixels, GVL_TYPE_NONVOID, bool, FXStream&, store) \
173 function(FXXPMImage_savePixels, GVL_TYPE_NONVOID, bool, FXStream&, store)
174
175
176 FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL )
177 FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_TARGET_DECL )
178
179 #endif /* end __gvl_wrappers_h */
0 require 'fox16'
1 require 'test/unit'
2 require 'testcase'
3 require 'openssl'
4
5 class TC_FXJPGImage < Fox::TestCase
6 include Fox
7
8 def setup
9 super(self.class.name)
10 end
11
12 def test_save_with_thread
13 w, h = 4000, 3000
14 img_data = OpenSSL::Random.random_bytes(w) * h * 4
15
16 count = 0
17 th = Thread.new do
18 loop do
19 sleep 0.01
20 count += 1
21 end
22 end
23
24 img = FXJPGImage.new(app)
25 img.setPixels( img_data, 0, w, h )
26
27 jpeg_data = FXMemoryStream.open(FXStreamSave, nil) do |outfile|
28 img.savePixels(outfile)
29 outfile.takeBuffer
30 end
31
32 th.kill
33
34 assert_operator(count, :>=, 10)
35 assert_operator(jpeg_data.bytesize, :>=, 1000)
36 end
37 end