![]() |
Maestro Types |
void read(int&); // read an integer from the message void read(void *buf, int size); // read a buffer from the message void write(int); // write an integer into the message void write(void *buf, int size); // write a buffer into the message unsigned size(); // get total size of the message unsigned getPos(); // get current position of message pointer void setPos(unsigned offset); // set position of message pointer void seek(int offset, Maestro_MsgSeek whence); // seek to the specified offset. // Pack an array of messages into the given msg. void pack(Maestro_Message *msgs, unsigned nmsgs); // Unpack an array of messages from the given msg. void unpack(Maestro_Message *&msgs, unsigned &nmsgs); void reset(); // reset the message int isWritable(); // return non-zero iff the message is writableRead/write operations on Maestro messages follow the stack paradigm (first in/last out). This is convenient in the layering architecture of Maestro/Ensemble, where layers push headers on outgoing messages and pop matching headers from incoming messages. There are also stream-like message I/O operators defined for basic types, such as int, Maestro_EndpID, Maestro_EndpList, Maestro_String. For example, consider the following code at the sender side:
Maestro_Message msg;
Maestro_EndpID endp;
Maestro_EndpList elist;
Maestro_String s("hello world");
.......
msg << endp << elist << s; // push endp, elist, s into msg
memb.cast(msg); // multicast msg to the memb's group
This could correspond to something like this at the destination:
receivedMsg >> s >> elist >> endp; // pop ent, elist, s from the msg
Maestro_Message m1, m2, m3; int i, pos; m1 << 5; // push an integer into m1 pos = m1.getPos(); // remember the current offset at m1 m1 >> i; // pop an integer from m1 m1.setPos(pos); // rewind m1 (which becomes read-only) m2 = m1; // make m2 an alias of m1 (m2 is read-only) m3 <<= m1; // copy m1 into m3 (m3 is writable)
NOTE: Byte ordering issues are not yet addressed in Maestro messages.
Maestro_EndpID endp; Maestro_Message msg1, msg2; ..... msg1 >> endp; // pop endp from the message msg2 << endp; // push endp onto the message cout << endp; // print out the value of endp
struct Maestro_ThreadOps { int stackSize; };
static void create(void (*proc)(void*),
void *arg,
Maestro_ThreadOps *ops = 0,
Maestro_ErrorHandler *error_handler = 0);
A call to Maestro_Thread::create(proc, arg) invokes proc(arg)
in a separate thread. The size of the thread's stack can be adjusted with
the ops argument.
Maestro_Semaphore sema; sema.dec();
Maestro_Lock lck; lck.lock(); // acquire the lock ....... lck.unlock(); // release the lock
The public methods defined by Maestro_Barrier are open(), close(), pass(), isOpen(), and isClosed().
Example:
Maestro_Barrier hb; hb.pass(); // doesn't block since the barrier is open hb.close(); // closes the barrier hb.pass(); // blocks until another thread calls open()
void panic(char *context); void panic(hot_err_t err, char *context);In the default implementation of panic() methods in the Maestro_ErrorHandler class, when panic() is invoked, an error message is printed, after which the process is terminated.
In order to be readable/writable from/to a Maestro_Message object, a subclass of Maestro_Base must overload the following two operators:
virtual void operator << (Maestro_Message& msg); // reading itself from msg virtual void operator >> (Maestro_Message& msg); // pushing itself onto msgThat is, a subclass of Maestro_Base is required to "know" how to read/write itself from/into a message if it is to support stream-like message I/O operations.
Maestro_String s1; // create an empty string
Maestro_String s2("hello world");
cout << s2 << endl; // print "hello world"
s1 = s2;
assert(s1 == s2);
Maestro_String s3; // s3 is empty
Maestro_Message m;
m << s1;
m >> s3;
assert(s1 == s3);
Maestro_OrderedSet implements standard operations on ordered sets: union, intersection, difference, and random access. As a subclass of Maestro_Base, Maestro_OrderedSet supports stream-like standard output and message I/O.
struct Foo {
Foo(Foo& f) {
key = f.key;
value = f.value;
}
int operator==(Foo& f) {
return (key == f.key);
}
int key, value;
};
// Note the syntax here! Parentheses () are used
// where the angle brackets <> would be used in a
// template instantiation:
typedef Maestro_OrderedSet(Foo) FooList;
FooList L; // creates an empty list
assert(L.size() == 0);
Foo f;
f.key = 1;
f.value = 2;
L += f; // add f to L
assert(L.size() == 1);
Foo f2;
f2.key = 1; // Note that f == f2
f2.value = 3;
FooList L2(f2); // L2 contains one element, f2
assert(L2.size() == 1);
assert(L2.contains(f2));
assert(L2[f2] == 0); // index of f2 in L2 is 0
assert(L2[0] == f2); // f2 is the 0'th element in L2
FooList L3(L2); // L2 and L3 have now the same contents
L3.clear(); // remove all elements from L3
assert(L3.size() == 0);
assert(f == f2); // Note that L already contains f
L += f2; // f2 is *not* added to L since f == f2
assert(L.size() == 1);
Foo f3;
f3.key = 5;
f3.value = 4;
L += f3; // add f3 to L
assert(L.size() == 2);
L -= f; // remove f from L
assert(L.size() == 1);
L -= f; // can't remove same thing twice
assert(L.size() == 1);
L3 = L; // now L and L3 have the same contents
L += L2; // L = set union of L and L2
L -= L2; // L = set difference of L and L2
L &= L2; // L = set intersection of L and L2
FooList L4;
L4 <<= L; // L4 "steals" the contents of L
assert(L.size() == 0); // L has become empty!
There are several ordered-set types defined in Maestro, such as
Maestro_EndpList
and
Maestro_MessageList.
Maestro_EndpList defines operators for message I/O and standard output,
for example:
Maestro_Message msg; Maestro_EndpID e1, e2, e3; Maestro_EndpList L, L2; L += e1; L += e2; L += e3; cout << L; // print the contents of L msg << L; // push L into the message msg >> L2; // read the list into L2