8 * most modern CPUs have a cache-line size of 64 or 128.
9 * We choose a bigger one by default since our structure is not
12 #ifndef CACHE_LINE_SIZE
13 # define CACHE_LINE_SIZE 128
16 /* each raindrop is a counter */
19 unsigned long counter
;
20 unsigned char padding
[CACHE_LINE_SIZE
];
22 } __attribute__((packed
));
24 /* allow mmap-ed regions can store more than one raindrop */
27 struct raindrop
*drops
;
31 static void evaporate(void *ptr
)
33 struct raindrops
*r
= ptr
;
36 int rv
= munmap(r
->drops
, sizeof(struct raindrop
) * r
->size
);
38 rb_bug("munmap failed in gc: %s", strerror(errno
));
44 /* automatically called at creation (before initialize) */
45 static VALUE
alloc(VALUE klass
)
49 return Data_Make_Struct(klass
, struct raindrops
, NULL
, evaporate
, r
);
52 static struct raindrops
*get(VALUE self
)
56 Data_Get_Struct(self
, struct raindrops
, r
);
61 /* initializes a Raindrops object to hold +size+ elements */
62 static VALUE
init(VALUE self
, VALUE size
)
64 struct raindrops
*r
= get(self
);
68 rb_raise(rb_eRuntimeError
, "already initialized");
70 r
->size
= NUM2LONG(size
);
72 rb_raise(rb_eArgError
, "size must be >= 1");
75 r
->drops
= mmap(NULL
, sizeof(struct raindrop
) * r
->size
,
76 PROT_READ
|PROT_WRITE
, MAP_ANON
|MAP_SHARED
, -1, 0);
77 if (r
->drops
== MAP_FAILED
) {
78 if ((errno
== EAGAIN
|| errno
== ENOMEM
) && tries
-- > 0) {
89 static VALUE
init_copy(VALUE dest
, VALUE source
)
91 struct raindrops
*dst
= get(dest
);
92 struct raindrops
*src
= get(source
);
94 init(dest
, LONG2NUM(src
->size
));
95 memcpy(dst
->drops
, src
->drops
, sizeof(struct raindrop
) * src
->size
);
100 static unsigned long *addr_of(VALUE self
, VALUE index
)
102 struct raindrops
*r
= get(self
);
103 unsigned long off
= FIX2ULONG(index
) * sizeof(struct raindrop
);
105 if (off
>= sizeof(struct raindrop
) * r
->size
)
106 rb_raise(rb_eArgError
, "offset overrun");
108 return (unsigned long *)((unsigned long)r
->drops
+ off
);
111 static unsigned long incr_decr_arg(int argc
, const VALUE
*argv
)
113 if (argc
> 2 || argc
< 1)
114 rb_raise(rb_eArgError
,
115 "wrong number of arguments (%d for 1+)", argc
);
117 return argc
== 2 ? NUM2ULONG(argv
[1]) : 1;
120 /* increments the value referred to by the +index+ constant by 1 */
121 static VALUE
incr(int argc
, VALUE
*argv
, VALUE self
)
123 unsigned long nr
= incr_decr_arg(argc
, argv
);
125 return ULONG2NUM(__sync_add_and_fetch(addr_of(self
, argv
[0]), nr
));
128 /* decrements the value referred to by the +index+ constant by 1 */
129 static VALUE
decr(int argc
, VALUE
*argv
, VALUE self
)
131 unsigned long nr
= incr_decr_arg(argc
, argv
);
133 return ULONG2NUM(__sync_sub_and_fetch(addr_of(self
, argv
[0]), nr
));
136 /* converts the raindrops structure to an Array */
137 static VALUE
to_ary(VALUE self
)
139 struct raindrops
*r
= get(self
);
140 VALUE rv
= rb_ary_new2(r
->size
);
142 unsigned long base
= (unsigned long)r
->drops
;
144 for (i
= 0; i
< r
->size
; i
++) {
145 rb_ary_push(rv
, ULONG2NUM(*((unsigned long *)base
)));
146 base
+= sizeof(struct raindrop
);
152 static VALUE
size(VALUE self
)
154 return LONG2NUM(get(self
)->size
);
157 static VALUE
aset(VALUE self
, VALUE index
, VALUE value
)
159 unsigned long *addr
= addr_of(self
, index
);
161 *addr
= NUM2ULONG(value
);
166 static VALUE
aref(VALUE self
, VALUE index
)
168 return ULONG2NUM(*addr_of(self
, index
));
172 void Init_raindrops_linux_inet_diag(void);
175 void Init_raindrops_ext(void)
177 VALUE cRaindrops
= rb_define_class("Raindrops", rb_cObject
);
178 rb_define_alloc_func(cRaindrops
, alloc
);
180 rb_define_method(cRaindrops
, "initialize", init
, 1);
181 rb_define_method(cRaindrops
, "incr", incr
, -1);
182 rb_define_method(cRaindrops
, "decr", decr
, -1);
183 rb_define_method(cRaindrops
, "to_ary", to_ary
, 0);
184 rb_define_method(cRaindrops
, "[]", aref
, 1);
185 rb_define_method(cRaindrops
, "[]=", aset
, 2);
186 rb_define_method(cRaindrops
, "size", size
, 0);
187 rb_define_method(cRaindrops
, "initialize_copy", init_copy
, 1);
190 Init_raindrops_linux_inet_diag();