This document is a part of the online Horus Documentation, under Horus Object Tools.
HorusErrorHandler eh; error_t err; err = foo(); // foo may return an error value if (!e_isok(err)) eh.panic(err, "foo"); // prints error type + "foo" err = boo(); if (!e_isok(err)) eh.panic("boo has failed for some reason");
In order to be readable/writeable from/to a HorusMessage object, a subclass of HorusBase has to overload the following two operators:
virtual void operator << (HorusMessage& msg); // reading itself from msg virtual void operator >> (HorusMessage& msg); // pushing itself onto msgThat is, a subclass of HorusBase is required to "know" how to read/push itself from/onto a message if it is to support stream-like message I/O operations.
Example:
const int FOO_MAGIC_NUMBER = 668668; class Foo: public HorusBase { public: void operator << (HorusMessage& msg) { msg >> data; // read `data' from msg } void operator >> (HorusMessage& msg) { msg << data; // push `data' onto msg } int messageMagic() const { return FOO_MAGIC_NUMBER; } private: int data; } HorusMessage msg, msg2; Foo foo1, foo2, foo3, foo4; msg << foo1 << foo2; // push foo1 and foo2 onto msg msg >> foo3 >> foo4; // read msg into foo3 and foo4 msg2 << 1995; // read an integer onto msg2 msg2 >> foo1; // this will panic: foo1 has a wrong type!
void read(int&); // read an integer void read(void *buf, int size); // read a buffer void push(int); // push an integer void push(void *buf, int size); // push a buffer int tail(); // position of msg pointer void seek(int offset, int whence);Other methods include:
void reset(); // makes message empty and writable void rewind(int offset); // seeks backwards from the endThere are also stream-like I/O operators defined for basic types, such as int, HorusEntity, HorusEntityList, HorusString. For example, at the sender side you might execute:
HorusMessage msg; HorusEntity ent; HorusEntityList elist; HorusString s("hello world"); ....... msg << ent << elist << s; // pushes ent, elist, s into msg memb.cast(msg); // casts msg to the memb's groupThat could correspond to something like this at the destination:
receivedMsg >> s >> elist >> ent; // read ent, elist, s
Here are some examples that illustrate message read/write properties:
HorusMessage m1, m2, m3; // m1, m2, and m3 are empty & writable m1 << HorusString("hello world"); // m1 is still writable m2 = m1; // now m1 is read-only, m2 is writable memb.cast(m2); // m2 has been released when cast returns int l = m1.tail(); // remember m1's size HorusString s; m1 >> s; // m1 is still readable; has to be rewound m1.rewind(l); // rewind m1, so it can be read again HorusString ss; m1 >> ss; // m1 is still readable; has to be rewound m1.rewind(l); // rewind m1, so it can be read again m3.copyFrom(m1); // m3 is writeable, same contents as m1; // m1 is read-only at this point memb.cast(m3); // m3 has been released at this point m1 >> s; // m1 is still readableNOTE: Byte ordering issues are not yet addressed in HOT messages.
HorusSemaphore sema; sema.dec();
struct Moo { void boo(char *s) { cout << "new thread with argument " << s; } static void foo(void *env, void *param) { Moo *moo = (Moo*) env; char *str = (char*) param; moo->boo(str); } }; HorusThread ht(Moo::foo); Moo m; ht.create(&m, "hello");will invoke m::boo("hello") in a new thread.
Other methods of HorusThread include yield, setPriority, and getPriority. Usually threads created by Horus have the same priority (currently 128), with some exceptions. A thread with lower priority won't be scheduled as long as there are runnable threads of higher priorities.
HorusLock hl; hl.lock(); // acquire the lock ....... hl.unlock(); // release the lock
There are two subclasses of HorusEntity, HorusEndpointEntity and HorusGroupEntity, which do create new eid's. Note that the total number of eid's per process is currently (arbitrarily) limited to 256, so that HorusEndpointEntity and HoruGroupEntity objects should be created only when a new entity is required. For example:
HorusEntity e1, e2; // creates two empty entities assert(e1 == e2); // empty entities are equal HorusEndpointEntity ee1, ee2; // creates new endpoint entities assert(e1 != ee1); assert(ee1 != ee2); // each entity is unique ee1 = ee2; assert(ee1 == ee2); HorusGroupEntity ge; // creates new group eid assert(ee1 != ge);
The methods of HorusBarrier are open, close, wait, isOpen, and isClosed. By default, the initial state is "open". When the open() method is invoked, the state of the barrier is set to "open", and all waiting threads are released. When close() is called, the barrier's status becomes "closed". A call to wait() returns immediately if the barrier is open, and blocks if the barrier is closed. For example:
HorusBarrier hb; hb.wait(); // won't block since the barrier is open hb.close(); // closes the barrier hb.wait(); // blocks until some thread calls open()
HorusString s1; // creates an empty string HorusString s2("hello world"); cout << s2 << endl; // prints "hello world" s1 = s2; assert(s1 == s2); HorusString s3; // s3 is empty at this point HorusMessage m; m << s1; m >> s3; assert(s1 == s3);
Two other methods are lock/unlock. If an entity is locked, a subsequent call to lock will block until unlock is invoked, or the lock expires (the locks will expire automatically after some time).
NOTE: An entity can be looked-up/(re)installed even if it's locked.
For example:
HorusEndpointEntity ent; HorusNameServer ns; HorusString entityName("my_entity"); ns.lock(entityName); // lock the entity // a second call to lock(entityName) would block ns.install(entityName, ent); HorusEntity tmp; assert(tmp != ent); ns.lookup(entityName, tmp); assert(tmp == ent); // this assertion may fail b/c of a race condition! ns.unlock(entityName);
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 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 HOT, such as HorusEntityList and HorusMessageList:
class HorusEntityList: public HorusBase, public OrderedSet(HorusEntity) { ... }; class HorusMessageList: public HorusBase, public OrderedSetHorusEntityList has operators for message I/O and standard output. For example:{};
HorusMessage msg; HorusEndpointEntity e1, e2, e3; HorusEntityList 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