rage-iodine 1.7.58

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.github/workflows/ruby.yml +42 -0
  4. data/.gitignore +20 -0
  5. data/.rspec +2 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1098 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/LIMITS.md +41 -0
  11. data/README.md +782 -0
  12. data/Rakefile +23 -0
  13. data/SPEC-PubSub-Draft.md +159 -0
  14. data/SPEC-WebSocket-Draft.md +239 -0
  15. data/bin/console +22 -0
  16. data/bin/info.md +353 -0
  17. data/bin/mustache_bench.rb +100 -0
  18. data/bin/poc/Gemfile.lock +23 -0
  19. data/bin/poc/README.md +37 -0
  20. data/bin/poc/config.ru +66 -0
  21. data/bin/poc/gemfile +1 -0
  22. data/bin/poc/www/index.html +57 -0
  23. data/examples/async_task.ru +92 -0
  24. data/examples/bates/README.md +3 -0
  25. data/examples/bates/config.ru +342 -0
  26. data/examples/bates/david+bold.pdf +0 -0
  27. data/examples/bates/public/drop-pdf.png +0 -0
  28. data/examples/bates/public/index.html +600 -0
  29. data/examples/config.ru +59 -0
  30. data/examples/echo.ru +59 -0
  31. data/examples/etag.ru +16 -0
  32. data/examples/hello.ru +29 -0
  33. data/examples/pubsub_engine.ru +81 -0
  34. data/examples/rack3.ru +12 -0
  35. data/examples/redis.ru +70 -0
  36. data/examples/shootout.ru +73 -0
  37. data/examples/sub-protocols.ru +90 -0
  38. data/examples/tcp_client.rb +66 -0
  39. data/examples/x-sendfile.ru +14 -0
  40. data/exe/iodine +280 -0
  41. data/ext/iodine/extconf.rb +110 -0
  42. data/ext/iodine/fio.c +12096 -0
  43. data/ext/iodine/fio.h +6390 -0
  44. data/ext/iodine/fio_cli.c +431 -0
  45. data/ext/iodine/fio_cli.h +189 -0
  46. data/ext/iodine/fio_json_parser.h +687 -0
  47. data/ext/iodine/fio_siphash.c +157 -0
  48. data/ext/iodine/fio_siphash.h +37 -0
  49. data/ext/iodine/fio_tls.h +129 -0
  50. data/ext/iodine/fio_tls_missing.c +649 -0
  51. data/ext/iodine/fio_tls_openssl.c +1056 -0
  52. data/ext/iodine/fio_tmpfile.h +50 -0
  53. data/ext/iodine/fiobj.h +44 -0
  54. data/ext/iodine/fiobj4fio.h +21 -0
  55. data/ext/iodine/fiobj_ary.c +333 -0
  56. data/ext/iodine/fiobj_ary.h +139 -0
  57. data/ext/iodine/fiobj_data.c +1185 -0
  58. data/ext/iodine/fiobj_data.h +167 -0
  59. data/ext/iodine/fiobj_hash.c +409 -0
  60. data/ext/iodine/fiobj_hash.h +176 -0
  61. data/ext/iodine/fiobj_json.c +622 -0
  62. data/ext/iodine/fiobj_json.h +68 -0
  63. data/ext/iodine/fiobj_mem.h +71 -0
  64. data/ext/iodine/fiobj_mustache.c +317 -0
  65. data/ext/iodine/fiobj_mustache.h +62 -0
  66. data/ext/iodine/fiobj_numbers.c +344 -0
  67. data/ext/iodine/fiobj_numbers.h +127 -0
  68. data/ext/iodine/fiobj_str.c +433 -0
  69. data/ext/iodine/fiobj_str.h +172 -0
  70. data/ext/iodine/fiobject.c +620 -0
  71. data/ext/iodine/fiobject.h +654 -0
  72. data/ext/iodine/hpack.h +1923 -0
  73. data/ext/iodine/http.c +2736 -0
  74. data/ext/iodine/http.h +1019 -0
  75. data/ext/iodine/http1.c +825 -0
  76. data/ext/iodine/http1.h +29 -0
  77. data/ext/iodine/http1_parser.h +1835 -0
  78. data/ext/iodine/http_internal.c +1279 -0
  79. data/ext/iodine/http_internal.h +248 -0
  80. data/ext/iodine/http_mime_parser.h +350 -0
  81. data/ext/iodine/iodine.c +1433 -0
  82. data/ext/iodine/iodine.h +64 -0
  83. data/ext/iodine/iodine_caller.c +218 -0
  84. data/ext/iodine/iodine_caller.h +27 -0
  85. data/ext/iodine/iodine_connection.c +941 -0
  86. data/ext/iodine/iodine_connection.h +55 -0
  87. data/ext/iodine/iodine_defer.c +420 -0
  88. data/ext/iodine/iodine_defer.h +6 -0
  89. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  90. data/ext/iodine/iodine_helpers.c +282 -0
  91. data/ext/iodine/iodine_helpers.h +12 -0
  92. data/ext/iodine/iodine_http.c +1280 -0
  93. data/ext/iodine/iodine_http.h +23 -0
  94. data/ext/iodine/iodine_json.c +302 -0
  95. data/ext/iodine/iodine_json.h +6 -0
  96. data/ext/iodine/iodine_mustache.c +567 -0
  97. data/ext/iodine/iodine_mustache.h +6 -0
  98. data/ext/iodine/iodine_pubsub.c +580 -0
  99. data/ext/iodine/iodine_pubsub.h +26 -0
  100. data/ext/iodine/iodine_rack_io.c +273 -0
  101. data/ext/iodine/iodine_rack_io.h +20 -0
  102. data/ext/iodine/iodine_store.c +142 -0
  103. data/ext/iodine/iodine_store.h +20 -0
  104. data/ext/iodine/iodine_tcp.c +346 -0
  105. data/ext/iodine/iodine_tcp.h +13 -0
  106. data/ext/iodine/iodine_tls.c +261 -0
  107. data/ext/iodine/iodine_tls.h +13 -0
  108. data/ext/iodine/mustache_parser.h +1546 -0
  109. data/ext/iodine/redis_engine.c +957 -0
  110. data/ext/iodine/redis_engine.h +79 -0
  111. data/ext/iodine/resp_parser.h +317 -0
  112. data/ext/iodine/scheduler.c +173 -0
  113. data/ext/iodine/scheduler.h +6 -0
  114. data/ext/iodine/websocket_parser.h +506 -0
  115. data/ext/iodine/websockets.c +752 -0
  116. data/ext/iodine/websockets.h +185 -0
  117. data/iodine.gemspec +50 -0
  118. data/lib/iodine/connection.rb +61 -0
  119. data/lib/iodine/json.rb +42 -0
  120. data/lib/iodine/mustache.rb +113 -0
  121. data/lib/iodine/pubsub.rb +55 -0
  122. data/lib/iodine/rack_utils.rb +43 -0
  123. data/lib/iodine/tls.rb +16 -0
  124. data/lib/iodine/version.rb +3 -0
  125. data/lib/iodine.rb +274 -0
  126. data/lib/rack/handler/iodine.rb +33 -0
  127. data/logo.png +0 -0
  128. metadata +284 -0
@@ -0,0 +1,273 @@
1
+ /*
2
+ Copyright: Boaz segev, 2016-2017
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #include "iodine_rack_io.h"
8
+
9
+ #include "iodine.h"
10
+
11
+ #include <ruby/encoding.h>
12
+ #include <ruby/io.h>
13
+ #include <unistd.h>
14
+
15
+ #ifndef _GNU_SOURCE
16
+ #define _GNU_SOURCE
17
+ #endif
18
+
19
+ /* IodineRackIO manages a minimal interface to act as an IO wrapper according to
20
+ these Rack specifications:
21
+
22
+ The input stream is an IO-like object which contains the raw HTTP POST data.
23
+ When applicable, its external encoding must be “ASCII-8BIT” and it must be
24
+ opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond
25
+ to gets, each, read and rewind.
26
+
27
+ gets must be called without arguments and return a string, or nil on EOF.
28
+
29
+ read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
30
+ length must be a non-negative Integer (>= 0) or nil, and buffer must be a String
31
+ and may not be nil. If length is given and not nil, then this method reads at
32
+ most length bytes from the input stream. If length is not given or nil, then
33
+ this method reads all data until EOF. When EOF is reached, this method returns
34
+ nil if length is given and not nil, or “” if length is not given or is nil. If
35
+ buffer is given, then the read data will be placed into buffer instead of a
36
+ newly created String object.
37
+
38
+ each must be called without arguments and only yield Strings.
39
+
40
+ rewind must be called without arguments. It rewinds the input stream back to the
41
+ beginning. It must not raise Errno::ESPIPE: that is, it may not be a pipe or a
42
+ socket. Therefore, handler developers must buffer the input data into some
43
+ rewindable object if the underlying input stream is not rewindable.
44
+
45
+ close must never be called on the input stream.
46
+
47
+ */
48
+
49
+ /* *****************************************************************************
50
+ Core data / helpers
51
+ */
52
+
53
+ static VALUE rRackIO;
54
+
55
+ static ID env_id;
56
+ static ID io_id;
57
+
58
+ static VALUE R_INPUT; /* rack.input */
59
+ static VALUE hijack_func_sym;
60
+ static VALUE TCPSOCKET_CLASS;
61
+ static ID for_fd_id;
62
+ static ID iodine_fd_var_id;
63
+ static ID iodine_new_func_id;
64
+ #ifdef __MINGW32__
65
+ static ID iodine_osffd_id;
66
+ #endif
67
+ static rb_encoding *IodineUTF8Encoding;
68
+ static rb_encoding *IodineBinaryEncoding;
69
+
70
+ #define set_handle(object, handle) \
71
+ rb_ivar_set((object), iodine_fd_var_id, ULL2NUM((uintptr_t)handle))
72
+
73
+ inline static http_s *get_handle(VALUE obj) {
74
+ VALUE i = rb_ivar_get(obj, iodine_fd_var_id);
75
+ return (http_s *)NUM2ULL(i);
76
+ }
77
+
78
+ /* *****************************************************************************
79
+ IO API
80
+ */
81
+
82
+ static inline FIOBJ get_data(VALUE self) {
83
+ VALUE i = rb_ivar_get(self, io_id);
84
+ return (FIOBJ)NUM2ULL(i);
85
+ }
86
+
87
+ static VALUE rio_rewind(VALUE self) {
88
+ FIOBJ io = get_data(self);
89
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
90
+ return Qnil;
91
+ fiobj_data_seek(io, 0);
92
+ return INT2NUM(0);
93
+ }
94
+ /**
95
+ Gets returns a line. this is okay for small lines,
96
+ but shouldn't really be used.
97
+
98
+ Limited to ~ 1Mb of a line length.
99
+ */
100
+ static VALUE rio_gets(VALUE self) {
101
+ FIOBJ io = get_data(self);
102
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
103
+ return Qnil;
104
+ fio_str_info_s line = fiobj_data_gets(io);
105
+ if (line.len) {
106
+ VALUE buffer = rb_str_new(line.data, line.len);
107
+ // make sure the buffer is binary encoded.
108
+ rb_enc_associate(buffer, IodineBinaryEncoding);
109
+ return buffer;
110
+ }
111
+ return Qnil;
112
+ }
113
+
114
+ // Reads data from the IO, according to the Rack specifications for `#read`.
115
+ static VALUE rio_read(int argc, VALUE *argv, VALUE self) {
116
+ FIOBJ io = get_data(self);
117
+ VALUE buffer = Qnil;
118
+ uint8_t ret_nil = 0;
119
+ ssize_t len = 0;
120
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
121
+ return (argc > 0 && argv[0] != Qnil) ? Qnil : rb_str_buf_new(0);
122
+ }
123
+
124
+ // get the buffer object if given
125
+ if (argc == 2) {
126
+ Check_Type(argv[1], T_STRING);
127
+ buffer = argv[1];
128
+ }
129
+ // get the length object, if given
130
+ if (argc > 0 && argv[0] != Qnil) {
131
+ Check_Type(argv[0], T_FIXNUM);
132
+ len = FIX2LONG(argv[0]);
133
+ if (len < 0)
134
+ rb_raise(rb_eRangeError, "length should be bigger then 0.");
135
+ if (len == 0)
136
+ return rb_str_buf_new(0);
137
+ ret_nil = 1;
138
+ }
139
+ // return if we're at the EOF.
140
+ fio_str_info_s buf = fiobj_data_read(io, len);
141
+ if (buf.len) {
142
+ // create the buffer if we don't have one.
143
+ if (buffer == Qnil) {
144
+ // make sure the buffer is binary encoded.
145
+ buffer = rb_enc_str_new(buf.data, buf.len, IodineBinaryEncoding);
146
+ } else {
147
+ // make sure the buffer is binary encoded.
148
+ rb_enc_associate(buffer, IodineBinaryEncoding);
149
+ if (rb_str_capacity(buffer) < (size_t)buf.len)
150
+ rb_str_resize(buffer, buf.len);
151
+ memcpy(RSTRING_PTR(buffer), buf.data, buf.len);
152
+ rb_str_set_len(buffer, buf.len);
153
+ }
154
+ return buffer;
155
+ }
156
+ return ret_nil ? Qnil : rb_str_buf_new(0);
157
+ }
158
+
159
+ // Does nothing - this is controlled by the server.
160
+ static VALUE rio_close(VALUE self) {
161
+ // FIOBJ io = get_data(self);
162
+ // fiobj_free(io); // we don't call fiobj_dup, do we?
163
+ rb_ivar_set(self, io_id, INT2NUM(0));
164
+ (void)self;
165
+ return Qnil;
166
+ }
167
+
168
+ // Passes each line of the input to the block. This should be avoided.
169
+ static VALUE rio_each(VALUE self) {
170
+ rb_need_block();
171
+ rio_rewind(self);
172
+ VALUE str = Qnil;
173
+ while ((str = rio_gets(self)) != Qnil) {
174
+ rb_yield(str);
175
+ }
176
+ return self;
177
+ }
178
+
179
+ /* *****************************************************************************
180
+ Hijacking
181
+ */
182
+
183
+ // defined by iodine_http
184
+ extern VALUE IODINE_R_HIJACK; // for Rack: rack.hijack
185
+ extern VALUE IODINE_R_HIJACK_CB; // for Rack: rack.hijack
186
+ extern VALUE IODINE_R_HIJACK_IO; // for Rack: rack.hijack_io
187
+
188
+ static VALUE rio_get_io(int argc, VALUE *argv, VALUE self) {
189
+ if (TCPSOCKET_CLASS == Qnil)
190
+ return Qfalse;
191
+ VALUE env = rb_ivar_get(self, env_id);
192
+ http_s *h = get_handle(self);
193
+ if (h == NULL) {
194
+ /* we're repeating ourselves, aren't we? */
195
+ VALUE io = rb_hash_aref(env, IODINE_R_HIJACK_IO);
196
+ return io;
197
+ }
198
+ // mark update
199
+ set_handle(self, NULL);
200
+ // hijack the IO object
201
+ intptr_t uuid = http_hijack(h, NULL);
202
+ #ifdef __MINGW32__
203
+ int osffd = fio_osffd4fd(fio_uuid2fd(uuid));
204
+ if (osffd == -1)
205
+ return Qfalse;
206
+ VALUE fd = INT2FIX(osffd);
207
+ #else
208
+ VALUE fd = INT2FIX(fio_uuid2fd(uuid));
209
+ #endif
210
+ // VALUE new_io = how the fuck do we create a new IO from the fd?
211
+ VALUE new_io = IodineCaller.call2(TCPSOCKET_CLASS, for_fd_id, 1,
212
+ &fd); // TCPSocket.for_fd(fd) ... cool...
213
+ rb_hash_aset(env, IODINE_R_HIJACK_IO, new_io);
214
+ if (argc)
215
+ rb_hash_aset(env, IODINE_R_HIJACK_CB, *argv);
216
+ return new_io;
217
+ }
218
+
219
+ /* *****************************************************************************
220
+ C land API
221
+ */
222
+
223
+ // new object
224
+ static VALUE new_rack_io(http_s *h, VALUE env) {
225
+ VALUE rack_io = rb_funcall2(rRackIO, iodine_new_func_id, 0, NULL);
226
+ rb_ivar_set(rack_io, io_id, ULL2NUM(h->body));
227
+ set_handle(rack_io, h);
228
+ rb_ivar_set(rack_io, env_id, env);
229
+ rb_hash_aset(env, IODINE_R_INPUT, rack_io);
230
+ rb_hash_aset(env, IODINE_R_HIJACK, rb_obj_method(rack_io, hijack_func_sym));
231
+ return rack_io;
232
+ }
233
+
234
+ static void close_rack_io(VALUE rack_io) {
235
+ // rio_close(rack_io);
236
+ rb_ivar_set(rack_io, io_id, INT2NUM(0));
237
+ set_handle(rack_io, NULL); /* this disables hijacking. */
238
+ }
239
+
240
+ // initialize library
241
+ static void init_rack_io(void) {
242
+ IodineUTF8Encoding = rb_enc_find("UTF-8");
243
+ IodineBinaryEncoding = rb_enc_find("binary");
244
+ rRackIO = rb_define_class_under(IodineBaseModule, "RackIO", rb_cObject);
245
+
246
+ io_id = rb_intern("rack_io");
247
+ env_id = rb_intern("env");
248
+ for_fd_id = rb_intern("for_fd");
249
+ iodine_fd_var_id = rb_intern("fd");
250
+ iodine_new_func_id = rb_intern("new");
251
+ #ifdef __MINGW32__
252
+ iodine_osffd_id = rb_intern("osffd");
253
+ #endif
254
+ hijack_func_sym = ID2SYM(rb_intern("_hijack"));
255
+
256
+ TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
257
+ // IO methods
258
+
259
+ rb_define_method(rRackIO, "rewind", rio_rewind, 0);
260
+ rb_define_method(rRackIO, "gets", rio_gets, 0);
261
+ rb_define_method(rRackIO, "read", rio_read, -1);
262
+ rb_define_method(rRackIO, "close", rio_close, 0);
263
+ rb_define_method(rRackIO, "each", rio_each, 0);
264
+ rb_define_method(rRackIO, "_hijack", rio_get_io, -1);
265
+ }
266
+
267
+ ////////////////////////////////////////////////////////////////////////////
268
+ // the API interface
269
+ struct IodineRackIO IodineRackIO = {
270
+ .create = new_rack_io,
271
+ .close = close_rack_io,
272
+ .init = init_rack_io,
273
+ };
@@ -0,0 +1,20 @@
1
+ /*
2
+ Copyright: Boaz segev, 2016-2017
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef RUBY_RACK_IO_H
8
+ #define RUBY_RACK_IO_H
9
+
10
+ #include <ruby.h>
11
+
12
+ #include "http.h"
13
+
14
+ extern struct IodineRackIO {
15
+ VALUE (*create)(http_s *h, VALUE env);
16
+ void (*close)(VALUE rack_io);
17
+ void (*init)(void);
18
+ } IodineRackIO;
19
+
20
+ #endif /* RUBY_RACK_IO_H */
@@ -0,0 +1,142 @@
1
+ #include "iodine.h"
2
+
3
+ #include "iodine_store.h"
4
+
5
+ #include <inttypes.h>
6
+ #include <stdint.h>
7
+
8
+ #define FIO_SET_NAME fio_store
9
+ #define FIO_SET_OBJ_TYPE uintptr_t
10
+ #include <fio.h>
11
+
12
+ static fio_lock_i iodine_storage_lock = FIO_LOCK_INIT;
13
+ static fio_store_s iodine_storage = FIO_SET_INIT;
14
+ static size_t iodine_storage_count_max = 0;
15
+
16
+ #ifndef IODINE_DEBUG
17
+ #define IODINE_DEBUG 0
18
+ #endif
19
+
20
+ /* *****************************************************************************
21
+ API
22
+ ***************************************************************************** */
23
+
24
+ /** Adds an object to the storage (or increases it's reference count). */
25
+ static VALUE storage_add(VALUE obj) {
26
+ if (!obj || obj == Qnil || obj == Qtrue || obj == Qfalse)
27
+ return obj;
28
+ uintptr_t old = 0;
29
+ fio_lock(&iodine_storage_lock);
30
+ fio_store_overwrite(&iodine_storage, obj, 1, &old);
31
+ if (old)
32
+ fio_store_overwrite(&iodine_storage, obj, old + 1, NULL);
33
+ if (iodine_storage_count_max < fio_store_count(&iodine_storage))
34
+ iodine_storage_count_max = fio_store_count(&iodine_storage);
35
+ fio_unlock(&iodine_storage_lock);
36
+ return obj;
37
+ }
38
+ /** Removes an object from the storage (or decreases it's reference count). */
39
+ static VALUE storage_remove(VALUE obj) {
40
+ if (!obj || obj == Qnil || obj == Qtrue || obj == Qfalse ||
41
+ iodine_storage.count == 0)
42
+ return obj;
43
+ fio_lock(&iodine_storage_lock);
44
+ uintptr_t old = 0;
45
+ fio_store_remove(&iodine_storage, obj, 0, &old);
46
+ if (old > 1)
47
+ fio_store_overwrite(&iodine_storage, obj, old - 1, NULL);
48
+ fio_unlock(&iodine_storage_lock);
49
+ return obj;
50
+ }
51
+ /** Should be called after forking to reset locks */
52
+ static void storage_after_fork(void) { iodine_storage_lock = FIO_LOCK_INIT; }
53
+
54
+ /** Prints debugging information to the console. */
55
+ static void storage_print(void) {
56
+ FIO_LOG_DEBUG("Ruby <=> C Memory storage stats (pid: %d):\n", getpid());
57
+ fio_lock(&iodine_storage_lock);
58
+ uintptr_t index = 0;
59
+ FIO_SET_FOR_LOOP(&iodine_storage, pos) {
60
+ if (pos->obj) {
61
+ fprintf(stderr, "[%" PRIuPTR "] => %" PRIuPTR " X obj %p type %d\n",
62
+ index++, pos->obj, (void *)pos->hash, TYPE(pos->hash));
63
+ }
64
+ }
65
+ fprintf(stderr, "Total of %" PRIuPTR " objects protected form GC\n", index);
66
+ fprintf(stderr,
67
+ "Storage uses %" PRIuPTR " Hash bins for %" PRIuPTR " objects\n"
68
+ "The largest collection was %zu objects.\n",
69
+ iodine_storage.capa, iodine_storage.count, iodine_storage_count_max);
70
+ fio_unlock(&iodine_storage_lock);
71
+ }
72
+
73
+ /**
74
+ * Used for debugging purposes (when testing iodine for Ruby object "leaks").
75
+ */
76
+ static VALUE storage_print_rb(VALUE self) {
77
+ storage_print();
78
+ return Qnil;
79
+ (void)self;
80
+ }
81
+ /* *****************************************************************************
82
+ GC protection
83
+ ***************************************************************************** */
84
+
85
+ /* a callback for the GC (marking active objects) */
86
+ static void storage_mark(void *ignore) {
87
+ (void)ignore;
88
+ if (FIO_LOG_LEVEL >= FIO_LOG_LEVEL_DEBUG)
89
+ storage_print();
90
+ fio_lock(&iodine_storage_lock);
91
+ // fio_store_compact(&iodine_storage);
92
+ FIO_SET_FOR_LOOP(&iodine_storage, pos) {
93
+ if (pos->obj) {
94
+ rb_gc_mark((VALUE)pos->hash);
95
+ }
96
+ }
97
+ fio_unlock(&iodine_storage_lock);
98
+ }
99
+
100
+ /* clear the registry (end of lifetime) */
101
+ static void storage_clear(void *ignore) {
102
+ (void)ignore;
103
+ FIO_LOG_DEBUG("Ruby<=>C Storage cleared.\n");
104
+ fio_lock(&iodine_storage_lock);
105
+ fio_store_free(&iodine_storage);
106
+ iodine_storage = (fio_store_s)FIO_SET_INIT;
107
+ fio_unlock(&iodine_storage_lock);
108
+ }
109
+
110
+ /*
111
+ the data-type used to identify the registry
112
+ this sets the callbacks.
113
+ */
114
+ static const struct rb_data_type_struct storage_type_struct = {
115
+ .wrap_struct_name = "RubyReferencesIn_C_Land",
116
+ .function.dfree = (void (*)(void *))storage_clear,
117
+ .function.dmark = (void (*)(void *))storage_mark,
118
+ };
119
+
120
+ /* *****************************************************************************
121
+ Initialization
122
+ ***************************************************************************** */
123
+
124
+ struct IodineStorage_s IodineStore = {
125
+ .add = storage_add,
126
+ .remove = storage_remove,
127
+ .after_fork = storage_after_fork,
128
+ .print = storage_print,
129
+ };
130
+
131
+ /** Initializes the storage unit for first use. */
132
+ void iodine_storage_init(void) {
133
+ fio_store_capa_require(&iodine_storage, 512);
134
+ VALUE tmp =
135
+ rb_define_class_under(rb_cObject, "IodineObjectStorage", rb_cObject);
136
+ VALUE storage_obj =
137
+ TypedData_Wrap_Struct(tmp, &storage_type_struct, &iodine_storage);
138
+ // rb_global_variable(&iodine_storage_obj);
139
+ rb_ivar_set(IodineModule, rb_intern2("storage", 7), storage_obj);
140
+ rb_define_module_function(IodineBaseModule, "db_print_protected_objects",
141
+ storage_print_rb, 0);
142
+ }
@@ -0,0 +1,20 @@
1
+ #ifndef H_IODINE_STORAGE_H
2
+ #define H_IODINE_STORAGE_H
3
+
4
+ #include "ruby.h"
5
+
6
+ extern struct IodineStorage_s {
7
+ /** Adds an object to the storage (or increases it's reference count). */
8
+ VALUE (*add)(VALUE);
9
+ /** Removes an object from the storage (or decreases it's reference count). */
10
+ VALUE (*remove)(VALUE);
11
+ /** Should be called after forking to reset locks */
12
+ void (*after_fork)(void);
13
+ /** Prints debugging information to the console. */
14
+ void (*print)(void);
15
+ } IodineStore;
16
+
17
+ /** Initializes the storage unit for first use. */
18
+ void iodine_storage_init(void);
19
+
20
+ #endif