[an error occurred while processing this directive]

4.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() ).

4.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

4.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

4.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);
 
}
[an error occurred while processing this directive]