isomorfeus-iodine 0.7.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +32 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1038 -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 +44 -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/config.ru +56 -0
  25. data/examples/echo.ru +59 -0
  26. data/examples/hello.ru +29 -0
  27. data/examples/pubsub_engine.ru +81 -0
  28. data/examples/redis.ru +70 -0
  29. data/examples/shootout.ru +73 -0
  30. data/examples/sub-protocols.ru +90 -0
  31. data/examples/tcp_client.rb +66 -0
  32. data/examples/x-sendfile.ru +14 -0
  33. data/exe/iodine +277 -0
  34. data/ext/iodine/extconf.rb +109 -0
  35. data/ext/iodine/fio.c +11985 -0
  36. data/ext/iodine/fio.h +6373 -0
  37. data/ext/iodine/fio_cli.c +431 -0
  38. data/ext/iodine/fio_cli.h +189 -0
  39. data/ext/iodine/fio_json_parser.h +687 -0
  40. data/ext/iodine/fio_siphash.c +157 -0
  41. data/ext/iodine/fio_siphash.h +37 -0
  42. data/ext/iodine/fio_tls.h +129 -0
  43. data/ext/iodine/fio_tls_missing.c +649 -0
  44. data/ext/iodine/fio_tls_openssl.c +1056 -0
  45. data/ext/iodine/fio_tmpfile.h +50 -0
  46. data/ext/iodine/fiobj.h +44 -0
  47. data/ext/iodine/fiobj4fio.h +21 -0
  48. data/ext/iodine/fiobj_ary.c +333 -0
  49. data/ext/iodine/fiobj_ary.h +139 -0
  50. data/ext/iodine/fiobj_data.c +1185 -0
  51. data/ext/iodine/fiobj_data.h +167 -0
  52. data/ext/iodine/fiobj_hash.c +409 -0
  53. data/ext/iodine/fiobj_hash.h +176 -0
  54. data/ext/iodine/fiobj_json.c +622 -0
  55. data/ext/iodine/fiobj_json.h +68 -0
  56. data/ext/iodine/fiobj_mem.h +71 -0
  57. data/ext/iodine/fiobj_mustache.c +317 -0
  58. data/ext/iodine/fiobj_mustache.h +62 -0
  59. data/ext/iodine/fiobj_numbers.c +344 -0
  60. data/ext/iodine/fiobj_numbers.h +127 -0
  61. data/ext/iodine/fiobj_str.c +433 -0
  62. data/ext/iodine/fiobj_str.h +172 -0
  63. data/ext/iodine/fiobject.c +620 -0
  64. data/ext/iodine/fiobject.h +654 -0
  65. data/ext/iodine/hpack.h +1923 -0
  66. data/ext/iodine/http.c +2754 -0
  67. data/ext/iodine/http.h +1002 -0
  68. data/ext/iodine/http1.c +912 -0
  69. data/ext/iodine/http1.h +29 -0
  70. data/ext/iodine/http1_parser.h +873 -0
  71. data/ext/iodine/http_internal.c +1278 -0
  72. data/ext/iodine/http_internal.h +237 -0
  73. data/ext/iodine/http_mime_parser.h +350 -0
  74. data/ext/iodine/iodine.c +1430 -0
  75. data/ext/iodine/iodine.h +63 -0
  76. data/ext/iodine/iodine_caller.c +218 -0
  77. data/ext/iodine/iodine_caller.h +27 -0
  78. data/ext/iodine/iodine_connection.c +933 -0
  79. data/ext/iodine/iodine_connection.h +55 -0
  80. data/ext/iodine/iodine_defer.c +420 -0
  81. data/ext/iodine/iodine_defer.h +6 -0
  82. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  83. data/ext/iodine/iodine_helpers.c +282 -0
  84. data/ext/iodine/iodine_helpers.h +12 -0
  85. data/ext/iodine/iodine_http.c +1171 -0
  86. data/ext/iodine/iodine_http.h +23 -0
  87. data/ext/iodine/iodine_json.c +302 -0
  88. data/ext/iodine/iodine_json.h +6 -0
  89. data/ext/iodine/iodine_mustache.c +567 -0
  90. data/ext/iodine/iodine_mustache.h +6 -0
  91. data/ext/iodine/iodine_pubsub.c +580 -0
  92. data/ext/iodine/iodine_pubsub.h +26 -0
  93. data/ext/iodine/iodine_rack_io.c +281 -0
  94. data/ext/iodine/iodine_rack_io.h +20 -0
  95. data/ext/iodine/iodine_store.c +142 -0
  96. data/ext/iodine/iodine_store.h +20 -0
  97. data/ext/iodine/iodine_tcp.c +346 -0
  98. data/ext/iodine/iodine_tcp.h +13 -0
  99. data/ext/iodine/iodine_tls.c +261 -0
  100. data/ext/iodine/iodine_tls.h +13 -0
  101. data/ext/iodine/mustache_parser.h +1546 -0
  102. data/ext/iodine/redis_engine.c +957 -0
  103. data/ext/iodine/redis_engine.h +79 -0
  104. data/ext/iodine/resp_parser.h +317 -0
  105. data/ext/iodine/websocket_parser.h +505 -0
  106. data/ext/iodine/websockets.c +735 -0
  107. data/ext/iodine/websockets.h +185 -0
  108. data/isomorfeus-iodine.gemspec +42 -0
  109. data/lib/iodine/connection.rb +61 -0
  110. data/lib/iodine/json.rb +42 -0
  111. data/lib/iodine/mustache.rb +113 -0
  112. data/lib/iodine/pubsub.rb +55 -0
  113. data/lib/iodine/rack_utils.rb +43 -0
  114. data/lib/iodine/tls.rb +16 -0
  115. data/lib/iodine/version.rb +3 -0
  116. data/lib/iodine.rb +274 -0
  117. data/lib/rack/handler/iodine.rb +33 -0
  118. data/logo.png +0 -0
  119. metadata +271 -0
@@ -0,0 +1,281 @@
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
+ #ifdef __MINGW32__
76
+ return (http_s *)NUM2ULL(i);
77
+ #else
78
+ return (http_s *)FIX2ULONG(i);
79
+ #endif
80
+ }
81
+
82
+ /* *****************************************************************************
83
+ IO API
84
+ */
85
+
86
+ static inline FIOBJ get_data(VALUE self) {
87
+ VALUE i = rb_ivar_get(self, io_id);
88
+ #ifdef __MINGW32__
89
+ return (FIOBJ)NUM2ULL(i);
90
+ #else
91
+ return (FIOBJ)FIX2ULONG(i);
92
+ #endif
93
+ }
94
+
95
+ static VALUE rio_rewind(VALUE self) {
96
+ FIOBJ io = get_data(self);
97
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
98
+ return Qnil;
99
+ fiobj_data_seek(io, 0);
100
+ return INT2NUM(0);
101
+ }
102
+ /**
103
+ Gets returns a line. this is okay for small lines,
104
+ but shouldn't really be used.
105
+
106
+ Limited to ~ 1Mb of a line length.
107
+ */
108
+ static VALUE rio_gets(VALUE self) {
109
+ FIOBJ io = get_data(self);
110
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
111
+ return Qnil;
112
+ fio_str_info_s line = fiobj_data_gets(io);
113
+ if (line.len) {
114
+ VALUE buffer = rb_str_new(line.data, line.len);
115
+ // make sure the buffer is binary encoded.
116
+ rb_enc_associate(buffer, IodineBinaryEncoding);
117
+ return buffer;
118
+ }
119
+ return Qnil;
120
+ }
121
+
122
+ // Reads data from the IO, according to the Rack specifications for `#read`.
123
+ static VALUE rio_read(int argc, VALUE *argv, VALUE self) {
124
+ FIOBJ io = get_data(self);
125
+ VALUE buffer = Qnil;
126
+ uint8_t ret_nil = 0;
127
+ ssize_t len = 0;
128
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
129
+ return (argc > 0 && argv[0] != Qnil) ? Qnil : rb_str_buf_new(0);
130
+ }
131
+
132
+ // get the buffer object if given
133
+ if (argc == 2) {
134
+ Check_Type(argv[1], T_STRING);
135
+ buffer = argv[1];
136
+ }
137
+ // get the length object, if given
138
+ if (argc > 0 && argv[0] != Qnil) {
139
+ Check_Type(argv[0], T_FIXNUM);
140
+ len = FIX2LONG(argv[0]);
141
+ if (len < 0)
142
+ rb_raise(rb_eRangeError, "length should be bigger then 0.");
143
+ if (len == 0)
144
+ return rb_str_buf_new(0);
145
+ ret_nil = 1;
146
+ }
147
+ // return if we're at the EOF.
148
+ fio_str_info_s buf = fiobj_data_read(io, len);
149
+ if (buf.len) {
150
+ // create the buffer if we don't have one.
151
+ if (buffer == Qnil) {
152
+ // make sure the buffer is binary encoded.
153
+ buffer = rb_enc_str_new(buf.data, buf.len, IodineBinaryEncoding);
154
+ } else {
155
+ // make sure the buffer is binary encoded.
156
+ rb_enc_associate(buffer, IodineBinaryEncoding);
157
+ if (rb_str_capacity(buffer) < (size_t)buf.len)
158
+ rb_str_resize(buffer, buf.len);
159
+ memcpy(RSTRING_PTR(buffer), buf.data, buf.len);
160
+ rb_str_set_len(buffer, buf.len);
161
+ }
162
+ return buffer;
163
+ }
164
+ return ret_nil ? Qnil : rb_str_buf_new(0);
165
+ }
166
+
167
+ // Does nothing - this is controlled by the server.
168
+ static VALUE rio_close(VALUE self) {
169
+ // FIOBJ io = get_data(self);
170
+ // fiobj_free(io); // we don't call fiobj_dup, do we?
171
+ rb_ivar_set(self, io_id, INT2NUM(0));
172
+ (void)self;
173
+ return Qnil;
174
+ }
175
+
176
+ // Passes each line of the input to the block. This should be avoided.
177
+ static VALUE rio_each(VALUE self) {
178
+ rb_need_block();
179
+ rio_rewind(self);
180
+ VALUE str = Qnil;
181
+ while ((str = rio_gets(self)) != Qnil) {
182
+ rb_yield(str);
183
+ }
184
+ return self;
185
+ }
186
+
187
+ /* *****************************************************************************
188
+ Hijacking
189
+ */
190
+
191
+ // defined by iodine_http
192
+ extern VALUE IODINE_R_HIJACK; // for Rack: rack.hijack
193
+ extern VALUE IODINE_R_HIJACK_CB; // for Rack: rack.hijack
194
+ extern VALUE IODINE_R_HIJACK_IO; // for Rack: rack.hijack_io
195
+
196
+ static VALUE rio_get_io(int argc, VALUE *argv, VALUE self) {
197
+ if (TCPSOCKET_CLASS == Qnil)
198
+ return Qfalse;
199
+ VALUE env = rb_ivar_get(self, env_id);
200
+ http_s *h = get_handle(self);
201
+ if (h == NULL) {
202
+ /* we're repeating ourselves, aren't we? */
203
+ VALUE io = rb_hash_aref(env, IODINE_R_HIJACK_IO);
204
+ return io;
205
+ }
206
+ // mark update
207
+ set_handle(self, NULL);
208
+ // hijack the IO object
209
+ intptr_t uuid = http_hijack(h, NULL);
210
+ #ifdef __MINGW32__
211
+ int osffd = fio_osffd4fd(fio_uuid2fd(uuid));
212
+ if (osffd == -1)
213
+ return Qfalse;
214
+ VALUE fd = INT2FIX(osffd);
215
+ #else
216
+ VALUE fd = INT2FIX(fio_uuid2fd(uuid));
217
+ #endif
218
+ // VALUE new_io = how the fuck do we create a new IO from the fd?
219
+ VALUE new_io = IodineCaller.call2(TCPSOCKET_CLASS, for_fd_id, 1,
220
+ &fd); // TCPSocket.for_fd(fd) ... cool...
221
+ rb_hash_aset(env, IODINE_R_HIJACK_IO, new_io);
222
+ if (argc)
223
+ rb_hash_aset(env, IODINE_R_HIJACK_CB, *argv);
224
+ return new_io;
225
+ }
226
+
227
+ /* *****************************************************************************
228
+ C land API
229
+ */
230
+
231
+ // new object
232
+ static VALUE new_rack_io(http_s *h, VALUE env) {
233
+ VALUE rack_io = rb_funcall2(rRackIO, iodine_new_func_id, 0, NULL);
234
+ rb_ivar_set(rack_io, io_id, ULL2NUM(h->body));
235
+ set_handle(rack_io, h);
236
+ rb_ivar_set(rack_io, env_id, env);
237
+ rb_hash_aset(env, IODINE_R_INPUT, rack_io);
238
+ rb_hash_aset(env, IODINE_R_HIJACK, rb_obj_method(rack_io, hijack_func_sym));
239
+ return rack_io;
240
+ }
241
+
242
+ static void close_rack_io(VALUE rack_io) {
243
+ // rio_close(rack_io);
244
+ rb_ivar_set(rack_io, io_id, INT2NUM(0));
245
+ set_handle(rack_io, NULL); /* this disables hijacking. */
246
+ }
247
+
248
+ // initialize library
249
+ static void init_rack_io(void) {
250
+ IodineUTF8Encoding = rb_enc_find("UTF-8");
251
+ IodineBinaryEncoding = rb_enc_find("binary");
252
+ rRackIO = rb_define_class_under(IodineBaseModule, "RackIO", rb_cObject);
253
+
254
+ io_id = rb_intern("rack_io");
255
+ env_id = rb_intern("env");
256
+ for_fd_id = rb_intern("for_fd");
257
+ iodine_fd_var_id = rb_intern("fd");
258
+ iodine_new_func_id = rb_intern("new");
259
+ #ifdef __MINGW32__
260
+ iodine_osffd_id = rb_intern("osffd");
261
+ #endif
262
+ hijack_func_sym = ID2SYM(rb_intern("_hijack"));
263
+
264
+ TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
265
+ // IO methods
266
+
267
+ rb_define_method(rRackIO, "rewind", rio_rewind, 0);
268
+ rb_define_method(rRackIO, "gets", rio_gets, 0);
269
+ rb_define_method(rRackIO, "read", rio_read, -1);
270
+ rb_define_method(rRackIO, "close", rio_close, 0);
271
+ rb_define_method(rRackIO, "each", rio_each, 0);
272
+ rb_define_method(rRackIO, "_hijack", rio_get_io, -1);
273
+ }
274
+
275
+ ////////////////////////////////////////////////////////////////////////////
276
+ // the API interface
277
+ struct IodineRackIO IodineRackIO = {
278
+ .create = new_rack_io,
279
+ .close = close_rack_io,
280
+ .init = init_rack_io,
281
+ };
@@ -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_cData);
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