/*
 * call-seq:
 *      Raindrops.new(size)  -> raindrops object
 *
 * Initializes a Raindrops object to hold +size+ counters.  +size+ is
 * only a hint and the actual number of counters the object has is
 * dependent on the CPU model, number of cores, and page size of
 * the machine.  The actual size of the object will always be equal
 * or greater than the specified +size+.
 */
static VALUE init(VALUE self, VALUE size)
{
        struct raindrops *r = DATA_PTR(self);
        int tries = 1;
        size_t tmp;

        if (r->drops != MAP_FAILED)
                rb_raise(rb_eRuntimeError, "already initialized");

        r->size = NUM2SIZET(size);
        if (r->size < 1)
                rb_raise(rb_eArgError, "size must be >= 1");

        tmp = PAGE_ALIGN(raindrop_size * r->size);
        r->capa = tmp / raindrop_size;
        assert(PAGE_ALIGN(raindrop_size * r->capa) == tmp && "not aligned");

retry:
        r->drops = mmap(NULL, tmp,
                        PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
        if (r->drops == MAP_FAILED) {
                if ((errno == EAGAIN || errno == ENOMEM) && tries-- > 0) {
                        rb_gc();
                        goto retry;
                }
                rb_sys_fail("mmap");
        }
        r->pid = getpid();

        return self;
}