| Unsafe mono | Aktuell | Seminare | Reports | Homepage | Software | ||
|
| |||||||
|
@informatik.hu-berlin.de Reports - postindustr.CC - XML/Ti Report - pTA StudienArbeit . - sch_llf study - Geschichte des PC TechDocs - Perl Objects - Installing Oracle - shell cmds in python - Using css for xml defs tricks - Unsafe mono [x] ! - Docbook Manpages - Java Bean Code rpm-suse - schema-mappingen ig cv hg re dv ev zz mk pr - java problemsen lang swing ext gtk jjtree xul boot -grub-netboot -grub-gtk -partclone freshmeat -partimage links -releaseuploader -guidod-pygtk
2005-03-23
|
Unsafe Mono C# CodeTarget of this documentation: learn how write/compile/run C# code that calls C/C++ functions in libraries (or kernel) of the underlying operating system - looking at the mono/linux platform for unsafe code. PrefaceThere is a lot false documentation floating around. Many state that mono can not compile unsafe code. Wrong, it can always do it. The problem is not the compiler but the runtime. Mono ships with a runtime and its abilities to call into libraries were limited. The biggest problem: each native code platform (linux or windows) differs heavily in the way to specify the dependencies. And that is the hard piece to learn about. Unsafe CodeThere is a short Unsafe CSharp Introduction that can help to get started. It is actually the preface to a coursework at a UK university. Basically, you need the mono framework along with the gtksharp assembly. The "Game" example over there uses pairs of "unsafe" / "fixed" to optimize the code for speed: the C# runtime will usually check sizes and object types of multi-dimensional arrays. And sure computer programmers know that it is about the small foreach loops on data that is the real time-consuming thing making the big program to feel slow in the end. Here we go: the example code shows how to create an "unsafe class Board". Yes, there is such a thing, basically it is a refcounted unmanaged C++ class definition (It won't be moved suddenly?). Everywhere that you create an object of that class or usethat object... you must wrap the portion containing such an object reference in "unsafe { ... }" braces. Furthermore, every argument that is pushed down into a method of that "unsafe class" must be "fixed". That looks like this:
public static void initialize_board(Config cf) {
unsafe {
int width = cf.Nb_cols;
int height = cf.Nb_rows;
b = new Board(&width, &height);
}
for(int i = 0; i < cf.Nb_cols; ++i) {
for(int j = 0; j < cf.Nb_rows; ++j) {
unsafe {
fixed (Cell* c = &b.grid[i, j]) {
c->count = sum_up (&b, i, j);
}
}
}
}
unsafe class Board {
public Cell[,] grid;
public Board(int* width, int* height) {
grid = new Cell[*width, *height];
}
}
The example presents the Board onto the screen using the GTK# libraries.
The full code is in Game.cs and the compiler is
being called along with
On Suse Linux, the "gtk-sharp"
package exists. But to compile you need to add the option -L /usr/lib/mono/gtk-sharp/
When the program would not contain any unsafe keywords, one can remove
the --unsafe switch from step 1. At that point the program may also work
with the Mono JIT so you can try also
When the program code no longer contains any unsafe keywords, you can remove the -unsafe switch from step 4. Importing Native FunctionsJava has JINI, CSharp has DllImport. I have some experiences with the java native interface support it is has a big problem: there compiled java objects ("*.class") do not have RPATHs or even any other dependency hint. When running a "*.class" or "*.jar" you have to specify all native code dependencies on the command line. The CSharp folks have solved it - using function attributes. Later Java has learned about generic attributes as well. We will see whether it helps with the native code import problems. In C# it does exist from day 1 simply because microsoft has so many native dlls. It was not a good idea to even try to recreated them from square 1 in "pure" managed code. Therefore we can be strict sure that the native function import works. Always. In our later "tomboy"-like gnome panel example it looks like:
// preload /opt/gnome/lib/libpanel-applet-2.so
[DllImport("panel-applet-2")]
// import this C symbol from the environment
static extern void panel_applet_factory_main(IntPtr raw,
out int size_hints, int n_elements, int base_size);
That should give you some clues. First of all, it easy to transfer integral types as arguments (and return values) since they identical in C/C++ and C#. For an external struct object just use "IntPtr" to get a generic pointer thing. The "out" parameter hint ensures that the address of object is being transfered. That object is automatically "fixed" of course. - Let's have a look a more problematic thing:
[DllImport("panel-applet-2")]
static extern IntPtr panel_applet_new();
[DllImport("panel-applet-2")]
static extern unsafe int panel_applet_gconf_get_int(IntPtr raw,
string key, out IntPtr opt_error);
public unsafe int GconfGetInt(string key) {
IntPtr error = IntPtr.Zero;
int ret = panel_applet_gconf_get_int(Handle, key, out error);
if (error != IntPtr.Zero) throw new GLib.GException (error);
return ret;
}
The "unsafe" on the GconfGetInt ensure that the "string" key is being fixed. Marking the import "gconf_get_int" as "unsafe" will remind us of that as well. Well, that's about it with library imports. A different thing might be when importing a functions from the kernel. When trying to call a function from a kernel API (like the "dvb" API or the "videodev" API) one has to remember that they look like function references but they are not. The header files for that will define an "inline function" or "parametric define" that maps the arguments on to an "ioctl" call - often along with an argument buffer instead of using a stack parameter block. That's why you have to write your own little C library that turns those inline function into real function references first. Then DllImport. One last note - apart from "unsafe" classes, "unsafe" functions and "static extern" functions there is also support for "internal" clsses, "internal" delegates, objects and a lot more. I have seen those on the results of the "gtk#" generator that turns C libraries in the gtk object-oriented style into wrapper C# assembly source. (I guess they have to do with `mono_add_internal_call ("Hello::Sample", sample);` that allows to export a function from the runtime. Instead of specifying a DllImport one just says "internal".) Building Wrapper AssembliesRemember that the base case to write optimized code is having a C library with simple code that convert complicated objects and API usages into a format that can be easily imported by a C# source DllImport. Theoretically there is "managed C++" as well but the mono compiler suite does not (yet) have it. In any case, the underlying "#define" code would need to be compiled ahead of time anyway. Anyway, if you want to have something redistributable you should remember the mono way of expressing complicated library dependencies. In the first attempt one would use function attributes or class attributes. That did work for windows and linux but it did fail on the next platform that the original developer of an assembly was not thinking of: Mac OS-X. Therefore, the best thing is to put it in an extra file that can be edited manually. Here is the tomboy xml file named Tomboy.exe.config <configuration> <dllmap dll="libglib-2.0-0.dll" target="libglib-2.0.so.0"/> <dllmap dll="libgobject-2.0-0.dll" target="libgobject-2.0.so.0"/> <dllmap dll="libgtkspell" target="libgtkspell.so.0"/> <dllmap dll="libtomboy" target="libtomboy.so"/> <dllmap dll="panel-applet-2" target="libpanel-applet-2.so.0"/> </configuration> Now watch for the "libtomboy" entry which differs from the other ones. Yes, most imports are referencing "ldd" system libraries but for libtomboy it is a dynamic shared object shipped by the project itself. It is not being installed in the public /usr/lib path but in the package-local /usr/lib/tomboy module path. A little wrapper script will ensure it is present in LD_LIBRARY_PATH. ........... to be continuedCSharp Gnome Panel AppletThe tomboy note applet is widely used already. Hence, it is a sophisticated example to have a look at. ........... to be continued | ||||||