ray 0.0.1 → 0.1.0.pre1

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.
Files changed (188) hide show
  1. data/.gemtest +0 -0
  2. data/.yardopts +4 -0
  3. data/README.md +17 -21
  4. data/Rakefile +18 -139
  5. data/VERSION +1 -1
  6. data/ext/audio.cpp +723 -0
  7. data/ext/{color.c → color.cpp} +25 -13
  8. data/ext/drawable.cpp +91 -0
  9. data/ext/event.cpp +460 -0
  10. data/ext/extconf.rb +5 -104
  11. data/ext/font.cpp +190 -0
  12. data/ext/image.cpp +733 -0
  13. data/ext/input.cpp +74 -0
  14. data/ext/ray.cpp +168 -0
  15. data/ext/ray.hpp +356 -0
  16. data/ext/{rect.c → rect.cpp} +51 -37
  17. data/ext/shader.cpp +169 -0
  18. data/ext/shape.cpp +409 -0
  19. data/ext/sprite.cpp +306 -0
  20. data/ext/text.cpp +181 -0
  21. data/ext/vector.cpp +215 -0
  22. data/guide.md +619 -0
  23. data/lib/ray/audio.rb +0 -41
  24. data/lib/ray/color.rb +32 -10
  25. data/lib/ray/drawable.rb +16 -0
  26. data/lib/ray/dsl/event_listener.rb +25 -2
  27. data/lib/ray/dsl/event_runner.rb +33 -5
  28. data/lib/ray/dsl/event_translator.rb +66 -30
  29. data/lib/ray/dsl/handler.rb +3 -2
  30. data/lib/ray/dsl/matcher.rb +58 -14
  31. data/lib/ray/font.rb +38 -96
  32. data/lib/ray/font_set.rb +8 -8
  33. data/lib/ray/game.rb +87 -66
  34. data/lib/ray/helper.rb +105 -10
  35. data/lib/ray/image.rb +150 -24
  36. data/lib/ray/image_set.rb +3 -1
  37. data/lib/ray/input.rb +10 -0
  38. data/lib/ray/music_set.rb +5 -3
  39. data/lib/ray/ray.rb +21 -9
  40. data/lib/ray/rect.rb +48 -7
  41. data/lib/ray/rmagick.rb +41 -0
  42. data/lib/ray/scene.rb +99 -43
  43. data/lib/ray/scene_list.rb +67 -0
  44. data/lib/ray/shape.rb +132 -0
  45. data/lib/ray/sound_set.rb +4 -2
  46. data/lib/ray/sprite.rb +49 -111
  47. data/lib/ray/text.rb +101 -0
  48. data/lib/ray/text_helper.rb +37 -0
  49. data/lib/ray/turtle.rb +215 -0
  50. data/lib/ray/vector.rb +226 -0
  51. data/samples/audio/spacial.rb +44 -0
  52. data/samples/hello_world/hello.rb +9 -13
  53. data/samples/hello_world/hello_dsl.rb +8 -12
  54. data/samples/hello_world/text.rb +15 -0
  55. data/samples/opengl/binding.rb +38 -0
  56. data/samples/opengl/image.rb +32 -0
  57. data/samples/opengl/opengl.rb +34 -0
  58. data/samples/opengl/shader.rb +42 -0
  59. data/samples/pong/pong.rb +14 -10
  60. data/samples/run_scene.rb +53 -0
  61. data/samples/shaders/scene.rb +40 -0
  62. data/samples/shaders/shaders.rb +42 -0
  63. data/samples/shaders/shape.rb +34 -0
  64. data/samples/sokoban/sokoban.rb +18 -18
  65. data/samples/test/actual_scene.rb +41 -0
  66. data/samples/test/scene_riot.rb +39 -0
  67. data/samples/test/scene_spec.rb +32 -0
  68. data/samples/test/scene_test_unit.rb +25 -0
  69. data/samples/turtle/byzantium.rb +45 -0
  70. data/samples/turtle/hilbert.rb +48 -0
  71. data/samples/turtle/koch.rb +55 -0
  72. data/samples/turtle/mandala.rb +61 -0
  73. data/samples/turtle/tree.rb +57 -0
  74. data/test/audio_test.rb +69 -0
  75. data/test/color_test.rb +77 -0
  76. data/test/drawable_test.rb +19 -0
  77. data/test/dsl_test.rb +93 -0
  78. data/test/font_test.rb +57 -0
  79. data/test/helpers.rb +94 -0
  80. data/test/image_test.rb +82 -0
  81. data/test/ray_test.rb +25 -0
  82. data/test/rect_test.rb +121 -0
  83. data/{spec → test}/res/VeraMono.ttf +0 -0
  84. data/{spec → test}/res/aqua.bmp +0 -0
  85. data/{spec → test}/res/aqua.png +0 -0
  86. data/{spec → test}/res/aqua2.bmp +0 -0
  87. data/{spec → test}/res/not_a_jpeg.jpeg +0 -0
  88. data/{spec → test}/res/pop.wav +0 -0
  89. data/test/resource_set_test.rb +99 -0
  90. data/test/run_all.rb +7 -0
  91. data/test/shape_test.rb +101 -0
  92. data/test/sprite_test.rb +89 -0
  93. data/test/text_test.rb +78 -0
  94. data/test/turtle_test.rb +176 -0
  95. data/test/vector_test.rb +111 -0
  96. data/yard_ext.rb +0 -28
  97. metadata +95 -139
  98. data/.gitignore +0 -23
  99. data/.gitmodules +0 -3
  100. data/.rspec +0 -3
  101. data/ext/audio.c +0 -473
  102. data/ext/event.c +0 -557
  103. data/ext/font.c +0 -287
  104. data/ext/image.c +0 -933
  105. data/ext/joystick.c +0 -145
  106. data/ext/ray.c +0 -489
  107. data/ext/ray.h +0 -245
  108. data/ext/ray_osx.m +0 -161
  109. data/lib/ray/joystick.rb +0 -30
  110. data/psp/SDL_psp_main.c +0 -84
  111. data/psp/bigdecimal/README +0 -60
  112. data/psp/bigdecimal/bigdecimal.c +0 -4697
  113. data/psp/bigdecimal/bigdecimal.h +0 -216
  114. data/psp/bigdecimal/lib/bigdecimal/jacobian.rb +0 -85
  115. data/psp/bigdecimal/lib/bigdecimal/ludcmp.rb +0 -84
  116. data/psp/bigdecimal/lib/bigdecimal/math.rb +0 -235
  117. data/psp/bigdecimal/lib/bigdecimal/newton.rb +0 -77
  118. data/psp/bigdecimal/lib/bigdecimal/util.rb +0 -65
  119. data/psp/digest/bubblebabble/bubblebabble.c +0 -142
  120. data/psp/digest/defs.h +0 -20
  121. data/psp/digest/digest.c +0 -643
  122. data/psp/digest/digest.h +0 -32
  123. data/psp/digest/lib/digest.rb +0 -50
  124. data/psp/digest/lib/md5.rb +0 -27
  125. data/psp/digest/lib/sha1.rb +0 -27
  126. data/psp/digest/md5/md5.c +0 -420
  127. data/psp/digest/md5/md5.h +0 -80
  128. data/psp/digest/md5/md5init.c +0 -40
  129. data/psp/digest/rmd160/rmd160.c +0 -457
  130. data/psp/digest/rmd160/rmd160.h +0 -56
  131. data/psp/digest/rmd160/rmd160init.c +0 -40
  132. data/psp/digest/sha1/sha1.c +0 -269
  133. data/psp/digest/sha1/sha1.h +0 -39
  134. data/psp/digest/sha1/sha1init.c +0 -40
  135. data/psp/digest/sha2/lib/sha2.rb +0 -73
  136. data/psp/digest/sha2/sha2.c +0 -919
  137. data/psp/digest/sha2/sha2.h +0 -109
  138. data/psp/digest/sha2/sha2init.c +0 -52
  139. data/psp/enumerator/enumerator.c +0 -298
  140. data/psp/etc/etc.c +0 -559
  141. data/psp/ext.c +0 -289
  142. data/psp/fcntl/fcntl.c +0 -187
  143. data/psp/lib/rbconfig.rb +0 -178
  144. data/psp/nkf/lib/kconv.rb +0 -367
  145. data/psp/nkf/nkf-utf8/config.h +0 -88
  146. data/psp/nkf/nkf-utf8/nkf.c +0 -6040
  147. data/psp/nkf/nkf-utf8/utf8tbl.c +0 -8500
  148. data/psp/nkf/nkf-utf8/utf8tbl.h +0 -34
  149. data/psp/nkf/nkf.c +0 -654
  150. data/psp/socket/addrinfo.h +0 -173
  151. data/psp/socket/getaddrinfo.c +0 -676
  152. data/psp/socket/getnameinfo.c +0 -270
  153. data/psp/socket/pspsocket.c +0 -71
  154. data/psp/socket/pspsocket.h +0 -28
  155. data/psp/socket/socket.c +0 -4662
  156. data/psp/socket/sockport.h +0 -76
  157. data/psp/stringio/stringio.c +0 -1306
  158. data/psp/strscan/strscan.c +0 -1320
  159. data/psp/syck/bytecode.c +0 -1166
  160. data/psp/syck/emitter.c +0 -1242
  161. data/psp/syck/gram.c +0 -1894
  162. data/psp/syck/gram.h +0 -79
  163. data/psp/syck/handler.c +0 -174
  164. data/psp/syck/implicit.c +0 -2990
  165. data/psp/syck/node.c +0 -408
  166. data/psp/syck/rubyext.c +0 -2367
  167. data/psp/syck/syck.c +0 -504
  168. data/psp/syck/syck.h +0 -456
  169. data/psp/syck/token.c +0 -2725
  170. data/psp/syck/yaml2byte.c +0 -257
  171. data/psp/syck/yamlbyte.h +0 -170
  172. data/psp/thread/thread.c +0 -1175
  173. data/psp/zlib/zlib.c +0 -3547
  174. data/script.rb +0 -10
  175. data/spec/ray/audio_spec.rb +0 -146
  176. data/spec/ray/color_spec.rb +0 -57
  177. data/spec/ray/event_spec.rb +0 -80
  178. data/spec/ray/font_spec.rb +0 -93
  179. data/spec/ray/image_set_spec.rb +0 -48
  180. data/spec/ray/image_spec.rb +0 -162
  181. data/spec/ray/joystick_spec.rb +0 -21
  182. data/spec/ray/matcher_spec.rb +0 -50
  183. data/spec/ray/ray_spec.rb +0 -88
  184. data/spec/ray/rect_spec.rb +0 -154
  185. data/spec/ray/resource_set_spec.rb +0 -105
  186. data/spec/ray/sprite_spec.rb +0 -163
  187. data/spec/spec.opts +0 -4
  188. data/spec/spec_helper.rb +0 -8
@@ -1,257 +0,0 @@
1
- /*
2
- * yaml2byte.c
3
- *
4
- * $Author: shyouhei $
5
- * $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
6
- *
7
- * Copyright (C) 2003 why the lucky stiff, clark evans
8
- *
9
- * WARNING WARNING WARNING --- THIS IS *NOT JUST* PLAYING
10
- * ANYMORE! -- WHY HAS EMBRACED THIS AS THE REAL THING!
11
- */
12
- #include <ruby/ruby.h>
13
- #include "syck.h"
14
- #include <assert.h>
15
- #define YAMLBYTE_UTF8
16
- #include "yamlbyte.h"
17
-
18
- #include <stdio.h>
19
- #define TRACE0(a) \
20
- do { printf(a); printf("\n"); fflush(stdout); } while(0)
21
- #define TRACE1(a,b) \
22
- do { printf(a,b); printf("\n"); fflush(stdout); } while(0)
23
- #define TRACE2(a,b,c) \
24
- do { printf(a,b,c); printf("\n"); fflush(stdout); } while(0)
25
- #define TRACE3(a,b,c,d) \
26
- do { printf(a,b,c,d); printf("\n"); fflush(stdout); } while(0)
27
-
28
- /* Reinvent the wheel... */
29
- #define CHUNKSIZE 64
30
- #define HASH ((long)0xCAFECAFE)
31
- typedef struct {
32
- long hash;
33
- char *buffer;
34
- long length;
35
- long remaining;
36
- int printed;
37
- } bytestring_t;
38
- bytestring_t *bytestring_alloc() {
39
- bytestring_t *ret;
40
- /*TRACE0("bytestring_alloc()");*/
41
- ret = S_ALLOC(bytestring_t);
42
- ret->hash = HASH;
43
- ret->length = CHUNKSIZE;
44
- ret->remaining = ret->length;
45
- ret->buffer = S_ALLOC_N(char, ret->length + 1 );
46
- ret->buffer[0] = 0;
47
- ret->printed = 0;
48
- return ret;
49
- }
50
- void bytestring_append(bytestring_t *str, char code,
51
- char *start, char *finish)
52
- {
53
- long grow;
54
- long length = 2; /* CODE + LF */
55
- char *curr;
56
- assert(str && HASH == str->hash);
57
- /*TRACE0("bytestring_append()");*/
58
- if(start) {
59
- if(!finish)
60
- finish = start + strlen(start);
61
- length += (finish-start);
62
- }
63
- if(length > str->remaining) {
64
- grow = (length - str->remaining) + CHUNKSIZE;
65
- str->remaining += grow;
66
- str->length += grow;
67
- str->buffer = S_REALLOC_N( str->buffer, char, str->length + 1 );
68
- assert(str->buffer);
69
- }
70
- curr = str->buffer + (str->length - str->remaining);
71
- *curr = code;
72
- curr += 1;
73
- if(start)
74
- while(start < finish)
75
- *curr ++ = *start ++;
76
- *curr = '\n';
77
- curr += 1;
78
- *curr = 0;
79
- str->remaining = str->remaining - length;
80
- assert( (str->buffer + str->length) - str->remaining );
81
- }
82
- void bytestring_extend(bytestring_t *str, bytestring_t *ext)
83
- {
84
- char *from;
85
- char *curr;
86
- char *stop;
87
- long grow;
88
- long length;
89
- assert(str && HASH == str->hash);
90
- assert(ext && HASH == ext->hash);
91
- if(ext->printed) {
92
- assert(ext->buffer[0] ==YAMLBYTE_ANCHOR);
93
- curr = ext->buffer;
94
- while( '\n' != *curr)
95
- curr++;
96
- bytestring_append(str, YAMLBYTE_ALIAS, ext->buffer + 1, curr);
97
- } else {
98
- ext->printed = 1;
99
- length = (ext->length - ext->remaining);
100
- if(length > str->remaining) {
101
- grow = (length - str->remaining) + CHUNKSIZE;
102
- str->remaining += grow;
103
- str->length += grow;
104
- str->buffer = S_REALLOC_N( str->buffer, char, str->length + 1 );
105
- }
106
- curr = str->buffer + (str->length - str->remaining);
107
- from = ext->buffer;
108
- stop = ext->buffer + length;
109
- while( from < stop )
110
- *curr ++ = *from ++;
111
- *curr = 0;
112
- str->remaining = str->remaining - length;
113
- assert( (str->buffer + str->length) - str->remaining );
114
- }
115
- }
116
-
117
- /* convert SyckNode into yamlbyte_buffer_t objects */
118
- SYMID
119
- syck_yaml2byte_handler(p, n)
120
- SyckParser *p;
121
- SyckNode *n;
122
- {
123
- SYMID oid;
124
- long i;
125
- char ch;
126
- char nextcode;
127
- char *start;
128
- char *current;
129
- char *finish;
130
- bytestring_t *val = NULL;
131
- bytestring_t *sav = NULL;
132
- /*TRACE0("syck_yaml2byte_handler()");*/
133
- val = bytestring_alloc();
134
- if(n->anchor) bytestring_append(val,YAMLBYTE_ANCHOR, n->anchor, NULL);
135
- if ( n->type_id )
136
- {
137
- if ( p->taguri_expansion )
138
- {
139
- bytestring_append(val,YAMLBYTE_TRANSFER, n->type_id, NULL);
140
- }
141
- else
142
- {
143
- char *type_tag = S_ALLOC_N( char, strlen( n->type_id ) + 1 );
144
- type_tag[0] = '\0';
145
- strcat( type_tag, "!" );
146
- strcat( type_tag, n->type_id );
147
- bytestring_append( val, YAMLBYTE_TRANSFER, type_tag, NULL);
148
- S_FREE(type_tag);
149
- }
150
- }
151
- switch (n->kind)
152
- {
153
- case syck_str_kind:
154
- nextcode = YAMLBYTE_SCALAR;
155
- start = n->data.str->ptr;
156
- finish = start + n->data.str->len - 1;
157
- current = start;
158
- /*TRACE2("SCALAR: %s %d", start, n->data.str->len); */
159
- while(1) {
160
- ch = *current;
161
- if('\n' == ch || 0 == ch || current > finish) {
162
- if(current >= start) {
163
- bytestring_append(val, nextcode, start, current);
164
- nextcode = YAMLBYTE_CONTINUE;
165
- }
166
- start = current + 1;
167
- if(current > finish)
168
- {
169
- break;
170
- }
171
- else if('\n' == ch )
172
- {
173
- bytestring_append(val,YAMLBYTE_NEWLINE,NULL,NULL);
174
- }
175
- else if(0 == ch)
176
- {
177
- bytestring_append(val,YAMLBYTE_NULLCHAR,NULL,NULL);
178
- }
179
- else
180
- {
181
- assert("oops");
182
- }
183
- }
184
- current += 1;
185
- }
186
- break;
187
- case syck_seq_kind:
188
- bytestring_append(val,YAMLBYTE_SEQUENCE,NULL,NULL);
189
- for ( i = 0; i < n->data.list->idx; i++ )
190
- {
191
- oid = syck_seq_read( n, i );
192
- syck_lookup_sym( p, oid, (char **)&sav );
193
- bytestring_extend(val, sav);
194
- }
195
- bytestring_append(val,YAMLBYTE_END_BRANCH,NULL,NULL);
196
- break;
197
- case syck_map_kind:
198
- bytestring_append(val,YAMLBYTE_MAPPING,NULL,NULL);
199
- for ( i = 0; i < n->data.pairs->idx; i++ )
200
- {
201
- oid = syck_map_read( n, map_key, i );
202
- syck_lookup_sym( p, oid, (char **)&sav );
203
- bytestring_extend(val, sav);
204
- oid = syck_map_read( n, map_value, i );
205
- syck_lookup_sym( p, oid, (char **)&sav );
206
- bytestring_extend(val, sav);
207
- }
208
- bytestring_append(val,YAMLBYTE_END_BRANCH,NULL,NULL);
209
- break;
210
- }
211
- oid = syck_add_sym( p, (char *) val );
212
- /*TRACE1("Saving: %s", val->buffer );*/
213
- return oid;
214
- }
215
-
216
- char *
217
- syck_yaml2byte(char *yamlstr)
218
- {
219
- SYMID oid;
220
- char *ret;
221
- bytestring_t *sav;
222
-
223
- SyckParser *parser = syck_new_parser();
224
- syck_parser_str_auto( parser, yamlstr, NULL );
225
- syck_parser_handler( parser, syck_yaml2byte_handler );
226
- syck_parser_error_handler( parser, NULL );
227
- syck_parser_implicit_typing( parser, 1 );
228
- syck_parser_taguri_expansion( parser, 1 );
229
- oid = syck_parse( parser );
230
-
231
- if ( syck_lookup_sym( parser, oid, (char **)&sav ) == 1 ) {
232
- ret = S_ALLOC_N( char, strlen( sav->buffer ) + 3 );
233
- ret[0] = '\0';
234
- strcat( ret, "D\n" );
235
- strcat( ret, sav->buffer );
236
- }
237
- else
238
- {
239
- ret = NULL;
240
- }
241
-
242
- syck_free_parser( parser );
243
- return ret;
244
- }
245
-
246
- #ifdef TEST_YBEXT
247
- #include <stdio.h>
248
- int main() {
249
- char *yaml = "test: 1\nand: \"with new\\nline\\n\"\nalso: &3 three\nmore: *3";
250
- printf("--- # YAML \n");
251
- printf(yaml);
252
- printf("\n...\n");
253
- printf(syck_yaml2byte(yaml));
254
- return 0;
255
- }
256
- #endif
257
-
@@ -1,170 +0,0 @@
1
- /* yamlbyte.h
2
- *
3
- * The YAML bytecode "C" interface header file. See the YAML bytecode
4
- * reference for bytecode sequence rules and for the meaning of each
5
- * bytecode.
6
- */
7
-
8
- #ifndef YAMLBYTE_H
9
- #define YAMLBYTE_H
10
- #include <stddef.h>
11
-
12
- /* define what a character is */
13
- typedef unsigned char yamlbyte_utf8_t;
14
- typedef unsigned short yamlbyte_utf16_t;
15
- #ifdef YAMLBYTE_UTF8
16
- #ifdef YAMLBYTE_UTF16
17
- #error Must only define YAMLBYTE_UTF8 or YAMLBYTE_UTF16
18
- #endif
19
- typedef yamlbyte_utf8_t yamlbyte_char_t;
20
- #else
21
- #ifdef YAMLBYTE_UTF16
22
- typedef yamlbyte_utf16_t yamlbyte_char_t;
23
- #else
24
- #error Must define YAMLBYTE_UTF8 or YAMLBYTE_UTF16
25
- #endif
26
- #endif
27
-
28
- /* specify list of bytecodes */
29
- #define YAMLBYTE_FINISH ((yamlbyte_char_t) 0)
30
- #define YAMLBYTE_DOCUMENT ((yamlbyte_char_t)'D')
31
- #define YAMLBYTE_DIRECTIVE ((yamlbyte_char_t)'V')
32
- #define YAMLBYTE_PAUSE ((yamlbyte_char_t)'P')
33
- #define YAMLBYTE_MAPPING ((yamlbyte_char_t)'M')
34
- #define YAMLBYTE_SEQUENCE ((yamlbyte_char_t)'Q')
35
- #define YAMLBYTE_END_BRANCH ((yamlbyte_char_t)'E')
36
- #define YAMLBYTE_SCALAR ((yamlbyte_char_t)'S')
37
- #define YAMLBYTE_CONTINUE ((yamlbyte_char_t)'C')
38
- #define YAMLBYTE_NEWLINE ((yamlbyte_char_t)'N')
39
- #define YAMLBYTE_NULLCHAR ((yamlbyte_char_t)'Z')
40
- #define YAMLBYTE_ANCHOR ((yamlbyte_char_t)'A')
41
- #define YAMLBYTE_ALIAS ((yamlbyte_char_t)'R')
42
- #define YAMLBYTE_TRANSFER ((yamlbyte_char_t)'T')
43
- /* formatting bytecodes */
44
- #define YAMLBYTE_COMMENT ((yamlbyte_char_t)'c')
45
- #define YAMLBYTE_INDENT ((yamlbyte_char_t)'i')
46
- #define YAMLBYTE_STYLE ((yamlbyte_char_t)'s')
47
- /* other bytecodes */
48
- #define YAMLBYTE_LINE_NUMBER ((yamlbyte_char_t)'#')
49
- #define YAMLBYTE_WHOLE_SCALAR ((yamlbyte_char_t)'<')
50
- #define YAMLBYTE_NOTICE ((yamlbyte_char_t)'!')
51
- #define YAMLBYTE_SPAN ((yamlbyte_char_t)')')
52
- #define YAMLBYTE_ALLOC ((yamlbyte_char_t)'@')
53
-
54
- /* second level style bytecodes, ie "s>" */
55
- #define YAMLBYTE_FLOW ((yamlbyte_char_t)'>')
56
- #define YAMLBYTE_LITERAL ((yamlbyte_char_t)'|')
57
- #define YAMLBYTE_BLOCK ((yamlbyte_char_t)'b')
58
- #define YAMLBYTE_PLAIN ((yamlbyte_char_t)'p')
59
- #define YAMLBYTE_INLINE_MAPPING ((yamlbyte_char_t)'{')
60
- #define YAMLBYTE_INLINE_SEQUENCE ((yamlbyte_char_t)'[')
61
- #define YAMLBYTE_SINGLE_QUOTED ((yamlbyte_char_t)39)
62
- #define YAMLBYTE_DOUBLE_QUOTED ((yamlbyte_char_t)'"')
63
-
64
- /*
65
- * The "C" API has two variants, one based on instructions,
66
- * with events delivered via pointers; and the other one
67
- * is character based where one or more instructions are
68
- * serialized into a buffer.
69
- *
70
- * Note: In the instruction based API, WHOLE_SCALAR does
71
- * not have the '<here' marshalling stuff.
72
- */
73
-
74
- typedef void * yamlbyte_consumer_t;
75
- typedef void * yamlbyte_producer_t;
76
-
77
- /* push and pull APIs need a way to communicate results */
78
- typedef enum {
79
- YAMLBYTE_OK = 0, /* proceed */
80
- YAMLBYTE_E_MEMORY = 'M', /* could not allocate memory */
81
- YAMLBYTE_E_READ = 'R', /* input stream read error */
82
- YAMLBYTE_E_WRITE = 'W', /* output stream write error */
83
- YAMLBYTE_E_OTHER = '?', /* some other error condition */
84
- YAMLBYTE_E_PARSE = 'P', /* parse error, check bytecodes */
85
- } yamlbyte_result_t;
86
-
87
- typedef const yamlbyte_char_t *yamlbyte_buff_t;
88
-
89
- /*
90
- * The "Instruction" API
91
- */
92
-
93
- typedef struct yaml_instruction {
94
- yamlbyte_char_t bytecode;
95
- yamlbyte_buff_t start;
96
- yamlbyte_buff_t finish; /* open range, *finish is _not_ part */
97
- } *yamlbyte_inst_t;
98
-
99
- /* producer pushes the instruction with one bytecode event to the
100
- * consumer; if the consumer's result is not YAMLBYTE_OK, then
101
- * the producer should stop */
102
- typedef
103
- yamlbyte_result_t
104
- (*yamlbyte_push_t)(
105
- yamlbyte_consumer_t self,
106
- yamlbyte_inst_t inst
107
- );
108
-
109
- /* consumer pulls a bytecode instruction from the producer; in this
110
- * case the instruction (and is buffer) are owned by the producer and
111
- * will remain valid till the pull function is called once again;
112
- * if the instruction is NULL, then there are no more results; and
113
- * it is important to call the pull function till it returns NULL so
114
- * that the producer can clean up its memory allocations */
115
- typedef
116
- yamlbyte_result_t
117
- (*yamlbyte_pull_t)(
118
- yamlbyte_producer_t self,
119
- yamlbyte_inst_t *inst /* to be filled in by the producer */
120
- );
121
-
122
- /*
123
- * Buffer based API
124
- */
125
-
126
- /* producer pushes a null terminated buffer filled with one or more
127
- * bytecode events to the consumer; if the consumer's result is not
128
- * YAMLBYTE_OK, then the producer should stop */
129
- typedef
130
- yamlbyte_result_t
131
- (*yamlbyte_pushbuff_t)(
132
- yamlbyte_consumer_t self,
133
- yamlbyte_buff_t buff
134
- );
135
-
136
- /* consumer pulls bytecode events from the producer; in this case
137
- * the buffer is owned by the producer, and will remain valid till
138
- * the pull function is called once again; if the buffer pointer
139
- * is set to NULL, then there are no more results; it is important
140
- * to call the pull function till it returns NULL so that the
141
- * producer can clean up its memory allocations */
142
- typedef
143
- yamlbyte_result_t
144
- (*yamlbyte_pullbuff_t)(
145
- yamlbyte_producer_t self,
146
- yamlbyte_buff_t *buff /* to be filled in by the producer */
147
- );
148
-
149
- /* convert a pull interface to a push interface; the reverse process
150
- * requires threads and thus is language dependent */
151
- #define YAMLBYTE_PULL2PUSH(pull,producer,push,consumer,result) \
152
- do { \
153
- yamlbyte_pullbuff_t _pull = (pull); \
154
- yamlbyte_pushbuff_t _push = (push); \
155
- yamlbyte_result_t _result = YAMLBYTE_OK; \
156
- yamlbyte_producer_t _producer = (producer); \
157
- yamlbyte_consumer_t _consumer = (consumer); \
158
- while(1) { \
159
- yamlbyte_buff_t buff = NULL; \
160
- _result = _pull(_producer,&buff); \
161
- if(YAMLBYTE_OK != result || NULL == buff) \
162
- break; \
163
- _result = _push(_consumer,buff); \
164
- if(YAMLBYTE_OK != result) \
165
- break; \
166
- } \
167
- (result) = _result; \
168
- } while(0)
169
-
170
- #endif
@@ -1,1175 +0,0 @@
1
- /*
2
- * Optimized Ruby Mutex implementation, loosely based on thread.rb by
3
- * Yukihiro Matsumoto <matz@ruby-lang.org>
4
- *
5
- * Copyright 2006-2007 MenTaLguY <mental@rydia.net>
6
- *
7
- * RDoc taken from original.
8
- *
9
- * This file is made available under the same terms as Ruby.
10
- */
11
-
12
- #include <ruby/ruby.h>
13
- #include <ruby/intern.h>
14
- #include <ruby/rubysig.h>
15
-
16
- static VALUE rb_cMutex;
17
- static VALUE rb_cConditionVariable;
18
- static VALUE rb_cQueue;
19
- static VALUE rb_cSizedQueue;
20
-
21
- static VALUE set_critical(VALUE value);
22
-
23
- static VALUE
24
- thread_exclusive_do(void)
25
- {
26
- rb_thread_critical = 1;
27
-
28
- return rb_yield(Qundef);
29
- }
30
-
31
- /*
32
- * call-seq:
33
- * Thread.exclusive { block } => obj
34
- *
35
- * Wraps a block in Thread.critical, restoring the original value
36
- * upon exit from the critical section, and returns the value of the
37
- * block.
38
- */
39
-
40
- static VALUE
41
- rb_thread_exclusive(void)
42
- {
43
- return rb_ensure(thread_exclusive_do, Qundef, set_critical, rb_thread_critical);
44
- }
45
-
46
- typedef struct _Entry {
47
- VALUE value;
48
- struct _Entry *next;
49
- } Entry;
50
-
51
- typedef struct _List {
52
- Entry *entries;
53
- Entry *last_entry;
54
- Entry *entry_pool;
55
- unsigned long size;
56
- } List;
57
-
58
- static void
59
- init_list(List *list)
60
- {
61
- list->entries = NULL;
62
- list->last_entry = NULL;
63
- list->entry_pool = NULL;
64
- list->size = 0;
65
- }
66
-
67
- static void
68
- mark_list(List *list)
69
- {
70
- Entry *entry;
71
- for (entry = list->entries; entry; entry = entry->next) {
72
- rb_gc_mark(entry->value);
73
- }
74
- }
75
-
76
- static void
77
- free_entries(Entry *first)
78
- {
79
- Entry *next;
80
- while (first) {
81
- next = first->next;
82
- xfree(first);
83
- first = next;
84
- }
85
- }
86
-
87
- static void
88
- finalize_list(List *list)
89
- {
90
- free_entries(list->entries);
91
- free_entries(list->entry_pool);
92
- }
93
-
94
- static void
95
- push_list(List *list, VALUE value)
96
- {
97
- Entry *entry;
98
-
99
- if (list->entry_pool) {
100
- entry = list->entry_pool;
101
- list->entry_pool = entry->next;
102
- } else {
103
- entry = ALLOC(Entry);
104
- }
105
-
106
- entry->value = value;
107
- entry->next = NULL;
108
-
109
- if (list->last_entry) {
110
- list->last_entry->next = entry;
111
- } else {
112
- list->entries = entry;
113
- }
114
- list->last_entry = entry;
115
-
116
- ++list->size;
117
- }
118
-
119
- static void
120
- push_multiple_list(List *list, VALUE *values, unsigned count)
121
- {
122
- unsigned i;
123
- for (i = 0; i < count; i++) {
124
- push_list(list, values[i]);
125
- }
126
- }
127
-
128
- static void
129
- recycle_entries(List *list, Entry *first_entry, Entry *last_entry)
130
- {
131
- #ifdef USE_MEM_POOLS
132
- last_entry->next = list->entry_pool;
133
- list->entry_pool = first_entry;
134
- #else
135
- last_entry->next = NULL;
136
- free_entries(first_entry);
137
- #endif
138
- }
139
-
140
- static VALUE
141
- shift_list(List *list)
142
- {
143
- Entry *entry;
144
- VALUE value;
145
-
146
- entry = list->entries;
147
- if (!entry) return Qundef;
148
-
149
- list->entries = entry->next;
150
- if (entry == list->last_entry) {
151
- list->last_entry = NULL;
152
- }
153
-
154
- --list->size;
155
-
156
- value = entry->value;
157
- recycle_entries(list, entry, entry);
158
-
159
- return value;
160
- }
161
-
162
- static void
163
- remove_one(List *list, VALUE value)
164
- {
165
- Entry **ref;
166
- Entry *entry;
167
-
168
- for (ref = &list->entries, entry = list->entries;
169
- entry != NULL;
170
- ref = &entry->next, entry = entry->next) {
171
- if (entry->value == value) {
172
- *ref = entry->next;
173
- recycle_entries(list, entry, entry);
174
- break;
175
- }
176
- }
177
- }
178
-
179
- static void
180
- clear_list(List *list)
181
- {
182
- if (list->last_entry) {
183
- recycle_entries(list, list->entries, list->last_entry);
184
- list->entries = NULL;
185
- list->last_entry = NULL;
186
- list->size = 0;
187
- }
188
- }
189
-
190
- static VALUE
191
- array_from_list(List const *list)
192
- {
193
- VALUE ary;
194
- Entry *entry;
195
- ary = rb_ary_new();
196
- for (entry = list->entries; entry; entry = entry->next) {
197
- rb_ary_push(ary, entry->value);
198
- }
199
- return ary;
200
- }
201
-
202
- static VALUE
203
- wake_thread(VALUE thread)
204
- {
205
- return rb_rescue2(rb_thread_wakeup, thread,
206
- NULL, Qundef, rb_eThreadError, 0);
207
- }
208
-
209
- static VALUE
210
- run_thread(VALUE thread)
211
- {
212
- return rb_rescue2(rb_thread_run, thread,
213
- NULL, Qundef, rb_eThreadError, 0);
214
- }
215
-
216
- static VALUE
217
- wake_one(List *list)
218
- {
219
- VALUE waking;
220
-
221
- waking = Qnil;
222
- while (list->entries && !RTEST(waking)) {
223
- waking = wake_thread(shift_list(list));
224
- }
225
-
226
- return waking;
227
- }
228
-
229
- static VALUE
230
- wake_all(List *list)
231
- {
232
- while (list->entries) {
233
- wake_one(list);
234
- }
235
- return Qnil;
236
- }
237
-
238
- static VALUE
239
- wait_list_inner(List *list)
240
- {
241
- push_list(list, rb_thread_current());
242
- rb_thread_stop();
243
- return Qnil;
244
- }
245
-
246
- static VALUE
247
- wait_list_cleanup(List *list)
248
- {
249
- /* cleanup in case of spurious wakeups */
250
- remove_one(list, rb_thread_current());
251
- return Qnil;
252
- }
253
-
254
- static void
255
- wait_list(List *list)
256
- {
257
- rb_ensure(wait_list_inner, (VALUE)list, wait_list_cleanup, (VALUE)list);
258
- }
259
-
260
- static void
261
- assert_no_survivors(List *waiting, const char *label, void *addr)
262
- {
263
- Entry *entry;
264
- for (entry = waiting->entries; entry; entry = entry->next) {
265
- if (RTEST(wake_thread(entry->value))) {
266
- rb_bug("%s %p freed with live thread(s) waiting", label, addr);
267
- }
268
- }
269
- }
270
-
271
- /*
272
- * Document-class: Mutex
273
- *
274
- * Mutex implements a simple semaphore that can be used to coordinate access to
275
- * shared data from multiple concurrent threads.
276
- *
277
- * Example:
278
- *
279
- * require 'thread'
280
- * semaphore = Mutex.new
281
- *
282
- * a = Thread.new {
283
- * semaphore.synchronize {
284
- * # access shared resource
285
- * }
286
- * }
287
- *
288
- * b = Thread.new {
289
- * semaphore.synchronize {
290
- * # access shared resource
291
- * }
292
- * }
293
- *
294
- */
295
-
296
- typedef struct _Mutex {
297
- VALUE owner;
298
- List waiting;
299
- } Mutex;
300
-
301
- static void
302
- mark_mutex(Mutex *mutex)
303
- {
304
- rb_gc_mark(mutex->owner);
305
- mark_list(&mutex->waiting);
306
- }
307
-
308
- static void
309
- finalize_mutex(Mutex *mutex)
310
- {
311
- finalize_list(&mutex->waiting);
312
- }
313
-
314
- static void
315
- free_mutex(Mutex *mutex)
316
- {
317
- assert_no_survivors(&mutex->waiting, "mutex", mutex);
318
- finalize_mutex(mutex);
319
- xfree(mutex);
320
- }
321
-
322
- static void
323
- init_mutex(Mutex *mutex)
324
- {
325
- mutex->owner = Qnil;
326
- init_list(&mutex->waiting);
327
- }
328
-
329
- /*
330
- * Document-method: new
331
- * call-seq: Mutex.new
332
- *
333
- * Creates a new Mutex
334
- *
335
- */
336
-
337
- static VALUE
338
- rb_mutex_alloc(VALUE klass)
339
- {
340
- Mutex *mutex;
341
- mutex = ALLOC(Mutex);
342
- init_mutex(mutex);
343
- return Data_Wrap_Struct(klass, mark_mutex, free_mutex, mutex);
344
- }
345
-
346
- /*
347
- * Document-method: locked?
348
- * call-seq: locked?
349
- *
350
- * Returns +true+ if this lock is currently held by some thread.
351
- *
352
- */
353
-
354
- static VALUE
355
- rb_mutex_locked_p(VALUE self)
356
- {
357
- Mutex *mutex;
358
- Data_Get_Struct(self, Mutex, mutex);
359
- return RTEST(mutex->owner) ? Qtrue : Qfalse;
360
- }
361
-
362
- /*
363
- * Document-method: try_lock
364
- * call-seq: try_lock
365
- *
366
- * Attempts to obtain the lock and returns immediately. Returns +true+ if the
367
- * lock was granted.
368
- *
369
- */
370
-
371
- static VALUE
372
- rb_mutex_try_lock(VALUE self)
373
- {
374
- Mutex *mutex;
375
-
376
- Data_Get_Struct(self, Mutex, mutex);
377
-
378
- if (RTEST(mutex->owner))
379
- return Qfalse;
380
-
381
- mutex->owner = rb_thread_current();
382
- return Qtrue;
383
- }
384
-
385
- /*
386
- * Document-method: lock
387
- * call-seq: lock
388
- *
389
- * Attempts to grab the lock and waits if it isn't available.
390
- *
391
- */
392
-
393
- static void
394
- lock_mutex(Mutex *mutex)
395
- {
396
- VALUE current;
397
- current = rb_thread_current();
398
-
399
- rb_thread_critical = 1;
400
-
401
- while (RTEST(mutex->owner)) {
402
- wait_list(&mutex->waiting);
403
- rb_thread_critical = 1;
404
- }
405
- mutex->owner = current;
406
-
407
- rb_thread_critical = 0;
408
- }
409
-
410
- static VALUE
411
- rb_mutex_lock(VALUE self)
412
- {
413
- Mutex *mutex;
414
- Data_Get_Struct(self, Mutex, mutex);
415
- lock_mutex(mutex);
416
- return self;
417
- }
418
-
419
- /*
420
- * Document-method: unlock
421
- *
422
- * Releases the lock. Returns +nil+ if ref wasn't locked.
423
- *
424
- */
425
-
426
- static VALUE
427
- unlock_mutex_inner(Mutex *mutex)
428
- {
429
- VALUE waking;
430
-
431
- if (!RTEST(mutex->owner)) {
432
- return Qundef;
433
- }
434
- mutex->owner = Qnil;
435
- waking = wake_one(&mutex->waiting);
436
-
437
- return waking;
438
- }
439
-
440
- static VALUE
441
- set_critical(VALUE value)
442
- {
443
- rb_thread_critical = (int)value;
444
- return Qundef;
445
- }
446
-
447
- static VALUE
448
- unlock_mutex(Mutex *mutex)
449
- {
450
- VALUE waking;
451
-
452
- rb_thread_critical = 1;
453
- waking = rb_ensure(unlock_mutex_inner, (VALUE)mutex, set_critical, 0);
454
-
455
- if (waking == Qundef) {
456
- return Qfalse;
457
- }
458
-
459
- if (RTEST(waking)) {
460
- run_thread(waking);
461
- }
462
-
463
- return Qtrue;
464
- }
465
-
466
- static VALUE
467
- rb_mutex_unlock(VALUE self)
468
- {
469
- Mutex *mutex;
470
- Data_Get_Struct(self, Mutex, mutex);
471
-
472
- if (RTEST(unlock_mutex(mutex))) {
473
- return self;
474
- } else {
475
- return Qnil;
476
- }
477
- }
478
-
479
- /*
480
- * Document-method: exclusive_unlock
481
- * call-seq: exclusive_unlock { ... }
482
- *
483
- * If the mutex is locked, unlocks the mutex, wakes one waiting thread, and
484
- * yields in a critical section.
485
- *
486
- */
487
-
488
- static VALUE
489
- rb_mutex_exclusive_unlock_inner(Mutex *mutex)
490
- {
491
- VALUE waking;
492
- waking = unlock_mutex_inner(mutex);
493
- rb_yield(Qundef);
494
- return waking;
495
- }
496
-
497
- static VALUE
498
- rb_mutex_exclusive_unlock(VALUE self)
499
- {
500
- Mutex *mutex;
501
- VALUE waking;
502
- Data_Get_Struct(self, Mutex, mutex);
503
-
504
- rb_thread_critical = 1;
505
- waking = rb_ensure(rb_mutex_exclusive_unlock_inner, (VALUE)mutex, set_critical, 0);
506
-
507
- if (waking == Qundef) {
508
- return Qnil;
509
- }
510
-
511
- if (RTEST(waking)) {
512
- run_thread(waking);
513
- }
514
-
515
- return self;
516
- }
517
-
518
- /*
519
- * Document-method: synchronize
520
- * call-seq: synchronize { ... }
521
- *
522
- * Obtains a lock, runs the block, and releases the lock when the block
523
- * completes. See the example under Mutex.
524
- *
525
- */
526
-
527
- static VALUE
528
- rb_mutex_synchronize(VALUE self)
529
- {
530
- rb_mutex_lock(self);
531
- return rb_ensure(rb_yield, Qundef, rb_mutex_unlock, self);
532
- }
533
-
534
- /*
535
- * Document-class: ConditionVariable
536
- *
537
- * ConditionVariable objects augment class Mutex. Using condition variables,
538
- * it is possible to suspend while in the middle of a critical section until a
539
- * resource becomes available.
540
- *
541
- * Example:
542
- *
543
- * require 'thread'
544
- *
545
- * mutex = Mutex.new
546
- * resource = ConditionVariable.new
547
- *
548
- * a = Thread.new {
549
- * mutex.synchronize {
550
- * # Thread 'a' now needs the resource
551
- * resource.wait(mutex)
552
- * # 'a' can now have the resource
553
- * }
554
- * }
555
- *
556
- * b = Thread.new {
557
- * mutex.synchronize {
558
- * # Thread 'b' has finished using the resource
559
- * resource.signal
560
- * }
561
- * }
562
- *
563
- */
564
-
565
- typedef struct _ConditionVariable {
566
- List waiting;
567
- } ConditionVariable;
568
-
569
- static void
570
- mark_condvar(ConditionVariable *condvar)
571
- {
572
- mark_list(&condvar->waiting);
573
- }
574
-
575
- static void
576
- finalize_condvar(ConditionVariable *condvar)
577
- {
578
- finalize_list(&condvar->waiting);
579
- }
580
-
581
- static void
582
- free_condvar(ConditionVariable *condvar)
583
- {
584
- assert_no_survivors(&condvar->waiting, "condition variable", condvar);
585
- finalize_condvar(condvar);
586
- xfree(condvar);
587
- }
588
-
589
- static void
590
- init_condvar(ConditionVariable *condvar)
591
- {
592
- init_list(&condvar->waiting);
593
- }
594
-
595
- /*
596
- * Document-method: new
597
- * call-seq: ConditionVariable.new
598
- *
599
- * Creates a new ConditionVariable
600
- *
601
- */
602
-
603
- static VALUE
604
- rb_condvar_alloc(VALUE klass)
605
- {
606
- ConditionVariable *condvar;
607
-
608
- condvar = ALLOC(ConditionVariable);
609
- init_condvar(condvar);
610
-
611
- return Data_Wrap_Struct(klass, mark_condvar, free_condvar, condvar);
612
- }
613
-
614
- /*
615
- * Document-method: wait
616
- * call-seq: wait
617
- *
618
- * Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
619
- *
620
- */
621
-
622
- static void
623
- wait_condvar(ConditionVariable *condvar, Mutex *mutex)
624
- {
625
- rb_thread_critical = 1;
626
- if (!RTEST(mutex->owner)) {
627
- rb_thread_critical = 0;
628
- return;
629
- }
630
- if (mutex->owner != rb_thread_current()) {
631
- rb_thread_critical = 0;
632
- rb_raise(rb_eThreadError, "Not owner");
633
- }
634
- mutex->owner = Qnil;
635
- wait_list(&condvar->waiting);
636
-
637
- lock_mutex(mutex);
638
- }
639
-
640
- static VALUE
641
- legacy_exclusive_unlock(VALUE mutex)
642
- {
643
- return rb_funcall(mutex, rb_intern("exclusive_unlock"), 0);
644
- }
645
-
646
- typedef struct {
647
- ConditionVariable *condvar;
648
- VALUE mutex;
649
- } legacy_wait_args;
650
-
651
- static VALUE
652
- legacy_wait(VALUE unused, legacy_wait_args *args)
653
- {
654
- wait_list(&args->condvar->waiting);
655
- rb_funcall(args->mutex, rb_intern("lock"), 0);
656
- return Qnil;
657
- }
658
-
659
- static VALUE
660
- rb_condvar_wait(VALUE self, VALUE mutex_v)
661
- {
662
- ConditionVariable *condvar;
663
- Data_Get_Struct(self, ConditionVariable, condvar);
664
-
665
- if (CLASS_OF(mutex_v) != rb_cMutex) {
666
- /* interoperate with legacy mutex */
667
- legacy_wait_args args;
668
- args.condvar = condvar;
669
- args.mutex = mutex_v;
670
- rb_iterate(legacy_exclusive_unlock, mutex_v, legacy_wait, (VALUE)&args);
671
- } else {
672
- Mutex *mutex;
673
- Data_Get_Struct(mutex_v, Mutex, mutex);
674
- wait_condvar(condvar, mutex);
675
- }
676
-
677
- return self;
678
- }
679
-
680
- /*
681
- * Document-method: broadcast
682
- * call-seq: broadcast
683
- *
684
- * Wakes up all threads waiting for this condition.
685
- *
686
- */
687
-
688
- static VALUE
689
- rb_condvar_broadcast(VALUE self)
690
- {
691
- ConditionVariable *condvar;
692
-
693
- Data_Get_Struct(self, ConditionVariable, condvar);
694
-
695
- rb_thread_critical = 1;
696
- rb_ensure(wake_all, (VALUE)&condvar->waiting, set_critical, 0);
697
- rb_thread_schedule();
698
-
699
- return self;
700
- }
701
-
702
- /*
703
- * Document-method: signal
704
- * call-seq: signal
705
- *
706
- * Wakes up the first thread in line waiting for this condition.
707
- *
708
- */
709
-
710
- static void
711
- signal_condvar(ConditionVariable *condvar)
712
- {
713
- VALUE waking;
714
- rb_thread_critical = 1;
715
- waking = rb_ensure(wake_one, (VALUE)&condvar->waiting, set_critical, 0);
716
- if (RTEST(waking)) {
717
- run_thread(waking);
718
- }
719
- }
720
-
721
- static VALUE
722
- rb_condvar_signal(VALUE self)
723
- {
724
- ConditionVariable *condvar;
725
- Data_Get_Struct(self, ConditionVariable, condvar);
726
- signal_condvar(condvar);
727
- return self;
728
- }
729
-
730
- /*
731
- * Document-class: Queue
732
- *
733
- * This class provides a way to synchronize communication between threads.
734
- *
735
- * Example:
736
- *
737
- * require 'thread'
738
- *
739
- * queue = Queue.new
740
- *
741
- * producer = Thread.new do
742
- * 5.times do |i|
743
- * sleep rand(i) # simulate expense
744
- * queue << i
745
- * puts "#{i} produced"
746
- * end
747
- * end
748
- *
749
- * consumer = Thread.new do
750
- * 5.times do |i|
751
- * value = queue.pop
752
- * sleep rand(i/2) # simulate expense
753
- * puts "consumed #{value}"
754
- * end
755
- * end
756
- *
757
- * consumer.join
758
- *
759
- */
760
-
761
- typedef struct _Queue {
762
- Mutex mutex;
763
- ConditionVariable value_available;
764
- ConditionVariable space_available;
765
- List values;
766
- unsigned long capacity;
767
- } Queue;
768
-
769
- static void
770
- mark_queue(Queue *queue)
771
- {
772
- mark_mutex(&queue->mutex);
773
- mark_condvar(&queue->value_available);
774
- mark_condvar(&queue->space_available);
775
- mark_list(&queue->values);
776
- }
777
-
778
- static void
779
- finalize_queue(Queue *queue)
780
- {
781
- finalize_mutex(&queue->mutex);
782
- finalize_condvar(&queue->value_available);
783
- finalize_condvar(&queue->space_available);
784
- finalize_list(&queue->values);
785
- }
786
-
787
- static void
788
- free_queue(Queue *queue)
789
- {
790
- assert_no_survivors(&queue->mutex.waiting, "queue", queue);
791
- assert_no_survivors(&queue->space_available.waiting, "queue", queue);
792
- assert_no_survivors(&queue->value_available.waiting, "queue", queue);
793
- finalize_queue(queue);
794
- xfree(queue);
795
- }
796
-
797
- static void
798
- init_queue(Queue *queue)
799
- {
800
- init_mutex(&queue->mutex);
801
- init_condvar(&queue->value_available);
802
- init_condvar(&queue->space_available);
803
- init_list(&queue->values);
804
- queue->capacity = 0;
805
- }
806
-
807
- /*
808
- * Document-method: new
809
- * call-seq: new
810
- *
811
- * Creates a new queue.
812
- *
813
- */
814
-
815
- static VALUE
816
- rb_queue_alloc(VALUE klass)
817
- {
818
- Queue *queue;
819
- queue = ALLOC(Queue);
820
- init_queue(queue);
821
- return Data_Wrap_Struct(klass, mark_queue, free_queue, queue);
822
- }
823
-
824
- static VALUE
825
- rb_queue_marshal_load(VALUE self, VALUE data)
826
- {
827
- Queue *queue;
828
- VALUE array;
829
- Data_Get_Struct(self, Queue, queue);
830
-
831
- array = rb_marshal_load(data);
832
- if (TYPE(array) != T_ARRAY) {
833
- rb_raise(rb_eRuntimeError, "expected Array of queue data");
834
- }
835
- if (RARRAY(array)->len < 1) {
836
- rb_raise(rb_eRuntimeError, "missing capacity value");
837
- }
838
- queue->capacity = NUM2ULONG(rb_ary_shift(array));
839
- push_multiple_list(&queue->values, RARRAY(array)->ptr, (unsigned)RARRAY(array)->len);
840
-
841
- return self;
842
- }
843
-
844
- static VALUE
845
- rb_queue_marshal_dump(VALUE self)
846
- {
847
- Queue *queue;
848
- VALUE array;
849
- Data_Get_Struct(self, Queue, queue);
850
-
851
- array = array_from_list(&queue->values);
852
- rb_ary_unshift(array, ULONG2NUM(queue->capacity));
853
- return rb_marshal_dump(array, Qnil);
854
- }
855
-
856
- /*
857
- * Document-method: clear
858
- * call-seq: clear
859
- *
860
- * Removes all objects from the queue.
861
- *
862
- */
863
-
864
- static VALUE
865
- rb_queue_clear(VALUE self)
866
- {
867
- Queue *queue;
868
- Data_Get_Struct(self, Queue, queue);
869
-
870
- lock_mutex(&queue->mutex);
871
- clear_list(&queue->values);
872
- signal_condvar(&queue->space_available);
873
- unlock_mutex(&queue->mutex);
874
-
875
- return self;
876
- }
877
-
878
- /*
879
- * Document-method: empty?
880
- * call-seq: empty?
881
- *
882
- * Returns +true+ if the queue is empty.
883
- *
884
- */
885
-
886
- static VALUE
887
- rb_queue_empty_p(VALUE self)
888
- {
889
- Queue *queue;
890
- VALUE result;
891
- Data_Get_Struct(self, Queue, queue);
892
-
893
- lock_mutex(&queue->mutex);
894
- result = queue->values.size == 0 ? Qtrue : Qfalse;
895
- unlock_mutex(&queue->mutex);
896
-
897
- return result;
898
- }
899
-
900
- /*
901
- * Document-method: length
902
- * call-seq: length
903
- *
904
- * Returns the length of the queue.
905
- *
906
- */
907
-
908
- static VALUE
909
- rb_queue_length(VALUE self)
910
- {
911
- Queue *queue;
912
- VALUE result;
913
- Data_Get_Struct(self, Queue, queue);
914
-
915
- lock_mutex(&queue->mutex);
916
- result = ULONG2NUM(queue->values.size);
917
- unlock_mutex(&queue->mutex);
918
-
919
- return result;
920
- }
921
-
922
- /*
923
- * Document-method: num_waiting
924
- * call-seq: num_waiting
925
- *
926
- * Returns the number of threads waiting on the queue.
927
- *
928
- */
929
-
930
- static VALUE
931
- rb_queue_num_waiting(VALUE self)
932
- {
933
- Queue *queue;
934
- VALUE result;
935
- Data_Get_Struct(self, Queue, queue);
936
-
937
- lock_mutex(&queue->mutex);
938
- result = ULONG2NUM(queue->value_available.waiting.size +
939
- queue->space_available.waiting.size);
940
- unlock_mutex(&queue->mutex);
941
-
942
- return result;
943
- }
944
-
945
- /*
946
- * Document-method: pop
947
- * call_seq: pop(non_block=false)
948
- *
949
- * Retrieves data from the queue. If the queue is empty, the calling thread is
950
- * suspended until data is pushed onto the queue. If +non_block+ is true, the
951
- * thread isn't suspended, and an exception is raised.
952
- *
953
- */
954
-
955
- static VALUE
956
- rb_queue_pop(int argc, VALUE *argv, VALUE self)
957
- {
958
- Queue *queue;
959
- int should_block;
960
- VALUE result;
961
- Data_Get_Struct(self, Queue, queue);
962
-
963
- if (argc == 0) {
964
- should_block = 1;
965
- } else if (argc == 1) {
966
- should_block = !RTEST(argv[0]);
967
- } else {
968
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
969
- }
970
-
971
- lock_mutex(&queue->mutex);
972
- if (!queue->values.entries && !should_block) {
973
- unlock_mutex(&queue->mutex);
974
- rb_raise(rb_eThreadError, "queue empty");
975
- }
976
-
977
- while (!queue->values.entries) {
978
- wait_condvar(&queue->value_available, &queue->mutex);
979
- }
980
-
981
- result = shift_list(&queue->values);
982
- if (queue->capacity && queue->values.size < queue->capacity) {
983
- signal_condvar(&queue->space_available);
984
- }
985
- unlock_mutex(&queue->mutex);
986
-
987
- return result;
988
- }
989
-
990
- /*
991
- * Document-method: push
992
- * call-seq: push(obj)
993
- *
994
- * Pushes +obj+ to the queue.
995
- *
996
- */
997
-
998
- static VALUE
999
- rb_queue_push(VALUE self, VALUE value)
1000
- {
1001
- Queue *queue;
1002
- Data_Get_Struct(self, Queue, queue);
1003
-
1004
- lock_mutex(&queue->mutex);
1005
- while (queue->capacity && queue->values.size >= queue->capacity) {
1006
- wait_condvar(&queue->space_available, &queue->mutex);
1007
- }
1008
- push_list(&queue->values, value);
1009
- signal_condvar(&queue->value_available);
1010
- unlock_mutex(&queue->mutex);
1011
-
1012
- return self;
1013
- }
1014
-
1015
- /*
1016
- * Document-class: SizedQueue
1017
- *
1018
- * This class represents queues of specified size capacity. The push operation
1019
- * may be blocked if the capacity is full.
1020
- *
1021
- * See Queue for an example of how a SizedQueue works.
1022
- *
1023
- */
1024
-
1025
- /*
1026
- * Document-method: new
1027
- * call-seq: new
1028
- *
1029
- * Creates a fixed-length queue with a maximum size of +max+.
1030
- *
1031
- */
1032
-
1033
- /*
1034
- * Document-method: max
1035
- * call-seq: max
1036
- *
1037
- * Returns the maximum size of the queue.
1038
- *
1039
- */
1040
-
1041
- static VALUE
1042
- rb_sized_queue_max(VALUE self)
1043
- {
1044
- Queue *queue;
1045
- VALUE result;
1046
- Data_Get_Struct(self, Queue, queue);
1047
-
1048
- lock_mutex(&queue->mutex);
1049
- result = ULONG2NUM(queue->capacity);
1050
- unlock_mutex(&queue->mutex);
1051
-
1052
- return result;
1053
- }
1054
-
1055
- /*
1056
- * Document-method: max=
1057
- * call-seq: max=(size)
1058
- *
1059
- * Sets the maximum size of the queue.
1060
- *
1061
- */
1062
-
1063
- static VALUE
1064
- rb_sized_queue_max_set(VALUE self, VALUE value)
1065
- {
1066
- Queue *queue;
1067
- unsigned long new_capacity;
1068
- unsigned long difference;
1069
- Data_Get_Struct(self, Queue, queue);
1070
-
1071
- new_capacity = NUM2ULONG(value);
1072
-
1073
- if (new_capacity < 1) {
1074
- rb_raise(rb_eArgError, "value must be positive");
1075
- }
1076
-
1077
- lock_mutex(&queue->mutex);
1078
- if (queue->capacity && new_capacity > queue->capacity) {
1079
- difference = new_capacity - queue->capacity;
1080
- } else {
1081
- difference = 0;
1082
- }
1083
- queue->capacity = new_capacity;
1084
- for (; difference > 0; --difference) {
1085
- signal_condvar(&queue->space_available);
1086
- }
1087
- unlock_mutex(&queue->mutex);
1088
-
1089
- return self;
1090
- }
1091
-
1092
- /*
1093
- * Document-method: push
1094
- * call-seq: push(obj)
1095
- *
1096
- * Pushes +obj+ to the queue. If there is no space left in the queue, waits
1097
- * until space becomes available.
1098
- *
1099
- */
1100
-
1101
- /*
1102
- * Document-method: pop
1103
- * call-seq: pop(non_block=false)
1104
- *
1105
- * Retrieves data from the queue and runs a waiting thread, if any.
1106
- *
1107
- */
1108
-
1109
- /* for marshalling mutexes and condvars */
1110
-
1111
- static VALUE
1112
- dummy_load(VALUE self, VALUE string)
1113
- {
1114
- return Qnil;
1115
- }
1116
-
1117
- static VALUE
1118
- dummy_dump(VALUE self)
1119
- {
1120
- return rb_str_new2("");
1121
- }
1122
-
1123
- void
1124
- Init_thread(void)
1125
- {
1126
- rb_define_singleton_method(rb_cThread, "exclusive", rb_thread_exclusive, 0);
1127
-
1128
- rb_cMutex = rb_define_class("Mutex", rb_cObject);
1129
- rb_define_alloc_func(rb_cMutex, rb_mutex_alloc);
1130
- rb_define_method(rb_cMutex, "marshal_load", dummy_load, 1);
1131
- rb_define_method(rb_cMutex, "marshal_dump", dummy_dump, 0);
1132
- rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
1133
- rb_define_method(rb_cMutex, "try_lock", rb_mutex_try_lock, 0);
1134
- rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
1135
- rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
1136
- rb_define_method(rb_cMutex, "exclusive_unlock", rb_mutex_exclusive_unlock, 0);
1137
- rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize, 0);
1138
-
1139
- rb_cConditionVariable = rb_define_class("ConditionVariable", rb_cObject);
1140
- rb_define_alloc_func(rb_cConditionVariable, rb_condvar_alloc);
1141
- rb_define_method(rb_cConditionVariable, "marshal_load", dummy_load, 1);
1142
- rb_define_method(rb_cConditionVariable, "marshal_dump", dummy_dump, 0);
1143
- rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, 1);
1144
- rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0);
1145
- rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0);
1146
-
1147
- rb_cQueue = rb_define_class("Queue", rb_cObject);
1148
- rb_define_alloc_func(rb_cQueue, rb_queue_alloc);
1149
- rb_define_method(rb_cQueue, "marshal_load", rb_queue_marshal_load, 1);
1150
- rb_define_method(rb_cQueue, "marshal_dump", rb_queue_marshal_dump, 0);
1151
- rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0);
1152
- rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0);
1153
- rb_define_method(rb_cQueue, "length", rb_queue_length, 0);
1154
- rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
1155
- rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1);
1156
- rb_define_method(rb_cQueue, "push", rb_queue_push, 1);
1157
- rb_alias(rb_cQueue, rb_intern("enq"), rb_intern("push"));
1158
- rb_alias(rb_cQueue, rb_intern("<<"), rb_intern("push"));
1159
- rb_alias(rb_cQueue, rb_intern("deq"), rb_intern("pop"));
1160
- rb_alias(rb_cQueue, rb_intern("shift"), rb_intern("pop"));
1161
- rb_alias(rb_cQueue, rb_intern("size"), rb_intern("length"));
1162
-
1163
- rb_cSizedQueue = rb_define_class("SizedQueue", rb_cQueue);
1164
- rb_define_method(rb_cSizedQueue, "initialize", rb_sized_queue_max_set, 1);
1165
- rb_define_method(rb_cSizedQueue, "num_waiting", rb_queue_num_waiting, 0);
1166
- rb_define_method(rb_cSizedQueue, "pop", rb_queue_pop, -1);
1167
- rb_define_method(rb_cSizedQueue, "push", rb_queue_push, 1);
1168
- rb_define_method(rb_cSizedQueue, "max", rb_sized_queue_max, 0);
1169
- rb_define_method(rb_cSizedQueue, "max=", rb_sized_queue_max_set, 1);
1170
- rb_alias(rb_cSizedQueue, rb_intern("enq"), rb_intern("push"));
1171
- rb_alias(rb_cSizedQueue, rb_intern("<<"), rb_intern("push"));
1172
- rb_alias(rb_cSizedQueue, rb_intern("deq"), rb_intern("pop"));
1173
- rb_alias(rb_cSizedQueue, rb_intern("shift"), rb_intern("pop"));
1174
- }
1175
-