prometheus-client-mmap 0.16.2 → 0.18.0

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.
@@ -3,319 +3,303 @@
3
3
  /**
4
4
  * Allocates a fresh unused token from the token pull.
5
5
  */
6
- static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens) {
7
- jsmntok_t *tok;
8
- if (parser->toknext >= num_tokens) {
9
- return NULL;
10
- }
11
- tok = &tokens[parser->toknext++];
12
- tok->start = tok->end = -1;
13
- tok->size = 0;
6
+ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
7
+ jsmntok_t *tokens, size_t num_tokens) {
8
+ jsmntok_t *tok;
9
+ if (parser->toknext >= num_tokens) {
10
+ return NULL;
11
+ }
12
+ tok = &tokens[parser->toknext++];
13
+ tok->start = tok->end = -1;
14
+ tok->size = 0;
14
15
  #ifdef JSMN_PARENT_LINKS
15
- tok->parent = -1;
16
+ tok->parent = -1;
16
17
  #endif
17
- return tok;
18
+ return tok;
18
19
  }
19
20
 
20
21
  /**
21
22
  * Fills token type and boundaries.
22
23
  */
23
- static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) {
24
- token->type = type;
25
- token->start = start;
26
- token->end = end;
27
- token->size = 0;
24
+ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
25
+ int start, int end) {
26
+ token->type = type;
27
+ token->start = start;
28
+ token->end = end;
29
+ token->size = 0;
28
30
  }
29
31
 
30
32
  /**
31
33
  * Fills next available token with JSON primitive.
32
34
  */
33
- static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) {
34
- jsmntok_t *token;
35
- int start;
35
+ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
36
+ size_t len, jsmntok_t *tokens, size_t num_tokens) {
37
+ jsmntok_t *token;
38
+ int start;
36
39
 
37
- start = parser->pos;
40
+ start = parser->pos;
38
41
 
39
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
40
- switch (js[parser->pos]) {
42
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
43
+ switch (js[parser->pos]) {
41
44
  #ifndef JSMN_STRICT
42
- /* In strict mode primitive must be followed by "," or "}" or "]" */
43
- case ':':
45
+ /* In strict mode primitive must be followed by "," or "}" or "]" */
46
+ case ':':
44
47
  #endif
45
- case '\t':
46
- case '\r':
47
- case '\n':
48
- case ' ':
49
- case ',':
50
- case ']':
51
- case '}':
52
- goto found;
53
- }
54
- if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
55
- parser->pos = start;
56
- return JSMN_ERROR_INVAL;
57
- }
58
- }
48
+ case '\t' : case '\r' : case '\n' : case ' ' :
49
+ case ',' : case ']' : case '}' :
50
+ goto found;
51
+ }
52
+ if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
53
+ parser->pos = start;
54
+ return JSMN_ERROR_INVAL;
55
+ }
56
+ }
59
57
  #ifdef JSMN_STRICT
60
- /* In strict mode primitive must be followed by a comma/object/array */
61
- parser->pos = start;
62
- return JSMN_ERROR_PART;
58
+ /* In strict mode primitive must be followed by a comma/object/array */
59
+ parser->pos = start;
60
+ return JSMN_ERROR_PART;
63
61
  #endif
64
62
 
65
63
  found:
66
- if (tokens == NULL) {
67
- parser->pos--;
68
- return 0;
69
- }
70
- token = jsmn_alloc_token(parser, tokens, num_tokens);
71
- if (token == NULL) {
72
- parser->pos = start;
73
- return JSMN_ERROR_NOMEM;
74
- }
75
- jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
64
+ if (tokens == NULL) {
65
+ parser->pos--;
66
+ return 0;
67
+ }
68
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
69
+ if (token == NULL) {
70
+ parser->pos = start;
71
+ return JSMN_ERROR_NOMEM;
72
+ }
73
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
76
74
  #ifdef JSMN_PARENT_LINKS
77
- token->parent = parser->toksuper;
75
+ token->parent = parser->toksuper;
78
76
  #endif
79
- parser->pos--;
80
- return 0;
77
+ parser->pos--;
78
+ return 0;
81
79
  }
82
80
 
83
81
  /**
84
82
  * Fills next token with JSON string.
85
83
  */
86
- static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) {
87
- jsmntok_t *token;
84
+ static int jsmn_parse_string(jsmn_parser *parser, const char *js,
85
+ size_t len, jsmntok_t *tokens, size_t num_tokens) {
86
+ jsmntok_t *token;
88
87
 
89
- int start = parser->pos;
88
+ int start = parser->pos;
90
89
 
91
- parser->pos++;
90
+ parser->pos++;
92
91
 
93
- /* Skip starting quote */
94
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
95
- char c = js[parser->pos];
92
+ /* Skip starting quote */
93
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
94
+ char c = js[parser->pos];
96
95
 
97
- /* Quote: end of string */
98
- if (c == '\"') {
99
- if (tokens == NULL) {
100
- return 0;
101
- }
102
- token = jsmn_alloc_token(parser, tokens, num_tokens);
103
- if (token == NULL) {
104
- parser->pos = start;
105
- return JSMN_ERROR_NOMEM;
106
- }
107
- jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
96
+ /* Quote: end of string */
97
+ if (c == '\"') {
98
+ if (tokens == NULL) {
99
+ return 0;
100
+ }
101
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
102
+ if (token == NULL) {
103
+ parser->pos = start;
104
+ return JSMN_ERROR_NOMEM;
105
+ }
106
+ jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
108
107
  #ifdef JSMN_PARENT_LINKS
109
- token->parent = parser->toksuper;
108
+ token->parent = parser->toksuper;
110
109
  #endif
111
- return 0;
112
- }
110
+ return 0;
111
+ }
113
112
 
114
- /* Backslash: Quoted symbol expected */
115
- if (c == '\\' && parser->pos + 1 < len) {
116
- int i;
117
- parser->pos++;
118
- switch (js[parser->pos]) {
119
- /* Allowed escaped symbols */
120
- case '\"':
121
- case '/':
122
- case '\\':
123
- case 'b':
124
- case 'f':
125
- case 'r':
126
- case 'n':
127
- case 't':
128
- break;
129
- /* Allows escaped symbol \uXXXX */
130
- case 'u':
131
- parser->pos++;
132
- for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
133
- /* If it isn't a hex character we have an error */
134
- if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
135
- (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
136
- (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
137
- parser->pos = start;
138
- return JSMN_ERROR_INVAL;
139
- }
140
- parser->pos++;
141
- }
142
- parser->pos--;
143
- break;
144
- /* Unexpected symbol */
145
- default:
146
- parser->pos = start;
147
- return JSMN_ERROR_INVAL;
148
- }
149
- }
150
- }
151
- parser->pos = start;
152
- return JSMN_ERROR_PART;
113
+ /* Backslash: Quoted symbol expected */
114
+ if (c == '\\' && parser->pos + 1 < len) {
115
+ int i;
116
+ parser->pos++;
117
+ switch (js[parser->pos]) {
118
+ /* Allowed escaped symbols */
119
+ case '\"': case '/' : case '\\' : case 'b' :
120
+ case 'f' : case 'r' : case 'n' : case 't' :
121
+ break;
122
+ /* Allows escaped symbol \uXXXX */
123
+ case 'u':
124
+ parser->pos++;
125
+ for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
126
+ /* If it isn't a hex character we have an error */
127
+ if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
128
+ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
129
+ (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
130
+ parser->pos = start;
131
+ return JSMN_ERROR_INVAL;
132
+ }
133
+ parser->pos++;
134
+ }
135
+ parser->pos--;
136
+ break;
137
+ /* Unexpected symbol */
138
+ default:
139
+ parser->pos = start;
140
+ return JSMN_ERROR_INVAL;
141
+ }
142
+ }
143
+ }
144
+ parser->pos = start;
145
+ return JSMN_ERROR_PART;
153
146
  }
154
147
 
155
148
  /**
156
149
  * Parse JSON string and fill tokens.
157
150
  */
158
- int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens) {
159
- int r;
160
- int i;
161
- jsmntok_t *token;
162
- int count = parser->toknext;
151
+ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
152
+ jsmntok_t *tokens, unsigned int num_tokens) {
153
+ int r;
154
+ int i;
155
+ jsmntok_t *token;
156
+ int count = parser->toknext;
163
157
 
164
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
165
- char c;
166
- jsmntype_t type;
158
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
159
+ char c;
160
+ jsmntype_t type;
167
161
 
168
- c = js[parser->pos];
169
- switch (c) {
170
- case '{':
171
- case '[':
172
- count++;
173
- if (tokens == NULL) {
174
- break;
175
- }
176
- token = jsmn_alloc_token(parser, tokens, num_tokens);
177
- if (token == NULL) return JSMN_ERROR_NOMEM;
178
- if (parser->toksuper != -1) {
179
- tokens[parser->toksuper].size++;
162
+ c = js[parser->pos];
163
+ switch (c) {
164
+ case '{': case '[':
165
+ count++;
166
+ if (tokens == NULL) {
167
+ break;
168
+ }
169
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
170
+ if (token == NULL)
171
+ return JSMN_ERROR_NOMEM;
172
+ if (parser->toksuper != -1) {
173
+ tokens[parser->toksuper].size++;
180
174
  #ifdef JSMN_PARENT_LINKS
181
- token->parent = parser->toksuper;
175
+ token->parent = parser->toksuper;
182
176
  #endif
183
- }
184
- token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
185
- token->start = parser->pos;
186
- parser->toksuper = parser->toknext - 1;
187
- break;
188
- case '}':
189
- case ']':
190
- if (tokens == NULL) break;
191
- type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
177
+ }
178
+ token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
179
+ token->start = parser->pos;
180
+ parser->toksuper = parser->toknext - 1;
181
+ break;
182
+ case '}': case ']':
183
+ if (tokens == NULL)
184
+ break;
185
+ type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
192
186
  #ifdef JSMN_PARENT_LINKS
193
- if (parser->toknext < 1) {
194
- return JSMN_ERROR_INVAL;
195
- }
196
- token = &tokens[parser->toknext - 1];
197
- for (;;) {
198
- if (token->start != -1 && token->end == -1) {
199
- if (token->type != type) {
200
- return JSMN_ERROR_INVAL;
201
- }
202
- token->end = parser->pos + 1;
203
- parser->toksuper = token->parent;
204
- break;
205
- }
206
- if (token->parent == -1) {
207
- if (token->type != type || parser->toksuper == -1) {
208
- return JSMN_ERROR_INVAL;
209
- }
210
- break;
211
- }
212
- token = &tokens[token->parent];
213
- }
187
+ if (parser->toknext < 1) {
188
+ return JSMN_ERROR_INVAL;
189
+ }
190
+ token = &tokens[parser->toknext - 1];
191
+ for (;;) {
192
+ if (token->start != -1 && token->end == -1) {
193
+ if (token->type != type) {
194
+ return JSMN_ERROR_INVAL;
195
+ }
196
+ token->end = parser->pos + 1;
197
+ parser->toksuper = token->parent;
198
+ break;
199
+ }
200
+ if (token->parent == -1) {
201
+ if(token->type != type || parser->toksuper == -1) {
202
+ return JSMN_ERROR_INVAL;
203
+ }
204
+ break;
205
+ }
206
+ token = &tokens[token->parent];
207
+ }
214
208
  #else
215
- for (i = parser->toknext - 1; i >= 0; i--) {
216
- token = &tokens[i];
217
- if (token->start != -1 && token->end == -1) {
218
- if (token->type != type) {
219
- return JSMN_ERROR_INVAL;
220
- }
221
- parser->toksuper = -1;
222
- token->end = parser->pos + 1;
223
- break;
224
- }
225
- }
226
- /* Error if unmatched closing bracket */
227
- if (i == -1) return JSMN_ERROR_INVAL;
228
- for (; i >= 0; i--) {
229
- token = &tokens[i];
230
- if (token->start != -1 && token->end == -1) {
231
- parser->toksuper = i;
232
- break;
233
- }
234
- }
209
+ for (i = parser->toknext - 1; i >= 0; i--) {
210
+ token = &tokens[i];
211
+ if (token->start != -1 && token->end == -1) {
212
+ if (token->type != type) {
213
+ return JSMN_ERROR_INVAL;
214
+ }
215
+ parser->toksuper = -1;
216
+ token->end = parser->pos + 1;
217
+ break;
218
+ }
219
+ }
220
+ /* Error if unmatched closing bracket */
221
+ if (i == -1) return JSMN_ERROR_INVAL;
222
+ for (; i >= 0; i--) {
223
+ token = &tokens[i];
224
+ if (token->start != -1 && token->end == -1) {
225
+ parser->toksuper = i;
226
+ break;
227
+ }
228
+ }
235
229
  #endif
236
- break;
237
- case '\"':
238
- r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
239
- if (r < 0) return r;
240
- count++;
241
- if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++;
242
- break;
243
- case '\t':
244
- case '\r':
245
- case '\n':
246
- case ' ':
247
- break;
248
- case ':':
249
- parser->toksuper = parser->toknext - 1;
250
- break;
251
- case ',':
252
- if (tokens != NULL && parser->toksuper != -1 && tokens[parser->toksuper].type != JSMN_ARRAY &&
253
- tokens[parser->toksuper].type != JSMN_OBJECT) {
230
+ break;
231
+ case '\"':
232
+ r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
233
+ if (r < 0) return r;
234
+ count++;
235
+ if (parser->toksuper != -1 && tokens != NULL)
236
+ tokens[parser->toksuper].size++;
237
+ break;
238
+ case '\t' : case '\r' : case '\n' : case ' ':
239
+ break;
240
+ case ':':
241
+ parser->toksuper = parser->toknext - 1;
242
+ break;
243
+ case ',':
244
+ if (tokens != NULL && parser->toksuper != -1 &&
245
+ tokens[parser->toksuper].type != JSMN_ARRAY &&
246
+ tokens[parser->toksuper].type != JSMN_OBJECT) {
254
247
  #ifdef JSMN_PARENT_LINKS
255
- parser->toksuper = tokens[parser->toksuper].parent;
248
+ parser->toksuper = tokens[parser->toksuper].parent;
256
249
  #else
257
- for (i = parser->toknext - 1; i >= 0; i--) {
258
- if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
259
- if (tokens[i].start != -1 && tokens[i].end == -1) {
260
- parser->toksuper = i;
261
- break;
262
- }
263
- }
264
- }
250
+ for (i = parser->toknext - 1; i >= 0; i--) {
251
+ if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
252
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
253
+ parser->toksuper = i;
254
+ break;
255
+ }
256
+ }
257
+ }
265
258
  #endif
266
- }
267
- break;
259
+ }
260
+ break;
268
261
  #ifdef JSMN_STRICT
269
- /* In strict mode primitives are: numbers and booleans */
270
- case '-':
271
- case '0':
272
- case '1':
273
- case '2':
274
- case '3':
275
- case '4':
276
- case '5':
277
- case '6':
278
- case '7':
279
- case '8':
280
- case '9':
281
- case 't':
282
- case 'f':
283
- case 'n':
284
- /* And they must not be keys of the object */
285
- if (tokens != NULL && parser->toksuper != -1) {
286
- jsmntok_t *t = &tokens[parser->toksuper];
287
- if (t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0)) {
288
- return JSMN_ERROR_INVAL;
289
- }
290
- }
262
+ /* In strict mode primitives are: numbers and booleans */
263
+ case '-': case '0': case '1' : case '2': case '3' : case '4':
264
+ case '5': case '6': case '7' : case '8': case '9':
265
+ case 't': case 'f': case 'n' :
266
+ /* And they must not be keys of the object */
267
+ if (tokens != NULL && parser->toksuper != -1) {
268
+ jsmntok_t *t = &tokens[parser->toksuper];
269
+ if (t->type == JSMN_OBJECT ||
270
+ (t->type == JSMN_STRING && t->size != 0)) {
271
+ return JSMN_ERROR_INVAL;
272
+ }
273
+ }
291
274
  #else
292
- /* In non-strict mode every unquoted value is a primitive */
293
- default:
275
+ /* In non-strict mode every unquoted value is a primitive */
276
+ default:
294
277
  #endif
295
- r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
296
- if (r < 0) return r;
297
- count++;
298
- if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++;
299
- break;
278
+ r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
279
+ if (r < 0) return r;
280
+ count++;
281
+ if (parser->toksuper != -1 && tokens != NULL)
282
+ tokens[parser->toksuper].size++;
283
+ break;
300
284
 
301
285
  #ifdef JSMN_STRICT
302
- /* Unexpected char in strict mode */
303
- default:
304
- return JSMN_ERROR_INVAL;
286
+ /* Unexpected char in strict mode */
287
+ default:
288
+ return JSMN_ERROR_INVAL;
305
289
  #endif
306
- }
307
- }
290
+ }
291
+ }
308
292
 
309
- if (tokens != NULL) {
310
- for (i = parser->toknext - 1; i >= 0; i--) {
311
- /* Unmatched opened object or array */
312
- if (tokens[i].start != -1 && tokens[i].end == -1) {
313
- return JSMN_ERROR_PART;
314
- }
315
- }
316
- }
293
+ if (tokens != NULL) {
294
+ for (i = parser->toknext - 1; i >= 0; i--) {
295
+ /* Unmatched opened object or array */
296
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
297
+ return JSMN_ERROR_PART;
298
+ }
299
+ }
300
+ }
317
301
 
318
- return count;
302
+ return count;
319
303
  }
320
304
 
321
305
  /**
@@ -323,7 +307,8 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *token
323
307
  * available.
324
308
  */
325
309
  void jsmn_init(jsmn_parser *parser) {
326
- parser->pos = 0;
327
- parser->toknext = 0;
328
- parser->toksuper = -1;
310
+ parser->pos = 0;
311
+ parser->toknext = 0;
312
+ parser->toksuper = -1;
329
313
  }
314
+
@@ -15,6 +15,58 @@
15
15
  #define DEBUGF(format, ...)
16
16
  #endif
17
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
+
18
70
  typedef struct {
19
71
  VALUE obj, *argv;
20
72
  ID id;
@@ -48,6 +100,8 @@ static VALUE mm_str(VALUE obj, int modify) {
48
100
  RSTRING(ret)->as.heap.aux.capa = i_mm->t->len;
49
101
  RSTRING(ret)->as.heap.len = i_mm->t->real;
50
102
 
103
+ weak_obj_tracker_add(obj, ret);
104
+
51
105
  DEBUGF("RString capa: %d, len: %d", RSTRING(ret)->as.heap.aux.capa, RSTRING(ret)->as.heap.len);
52
106
 
53
107
  if (modify & MM_ORIGIN) {
@@ -208,6 +262,10 @@ VALUE mm_init(VALUE obj, VALUE fname) {
208
262
  path = 0;
209
263
  fd = -1;
210
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
+
211
269
  fname = rb_str_to_str(fname);
212
270
  SafeStringValue(fname);
213
271
  path = StringValuePtr(fname);
@@ -52,4 +52,10 @@ VALUE mm_aref_m(int argc, VALUE *argv, VALUE obj);
52
52
  VALUE mm_msync(int argc, VALUE *argv, VALUE obj);
53
53
  VALUE mm_unmap(VALUE obj);
54
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
+
55
61
  #endif