prometheus-client-mmap 0.20.3-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +253 -0
  3. data/ext/fast_mmaped_file/extconf.rb +30 -0
  4. data/ext/fast_mmaped_file/fast_mmaped_file.c +122 -0
  5. data/ext/fast_mmaped_file/file_format.c +5 -0
  6. data/ext/fast_mmaped_file/file_format.h +11 -0
  7. data/ext/fast_mmaped_file/file_parsing.c +195 -0
  8. data/ext/fast_mmaped_file/file_parsing.h +27 -0
  9. data/ext/fast_mmaped_file/file_reading.c +102 -0
  10. data/ext/fast_mmaped_file/file_reading.h +30 -0
  11. data/ext/fast_mmaped_file/globals.h +14 -0
  12. data/ext/fast_mmaped_file/mmap.c +427 -0
  13. data/ext/fast_mmaped_file/mmap.h +61 -0
  14. data/ext/fast_mmaped_file/rendering.c +199 -0
  15. data/ext/fast_mmaped_file/rendering.h +8 -0
  16. data/ext/fast_mmaped_file/utils.c +56 -0
  17. data/ext/fast_mmaped_file/utils.h +22 -0
  18. data/ext/fast_mmaped_file/value_access.c +242 -0
  19. data/ext/fast_mmaped_file/value_access.h +15 -0
  20. data/ext/fast_mmaped_file_rs/.cargo/config.toml +23 -0
  21. data/ext/fast_mmaped_file_rs/Cargo.lock +790 -0
  22. data/ext/fast_mmaped_file_rs/Cargo.toml +30 -0
  23. data/ext/fast_mmaped_file_rs/README.md +52 -0
  24. data/ext/fast_mmaped_file_rs/extconf.rb +30 -0
  25. data/ext/fast_mmaped_file_rs/src/error.rs +174 -0
  26. data/ext/fast_mmaped_file_rs/src/file_entry.rs +579 -0
  27. data/ext/fast_mmaped_file_rs/src/file_info.rs +190 -0
  28. data/ext/fast_mmaped_file_rs/src/lib.rs +79 -0
  29. data/ext/fast_mmaped_file_rs/src/macros.rs +14 -0
  30. data/ext/fast_mmaped_file_rs/src/map.rs +492 -0
  31. data/ext/fast_mmaped_file_rs/src/mmap.rs +151 -0
  32. data/ext/fast_mmaped_file_rs/src/parser.rs +346 -0
  33. data/ext/fast_mmaped_file_rs/src/raw_entry.rs +473 -0
  34. data/ext/fast_mmaped_file_rs/src/testhelper.rs +222 -0
  35. data/ext/fast_mmaped_file_rs/src/util.rs +121 -0
  36. data/lib/2.7/fast_mmaped_file.bundle +0 -0
  37. data/lib/2.7/fast_mmaped_file_rs.bundle +0 -0
  38. data/lib/3.0/fast_mmaped_file.bundle +0 -0
  39. data/lib/3.0/fast_mmaped_file_rs.bundle +0 -0
  40. data/lib/3.1/fast_mmaped_file.bundle +0 -0
  41. data/lib/3.1/fast_mmaped_file_rs.bundle +0 -0
  42. data/lib/3.2/fast_mmaped_file.bundle +0 -0
  43. data/lib/3.2/fast_mmaped_file_rs.bundle +0 -0
  44. data/lib/prometheus/client/configuration.rb +23 -0
  45. data/lib/prometheus/client/counter.rb +27 -0
  46. data/lib/prometheus/client/formats/text.rb +118 -0
  47. data/lib/prometheus/client/gauge.rb +40 -0
  48. data/lib/prometheus/client/helper/entry_parser.rb +132 -0
  49. data/lib/prometheus/client/helper/file_locker.rb +50 -0
  50. data/lib/prometheus/client/helper/json_parser.rb +23 -0
  51. data/lib/prometheus/client/helper/metrics_processing.rb +45 -0
  52. data/lib/prometheus/client/helper/metrics_representation.rb +51 -0
  53. data/lib/prometheus/client/helper/mmaped_file.rb +64 -0
  54. data/lib/prometheus/client/helper/plain_file.rb +29 -0
  55. data/lib/prometheus/client/histogram.rb +80 -0
  56. data/lib/prometheus/client/label_set_validator.rb +86 -0
  57. data/lib/prometheus/client/metric.rb +80 -0
  58. data/lib/prometheus/client/mmaped_dict.rb +79 -0
  59. data/lib/prometheus/client/mmaped_value.rb +154 -0
  60. data/lib/prometheus/client/page_size.rb +17 -0
  61. data/lib/prometheus/client/push.rb +203 -0
  62. data/lib/prometheus/client/rack/collector.rb +88 -0
  63. data/lib/prometheus/client/rack/exporter.rb +96 -0
  64. data/lib/prometheus/client/registry.rb +65 -0
  65. data/lib/prometheus/client/simple_value.rb +31 -0
  66. data/lib/prometheus/client/summary.rb +69 -0
  67. data/lib/prometheus/client/support/unicorn.rb +35 -0
  68. data/lib/prometheus/client/uses_value_type.rb +20 -0
  69. data/lib/prometheus/client/version.rb +5 -0
  70. data/lib/prometheus/client.rb +58 -0
  71. data/lib/prometheus.rb +3 -0
  72. data/vendor/c/hashmap/.gitignore +52 -0
  73. data/vendor/c/hashmap/LICENSE +21 -0
  74. data/vendor/c/hashmap/README.md +90 -0
  75. data/vendor/c/hashmap/_config.yml +1 -0
  76. data/vendor/c/hashmap/src/hashmap.c +692 -0
  77. data/vendor/c/hashmap/src/hashmap.h +267 -0
  78. data/vendor/c/hashmap/test/Makefile +22 -0
  79. data/vendor/c/hashmap/test/hashmap_test.c +608 -0
  80. data/vendor/c/jsmn/.travis.yml +4 -0
  81. data/vendor/c/jsmn/LICENSE +20 -0
  82. data/vendor/c/jsmn/Makefile +41 -0
  83. data/vendor/c/jsmn/README.md +168 -0
  84. data/vendor/c/jsmn/example/jsondump.c +126 -0
  85. data/vendor/c/jsmn/example/simple.c +76 -0
  86. data/vendor/c/jsmn/jsmn.c +314 -0
  87. data/vendor/c/jsmn/jsmn.h +76 -0
  88. data/vendor/c/jsmn/library.json +16 -0
  89. data/vendor/c/jsmn/test/test.h +27 -0
  90. data/vendor/c/jsmn/test/tests.c +407 -0
  91. data/vendor/c/jsmn/test/testutil.h +94 -0
  92. metadata +243 -0
@@ -0,0 +1,102 @@
1
+ #include "file_reading.h"
2
+
3
+ #include <errno.h>
4
+ #include <fcntl.h>
5
+
6
+ #include "utils.h"
7
+
8
+ static int file_open(file_t *source, const char *filepath) {
9
+ source->file = fopen(filepath, "r");
10
+ size_t filepath_len = strlen(filepath) + sizeof(char);
11
+ source->path = malloc(filepath_len);
12
+ memcpy(source->path, filepath, filepath_len);
13
+
14
+ if (source->file == NULL) {
15
+ save_exception(rb_eArgError, "Can't open %s, errno: %d", filepath, errno);
16
+
17
+ return 0;
18
+ }
19
+
20
+ struct stat sb;
21
+ if (fstat(fileno(source->file), &sb) != 0) {
22
+ fclose(source->file);
23
+ save_exception(rb_eIOError, "Can't stat file, errno: %d", errno);
24
+
25
+ return 0;
26
+ }
27
+ source->length = sb.st_size;
28
+
29
+ // go to start
30
+ if (fseek(source->file, 0L, SEEK_SET) != 0) {
31
+ fclose(source->file);
32
+ save_exception(rb_eIOError, "Can't fseek %zu, errno: %d", 0, errno);
33
+
34
+ return 0;
35
+ }
36
+
37
+ return 1;
38
+ }
39
+
40
+ int file_close(file_t *source) {
41
+ free(source->path);
42
+ if (fclose(source->file) != 0) {
43
+ save_exception(rb_eIOError, "Can't fclose file, errno: %d", 0, errno);
44
+ return 0;
45
+ }
46
+ source->file = 0;
47
+
48
+ return 1;
49
+ }
50
+
51
+ int file_open_from_params(file_t *source, VALUE params) {
52
+ if (RARRAY_LEN(params) != 4) {
53
+ save_exception(rb_eArgError, "wrong number of arguments %lu instead of 4", RARRAY_LEN(params));
54
+ return 0;
55
+ }
56
+
57
+ VALUE filepath = rb_ary_entry(params, 0);
58
+
59
+ source->multiprocess_mode = rb_sym2id(rb_ary_entry(params, 1));
60
+ source->type = rb_sym2id(rb_ary_entry(params, 2));
61
+ source->pid = rb_ary_entry(params, 3);
62
+
63
+ return file_open(source, StringValueCStr(filepath));
64
+ }
65
+
66
+ int read_from_file(const file_t *source, buffer_t *data) {
67
+ data->size = 0;
68
+ if (data->buffer == NULL) {
69
+ data->buffer = malloc(source->length);
70
+ if (data->buffer == NULL) {
71
+ save_exception(rb_eIOError, "Can't malloc %zu, errno: %d", source->length, errno);
72
+ return 0;
73
+ }
74
+
75
+ data->capacity = source->length;
76
+ } else if (data->capacity < source->length) {
77
+ data->buffer = realloc(data->buffer, source->length);
78
+ if (data->buffer == NULL) {
79
+ save_exception(rb_eIOError, "Can't realloc %zu, errno: %d", source->length, errno);
80
+ return 0;
81
+ }
82
+
83
+ data->capacity = source->length;
84
+ }
85
+
86
+ data->size = fread(data->buffer, sizeof(char), source->length, source->file);
87
+ if (data->size != source->length) {
88
+ save_exception(rb_eIOError, "Couldn't read whole file, read %zu, instead of %zu", data->size, source->length);
89
+ return 0;
90
+ }
91
+
92
+ return 1;
93
+ }
94
+
95
+ void buffer_dispose(buffer_t *buffer) {
96
+ if (buffer->buffer) {
97
+ free(buffer->buffer);
98
+ }
99
+ buffer->buffer = NULL;
100
+ buffer->size = 0;
101
+ buffer->capacity = 0;
102
+ }
@@ -0,0 +1,30 @@
1
+ #ifndef FILE_READING_H
2
+ #define FILE_READING_H
3
+ #include <ruby.h>
4
+
5
+ typedef struct {
6
+ FILE *file;
7
+ size_t length;
8
+ char *path;
9
+
10
+ // Information processed from file path
11
+ ID multiprocess_mode;
12
+ ID type;
13
+ VALUE pid;
14
+ } file_t;
15
+
16
+ typedef struct {
17
+ char *buffer;
18
+ size_t size;
19
+ size_t capacity;
20
+ } buffer_t;
21
+
22
+ int file_close(file_t *file);
23
+
24
+ int file_open_from_params(file_t *file, VALUE params);
25
+
26
+ int read_from_file(const file_t *source, buffer_t *data);
27
+
28
+ void buffer_dispose(buffer_t *buffer);
29
+
30
+ #endif
@@ -0,0 +1,14 @@
1
+ #ifndef GLOBALS_H
2
+ #define GLOBALS_H
3
+ #include <ruby.h>
4
+
5
+ extern ID sym_min;
6
+ extern ID sym_max;
7
+ extern ID sym_livesum;
8
+ extern ID sym_gauge;
9
+ extern ID sym_pid;
10
+ extern ID sym_samples;
11
+
12
+ extern VALUE prom_eParsingError;
13
+
14
+ #endif
@@ -0,0 +1,427 @@
1
+ #include "mmap.h"
2
+
3
+ #include <errno.h>
4
+ #include <fcntl.h>
5
+ #include <ruby/util.h>
6
+ #include <sys/mman.h>
7
+
8
+ #include "file_format.h"
9
+ #include "utils.h"
10
+
11
+ #if 0
12
+ #include <stdio.h>
13
+ #define DEBUGF(format, ...) printf("%d: " format "\n", __LINE__, __VA_ARGS__)
14
+ #else
15
+ #define DEBUGF(format, ...)
16
+ #endif
17
+
18
+ /* This is the ID of the WeakMap used to track strings allocated that
19
+ * are backed by a memory-mapped file.
20
+ */
21
+ #define WEAK_OBJ_TRACKER "@weak_obj_tracker"
22
+
23
+ /**
24
+ * Maps a given VALUE to some key for the WeakMap. For now, we just use
25
+ * the integer value as the key since that suffices, though this does
26
+ * require Ruby 2.7 due to https://bugs.ruby-lang.org/issues/16035.
27
+ */
28
+ static VALUE weak_obj_tracker_get_key(VALUE val) { return val; }
29
+
30
+ /**
31
+ * Adds a T_STRING type to the WeakMap. The WeakMap should be stored
32
+ * as an instance variable.
33
+ */
34
+ static void weak_obj_tracker_add(VALUE obj, VALUE val) {
35
+ Check_Type(val, T_STRING);
36
+
37
+ VALUE tracker = rb_iv_get(obj, WEAK_OBJ_TRACKER);
38
+ VALUE key = weak_obj_tracker_get_key(val);
39
+
40
+ rb_funcall(tracker, rb_intern("[]="), 2, key, val);
41
+ }
42
+
43
+ /**
44
+ * Iterator function for updating a single element from the WeakMap.
45
+ */
46
+ VALUE mm_update_obj_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, self)) {
47
+ Check_Type(self, T_DATA);
48
+ Check_Type(i, T_STRING);
49
+ rb_check_arity(argc, 1, 1);
50
+
51
+ mm_ipc *i_mm;
52
+ GET_MMAP(self, i_mm, MM_MODIFY);
53
+
54
+ RSTRING(i)->as.heap.ptr = i_mm->t->addr;
55
+ RSTRING(i)->as.heap.len = i_mm->t->real;
56
+
57
+ return Qtrue;
58
+ }
59
+
60
+ /**
61
+ * This iterates through the WeakMap defined on the class and updates
62
+ * the RStrings to use the newly-allocated memory region.
63
+ */
64
+ void mm_update(VALUE obj) {
65
+ VALUE tracker = rb_iv_get(obj, WEAK_OBJ_TRACKER);
66
+
67
+ rb_block_call(tracker, rb_intern("each_value"), 0, NULL, mm_update_obj_i, obj);
68
+ }
69
+
70
+ typedef struct {
71
+ VALUE obj, *argv;
72
+ ID id;
73
+ int flag, argc;
74
+ } mm_bang;
75
+
76
+ static VALUE mm_protect_bang(VALUE *t) { return rb_funcall2(t[0], (ID)t[1], (int)t[2], (VALUE *)t[3]); }
77
+
78
+ static VALUE mm_recycle(VALUE str) {
79
+ rb_gc_force_recycle(str);
80
+ return str;
81
+ }
82
+
83
+ static VALUE mm_vunlock(VALUE obj) {
84
+ mm_ipc *i_mm;
85
+
86
+ GET_MMAP(obj, i_mm, 0);
87
+ return Qnil;
88
+ }
89
+
90
+ static VALUE mm_str(VALUE obj, int modify) {
91
+ mm_ipc *i_mm;
92
+ VALUE ret = Qnil;
93
+
94
+ GET_MMAP(obj, i_mm, modify & ~MM_ORIGIN);
95
+ if (modify & MM_MODIFY) {
96
+ if (i_mm->t->flag & MM_FROZEN) rb_error_frozen("mmap");
97
+ }
98
+ ret = rb_obj_alloc(rb_cString);
99
+ RSTRING(ret)->as.heap.ptr = i_mm->t->addr;
100
+ RSTRING(ret)->as.heap.aux.capa = i_mm->t->len;
101
+ RSTRING(ret)->as.heap.len = i_mm->t->real;
102
+
103
+ weak_obj_tracker_add(obj, ret);
104
+
105
+ DEBUGF("RString capa: %d, len: %d", RSTRING(ret)->as.heap.aux.capa, RSTRING(ret)->as.heap.len);
106
+
107
+ if (modify & MM_ORIGIN) {
108
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
109
+ RSTRING(ret)->as.heap.aux.shared = obj;
110
+ FL_SET(ret, RSTRING_NOEMBED);
111
+ FL_SET(ret, FL_USER18);
112
+ #else
113
+ RSTRING(ret)->orig = ret;
114
+ #endif
115
+ }
116
+ if (i_mm->t->flag & MM_FROZEN) {
117
+ ret = rb_obj_freeze(ret);
118
+ }
119
+ return ret;
120
+ }
121
+
122
+ static VALUE mm_i_bang(bang_st) mm_bang *bang_st;
123
+ {
124
+ VALUE str, res;
125
+ mm_ipc *i_mm;
126
+
127
+ str = mm_str(bang_st->obj, bang_st->flag);
128
+ if (bang_st->flag & MM_PROTECT) {
129
+ VALUE tmp[4];
130
+ tmp[0] = str;
131
+ tmp[1] = (VALUE)bang_st->id;
132
+ tmp[2] = (VALUE)bang_st->argc;
133
+ tmp[3] = (VALUE)bang_st->argv;
134
+ res = rb_ensure(mm_protect_bang, (VALUE)tmp, mm_recycle, str);
135
+ } else {
136
+ res = rb_funcall2(str, bang_st->id, bang_st->argc, bang_st->argv);
137
+ RB_GC_GUARD(res);
138
+ }
139
+ if (res != Qnil) {
140
+ GET_MMAP(bang_st->obj, i_mm, 0);
141
+ i_mm->t->real = RSTRING_LEN(str);
142
+ }
143
+ return res;
144
+ }
145
+
146
+ static VALUE mm_bang_i(VALUE obj, int flag, ID id, int argc, VALUE *argv) {
147
+ VALUE res;
148
+ mm_ipc *i_mm;
149
+ mm_bang bang_st;
150
+
151
+ GET_MMAP(obj, i_mm, 0);
152
+ if ((flag & MM_CHANGE) && (i_mm->t->flag & MM_FIXED)) {
153
+ rb_raise(rb_eTypeError, "try to change the size of a fixed map");
154
+ }
155
+ bang_st.obj = obj;
156
+ bang_st.flag = flag;
157
+ bang_st.id = id;
158
+ bang_st.argc = argc;
159
+ bang_st.argv = argv;
160
+ if (i_mm->t->flag & MM_IPC) {
161
+ res = rb_ensure(mm_i_bang, (VALUE)&bang_st, mm_vunlock, obj);
162
+ } else {
163
+ res = mm_i_bang(&bang_st);
164
+ }
165
+ if (res == Qnil) return res;
166
+ return (flag & MM_ORIGIN) ? res : obj;
167
+ }
168
+
169
+ static void mm_free(mm_ipc *i_mm) {
170
+ if (i_mm->t->path) {
171
+ if (munmap(i_mm->t->addr, i_mm->t->len) != 0) {
172
+ if (i_mm->t->path != (char *)-1 && i_mm->t->path != NULL) {
173
+ free(i_mm->t->path);
174
+ }
175
+ free(i_mm);
176
+
177
+ rb_raise(rb_eRuntimeError, "munmap failed at %s:%d with errno: %d", __FILE__, __LINE__, errno);
178
+ }
179
+
180
+ if (i_mm->t->path != (char *)-1) {
181
+ if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE &&
182
+ truncate(i_mm->t->path, i_mm->t->real) == -1) {
183
+ free(i_mm->t->path);
184
+ free(i_mm);
185
+ rb_raise(rb_eTypeError, "truncate");
186
+ }
187
+ free(i_mm->t->path);
188
+ }
189
+ }
190
+ free(i_mm);
191
+ }
192
+
193
+ /*
194
+ * call-seq:
195
+ * new(file)
196
+ *
197
+ * create a new Mmap object
198
+ *
199
+ * * <em>file</em>
200
+ *
201
+ *
202
+ * Creates a mapping that's shared with all other processes
203
+ * mapping the same areas of the file.
204
+ *
205
+ */
206
+ VALUE mm_s_new(int argc, VALUE *argv, VALUE obj) {
207
+ VALUE res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
208
+ rb_obj_call_init(res, argc, argv);
209
+ return res;
210
+ }
211
+
212
+ VALUE mm_s_alloc(VALUE obj) {
213
+ VALUE res;
214
+ mm_ipc *i_mm;
215
+
216
+ res = Data_Make_Struct(obj, mm_ipc, 0, mm_free, i_mm);
217
+ i_mm->t = ALLOC_N(mm_mmap, 1);
218
+ MEMZERO(i_mm->t, mm_mmap, 1);
219
+ i_mm->t->fd = -1;
220
+ return res;
221
+ }
222
+
223
+ size_t next_page_boundary(size_t value) {
224
+ size_t page_size = sysconf(_SC_PAGESIZE);
225
+
226
+ while (page_size < value) {
227
+ page_size *= 2;
228
+ }
229
+
230
+ return page_size;
231
+ }
232
+
233
+ /* Reference implementations:
234
+ * mozilla: https://hg.mozilla.org/mozilla-central/file/3d846420a907/xpcom/glue/FileUtils.cpp#l71
235
+ * glibc: https://github.com/lattera/glibc/blob/master/sysdeps/posix/posix_fallocate.c
236
+ */
237
+ int reserve_mmap_file_bytes(int fd, size_t size) {
238
+ #if __linux__
239
+ /* From https://stackoverflow.com/a/22820221: The difference with
240
+ * ftruncate(2) is that (on file systems supporting it, e.g. Ext4)
241
+ * disk space is indeed reserved by posix_fallocate but ftruncate
242
+ * extends the file by adding holes (and without reserving disk
243
+ * space). */
244
+ return posix_fallocate(fd, 0, size);
245
+ #else
246
+ /* We simplify the reference implemnetations since we generally
247
+ * don't need to reserve more than a page size. */
248
+ return ftruncate(fd, size);
249
+ #endif
250
+ }
251
+
252
+ VALUE mm_init(VALUE obj, VALUE fname) {
253
+ struct stat st;
254
+ int fd, smode = 0, pmode = 0, vscope, perm, init;
255
+ MMAP_RETTYPE addr;
256
+ mm_ipc *i_mm;
257
+ char *path;
258
+ size_t size = 0;
259
+ off_t offset;
260
+
261
+ vscope = 0;
262
+ path = 0;
263
+ fd = -1;
264
+
265
+ VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
266
+ VALUE weak_obj_tracker = rb_class_new_instance(0, NULL, klass);
267
+ rb_iv_set(obj, WEAK_OBJ_TRACKER, weak_obj_tracker);
268
+
269
+ fname = rb_str_to_str(fname);
270
+ SafeStringValue(fname);
271
+ path = StringValuePtr(fname);
272
+
273
+ vscope = MAP_SHARED;
274
+ size = 0;
275
+ perm = 0666;
276
+
277
+ smode = O_RDWR;
278
+ pmode = PROT_READ | PROT_WRITE;
279
+
280
+ if ((fd = open(path, smode, perm)) == -1) {
281
+ rb_raise(rb_eArgError, "Can't open %s", path);
282
+ }
283
+
284
+ if (fstat(fd, &st) == -1) {
285
+ close(fd);
286
+ rb_raise(rb_eArgError, "Can't stat %s", path);
287
+ }
288
+ size = st.st_size;
289
+
290
+ Data_Get_Struct(obj, mm_ipc, i_mm);
291
+
292
+ offset = 0;
293
+ init = 0;
294
+
295
+ if (size == 0) {
296
+ init = 1;
297
+ size = INITIAL_SIZE;
298
+ }
299
+
300
+ /* We need to ensure the underlying file descriptor is at least a page size.
301
+ * Otherwise, we could get a SIGBUS error if mmap() attempts to read or write
302
+ * past the file. */
303
+ size_t reserve_size = next_page_boundary(size);
304
+
305
+ if (reserve_mmap_file_bytes(fd, reserve_size) != 0) {
306
+ close(fd);
307
+ rb_raise(rb_eIOError, "Can't reserve %zu bytes for memory-mapped file in %s", reserve_size, path);
308
+ }
309
+
310
+ addr = mmap(0, size, pmode, vscope, fd, offset);
311
+
312
+ if (addr == MAP_FAILED || !addr) {
313
+ close(fd);
314
+ rb_raise(rb_eArgError, "mmap failed (%d)", errno);
315
+ }
316
+ i_mm->t->fd = fd;
317
+ i_mm->t->addr = addr;
318
+ i_mm->t->len = size;
319
+ if (!init) {
320
+ i_mm->t->real = size;
321
+ }
322
+ i_mm->t->pmode = pmode;
323
+ i_mm->t->vscope = vscope;
324
+ i_mm->t->smode = smode & ~O_TRUNC;
325
+ i_mm->t->path = (path) ? ruby_strdup(path) : (char *)-1;
326
+
327
+ if (smode == O_WRONLY) {
328
+ i_mm->t->flag |= MM_FIXED;
329
+ }
330
+ return obj;
331
+ }
332
+
333
+ /*
334
+ * Document-method: []
335
+ * Document-method: slice
336
+ *
337
+ * call-seq: [](args)
338
+ *
339
+ * Element reference - with the following syntax:
340
+ *
341
+ * self[nth]
342
+ *
343
+ * retrieve the <em>nth</em> character
344
+ *
345
+ * self[start..last]
346
+ *
347
+ * return a substring from <em>start</em> to <em>last</em>
348
+ *
349
+ * self[start, length]
350
+ *
351
+ * return a substring of <em>lenght</em> characters from <em>start</em>
352
+ */
353
+ VALUE mm_aref_m(int argc, VALUE *argv, VALUE obj) { return mm_bang_i(obj, MM_ORIGIN, rb_intern("[]"), argc, argv); }
354
+
355
+ /*
356
+ * Document-method: msync
357
+ * Document-method: sync
358
+ * Document-method: flush
359
+ *
360
+ * call-seq: msync
361
+ *
362
+ * flush the file
363
+ */
364
+ VALUE mm_msync(int argc, VALUE *argv, VALUE obj) {
365
+ mm_ipc *i_mm;
366
+ GET_MMAP(obj, i_mm, MM_MODIFY);
367
+
368
+ VALUE oflag;
369
+ int ret;
370
+ int flag = MS_SYNC;
371
+
372
+ if (argc) {
373
+ rb_scan_args(argc, argv, "01", &oflag);
374
+ flag = NUM2INT(oflag);
375
+ }
376
+ if ((ret = msync(i_mm->t->addr, i_mm->t->len, flag)) != 0) {
377
+ rb_raise(rb_eArgError, "msync(%d)", ret);
378
+ }
379
+
380
+ return obj;
381
+ }
382
+
383
+ /*
384
+ * Document-method: munmap
385
+ * Document-method: unmap
386
+ *
387
+ * call-seq: munmap
388
+ *
389
+ * terminate the association
390
+ */
391
+ VALUE mm_unmap(VALUE obj) {
392
+ mm_ipc *i_mm;
393
+
394
+ GET_MMAP(obj, i_mm, 0);
395
+ if (i_mm->t->path) {
396
+ if (munmap(i_mm->t->addr, i_mm->t->len) != 0) {
397
+ if (i_mm->t->path != (char *)-1 && i_mm->t->path != NULL) {
398
+ free(i_mm->t->path);
399
+ i_mm->t->path = NULL;
400
+ }
401
+
402
+ rb_raise(rb_eRuntimeError, "munmap failed at %s:%d with errno: %d", __FILE__, __LINE__, errno);
403
+ }
404
+
405
+ if (i_mm->t->path != (char *)-1) {
406
+ if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE &&
407
+ truncate(i_mm->t->path, i_mm->t->real) == -1) {
408
+ rb_raise(rb_eTypeError, "truncate");
409
+ }
410
+ free(i_mm->t->path);
411
+ }
412
+
413
+ // Ensure any lingering RString values get a length of zero. We
414
+ // can't zero out the address since GET_MMAP() inside
415
+ // mm_update_obj_i() expects a non-null address and path.
416
+ i_mm->t->len = 0;
417
+ i_mm->t->real = 0;
418
+ mm_update(obj);
419
+
420
+ i_mm->t->addr = NULL;
421
+ i_mm->t->path = NULL;
422
+ }
423
+
424
+ close(i_mm->t->fd);
425
+
426
+ return Qnil;
427
+ }
@@ -0,0 +1,61 @@
1
+ #ifndef MMAP_H
2
+ #define MMAP_H
3
+
4
+ #include <ruby.h>
5
+ #include <unistd.h>
6
+
7
+ #define MM_MODIFY 1
8
+ #define MM_ORIGIN 2
9
+ #define MM_CHANGE (MM_MODIFY | 4)
10
+ #define MM_PROTECT 8
11
+
12
+ #define MM_FROZEN (1 << 0)
13
+ #define MM_FIXED (1 << 1)
14
+ #define MM_ANON (1 << 2)
15
+ #define MM_LOCK (1 << 3)
16
+ #define MM_IPC (1 << 4)
17
+ #define MM_TMP (1 << 5)
18
+
19
+ #ifndef MMAP_RETTYPE
20
+ #define MMAP_RETTYPE void *
21
+ #endif
22
+
23
+ typedef struct {
24
+ MMAP_RETTYPE addr;
25
+ int smode, pmode, vscope;
26
+ int advice, flag;
27
+ VALUE key;
28
+ size_t len, real;
29
+ off_t offset;
30
+ int fd;
31
+ char *path;
32
+ } mm_mmap;
33
+
34
+ typedef struct {
35
+ int count;
36
+ mm_mmap *t;
37
+ } mm_ipc;
38
+
39
+ #define GET_MMAP(obj, i_mm, t_modify) \
40
+ Data_Get_Struct(obj, mm_ipc, i_mm); \
41
+ if (!i_mm->t->path || i_mm->t->fd < 0 || i_mm->t->addr == NULL || i_mm->t->addr == MAP_FAILED) { \
42
+ rb_raise(rb_eIOError, "unmapped file"); \
43
+ } \
44
+ if ((t_modify & MM_MODIFY) && (i_mm->t->flag & MM_FROZEN)) { \
45
+ rb_error_frozen("mmap"); \
46
+ }
47
+
48
+ VALUE mm_s_alloc(VALUE obj);
49
+ VALUE mm_s_new(int argc, VALUE *argv, VALUE obj);
50
+ VALUE mm_init(VALUE obj, VALUE fname);
51
+ VALUE mm_aref_m(int argc, VALUE *argv, VALUE obj);
52
+ VALUE mm_msync(int argc, VALUE *argv, VALUE obj);
53
+ VALUE mm_unmap(VALUE obj);
54
+
55
+ /* If memory is ever reallocated, any allocated Ruby strings that have not been
56
+ * garbage collected need to be updated with the new region. If this isn't done,
57
+ * iterating over the Ruby object space and accessing the string data will seg fault.
58
+ */
59
+ void mm_update(VALUE obj);
60
+
61
+ #endif