Всем привет. Не сильно надеюсь, что будет ответ, но вдруг
Играюсь с GraalVM и прямому доступу к линуксу.
С вызовом функций с простыми типами, как mmap, strerror, ну и всяким прочим open/close/write/read проблем добраться и использовать нет.
Проблемы приши после попыток дотянуться до ioctl, а именно когда пришлось передавать стуктуры и указатели на структуру.
Скупая документация на GraalVM фактически сводится к одному примеру , который не особо помог с ответом.
А нужно протянуть в java что-то примерно такое:
typedef union my_union
{
uint8_t bb;
uint16_t ww;
uint8_t arr[32]; // <-- Проблема раз, как заалоцировать
} my_union;
typedef struct my_struct
{
char cc;
int size;
union my_union *data ; // <-- Проблема как создать и присобачить указатель на union тут
} my_struct;
В Graal это привращается во что-то такое (оно даже компиляется и запускается):
@CStruct("my_union")
public interface my_union extends PointerBase {
@CField("bb")
byte getBb();
@CField("bb")
void setBb(byte b);
@CField("ww")
short getWw();
@CField("ww")
void setWw(short word);
@CFieldAddress("arr")
Pointer getBlock(); // Какой тут тип должен быть?
}
@CStruct("my_struct")
public interface my_struct extends Pointer {
@CField("сс")
byte getСс();
@CField("сс")
void setСс(byte rw);
@CField("size")
int getSize();
@CField("size")
void setSize(int size);
@CFieldAddress("data")
CIntPointer getData(); // Какой тут тип должен быть? И как установить указатель на my_union
}
При передаче в таком виде, оно падает с ошибкой ioctl failed: -1
Соответственно вопросы:
1. Как правильно объявить структуры в GraalVM
2. Как правильно инициализировать и установить указатели.
Либо хотя бы как отдэбажить что native-image генерит(оно в момент трет исходики нативные) и что в ioctl пришло. Заранее благодарен за ответы.
Здравствуйте, Infernal, Вы писали:
I>Играюсь с GraalVM и прямому доступу к линуксу.
Мне кажется, что просто использовать CStruct для union не получится.
По поводу указателя, есть аннотация CPointerTo, мне кажется она как раз для этого.
Здравствуйте, StanislavK, Вы писали:
SK>Здравствуйте, Infernal, Вы писали:
I>>Играюсь с GraalVM и прямому доступу к линуксу. SK>Мне кажется, что просто использовать CStruct для union не получится. SK>По поводу указателя, есть аннотация CPointerTo, мне кажется она как раз для этого.
SK>JNI не подходит?
Тут как раз от него хочется отказаться.
Под JVM вполне все прекрасно выходит под сделать под JNA.
Сейчас осваиваю компиляцию того же кода, только в натив без всяких дополнительных нативных библиотек.
CPointerTo я видел, но с ходу не понял как его можно применить. Эта аннотация на интефейс, а не на поле в виде указателя. Сейчас вроде начало доходить, спасибо, попробую.
Походу придется копать в натив. По идее, зная размеры структур, оффсеты полей (это можно достать прямо через функции грааля, дабы не хардкодить), можно через malloc/free все замутить, если через аннотации не получится.
Здравствуйте, StanislavK, Вы писали:
SK>Здравствуйте, Infernal, Вы писали:
I>>Здравствуйте, StanislavK, Вы писали:
I>>CPointerTo я видел, но с ходу не понял как его можно применить. Эта аннотация на интефейс, а не на поле в виде указателя. Сейчас вроде начало доходить, спасибо, попробую. SK>Тут, как я понимаю, довольно много примеров: SK>https://github.com/oracle/graal/tree/master/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers
SK>В substratevm много чего есть.
Да, это я видел, маппинг некоторых функций, которые им самим похоже потребовались. Кое что оттуда вынес. Но с конкретной задачей это не помогло.
Проверил как Graal собирает struct/union на предмет размеров и offsets полей. Вроде для обоих типов правильно.
Но опять же при передаче — ошибка. Если знаете как посмотреть в линукс, что передалось в ioctl и получить дебаг информацию, то буду благодарен. Гугл не помог.
Здравствуйте, Infernal, Вы писали:
I>Проверил как Graal собирает struct/union на предмет размеров и offsets полей. Вроде для обоих типов правильно.
Мне кажется, что тогда для union надо задавать offset для каждого поля, иначе я не понимаю, как оно может работать.
I>Но опять же при передаче — ошибка. Если знаете как посмотреть в линукс, что передалось в ioctl и получить дебаг информацию, то буду благодарен. Гугл не помог.
А вот это: https://www.graalvm.org/reference-manual/native-image/DebugInfo/
ну и потом с dbg.
Здравствуйте, Infernal, Вы писали:
I>Проверил как Graal собирает struct/union на предмет размеров и offsets полей. Вроде для обоих типов правильно.
Правильно — это сколько? И как вы победили массив? В вашем примере у my_union размер должен быть 32 байта. И меня очень смущает стрелочка на arr в вопросе про аллокацию. Это же C, тот конкретный arr не нужно вообще аллоцировать. Стрелочка должна показывать на сам struct. Или в graal какие-то секретные аннотации есть?
I>Но опять же при передаче — ошибка. Если знаете как посмотреть в линукс, что передалось в ioctl и получить дебаг информацию, то буду благодарен. Гугл не помог.
Если только посмотреть — есть strace. Если еще пощупать — уже предложили gdb. Можно что-нибудь визуальное поверх него, например — ddd. Если инструментов нет — устанавливайте соответствующие пакеты, они почти во всех дистрибутивах должны быть.
Здравствуйте, maxkar, Вы писали:
M>Здравствуйте, Infernal, Вы писали:
I>>Проверил как Graal собирает struct/union на предмет размеров и offsets полей. Вроде для обоих типов правильно. M>Правильно — это сколько? И как вы победили массив? В вашем примере у my_union размер должен быть 32 байта. И меня очень смущает стрелочка на arr в вопросе про аллокацию. Это же C, тот конкретный arr не нужно вообще аллоцировать. Стрелочка должна показывать на сам struct. Или в graal какие-то секретные аннотации есть?
Проверил, в момент компиляции native-image все нормально все аллоцируется, грааль размер получает правильный.
I>>Но опять же при передаче — ошибка. Если знаете как посмотреть в линукс, что передалось в ioctl и получить дебаг информацию, то буду благодарен. Гугл не помог. M>Если только посмотреть — есть strace. Если еще пощупать — уже предложили gdb. Можно что-нибудь визуальное поверх него, например — ddd. Если инструментов нет — устанавливайте соответствующие пакеты, они почти во всех дистрибутивах должны быть.
Как предложил Станислав, через @CPointerTo struct/union прекрасно связались. Спасибо ему.
Пошел несколько дальше. Написал враппер в виде лайбрари на си, в котором вызываю ioctl.
Дергаю вызов одинаковых структур, с одинаковыми параметрами из си и структур из явы и сравниваю.
Размеры — одинаковые, данные — тоже. Проверял через GDB.
Единственная разница, в си указатели идут последовательно:
7ffffff150 — для структуры
7ffffff160 — для union
Для явы — нет:
5555e12a00
5555e127e0
Из Си все работает, в яве — ошибка.
Если делать то же самое под JNA, то решается как просто создаем вместо структуры Memory, заполняем и в качестве union кладем тоже Memory. Тогда все норм.
Есть подозрение, что надо тоже единый вектор памяти под структуры создавать и его передавать. Копаю дальше.
Здравствуйте, StanislavK, Вы писали:
SK>Здравствуйте, Infernal, Вы писали:
I>>Вроде разобрался. Завтра если интересно, отпишусь по результатам. SK>Ну и где результаты?
Да, сорри.
Example.java
package test;
import org.graalvm.nativeimage.c.CContext;
import org.graalvm.nativeimage.c.function.CLibrary;
import org.graalvm.nativeimage.c.struct.CField;
import org.graalvm.nativeimage.c.struct.CFieldAddress;
import org.graalvm.nativeimage.c.struct.CPointerTo;
import org.graalvm.nativeimage.c.struct.CStruct;
import org.graalvm.word.Pointer;
import org.graalvm.word.PointerBase;
import java.util.Collections;
import java.util.List;
@CContext(Example.Headers.class)
@CLibrary("c")
public class Example {
public static class Headers implements CContext.Directives {
@Override
public List<String> getHeaderFiles() {
return Collections.singletonList("\"[path_to]/my_header.h\"");
}
}
@CPointerTo(MyUnion.class)
public interface MyUnionPtr extends PointerBase {
MyUnion read();
void write(MyUnion data);
}
/*
typedef union my_union
{
uint8_t bb;
uint16_t ww;
uint8_t arr[32];
} my_union;
*/
@CStruct("union my_union")
public interface MyUnion extends PointerBase {
@CField("bb")
byte getByte();
@CField("bb")
void setByte(byte b);
@CField("ww")
short getWord();
@CField("ww")
void setWord(short word);
@CFieldAddress("arr")
Pointer getArray();
}
/*
typedef struct my_struct
{
char cc;
int size;
union my_union *data ;
} my_struct;
*/
@CStruct("my_struct")
public interface MyStruct extends PointerBase {
@CField("cc")
byte getChar();
@CField("cc")
void setChar(byte b);
@CField("size")
int getSize();
@CField("size")
void setSize(int size);
@CFieldAddress("data")
MyUnionPtr getData();
}
}
ExampleIoctl.java
package test;
import org.graalvm.nativeimage.UnmanagedMemory;
import org.graalvm.nativeimage.c.CContext;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.function.CLibrary;
import org.graalvm.nativeimage.c.struct.SizeOf;
import org.graalvm.word.PointerBase;
import java.util.Collections;
import java.util.List;
@CContext(ExampleIoctl.Headers.class)
@CLibrary("c")
public class ExampleIoctl {
public class Headers implements CContext.Directives {
public List<String> getHeaderFiles() {
return Collections.singletonList(
"\"/usr/include/linux/ioctl.h\""
);
}
}
private static class Delegate {
@CFunction(transition = CFunction.Transition.NO_TRANSITION)
public static native int ioctl(int fd, long command, PointerBase ptr);
}
public static void static void main(String[] args) {
Example.MyStruct struct = UnmanagedMemory.malloc(
SizeOf.get(Example.MyStruct.class)
);
Example.MyUnion union = UnmanagedMemory.malloc(
SizeOf.get(Example.MyUnion.class)
);
try {
// TODO fill values for struct/union
// Set ptr
struct.getData().write(union);
Delegate.ioctl([file_id], [command],struct);
} finally {
UnmanagedMemory.free(union);
UnmanagedMemory.free(struct);
}
}
}