Class: Winipc::SharedMemory

Inherits:
Object
  • Object
show all
Defined in:
lib/winipc.rb,
ext/winipc/winipc.c

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._create(wname, vsize, rw, access) ⇒ Object

SharedMemory._create(wname, size, readwrite, access) -> SharedMemory



813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
# File 'ext/winipc/winipc.c', line 813

static VALUE
shm_create(VALUE klass, VALUE wname, VALUE vsize, VALUE rw, VALUE access)
{
    VALUE obj = shm_alloc(cSharedMemory);
    shm_t *s = shm_get(obj);
    unsigned long long size = NUM2ULL(vsize);
    int writable = RTEST(rw);
    SECURITY_ATTRIBUTES sa;
    PSECURITY_DESCRIPTOR psd = NULL;
    DWORD prot = writable ? PAGE_READWRITE : PAGE_READONLY;
    DWORD hi = (DWORD)(size >> 32), lo = (DWORD)(size & 0xFFFFFFFFull);
    DWORD gle;
    int use_sa;
    WCHAR *name;

    if (size == 0) rb_raise(rb_eArgError, "winipc: size must be > 0");
    use_sa = build_sa(access, &sa, &psd); /* may raise; do before allocating name */
    name = to_wide(wname);

    s->map = CreateFileMappingW(INVALID_HANDLE_VALUE, use_sa ? &sa : NULL, prot, hi, lo, name);
    gle = GetLastError();
    xfree(name);
    if (psd) LocalFree(psd);
    if (!s->map) raise_gle("CreateFileMapping", gle);
    if (gle == ERROR_ALREADY_EXISTS) {
        /* a mapping of that name already exists with its OWN size — refuse */
        CloseHandle(s->map); s->map = NULL;
        raise_code(eExists, "CreateFileMapping", ERROR_ALREADY_EXISTS);
    }

    s->view = MapViewOfFile(s->map, writable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, 0);
    if (!s->view) raise_gle("MapViewOfFile", GetLastError());
    s->size = size;
    s->writable = writable;
    return obj;
}

._open(wname, rw) ⇒ Object

SharedMemory._open(wname, readwrite) -> SharedMemory



851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
# File 'ext/winipc/winipc.c', line 851

static VALUE
shm_open(VALUE klass, VALUE wname, VALUE rw)
{
    VALUE obj = shm_alloc(cSharedMemory);
    shm_t *s = shm_get(obj);
    int writable = RTEST(rw);
    WCHAR *name = to_wide(wname);
    DWORD acc = writable ? FILE_MAP_WRITE : FILE_MAP_READ;
    MEMORY_BASIC_INFORMATION mbi;
    DWORD gle;

    s->map = OpenFileMappingW(acc, FALSE, name);
    gle = GetLastError();
    xfree(name);
    if (!s->map) raise_gle("OpenFileMapping", gle);

    s->view = MapViewOfFile(s->map, acc, 0, 0, 0);
    if (!s->view) raise_gle("MapViewOfFile", GetLastError());
    /* Discover the mapped region size (the opener didn't specify it). */
    if (VirtualQuery(s->view, &mbi, sizeof(mbi)) == 0)
        raise_gle("VirtualQuery", GetLastError());
    s->size = (unsigned long long)mbi.RegionSize;
    s->writable = writable;
    return obj;
}

.create(name, size, access: :readwrite, scope: :local, security: :owner) ⇒ Object

Create a named, pagefile-backed shared-memory region of size bytes.



226
227
228
# File 'lib/winipc.rb', line 226

def self.create(name, size, access: :readwrite, scope: :local, security: :owner)
  _create(Winipc.obj_path(name, scope), Integer(size), access != :readonly, security)
end

.open(name, access: :readwrite, scope: :local) ⇒ Object

Open an existing named region.



231
232
233
# File 'lib/winipc.rb', line 231

def self.open(name, access: :readwrite, scope: :local)
  _open(Winipc.obj_path(name, scope), access != :readonly)
end

Instance Method Details

#_flush(voff, vlen) ⇒ Object



912
913
914
915
916
917
918
919
920
921
922
923
# File 'ext/winipc/winipc.c', line 912

static VALUE
shm_flush(VALUE self, VALUE voff, VALUE vlen)
{
    shm_t *s = shm_live(self);
    unsigned long long off = NUM2ULL(voff), len = NIL_P(vlen) ? 0 : NUM2ULL(vlen);
    if (off > s->size) rb_raise(eRangeError, "winipc: flush offset out of bounds");
    if (len) shm_bounds(s, off, len);
    if (off >= s->size) return self; /* nothing past the end to flush (no-op) */
    if (!FlushViewOfFile((char *)s->view + off, (SIZE_T)len))
        raise_gle("FlushViewOfFile", GetLastError());
    return self;
}

#closeObject



927
928
929
930
931
932
933
934
935
# File 'ext/winipc/winipc.c', line 927

static VALUE
shm_close(VALUE self)
{
    shm_t *s = shm_get(self);
    if (s->view) { UnmapViewOfFile(s->view); s->view = NULL; }
    if (s->map) { CloseHandle(s->map); s->map = NULL; }
    s->closed = 1;
    return Qnil;
}

#closed?Boolean

Returns:

  • (Boolean)


937
# File 'ext/winipc/winipc.c', line 937

static VALUE shm_closed_p(VALUE self) { return shm_get(self)->closed ? Qtrue : Qfalse; }

#flush(offset = 0, len = nil) ⇒ Object

Flush a range (default: whole region) to backing storage.



236
237
238
# File 'lib/winipc.rb', line 236

def flush(offset = 0, len = nil)
  _flush(offset, len)
end

#read(voff, vlen) ⇒ Object



885
886
887
888
889
890
891
892
893
894
895
896
897
# File 'ext/winipc/winipc.c', line 885

static VALUE
shm_read(VALUE self, VALUE voff, VALUE vlen)
{
    shm_t *s = shm_live(self);
    unsigned long long off = NUM2ULL(voff), len = NUM2ULL(vlen);
    VALUE out;
    shm_bounds(s, off, len);
    if (len > (unsigned long long)LONG_MAX)
        rb_raise(rb_eArgError, "winipc: read length too large");
    out = rb_str_new((const char *)s->view + off, (long)len);
    rb_enc_associate(out, rb_ascii8bit_encoding());
    return out;
}

#sizeObject



925
# File 'ext/winipc/winipc.c', line 925

static VALUE shm_size(VALUE self) { return ULL2NUM(shm_get(self)->size); }

#write(voff, data) ⇒ Object



899
900
901
902
903
904
905
906
907
908
909
910
# File 'ext/winipc/winipc.c', line 899

static VALUE
shm_write(VALUE self, VALUE voff, VALUE data)
{
    shm_t *s = shm_live(self);
    unsigned long long off = NUM2ULL(voff);
    DWORD len;
    if (!s->writable) rb_raise(eError, "winipc: shared memory is read-only");
    len = dword_len(data);
    shm_bounds(s, off, (unsigned long long)len);
    memcpy((char *)s->view + off, RSTRING_PTR(data), len);
    return ULONG2NUM(len);
}