RPC and Dynamic function call

grauzone none at example.net
Fri Nov 20 19:54:11 PST 2009


Denis Koroskin wrote:
> type-safe manner anymore (well, one could create a set of trampolines 
> for each of set of types involved in a call, but I don't think it's 
> reasonable or even possible; I'll look into it, too, though). That's why 

Yes, it is possible. You'll have to pass the method as alias template 
parameter. Then you get a tuple of the parameter types. You can foreach 
over that tuple and serialize/deserialize the actual values and 
read/write them from the tuple. You also can declare a nested function 
that does the actual call to the server's function. That delegate can 
have a type independent from the method, and thus can be stored in the 
non-template world.

Basically like this (pseudo code):

//client function to invoke a specific RPC
//the parameters can be passed normally thanks to tuples
void makeDynamicCall(Params...)(Stream stream, char[] method, Params p) {
	stream.write(method);

	//serialize the parameters
	foreach (int index, _; p) {
		auto val = p[index];
		stream.write!(typeof(val))(val);
	}
}

alias void delegate(Stream) Stub;

//registry of server functions
Stub[char[]] stubs;

//the server network code calls this on incomming RPC requests
void receiveDynamicCall(Stream stream) {
	auto method = stream.read!(char[])();
	stubs[method].call(stream);
}

//the server calls this on program initialization
//he passes an alias to the server function, and its name
void registerStub(alias Function)(char[] name) {
	//generate code to deserialize a RPC and to call the server
	void stub(Stream stream) {
		//you can get the param tuple of a function
		//Phobos2 and Tango should have something similar
		alias ParamTupleOfFunction!(Function) Params;

		//deserialize the arguments
		Params p;
		foreach (int index, _; p) {
			alias typeof(p[index]) PT;
			p[index] = stream.read!(PT)();
		}

		//actually call the function
		Function(p);
	}

	stubs[name] = &stub;
}

It all can be typesafe and non-compiler specific.

The question is; how much template bloat will this emit into the 
application binary? You have to consider the instantiations of 
Stream.read and Stream.write, too.

> Note that all the asm it uses is just 3 constructs: naked, ret and call! 
> Everything else is implemented with a help of compiler (i.e. pushing 
> arguments, grabbing result, stack alignment etc). My code is most 
> probably not very portable (I didn't test it on anything other that 
> Windows), it doesn't account x64 specifics etc, but it shouldn't be hard 
> to fix.

Wow, I'm surprised that this works. Actually, I'd *like* to do it this 
way, but the code is completely compiler and platform specific. Maybe it 
also depends from the compiler code generator's mood if it works. And if 
you want to deal with user-define types (structs), you're completely out 
of luck.



More information about the Digitalmars-d mailing list