 |
5.0 Example translations: the simple class
The simple class in this example is a nonsense class that does no meaningful computation. However, it exercises the library's full functionality and illustrates how our compiler generates translations. The example shows the C++ class, its translation, and a sample program that illustrates how we invoke methods.
To write the translation we first define a wrapper class called Legion_Simple. This wrapper contains a protected data member, an object of the translated C++ class. We call this the wrapped object. For each wrapped object member function we define a corresponding member function in Legion_Simple. The Legion_Simple member functions' job is to take a work unit, build a corresponding call to the wrapped object's member function, execute the call, and package up any return values.
Legion_Simple has additional member functions that figure out which wrapper member function should be called (invoke_method()), indicate to the invocation store which member functions will be accepted (enable_functions()), and perform the server loop (accept_member_functions()).
5.1 Simple.h and Simple.c
%-----------------Simple.h-------------------------%
// A very simple class definition
#ifndef _H_Simple_
#define _H_Simple_
#include <stdio.h>
class Simple
{
int data;
public:
Simple();
~Simple();
int op1(int foo);
int op2(int &foo, int &bar);
};
#endif
%-----------------Simple.c-------------------------%
// A very simple class definition
#ifndef _C_Simple_
#define _C_Simple_
#include <stdio.h>
#include "Simple.h"
Simple::Simple() {
data = 0;
}
Simple::op1(int foo) {
data = foo;
}
int
Simple::op2(int &foo, int &bar) {
foo = data*data;
bar = data+data;
return foo+bar;
}
Simple::
~Simple()
{
}
#endif
5.2 Simple.trans.h and Simple.trans.c
%--------------Simple.trans.h-----------------------%
// Legion `wrapper' class definition for the Simple
// class
#ifndef _H_Simple_trans_
#include <stdio.h>
#include "legion/Legion.h"
#include "Simple.h"
#define SIMPLE_OBJECT_CLASS_ID "Simple"
#define SIMPLE_OP1_FUNCTION_NUMBER 1
#define SIMPLE_OP2_FUNCTION_NUMBER 2
// class Legion_Simple
class Legion_Simple
{
private:
// the object being wrapped
Simple *object;
// For generating methodDone events
virtual void generate_MethodDoneEvent();
public:
Legion_Simple();
~Legion_Simple();
// wrapper member functions for each member
// function in `object'
void Legion_op1(UVaL_Reference<LegionWorkUnit> wu);
void Legion_op2(UVaL_Reference<LegionWorkUnit> wu);
// auxiliary member functions needed
virtual void enable_functions
(LegionInvocationStore *);
virtual int invoke_method
(UVaL_Reference<LegionWorkUnit> wu);
virtual void accept_member_functions();
};
#endif
%--------------Simple.trans.c-----------------------%
// The `wrapper' class definition
#ifndef _C_Simple_trans_
#include <stdio.h>
#include <unistd.h>
#include "legion/Legion.h"
#include "Simple.trans.h"
// This is the wrapped object
static Legion_Simple *wrapper;
// This is the event handler for invoking a method
static int LegionMethodInvoke
(UVaL_Reference<LegionEvent>);
// --------------------------------------------------
// Generates a MethodDone event. Should be called
// right after the call to the wrapped object's
// member function.
void
Legion_Simple::
generate_MethodDoneEvent()
{
UVaL_Reference<LegionEvent> methodDoneEvent;
methodDoneEvent = new LegionEvent
(LegionEvent_MethodDone, (void *) NULL);
LegionEventManagerDefault.announce
(methodDoneEvent, LegionEventAnnounceNow);
}
// --------------------------------------------------
// Allocates the wrapped object and enables the
// corresponding functions in the invocation store.
Legion_Simple::
Legion_Simple()
{
object = new Simple();
wrapper = this;
enable_functions(LegionInvocationStoreLL_Default);
}
// --------------------------------------------------
// De-allocates the wrapped object
Legion_Simple::
~Legion_Simple()
{
delete object;
wrapper = NULL;
}
// --------------------------------------------------
// wrapper member function for wrapped.op1()
void
Legion_Simple::
Legion_op1(UVaL_Reference<LegionWorkUnit> wu)
{
// get the parameter from the work unit
int parm1;
UVaL_Reference<LegionBuffer> lb;
lb = wu->get_parameter(1);
lb->get_int(&parm1, 1);
// Invoke the wrapped member function
int result = object->op1(parm1);
generate_MethodDoneEvent();
// Return the result.
UVaL_Reference<LegionBuffer> return_lb;
return_lb = new LegionBuffer();
return_lb->put_int(&result, 1);
Legion_return(UVaL_METHOD_RETURN_VALUE,
*(wu->get_continuation_list()), return_lb);
}
// --------------------------------------------------
// wrapper member function for wrapped.op2()
void
Legion_Simple::
Legion_op2(UVaL_Reference<LegionWorkUnit> wu)
{
int parm1, parm2;
UVaL_Reference<LegionBuffer> lb;
lb = wu->get_parameter(1);
lb->get_int(&parm1, 1);
lb = wu->get_parameter(2);
lb->get_int(&parm2, 1);
int result = object->op2(parm1, parm2);
generate_MethodDoneEvent();
// Return all results. In this case, there are
// three of them (return value + 3 in/out
// parameters).
UVaL_Reference<LegionBuffer> return_lb;
return_lb = new LegionBuffer();
return_lb->put_int(&result, 1);
Legion_return(UVaL_METHOD_RETURN_VALUE,
*(wu->get_continuation_list()), return_lb);
return_lb = new LegionBuffer();
return_lb->put_int(&parm1, 1);
Legion_return(1,
*(wu->get_continuation_list()), return_lb);
return_lb = new LegionBuffer();
return_lb->put_int(&parm2, 1);
Legion_return(2,
*(wu->get_continuation_list()), return_lb);
}
// --------------------------------------------------
// Invokes the appropriate method based on the
// function number in the supplied work unit.
int
Legion_Simple::
invoke_method(UVaL_Reference<LegionWorkUnit> wu)
{
switch (wu->get_function_number()) {
case SIMPLE_OP1_FUNCTION_NUMBER:
Legion_op1(wu);
break;
case SIMPLE_OP2_FUNCTION_NUMBER:
Legion_op2(wu);
break;
default:
fprintf(stderr,"Legion_Simple::invoke_method()\n");
fprintf(stderr,"This object does not export
function number %d\n",
wu->get_function_number());
exit(0);
break;
}
}
// --------------------------------------------------
// This is the server loop.
// EventMgr.serverLoop() continuously flushes events
// and then blocks waiting for events to become
// available.
void
Legion_Simple::
accept_member_functions()
{
LegionEventManagerDefault.serverLoop();
}
// --------------------------------------------------
// Enable the wrapped object's functions. The LIS
// must be explicitly told which functions to accept.
// There will eventually be some object mandatory
// functions in here too.
void
Legion_Simple::enable_functions(LegionInvocationStore *LIS)
{
// Enable the function numbers that I can handle...
LegionInvocationStoreLL_Default->enable_function(
SIMPLE_OP1_FUNCTION_NUMBER, DEFAULT_PRIORITY);
LegionInvocationStoreLL_Default->enable_function(
SIMPLE_OP2_FUNCTION_NUMBER, DEFAULT_PRIORITY);
// Register my event handler...
LegionEvent_MethodReady.addHandler
(LegionMethodInvoke, 1.0);
}
// --------------------------------------------------
// This is the event handler that get called on a
// MethodReady event. A MethodReady event is
// generated every time a ready invocation is
// inserted into the invocation store.
static int
LegionMethodInvoke(UVaL_Reference<LegionEvent> event)
{
UVaL_Reference<LegionBuffer> lb;
int parameter;
if (LegionInvocationStoreLL_Default->any_ready()) {
UVaL_Reference<LegionWorkUnit> wu;
wu = LegionInvocationStoreLL_Default->next_matched();
wrapper->invoke_method(wu);
}
return 0;
}
// --------------------------------------------------
int
main (int argc, char **argv)
{
Legion.init();
wrapper = new Legion_Simple();
Legion.AcceptMethods();
wrapper->accept_member_functions();
}
#endif
5.3 ex1_Simple.c
%--------------ex1_Simple.c---------------%
#include <stdio.h>
#include "Simple.trans.h"
#include "legion/Legion.h"
UVaL_Reference<LegionParameter>
make_int_parameter(int parm_value, int parm_number)
{
UVaL_Reference<LegionBuffer> lb;
UVaL_Reference<LegionParameter> parm;
lb = (LegionBuffer *) new LegionBuffer();
lb->put_int(&parm_value, 1);
parm = (LegionParameter *)
new LegionParameter(parm_number, lb);
return parm;
}
int
main(int argc, char **argv)
{
// Variables for the `user' code
int a = 10, b = 15;
int x, y, z;
// Initialize legion state
// All of the below to get a random instance number
int my_instance_number;
struct timeval tv;
gettimeofday(&tv,NULL);
srand(tv.tv_sec ^ tv.tv_usec);
my_instance_number =
rand() ^ tv.tv_sec ^ tv.tv_usec;
// Initialize Legion Library
Legion.init();
// Manufacture my own LOID because I'm a command
// line object
Legion.SetMyLOID
(make_loid(UVaL_CLASS_ID_COMMANDLINE,
my_instance_number));
// Tell my creator I'm ready to go
Legion.AcceptMethods();
// Create an empty program graph
LegionProgramGraph G(Legion.GetMyLOID());
// Create a couple of `Simple' objects
UVaL_Reference<LegionLOID> A_name, B_name;
A_name = Legion.CreateObject
(SIMPLE_OBJECT_CLASS_ID);
B_name = Legion.CreateObject
(SIMPLE_OBJECT_CLASS_ID);
// Get handles for each object
LegionCoreHandle A_handle(A_name),
B_handle(B_name);
// First call: x = A.op1(a);
// invoke()'s signature is
// invoke(function_num, num_parms, num_results);
UVaL_Reference<LegionInvocation> inv1;
inv1 = A_handle.invoke
(SIMPLE_OP1_FUNCTION_NUMBER, 1, 1);
G.add_invocation(inv1);
UVaL_Reference<LegionParameter> parm1;
parm1 = make_int_parameter(a, 1);
G.add_constant_parameter(inv1, parm1, 1);
// Second call: y = B.op1(b);
UVaL_Reference<LegionInvocation> inv2;
inv2 = B_handle.invoke
(SIMPLE_OP1_FUNCTION_NUMBER, 1, 1);
G.add_invocation(inv2);
UVaL_Reference<LegionParameter> parm2;
parm2 = make_int_parameter(b, 1);
G.add_constant_parameter(inv2, parm2, 1);
// Third call: z = A.op1(x, y);
// Both parameters are values yet to be computed,
// so they must be invocation parameters.
UVaL_Reference<LegionInvocation> inv3;
inv3 = A_handle.invoke
(SIMPLE_OP2_FUNCTION_NUMBER, 2, 3);
G.add_invocation(inv3);
G.add_invocation_parameter
(inv3, inv1, 1, UVaL_METHOD_RETURN_VALUE);
G.add_invocation_parameter
(inv3, inv2, 2, UVaL_METHOD_RETURN_VALUE);
// We specifically ask for the in/out parameters.
// Don't get them otherwise.
G.add_result_dependency(inv3, 1);
G.add_result_dependency(inv3, 2);
// printf ("%d\n", z);
// We need `z', so we must execute
G.execute();
// and wait for the return.
UVaL_Reference<LegionBuffer> lb;
lb = G.get_value (inv3, UVaL_METHOD_RETURN_VALUE);
lb->get_int(&z, 1);
printf ("z is%d\n", z);
// Since we asked for them, we can get the other
// values too.
G.release_all_values();
lb = G.get_value (inv3, 1);
lb->get_int(&x, 1);
printf ("x is %d\n", x);
lb = G.get_value (inv3, 2);
lb->get_int(&y, 1);
printf ("y is %d\n", y);
Legion.DestroyObject(A_name);
Legion.DestroyObject(B_name);
}
legion@Virginia.edu
http://legion.virginia.edu/
|