I need to call the Linux-function sysinfo
It's declaration is int sysinfo(struct sysinfo *info); with
Until Linux 2.3.16, sysinfo() used to return information in the following structure:
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
char _f[22]; /* Pads structure to 64 bytes */
};
and the sizes were given in bytes.
Since Linux 2.3.23 (i386), 2.3.48 (all architectures) the structure is:
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
};
This is what I have so far:
The function pinvoke:
private const string DoesntFindLibC =@"/lib/x86_64-linux-gnu/libc.so.6";
[System.Runtime.InteropServices.DllImport(DoesntFindLibC)]
private static extern int sysinfo(ref sysinfo_t info);
And the struct mapping:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct sysinfo_t
{
public System.UIntPtr uptime; /* Seconds since boot */
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=3)]
public System.UIntPtr [] loads; /* 1, 5, and 15 minute load averages */
public System.UIntPtr totalram; /* Total usable main memory size */
public System.UIntPtr freeram; /* Available memory size */
public System.UIntPtr sharedram; /* Amount of shared memory */
public System.UIntPtr bufferram; /* Memory used by buffers */
// [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.
public System.UIntPtr totalswap; /* Total swap space size */
public System.UIntPtr freeswap; /* swap space still available */
public ushort procs; /* Number of current processes */
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=22)]
public char[] _f; /* Pads structure to 64 bytes */
}
The problem is that "long" in C code is processor-architecture-specific, because in x86 32-Bit Linux, long's size is 32 Bit, and in x86 64-Bit Linux, it's 64 bit, so I have to take IntPtr, and because it's unsigned, I take UIntPtr.
In C#/mono however, long is always defined as Int64.
Now it's a bit inconvenient to work with IntPtr. Is there any MarshalAs attribute I could apply, or a custom marshaler that I could write so that I can actually have ulong in the struct, but it maps natively to IntPtr ? So that the same code works on both x86-32 and x86-64.
No, there isn't any marshalling magic you can do to fix this.
You can however hide the fields and provide property accessors:
using System.Runtime.InteropServices;
[StructLayoutAttribute(LayoutKind.Sequential)]
struct sysinfo_t
{
System.UIntPtr _uptime; /* Seconds since boot */
public ulong uptime {
get { return (ulong) _uptime; }
set { _uptime = new UIntPtr (value); }
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
System.UIntPtr [] _loads; /* 1, 5, and 15 minute load averages */
public ulong[] loads {
get { return new ulong [] { (ulong) _loads [0], (ulong) _loads [1], (ulong) _loads [1]) };
set { _loads = new UIntPtr [] { new UIntPtr (value [0]), new UIntPtr (value [1]), new UIntPtr (value [2]) }; }
}
// etc
}