[Mono-list] Writing daemons in C#

Miguel de Icaza miguel@ximian.com
20 Nov 2002 05:44:44 -0500


Hello,

> I'm presuming DllImport and P/Invoke aren't the preferred methods here? 
> I looked at System.Net.Socket, since that would appear to be a task
> similar to implementing POSIX APIs.  It uses InternalCall, which I'm
> presuming (C# In A Nutshell is not so clear on this) is implemented
> within the interpreter.  I poked through mono and found the file
> mono/io-layer/sockets.c which appears to be the internal implementation
> of the Sockets API.  Would the POSIX implementation look similar to
> this?  Is there someplace all this is documented or am I on my own?

Ok, here is where it gets tricky.  The official response is `Only use
P/Invoke', but sometimes it might be convenient (for speed reasons) to
use internal calls.  The tricky bit is: internal calls are only
available on the runtime.

Now, I figured that there is a *hack* we can use, but it is a hack, in
which you P/Invoke into a bootstrap routine (called from a static
constructor), and the bootstrap routine in turn registers the
InternalCalls with the runtime, and then the rest of the code uses
internalcalls.

My suggestion is: for now stick to using P/Invoke, and we will later
implement the performance hack.

Now, another of the tricky bits is this: enumerations and constants are
different across the various Unix implementations, so it is not possible
to P/Invoke a library with constants that are defined in C# directly,
because they will likely change (in fact, the values change across Linux
ports: the same system constant value is different across ports).

So the process to assemble this is multi-process:

	* A C# file containing all the enumeration values.

	* A C# program that can read these enumeration values and
	  generate "support" header file for C consumption.

	* A C program that includes the header file, and maps constants
	  to their native valuess.

	* A C# set of definitions to P/Invoke into it.

Let me give you an illustration:

PosixEnums.cs:
[IncludeFile ("fcntl.h")]
[IncludeFile ("sys/stat.h")]
	enum OpenMode {
		O_CREAT,
		O_EXCL,
		O_APPEND
	}

The a C# program uses reflection to generate the following header file:

#include <fcntl.h>
#include <sys/stat.h>
#define OpenMode_O_CREAT	O_CREAT
#define OpenMode_O_EXCL         O_EXCL
#define OpenMode_O_APPEND       O_APPEND

And the following C helper file:

#include "PosixEnums.h"
map_OpenMode (int flags)
{
	switch (flags){
		case OpenMode_O_CREAT: return O_CREAT;
		case OpenMode_O_EXCEL: return O_EXCL;
		case OpenMode_O_APPEND: return O_APPEND;
	}
}

Notice that the source file contains the attribute "IncludeFile" (that
you will have to create, and "pull" it out yourself to generate the
corresponding header files).

Then you have to write the C code, *manually*:

int posix_open (string filename, int flags)
{
	return open (filename, 	map_OpenMode (flags));
}

Then from C# you write (again manually) the P/Invoke invocation:

[DllImport ("Mono.Posix.so", EntryPoint="posix_open")]
int open (string filename, OpenMode mode);

Once you have the code, we can integrate it into the build.

Hope this helps,
Miguel.