0

I was trying to find effective way to read shared memory in form of array of struct (in C):

typedef struct the_struct {
    int id;
    int data;
} the_c_struct;
static the_c_struct *the_struc_ptr = NULL;

Currently I use following JNA Structure code to retrieve the data from shared memory:

public class MyCStruc extends Structure {

    public int id;
    public int data;

    @Override
    protected List getFieldOrder() {
        return Arrays.asList(new String[]{"id", "data"});
    }

    @Override
    public void useMemory(Pointer m, int offset) {
        super.useMemory(m, offset);
        super.read();
    }

    @Override
    public void useMemory(Pointer m) {
        super.useMemory(m);
        super.read();
    }

}

And read shared memory using native implementation of shmget and shmat:

memId = NativeLib.INSTANCE.shmget(0x999, memSize, 0);
CStructPtr = NativeLib.INSTANCE.shmat(memId, null, 0);

MyCStruc cs=new MyCStruc();
for (int i=0;i<CStructArraySize;i+=8) {
    cs.useMemory(CStructPtr,i);
    // to read a record of struct array
    // do something with the data
}

Above code is actually worked, but I guess I can do something more effective to read array of struct? right?

Note: size of array of struct is dynamic, but I can managed to get the size of the shared memory.

sybond
  • 167
  • 9
  • Sorry, why is i+=8 in the for loop? – terence hill Nov 09 '15 at 10:15
  • @terencehill That is because the struct size is 8 in bytes; so to access every struct in the array I do the offset indexing based on the size of struct. – sybond Nov 09 '15 at 14:52
  • Maybe in this case it is always equal to 8 but are you aware of this? http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member – terence hill Nov 09 '15 at 15:06
  • @terencehill Yes, that would be next problem when it comes to struct data processing. I'm sure JNA already provide some nice implementation to handle correct data alignment. – sybond Nov 09 '15 at 15:46
  • I found [this](http://www.eshayne.com/jnaex/example07.html) example. I'll try it tomorrow. – sybond Nov 09 '15 at 16:07
  • Have you looked at NIO buffers? You can also access the stuff directly with `Pointer`, no need for the extra `Structure` overhead. – technomage Nov 09 '15 at 17:28

2 Answers2

1

Don't bother with a Structure here, just have the shmat call return a Pointer and use Pointer.getInt(0) to get the ID and Pointer.getInt(4) to get the data field.

You can even use Native.getDirectBufferPointer() to give you an NIO buffer that you can pass off to other Java code.

If you're reading an array of contiguously allocated struct, then you should create your first Structure using the Pointer-based constructor, then invoke Structure.toArray(size) on that instance to load the full array.

Pointer p = lib.shmat();
MyCStruc s = new MyCStruc(p);
MyCStruc[] array = (MyCStruc[])s.toArray(size);

And the constructor:

public class MyCStruc extends Structure {
    public MyCStruc(Pointer p) {
        super(p);
        read();
    }
}
technomage
  • 9,861
  • 2
  • 26
  • 40
  • Nice. I'll test it on my environment. In addition does 'Pointer' aware of endianess? – sybond Nov 09 '15 at 21:52
  • If the memory for some reason has different endianness than the JVM there might be an issue. NIO Buffer has some options around that, but I don't know if you can tweak them after the buffer is created. – technomage Nov 09 '15 at 23:20
0

Here is my final code:

memId = NativeLib.INSTANCE.shmget(0x999, memSize, 0);
CStructPtr = NativeLib.INSTANCE.shmat(memId, null, 0);
CStructArraySize=memSize/8;
MyCStruc cs=new MyCStruc(CStructPtr);
MyCStruc[] acs=(MyCStruc[])cs.toArray(CStructArraySize);
int i=0;
while (i<CStructArraySize) {
    System.out.printf("id=%d data=%d\n", acs[i].id, acs[i].data);
    // do something else with the data
    i++;
}

MyCStruc now:

public class MyCStruc extends Structure {
    public int id;
    public int data;

    @Override
    protected List getFieldOrder() {
        return Arrays.asList(new String[]{"id", "data"});
    }
    public MyCStruc(Pointer p) {
        super(p);
        read();
    }
}
sybond
  • 167
  • 9