Class: ConcurrentSHM::Region

Inherits:
Object
  • Object
show all
Defined in:
ext/concurrent-shm/posix.c,
ext/concurrent-shm/posix.c

Overview

A memory-mapped region of a file or shared memory space.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.map(file, off, len) ⇒ Region

Memory-map a region of a file or shared memory space. The region is read/write and shared.

Parameters:

  • file (IO|SharedMemory)

    the file or shared memory space

  • off (Integer)

    the offset of the region

  • len (Integer)

    the length of the region

Returns:

  • (Region)

    the mapped region

Raises:

  • (Errno::EACCES)

    if the file is not a regular file, or the file is not open for reading, not open for writing, or append-only

  • (Errno::EAGAIN)

    if the file is locked or too much memory has been locked

  • (Errno::EBADF)

    if ‘file.lineno` is not a valid file descriptor

  • (Errno::EINVAL)

    if the length or offset are too large or the length is 0

  • (Errno::ENFILE)

    if the system-wide limit on the total number of open files has been reached

  • (Errno::ENODEV)

    if the underlying filesystem of the specified file does not support memory mapping

  • (Errno::ENOMEM)

    if no memory is available, or the process’s number of mappings limit has been reached

  • (Errno::EPERM)

    if the operation was prevented by a file seal



328
329
330
331
332
333
334
335
336
337
338
339
# File 'ext/concurrent-shm/posix.c', line 328

static VALUE region_map(VALUE self, VALUE file, VALUE off, VALUE len)
{
    UNUSED(self);

    int fd = FIX2INT(rb_funcall(file, rb_intern("fileno"), 0));
    void * data = mmap(NULL, FIX2INT(len), PROT_READ | PROT_WRITE, MAP_SHARED, fd, FIX2INT(off));
    if (data == MAP_FAILED) {
        rb_syserr_fail_strf(errno, "mmap(fd=%d, len=%d)", fd, FIX2INT(len));
    }

    return __new_region(data, FIX2INT(len), 1, file);
}

.unmap(region) ⇒ Object

Unmaps a memory-mapped region.

Parameters:

  • region (Region)

    the region to unmap



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'ext/concurrent-shm/posix.c', line 344

static VALUE region_unmap(VALUE self, VALUE region)
{
    UNUSED(self);

    region_t * r = value_as_region(region);
    if (!r->mapped) {
        rb_raise(rb_eArgError, "Not a memory mapped region");
    }

    if (!r->data) {
        return Qnil;
    }

    chk_errno(munmap, (r->data, r->len), "");

    r->data = NULL;
    r->len = 0;
    return Qnil;
}

Instance Method Details

#[](start) ⇒ Region #[](start...) ⇒ Region #[](start, length) ⇒ Region #[](start..end) ⇒ Region #[](start...end) ⇒ Region

Get a subregion of the receiver.

Overloads:

  • #[](start) ⇒ Region

    The subregion from the start index to the end of the region.

    Parameters:

    • start (Integer)

      the starting index of the subset

    Raises:

    • ArgumentError unless ‘start` is an integer

  • #[](start...) ⇒ Region

    The subregion from the start index to the end of the region.

    Parameters:

    • start (Integer)

      the starting index of the subset

    Raises:

    • ArgumentError unless ‘start` is an integer

  • #[](start, length) ⇒ Region

    The subregion from the start index with the specified length.

    Parameters:

    • start (Integer)

      the starting index of the subset

    • length (Integer)

      the length of the subset

    Raises:

    • ArgumentError unless ‘start` and `length` are integers

  • #[](start..end) ⇒ Region

    The subregion from the start index to the end index, inclusive.

    Parameters:

    • start (Integer)

      the starting index of the subset

    • end (Integer)

      the ending index of the subset

    Raises:

    • ArgumentError unless ‘start` and `end` are integers

  • #[](start...end) ⇒ Region

    The subregion from the start index to the end index, exclusive.

    Parameters:

    • start (Integer)

      the starting index of the subset

    • end (Integer)

      the ending index of the subset

    Raises:

    • ArgumentError unless ‘start` and `end` are integers

Returns:

Raises:

  • ArgumentError if the arguments are not one of the allowed overloads

  • RangeError if the arguments do not refer to a valid subrange



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'ext/concurrent-shm/posix.c', line 412

static VALUE region_at(int argc, VALUE * argv, VALUE self)
{
    VALUE at, len;
    rb_scan_args(argc, argv, "11", &at, &len);

    if (RB_TYPE_P(at, T_FIXNUM) && RB_TYPE_P(len, T_FIXNUM)) {
        return __region_at_len(self, FIX2INT(at), FIX2INT(len));

    } else if (RB_TYPE_P(at, T_FIXNUM) && NIL_P(len)) {
        return __region_at_len(self, FIX2INT(at), 1);

    } else if (rb_obj_is_kind_of(at, rb_cRange) && NIL_P(len)) {
        // continue

    } else {
        rb_raise(rb_eArgError, "Region#[at, len] accepts [int,int], [int], [int...nil], or [int...int]");
    }

    VALUE begin = rb_funcall(at, rb_intern("begin"), 0);
    VALUE end = rb_funcall(at, rb_intern("end"), 0);
    VALUE excl = rb_funcall(at, rb_intern("exclude_end?"), 0);

    if (!RB_TYPE_P(begin, T_FIXNUM)) {
        rb_raise(rb_eArgError, "Region#[at, len] accepts [int,int], [int], [int...nil], or [int...int]");
    }

    if (NIL_P(end)) {
        region_t * r = value_as_region(self);
        return __region_at(self, FIX2INT(begin), r->len, Qtrue);
    }

    if (!RB_TYPE_P(end, T_FIXNUM)) {
        rb_raise(rb_eArgError, "Region#[at, len] accepts [int,int], [int], [int...nil], or [int...int]");
    }

    return __region_at(self, FIX2INT(begin), FIX2INT(end), excl);
}

#aligned?(bytes) ⇒ Boolean

Returns true if the region is aligned to the specified byte boundary. Equivalent to ‘addr % bytes == 0`.

Returns:

  • (Boolean)

    ‘true` if the region is aligned to the specified boundary



500
501
502
503
504
# File 'ext/concurrent-shm/posix.c', line 500

static VALUE region_aligned_q(VALUE self, VALUE bytes)
{
    region_t * r = value_as_region(self);
    return ralign(r, FIX2INT(bytes)) == 0 ? Qtrue : Qfalse;
}

#alignment(bytes) ⇒ Integer

The alignment of the region to the specified byte boundary. Equivalent to ‘addr % bytes`.

Returns:

  • (Integer)

    the region’s alignment to the specified boundary



490
491
492
493
494
# File 'ext/concurrent-shm/posix.c', line 490

static VALUE region_alignment(VALUE self, VALUE bytes)
{
    region_t * r = value_as_region(self);
    return INT2FIX(ralign(r, FIX2INT(bytes)));
}

#as_intptrValue::IntPtr

Returns a pointer to the region as a signed integer pointer of the same width as the region.

Returns:

Raises:

  • (RangeError)

    if the region is not 1, 2, 4, or 8 bytes wide



455
456
457
458
459
460
461
462
463
464
465
# File 'ext/concurrent-shm/posix.c', line 455

static VALUE region_as_intptr(VALUE self)
{
    region_t * r = value_as_region(self);
    switch (r->len) {
    case 1: return Int8Ptr2Value ((int8_t *) r->data);
    case 2: return Int16Ptr2Value((int16_t *)r->data);
    case 4: return Int32Ptr2Value((int32_t *)r->data);
    case 8: return Int64Ptr2Value((int64_t *)r->data);
    default: rb_raise(rb_eRangeError, "Region length must be 1, 2, 4, or 8 bytes to use as an integer pointer");
    }
}

#as_uintptrValue::IntPtr

Returns a pointer to the region as an unsigned integer pointer of the same width as the region.

Returns:

Raises:

  • (RangeError)

    if the region is not 1, 2, 4, or 8 bytes wide



472
473
474
475
476
477
478
479
480
481
482
# File 'ext/concurrent-shm/posix.c', line 472

static VALUE region_as_uintptr(VALUE self)
{
    region_t * r = value_as_region(self);
    switch (r->len) {
    case 1: return UInt8Ptr2Value ((uint8_t *) r->data);
    case 2: return UInt16Ptr2Value((uint16_t *)r->data);
    case 4: return UInt32Ptr2Value((uint32_t *)r->data);
    case 8: return UInt64Ptr2Value((uint64_t *)r->data);
    default: rb_raise(rb_eRangeError, "Region length must be 1, 2, 4, or 8 bytes to use as an integer pointer");
    }
}

#fromIO|SharedMemory|Region

The file, shared memory space, or region the receiver was created from.

Returns:



509
510
511
512
513
# File 'ext/concurrent-shm/posix.c', line 509

static VALUE region_from(VALUE self)
{
    region_t * r = value_as_region(self);
    return r->from;
}

#readString

Read data from the region.

Returns:

  • (String)

    the data read



527
528
529
530
531
# File 'ext/concurrent-shm/posix.c', line 527

static VALUE region_read(VALUE self)
{
    region_t * r = value_as_region(self);
    return rb_str_new((const char *)r->data, r->len);
}

#sizeInteger

The width of the region.

Returns:

  • (Integer)

    the width of the region



518
519
520
521
522
# File 'ext/concurrent-shm/posix.c', line 518

static VALUE region_size(VALUE self)
{
    region_t * r = value_as_region(self);
    return INT2FIX(r->len);
}

#write(str) ⇒ nil

Write data to the region.

Parameters:

  • str (String)

    the data to write

Returns:

  • (nil)


537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'ext/concurrent-shm/posix.c', line 537

static VALUE region_write(VALUE self, VALUE str)
{
    if (!RB_TYPE_P(str, T_STRING)) {
        str = rb_funcall(str, rb_intern("to_s"), 0);
        if (!RB_TYPE_P(str, T_STRING)) {
            rb_raise(rb_eArgError, "str.to_s is not a string");
        }
    }

    region_t * r = value_as_region(self);
    size_t len = RSTRING_LEN(str);
    if (len > r->len) {
        rb_raise(rb_eRangeError, "string is longer than region");
    }

    memcpy(r->data, StringValuePtr(str), len);
    return Qnil;
}