e0dec79706a94255e30f14d00c61b664197f9553
[charm.git] / src / ck-core / envelope.h
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7 /**
8 \file
9 \addtogroup CkEnvelope
10 */
11 #ifndef _ENVELOPE_H
12 #define _ENVELOPE_H
13
14 #ifndef CkIntbits
15 #define CkIntbits (sizeof(int)*8)
16 #endif
17
18 #ifndef CMK_OPTIMIZE
19 #define _SET_USED(env, x) (env)->setUsed((x))
20 #define _CHECK_USED(env) do { if(env->isUsed()) \
21                            CmiAbort("Message being re-sent. Aborting...\n"); \
22                          } while(0)
23 #else
24 #define _SET_USED(env, x) do{}while(0)
25 #define _CHECK_USED(env) do{}while(0)
26 #endif
27
28 #define CkMsgAlignmentMask     (sizeof(double)-1)
29 #define CkMsgAlignLength(x) (((x)+CkMsgAlignmentMask)&(~(CkMsgAlignmentMask)))
30 #define CkMsgAlignOffset(x)     (CkMsgAlignLength(x)-(x))
31 #define CkPriobitsToInts(nBits)    ((nBits+CkIntbits-1)/CkIntbits)
32 // silly ancient name: for backward compatability only.
33 #define PW(x) CkPriobitsToInts(x) 
34
35 /**
36  This set of message type (mtype) constants
37  defines the basic class of charm++ message.
38  
39  It is very questionable whether bizarre stuff like
40  "ExitMsg", "StatMsg", "ROMsgMsg" should actually
41  share the envelope with regular user messages;
42  but it doesn't waste any space so it's probably OK.
43 */
44 typedef enum {
45   NewChareMsg    =1,
46   NewVChareMsg   =2,
47   BocInitMsg     =3,
48   ForChareMsg    =4,
49   ForBocMsg      =5,
50   ForVidMsg      =6,
51   FillVidMsg     =7,
52   RODataMsg      =8,
53   ROMsgMsg       =9,
54   ExitMsg        =10,
55   ReqStatMsg     =11,
56   StatMsg        =12,
57   NodeBocInitMsg =13,
58   ForNodeBocMsg  =14,
59   ArrayEltInitMsg =15,
60   ForArrayEltMsg  =16
61 } CkEnvelopeType;
62
63 typedef unsigned int   UInt;
64 typedef unsigned short UShort;
65 typedef unsigned char  UChar;
66
67 #include "charm.h" // for CkGroupID
68
69 /**
70 The "envelope" sits at the start of every Charm++
71 message. It stores information about the handler and
72 destination of the charm++ message that follows, and 
73 what to do with it on the receiving side.
74
75 A Charm++ message's memory layout has the 
76 Charm envelope ("envelope" class) first, which includes
77 a Converse envelope as its first field.  After the 
78 Charm envelope is a variable-length amount of user 
79 data, and finally the priority data stored as ints.
80
81 <pre>
82  Envelope pointer        \
83  Converse message pointer -> [ [ Converse envelope ]       ]
84                              [       Charm envelope        ] 
85  User message pointer     -> [ User data ... ]
86  Priority pointer         -> [ Priority ints ... ]
87 </pre>
88
89 The "message pointers" passed to and from
90 users bypass the envelope and point *directly* to the 
91 user data--the routine "EnvToUsr" below adjusts an 
92 envelope (or converse message) pointer into this 
93 direct-to-user pointer.  There is a corresponding
94 routine "UsrToEnv" which takes the user data pointer
95 and returns a pointer to the envelope/converse message.
96
97 Unfortunately, in the guts of Charm++ it's not always 
98 clear whether you've been given a converse or user
99 message pointer, as both tend to be passed as void *.
100 Confusing the two will invariably result in data 
101 corruption and bizarre crashes.
102
103 FIXME: Make CkMessage inherit from envelope,
104 which would unify converse, envelope, and 
105 user message pointers.
106 */
107 class envelope {
108   private:
109     /// Converse message envelope
110     char   core[CmiReservedHeaderSize];
111 public:
112  /**
113    This union stores the type-specific message information.
114    Keeing this in a union allows the different kinds of messages 
115    to have different fields/types, in an alignment-safe way, 
116    without wasting any storage.
117  */
118     union u_type {
119       struct s_chare { //NewChareMsg, NewVChareMsg, ForChareMsg, ForVidMsg, FillVidMsg
120         void *ptr;
121         UInt forAnyPe; ///< Used only by newChare
122       } chare;
123       struct s_group {
124         CkGroupID g; ///< GroupID
125         CkNodeGroupID rednMgr; ///< Reduction manager for this group (constructor only!)
126         int epoch; ///< "epoch" this group was created during (0--mainchare, 1--later)
127         UShort arrayEp; ///< Used only for array broadcasts
128       } group;
129       struct s_array{ ///< For arrays only
130         CkArrayIndexStruct index;///< Array element index
131         int listenerData[CK_ARRAYLISTENER_MAXLEN]; ///< For creation
132         CkGroupID arr; ///< Array manager GID
133         UChar hopCount;///< number of times message has been routed
134         UChar ifNotThere; ///< what to do if array element is missing
135       } array;
136       struct s_roData { ///< RODataMsg
137         UInt count;
138       } roData;
139       struct s_roMsg { ///< ROMsgMsg
140         UInt roIdx;
141       } roMsg;
142     };
143     struct s_attribs { //Packed bitwise struct
144         UChar msgIdx; ///< Usertype of message (determines pack routine)
145         UChar mtype; ///< e.g., ForBocMsg
146         UChar queueing:4; ///< Queueing strategy (FIFO, LIFO, PFIFO, ...)
147         UChar isPacked:1; ///< If true, message must be unpacked before use
148         UChar isUsed:1; ///< Marker bit to prevent message re-send.
149     };
150 private:
151     u_type type; ///< Depends on message type (attribs.mtype)
152     UShort ref; ///< Used by futures
153     s_attribs attribs;
154     UChar align[CkMsgAlignOffset(CmiReservedHeaderSize+sizeof(u_type)+sizeof(UShort)+sizeof(s_attribs))];
155     
156     //This struct should now be sizeof(void*) aligned.
157     UShort priobits; ///< Number of bits of priority data after user data
158     UShort epIdx;  ///< Entry point to call
159     UInt   pe;    ///< source processor
160     UInt   event; ///< used by projections
161     UInt   totalsize; ///< Byte count from envelope start to end of priobits
162     
163   public:
164     void pup(PUP::er &p);
165     UInt   getEvent(void) const { return event; }
166     void   setEvent(const UInt e) { event = e; }
167     UInt   getRef(void) const { return ref; }
168     void   setRef(const UShort r) { ref = r; }
169     UChar  getQueueing(void) const { return attribs.queueing; }
170     void   setQueueing(const UChar q) { attribs.queueing=q; }
171     UChar  getMsgtype(void) const { return attribs.mtype; }
172     void   setMsgtype(const UChar m) { attribs.mtype = m; }
173 #ifndef CMK_OPTIMIZE
174     UChar  isUsed(void) { return attribs.isUsed; }
175     void   setUsed(const UChar u) { attribs.isUsed=u; }
176 #else /* CMK_OPTIMIZE */
177     inline void setUsed(const UChar u) {}
178 #endif
179     UChar  getMsgIdx(void) const { return attribs.msgIdx; }
180     void   setMsgIdx(const UChar idx) { attribs.msgIdx = idx; }
181     UInt   getTotalsize(void) const { return totalsize; }
182     void   setTotalsize(const UInt s) { totalsize = s; }
183     UInt   getUsersize(void) const { return totalsize - priobits - sizeof(envelope); }
184     UChar  isPacked(void) const { return attribs.isPacked; }
185     void   setPacked(const UChar p) { attribs.isPacked = p; }
186     UShort getPriobits(void) const { return priobits; }
187     void   setPriobits(const UShort p) { priobits = p; }
188     UShort getPrioWords(void) const { return CkPriobitsToInts(priobits); }
189     UShort getPrioBytes(void) const { return getPrioWords()*sizeof(int); }
190     void*  getPrioPtr(void) const { 
191       return (void *)((char *)this + totalsize - getPrioBytes());
192     }
193     static envelope *alloc(const UChar type, const UInt size=0, const UShort prio=0)
194     {
195       CkAssert(type>=NewChareMsg && type<=ForArrayEltMsg);
196       register UInt tsize = sizeof(envelope)+ 
197             CkMsgAlignLength(size)+
198             sizeof(int)*CkPriobitsToInts(prio);
199       register envelope *env = (envelope *)CmiAlloc(tsize);
200       env->setMsgtype(type);
201       env->totalsize = tsize;
202       env->priobits = prio;
203       env->setPacked(0);
204       _SET_USED(env, 0);
205       //for record-replay
206       env->setEvent(0);
207       return env;
208     }
209     UShort getEpIdx(void) const { return epIdx; }
210     void   setEpIdx(const UShort idx) { epIdx = idx; }
211     UInt   getSrcPe(void) const { return pe; }
212     void   setSrcPe(const UInt s) { pe = s; }
213     static void setSrcPe(char *env, const UInt s) { ((envelope*)env)->setSrcPe(s); }
214
215 // Readonly-specific fields
216     UInt   getCount(void) const { 
217       CkAssert(getMsgtype()==RODataMsg); return type.roData.count; 
218     }
219     void   setCount(const UInt c) { 
220       CkAssert(getMsgtype()==RODataMsg); type.roData.count = c; 
221     }
222     UInt   getRoIdx(void) const { 
223       CkAssert(getMsgtype()==ROMsgMsg); return type.roMsg.roIdx; 
224     }
225     void   setRoIdx(const UInt r) { 
226       CkAssert(getMsgtype()==ROMsgMsg); type.roMsg.roIdx = r; 
227     }
228     
229  // Chare-specific fields
230     UInt isForAnyPE(void) { 
231       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
232       return type.chare.forAnyPe; 
233     }
234     void setForAnyPE(UInt f) { 
235       CkAssert(getMsgtype()==NewChareMsg || getMsgtype()==NewVChareMsg); 
236       type.chare.forAnyPe = f; 
237     }
238     void*  getVidPtr(void) const {
239       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
240           || getMsgtype()==FillVidMsg);
241       return type.chare.ptr;
242     }
243     void   setVidPtr(void *p) {
244       CkAssert(getMsgtype()==NewVChareMsg || getMsgtype()==ForVidMsg
245           || getMsgtype()==FillVidMsg);
246       type.chare.ptr = p;
247     }
248     void*  getObjPtr(void) const { 
249       CkAssert(getMsgtype()==ForChareMsg); return type.chare.ptr; 
250     }
251     void   setObjPtr(void *p) { 
252       CkAssert(getMsgtype()==ForChareMsg); type.chare.ptr = p; 
253     }
254
255 // Group-specific fields
256     CkGroupID   getGroupNum(void) const {
257       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
258           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
259       return type.group.g;
260     }
261     void   setGroupNum(const CkGroupID g) {
262       CkAssert(getMsgtype()==BocInitMsg || getMsgtype()==ForBocMsg
263           || getMsgtype()==NodeBocInitMsg || getMsgtype()==ForNodeBocMsg);
264       type.group.g = g;
265     }
266     void setGroupEpoch(int epoch) { type.group.epoch=epoch; }
267     int getGroupEpoch(void) { return type.group.epoch; }
268     void setRednMgr(CkNodeGroupID r){ type.group.rednMgr = r; }
269     CkNodeGroupID getRednMgr(){ return type.group.rednMgr; }
270
271 // Array-specific fields
272     CkGroupID &getsetArrayMgr(void) {return type.array.arr;}
273     UShort &getsetArrayEp(void) {return epIdx;}
274     UShort &getsetArrayBcastEp(void) {return type.group.arrayEp;}
275     UInt &getsetArraySrcPe(void) {return pe;}
276     UChar &getsetArrayHops(void) {return type.array.hopCount;}
277     int getArrayIfNotThere(void) {return type.array.ifNotThere;}
278     void setArrayIfNotThere(int nt) {type.array.ifNotThere=nt;}
279     int *getsetArrayListenerData(void) {return type.array.listenerData;}
280     CkArrayIndexMax &getsetArrayIndex(void) 
281         {return *(CkArrayIndexMax *)&type.array.index;}
282 };
283
284 inline envelope *UsrToEnv(const void *const msg) {
285   return (((envelope *) msg)-1);
286 }
287
288 inline void *EnvToUsr(const envelope *const env) {
289   return ((void *)(env+1));
290 }
291
292 inline envelope *_allocEnv(const int msgtype, const int size=0, const int prio=0) {
293   return envelope::alloc(msgtype,size,prio);
294 }
295
296 inline void *_allocMsg(const int msgtype, const int size, const int prio=0) {
297   return EnvToUsr(envelope::alloc(msgtype,size,prio));
298 }
299
300 extern UChar   _defaultQueueing;
301
302 extern void CkPackMessage(envelope **pEnv);
303 extern void CkUnpackMessage(envelope **pEnv);
304
305 class MsgPool: public SafePool<void *> {
306 private:
307     static void *_alloc(void) {
308       /* CkAllocSysMsg() called in .def.h is not thread of sigio safe */
309       register envelope *env = _allocEnv(ForChareMsg,0,0);
310       env->setQueueing(_defaultQueueing);
311       env->setMsgIdx(0);
312       return EnvToUsr(env);
313     }
314 public:
315     MsgPool():SafePool<void*>(_alloc, CkFreeMsg) {}
316 };
317
318 CkpvExtern(MsgPool*, _msgPool);
319
320 #endif