I am attempting to map the kstat library in Solaris 11.3 to Java using JNA. While I've managed to get most of the structures working, I've spent the last 24 hours fighting with a particularly difficult union-within-a-structure-within-a-union.
I am successfully retrieving a pointer to a kstat_named structure I need using kstat_data_lookup(). My code properly retrieves most of the data (name, data_type, and non-struct members of the union) in this C structure:
typedef struct kstat_named {
char name[KSTAT_STRLEN]; /* name of counter */
uchar_t data_type; /* data type */
union {
charc[16]; /* enough for 128-bit ints */
struct {
union {
char *ptr; /* NULL-terminated string */
} addr;
uint32_t len; /* length of string */
} str;
int32_t i32;
uint32_t ui32;
int64_t i64;
uint64_t ui64;
/* These structure members are obsolete */
int32_t l;
uint32_t ul;
int64_t ll;
uint64_t ull;
} value; /* value of counter */
} kstat_named_t;
I have mapped this in JNA as follows:
class KstatNamed extends Structure {
public static class UNION extends Union {
public byte[] charc = new byte[16]; // enough for 128-bit ints
public Pointer str; // KstatNamedString
public int i32;
public int ui32;
public long i64;
public long ui64;
}
public byte[] name = new byte[KSTAT_STRLEN]; // name of counter
public byte data_type; // data type
public UNION value; // value of counter
public KstatNamed() {
super();
}
public KstatNamed(Pointer p) {
super();
this.useMemory(p);
this.read();
}
#Override
public void read() {
super.read();
switch (data_type) {
case KSTAT_DATA_CHAR:
value.setType(byte[].class);
break;
case KSTAT_DATA_STRING:
value.setType(Pointer.class);
break;
case KSTAT_DATA_INT32:
case KSTAT_DATA_UINT32:
value.setType(int.class);
break;
case KSTAT_DATA_INT64:
case KSTAT_DATA_UINT64:
value.setType(long.class);
break;
default:
break;
}
value.read();
}
#Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "name", "data_type", "value" });
}
}
This code works correctly for int32 types (KSTAT_DATA_INT32). However, when the data type is KSTAT_DATA_STRING, which corresponds to the str structure inside the union, I am not having any success in properly retrieving the data.
I have mapped the nested structure like this:
class KstatNamedString extends Structure {
public static class UNION extends Union {
public Pointer ptr; // NULL-terminated string
}
public UNION addr;
public int len; // length of string
public KstatNamedString() {
super();
}
public KstatNamedString(Pointer p) {
super();
this.useMemory(p);
this.read();
}
#Override
public void read() {
super.read();
addr.setType(Pointer.class);
addr.read();
}
#Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "addr", "len" });
}
}
Ultimately I'm trying to replicate the behavior of this C macro:
#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.str.addr.ptr)
I've tried multiple different methods of trying to get access to the above structure, but it never seems to read the correct data (the len value is in the millions and attempting to read the string ptr causes segfault). I've tried:
Pointer p = LibKstat.INSTANCE.kstat_data_lookup(ksp, name);
KstatNamed data = new KstatNamed(p);
KstatNamedString str = new KstatNamedString(data.value.str);
return str.addr.ptr.getString(0); // <--- Segfault on C side
I've also tried:
Specifying KstatNamedString as the type instead of the Pointer type
Using various combinations of ByReference in both the structures and the unions
I've googled everywhere, including trying what I thought was a promising result here, but nothing seems to work.
I'm sure I'm missing something simple.
Use KstatNamedString instead of Pointer type.
Change your pointer-based constructors like this:
public KstatNamed(Pointer p) {
super(p);
this.read();
}
public KstatNamedString(Pointer p) {
super(p);
this.read();
}
and change the addr field of the str struct field to be a simple Pointer (no need for the union bits around it).
public Pointer /*UNION*/ addr;
Run your JVM with -Djna.dump_memory=true and print your newly-initialized Structure as a string. That will show you how JNA interprets the memory layout of the struct, and how the native memory is initialized. That should help you determine how to extract the string you're looking for (assuming it's there).
You can also tune your union read() method to initially read only the type field (using Structure.readField("data_type")) before setting the union type.
Related
I am trying to return values from a struct, different approaches weren`successful
struct Briefing {
string description;
uint max_influencer;
uint jobvalue;
bool achievement;
}
function getSummary() public view returns (Briefing) {
return Briefing (
string,
uint,
uint,
bool
);
When you're working with reference types (such as struct), you always need to specify the data location. In this case, it's memory, because you need to load the values to memory first, and then return them from the memory.
Your question doesn't specify if you need to return a new instance of the struct or load it from storage, so here's example of both:
pragma solidity ^0.8;
contract MyContract {
struct Briefing {
string description;
uint max_influencer;
uint jobvalue;
bool achievement;
}
Briefing summary;
function getSummaryHardcoded() public view returns (Briefing memory) {
return Briefing("desc", 1, 1, true);
}
function getSummaryStored() public view returns (Briefing memory) {
return summary;
}
}
I have a C function that expects a struct that contains a non-const String.
typedef struct _A {
char* str;
} A;
void myFunc(A* aptr) { ... }
I've tried for a long time to pass this thing via JNA but didn't manage so far.
public class A extends Structure {
public String str;
protected List getFieldOrder() { ...
}
doesn't work because String will be turned into a const char* instead of char* which I need.
public class A extends Structure {
public byte[] str;
protected List getFieldOrder() { ...
}
doesn't work because the byte array inside a struct gets turned into contiguous memory and not a pointer.
I know I can do it by using Memory and copying the String over. But I can't imagine that this is the preferred way to do it.
I also tried something like
public class NonConstStringMember extends Structure {
public static class ByReference extends NonConstStringMember implements Structure.ByReference {}
public byte[] stringMember;
protected List getFieldOrder() { ...
}
public class A extends Structure {
public NonConstStringMember.ByReference str;
}
but it doesn't work either, maybe because of alignment issues.
What is the preferred way to do this with JNA?
Assuming you want this to point to an arbitrary buffer which you may write to, use Pointer (and assign it a Memory value if you're allocating the buffer).
You then use Pointer.getString(0) or Pointer.setString(0, s) to manipulate the buffer contents.
EDIT
Windows libraries usually have an ascii or unicode version of most functions. While in most cases you can define a single Structure for use in both cases, sometimes you need to provide a little additional handling to ensure the correct types are used. Since the two modes are rarely, if ever, used simultaneously, JNA sets up options to default to one or the other (automatically mapping to the right function suffix, and automatically mapping String to either native const char* or const wchar_t* depending on the mode).
Use setWideString() if using unicode mode and setString() otherwise, or make some accessors on your Structure to handle that for you automatically. For example:
class MyStructure extends Structure {
private static final boolean ASCII = Boolean.getBoolean("w32.ascii");
public Pointer stringBuffer = new Memory(X);
void setStringBuffer(String s) {
stringBuffer.setString(0, s, ASCII);
}
String getStringBuffer() {
return stringBuffer.getString(0, ASCII);
}
}
EDIT
Please note that in most cases you should use a String as the field type and rely on a TypeMapper to use WString behind the scenes where appropriate (e.g. User32 and W32APIOptions.DEFAULT_OPTIONS).
I've been trying to figure this out for a few hours now.
In order to start up the audio, I need to create an SDL.AudioSpec object and pass it to SDL.Audio.Open. The problem is, AudioSpec is a class with a private constructor, so when I try to create one I get:
sdl.vala:18.25-18.43: error: `SDL.AudioSpec' does not have a default constructor
AudioSpec audiospec = new SDL.AudioSpec();
^^^^^^^^^^^^^^^^^^^
And if I try to just assign values to it's member vars like a struct (it's a struct in normal sdl) I get:
sdl.vala:20.3-20.25: error: use of possibly unassigned local variable `audiospec'
audiospec.freq = 22050;
^^^^^^^^^^^^^^^^^^^^^^^
I found the valac doc here: http://valadoc.org/sdl/SDL.AudioSpec.html
But it isn't much help at all.
The offending code block looks like this:
// setup the audio configuration
AudioSpec audiospec;
AudioSpec specback;
audiospec.freq = 22050;
audiospec.format = SDL.AudioFormat.S16LSB;
audiospec.channels = 2;
audiospec.samples = 512;
// try to initialize sound with these values
if (SDL.Audio.open(audiospec, specback) < 0)
{
stdout.printf("ERROR! Check audio settings!\n");
return 1;
}
Any help would be greatly appreciated!
Another update, as I'm still having some trouble. I've changed the vapi file, and this is what I have now:
public delegate void AudioCallback (out void* userdata, out uchar stream, int len);
[CCode (cname="SDL_AudioSpec")]
[Compact]
public struct AudioSpec {
public int freq;
public AudioFormat format;
public uchar channels;
public uchar silence;
public uint16 samples;
public uint16 padding;
public uint32 size;
public AudioCallback callback;
public void* userdata;
}// AudioSpec
I have a method that (tries?) to meet this function signature:
public void callback(out void* userdata, out uchar stream, int len)
{
stream = 0;
userdata = null;
}
And assigning it as:
audiospec.callback = gen.callback;
Needless to say, this still isn't working, get lots of errors:
/home/gukid/vala/soundgen.vala.c: In function ‘sound_gen_main’:
/home/gukid/vala/soundgen.vala.c:766:12: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
/home/gukid/vala/soundgen.vala.c:766:72: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
/home/gukid/vala/soundgen.vala.c:766:114: error: ‘SDL_AudioSpec’ has no member named ‘callback_target’
/home/gukid/vala/soundgen.vala.c:768:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target’
/home/gukid/vala/soundgen.vala.c:769:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
/home/gukid/vala/soundgen.vala.c:770:21: warning: assignment from incompatible pointer type [enabled by default]
/home/gukid/vala/soundgen.vala.c:771:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target’
/home/gukid/vala/soundgen.vala.c:772:11: error: ‘SDL_AudioSpec’ has no member named ‘callback_target_destroy_notify’
error: cc exited with status 256
So I'm at a bit of another sticky point.
3rd post: EUREKA! I have a solution! (debatable :P)
First off, the sdl.vapi looks like:
[CCode (cheader_filename = "SDL.h")]
public delegate void AudioCallback (void* userdata, uchar* stream, int len);
[CCode (cname="SDL_AudioSpec", has_type_id=false)]
public struct AudioSpec {
public int freq;
public AudioFormat format;
public uchar channels;
public uchar silence;
public uint16 samples;
public uint16 padding;
public uint32 size;
[CCode (delegate_target = false, type = "void*")]
public weak AudioCallback callback;
public void* userdata;
}// AudioSpec
And then I can just create a function:
public static void callback(void* userdata, uchar* stream, int len)
And:
audiospec.callback = callback;
Ahhh, finally my beautiful white noise generator is complete!
I think it's a bug in the VAPI. In sdl.vapi, try changing
[Compact]
public class AudioSpec {
to
public struct AudioSpec {
and
[CCode (cname="SDL_OpenAudio")]
public static int open(AudioSpec desired, AudioSpec obtained);
to
[CCode (cname="SDL_OpenAudio")]
public static int open(AudioSpec desired, out AudioSpec obtained);
and make your code look like:
AudioSpec audiospec = AudioSpec();
AudioSpec specback;
audiospec.freq = 22050;
audiospec.format = SDL.AudioFormat.S16LSB;
audiospec.channels = 2;
audiospec.samples = 512;
// try to initialize sound with these values
if (SDL.Audio.open(audiospec, out specback) < 0)
{
stdout.printf("ERROR! Check audio settings!\n");
return 1;
}
and give it a test. It seems to generate the correct code according to the SDL docs. If it works, consider submitting the VAPI changes to the Vala bugzilla.
Okay, the delegate:
public delegate void AudioCallback (out void* userdata, out uchar stream, int len);
has the C type:
void(*AudioCallback)(void**userdata, unsigned char* stream, int len);
where userdata and stream are write-only, which is not really what you want.
void (*callback)(void *userdata, Uint8 *stream, int len);
In this, userdata is just a pointer to some stuff for your use. In Vala's terms, it's the target of a delegate. stream is an array, but SDL has allocated it, so it's not out and len is the length of the array, so we can have Vala deal with that automatically with just uint8[] stream. Putting it all together:
[CCode(instance_pos = 0)]
public delegate void AudioCallback(uint8[] stream);
The instance_pos tells Vala where the userdata is. It normally assumes it to be last. As for the struct:
[CCode (cname="SDL_AudioSpec", destroy_function = "")]
public struct AudioSpec {
...
[CCode(delegate_target_cname = "userdata")]
public AudioCallback callback;
}
This will create a callback that stores the target in userdata. Now, to avoid leaking memory, Vala is going to try to assign a destructor to callback_target_destroy_notify...and now we're stuck because we have no member for that. So, let's back up and try again:
[CCode(has_target = false)]
public delegate void AudioCallback(void* userdata, uint8[] stream);
The has_target tells Vala there is no userdata and we include it manually. As for the struct:
[CCode (cname="SDL_AudioSpec", destroy_function = "")]
public struct AudioSpec {
...
public AudioCallback callback;
public void* userdata;
}
So, userdata will get passed to your callback, but you'll have to cast it yourself and you'll have to manage the memory. Additionally, when the structs go out of scope, Vala is going to call a destroy function. By specifying an empty string, it will do nothing. Normally, this frees memory inside the struct, but we don't need to worry here.
I have the following scenario. The managed code will initialize lots of object of a class which is a wrapper around an unmanaged struct. There are two approaches that I can do for this. One is to have a managed class wrapper that just has a pointer to the unmanaged object. The other is to have a full fledged managed class and create the unmanaged object when required to call into unmanaged methods. I have provided both the methods below. I was told that if I use the approach 1(having a pointer to unmanged object), the GC will have lots of issue knowing about the unmanaged portion and it is better to do approach 2. Does someone tell me which is better or if there is some other approach that is even better. My concern with Approach 2 is that there are copying to and fro everytime a unmanaged method is called. I am not sure if the GC issue outweighs it.
EDIT- the first approach has a ref class and the second has a value class. The reason the second is value is so that it can be added to lists more efficiently
In unmanaged:
struct A_UNMANAGED
{
int a;
int b[20];
};
void GetData(A_UNMANAGED& a); // populates A
In managed (First Approach)
public ref class A_MANAGED
{
A_UNMANGED* ap;
public:
property System::UInt32 a
{
System::UInt32 get() { return ap->a; }
void set(System::UInt32 value) { ap->a = value; }
}
property array<System::UInt32>^ b
{
array<System::UInt32>^ get() { return ap->b; }
void set(array<System::UInt32>^ value) { b = value; } // assume this copy works
}
internal:
void GetData()
{
GetData(ap);
}
};
In managed (Second Approach) (EDIT: updated to ref. Assume all the garbage collection and pointer creation is written correctly)
public value class A_MANAGED
{
System::UInt32 a;
array<System::UInt32>^ b;
public:
property System::UInt32 a
{
System::UInt32 get() { return a; }
void set(System::UInt32 value) { a = value; }
}
property array<System::UInt32>^ b
{
array<System::UInt32>^ get() { return b; }
void set(array<System::UInt32>^ value) { b = value; }
}
internal:
void GetUnmanaged(A_UNMANAGED& obj1)
{
obj1.a = a;
pin_ptr<System::UInt32> bp = &b[0];
memcpy(obj1.b, bp, 20);
}
void GetData()
{
A_UNMANAGED obj2;
GetUnmanaged(obj2);
GetData(obj2);
// copy from obj2 to member variables
}
};
No, the 1st snippet it the canonical way. The garbage collector only moves the pointer, it doesn't move the pointed-to object. That one should have been allocated with malloc() or the new operator, it cannot be moved.
There are otherwise several serious problems in your code. You don't seem to allocate the memory for A_UNMANAGED unless GetData() takes its argument by reference. GetData() is never called. This must normally be a ref class (not ref value) so you can provide a destructor and a finalizer to release the memory. The b property setter will bomb your program with a StackOverflowException. Be sure to study the language before tackling this project.
Check this answer for sample code.
As Hans said, the first way is the usual approach (though personally, I think P/Invoke would be more succinct in this particular case...). However, your A_MANAGED::b implementation will not work, which would be obvious if one were to try simply compiling it. Try this instead:
public ref class A_MANAGED
{
A_UNMANAGED* ap;
public:
A_MANAGED() : ap(new A_UNMANAGED() ) { }
~A_MANAGED() { this->!A_MANAGED(); }
!A_MANAGED() { delete ap; ap = nullptr; }
property int a
{
int get() { return ap->a; }
void set(int value) { ap->a = value; }
}
property array<int>^ b
{
array<int>^ get()
{
using System::Runtime::InteropServices::Marshal;
array<int>^ arr = gcnew array<int>(20);
Marshal::Copy(System::IntPtr(ap->b), arr, 0, 20);
return arr;
}
void set(array<int>^ value)
{
using System::Runtime::InteropServices::Marshal;
Marshal::Copy(value, 0, System::IntPtr(ap->b), 20);
}
}
internal:
void GetData()
{
::GetData(*ap);
}
};
And then there's the usual caveat about returning arrays from properties: it's a bad idea. Unless you really want to maintain parity with the unmanaged class' public interface, b should really be a pair of set/get functions rather than a property.
I was just trying to code the following extension method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _4Testing
{
static class ExtensionMethods
{
public static void AssignMe(this int me, int value)
{
me = value;
}
}
}
But it is not working, i mean, can I use an extension method to alter values from extended classes? I don't want to change void return type to int, just changing extended class value. Thanks in advance
Your example uses int, which is a value type. Classes are reference types and behaves a bit differently in this case.
While you could make a method that takes another reference like AssignMe(this MyClass me, MyClass other), the method would work on a copy of the reference, so if you assign other to me it would only affect the local copy of the reference.
Also, keep in mind that extension methods are just static methods in disguise. I.e. they can only access public members of the extended types.
public sealed class Foo {
public int PublicValue;
private int PrivateValue;
}
public static class FooExtensions {
public static void Bar(this Foo f) {
f.PublicValue = 42;
// Doesn't compile as the extension method doesn't have access to Foo's internals
f.PrivateValue = 42;
}
}
// a work around for extension to a wrapping reference type is following ....
using System;
static class Program
{
static void Main(string[] args)
{
var me = new Integer { value = 5 };
int y = 2;
me.AssignMe(y);
Console.WriteLine(me); // prints 2
Console.ReadLine();
}
public static void AssignMe(this Integer me, int value)
{
me.value = value;
}
}
class Integer
{
public int value { get; set; }
public Integer()
{
value = 0;
}
public override string ToString()
{
return value.ToString();
}
}
Ramon what you really need is a ref modifier on the first (i.e. int me ) parameter of the extension method, but C# does not allow ref modifier on parameters having 'this' modifiers.
[Update]
No workaround should be possible for your particular case of an extension method for a value type. Here is the "reductio ad absurdum" that you are asking for if you are allowed to do what you want to do; consider the C# statement:
5.AssignMe(10);
... now what on earth do you think its suppose to do ? Are you trying to assign 10 to 5 ??
Operator overloading cannot help you either.
This is an old post but I ran into a similar problem trying to implement an extender for the String class.
My original code was this:
public static void Revert(this string s)
{
char[] xc = s.ToCharArray();
s = new string(xc.Reverse());
}
By using the new keyword I am creating a new object and since s is not passed by reference it will not be modified.
I changed it to the following which provides a solution to Ramon's problem:
public static string Reverse(this string s)
{
char[] xc = s.ToCharArray();
Array.Reverse(xc);
return new string(xc);
}
In which case the calling code will be:
s = s.Reverse();
To manipulate integers you can do something like:
public static int Increment(this int i)
{
return i++;
}
i = i.Increment();