doc: Add serial to list of ci file reserved words
[charm.git] / src / conv-core / global-elfcopy.C
1 /*  Library to manage the program's global and static varaibles manually
2  *  by copying them during context switch.
3  *
4  *
5  *  Developed by Gengbin Zheng (gzheng@uiuc.edu) 12/06
6  *
7  */
8
9 #include "converse.h"
10 #include "cklists.h"
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <strings.h>
15 #include <errno.h>
16
17 #include "charm.h"
18 #include "pup.h"
19
20 #if CMK_HAS_ELF_H
21 #include <elf.h>
22
23 #define DEBUG_GOT_MANAGER 0
24
25 #if !CMK_SHARED_VARS_UNAVAILABLE
26 #  error "Global-elfcopy won't work properly under smp version: -copyglobals disabled"
27 #endif
28
29 CpvDeclare(int, CmiPICMethod);
30
31 #if CMK_AMD64 || CMK_CRAYXT
32 typedef Elf64_Addr    ELFXX_TYPE_Addr;
33 typedef Elf64_Dyn     ELFXX_TYPE_Dyn;
34 typedef Elf64_Rela    ELFXX_TYPE_Rel;
35 typedef Elf64_Sym     ELFXX_TYPE_Sym;
36 #define ELFXX_R_TYPE   ELF64_R_TYPE
37 #define ELFXX_R_SYM    ELF64_R_SYM
38 #define ELFXX_ST_TYPE  ELF64_ST_TYPE
39 #define CMK_DT_REL     DT_RELA
40 #define CMK_DT_RELSZ   DT_RELASZ
41 #define is_elf_global(x)  ((x) == R_X86_64_GLOB_DAT)
42 #elif CMK_IA64
43 #error "NOT SUPPORTED"
44 #else
45 typedef Elf32_Addr    ELFXX_TYPE_Addr;
46 typedef Elf32_Dyn     ELFXX_TYPE_Dyn;
47 typedef Elf32_Rel     ELFXX_TYPE_Rel;
48 typedef Elf32_Sym     ELFXX_TYPE_Sym;
49 #define ELFXX_R_TYPE   ELF32_R_TYPE
50 #define ELFXX_R_SYM    ELF32_R_SYM
51 #define ELFXX_ST_TYPE  ELF32_ST_TYPE
52 #define CMK_DT_REL     DT_REL
53 #define CMK_DT_RELSZ   DT_RELSZ
54 #define is_elf_global(x)  ((x) == R_386_GLOB_DAT)
55 #endif
56
57 extern ELFXX_TYPE_Dyn _DYNAMIC[];      //The Dynamic section table pointer
58
59 /****************** Global Variable Understanding *********************/
60 /**
61   Keeps a list of global variables.
62   */
63 class CtgGlobalList
64 {
65   int datalen; ///< Number of bytes in the table of global data.
66   struct CtgRec {
67     void *got; ///< Points to our entry in the GOT.
68     int off; ///< Our byte offset into the table of global data.
69     int size;
70     CtgRec() {got=NULL;}
71     CtgRec(void *got_,int off_,int size_) :got(got_), off(off_), size(size_) {}
72   };
73   CkVec<CtgRec> rec;
74   int nRec;
75   public:
76   /**
77     Analyze the current set of global variables, determine 
78     which are user globals and which are system globals, 
79     and store the list of user globals. 
80     */
81   CtgGlobalList();
82
83   /// Return the number of bytes needed to store our global data.
84   inline int getSize(void) const {return datalen;}
85
86   /// Copy the current set of global data into this set,
87   ///   which must be getSize() bytes.
88   void read(void *datav) const;
89
90   /// copy data to globals
91   inline void install(void *datav) const {
92     char *data=(char *)datav;
93     for (int i=0;i<nRec;i++) {
94       memcpy((void *)rec[i].got, data+rec[i].off, rec[i].size);
95     }
96   }
97
98   inline void install_var(void *datav, void *ptr) const {
99     char *data=(char *)datav;
100     for (int i=0;i<nRec;i++) {
101       long offset = (char*)ptr-(char *)rec[i].got;
102       if (offset >= 0 && offset < rec[i].size) {
103         memcpy((void *)rec[i].got, data+rec[i].off, rec[i].size);
104         break;
105       }
106     }
107   }
108
109   void read_var(void *datav, void *ptr) const;
110
111   private:
112   /* Return 1 if this is the name of a user global variable;
113      0 if this is the name of some other (Charm or system)
114      global variable. */
115   int isUserSymbol(const char *name);
116 };
117
118 int CtgGlobalList::isUserSymbol(const char *name) {
119   // return 1;
120   if((strncmp("_", name, 1) == 0) || (strncmp("Cpv_", name, 4) == 0)
121       || (strncmp("Csv_", name, 4) == 0) || (strncmp("Ctv_", name, 4) == 0)
122       || (strncmp("Bnv_", name, 4) == 0) || (strncmp("Bpv_", name, 4) == 0)
123       || (strncmp("ckout", name, 5) == 0) || (strncmp("stdout", name, 6) == 0)
124       || (strncmp("environ", name, 7) == 0)
125       || (strncmp("stderr", name, 6) == 0) || (strncmp("stdin", name, 5) == 0))
126     return 0;
127
128   return 1;
129 }
130
131 void CtgGlobalList::read(void *datav) const {
132   char *data=(char *)datav;
133   for (int i=0;i<nRec;i++) {
134     memcpy(data+rec[i].off, (void *)rec[i].got, rec[i].size);
135   }
136 }
137
138 void CtgGlobalList::read_var(void *datav, void *ptr) const {
139   char *data=(char *)datav;
140   for (int i=0;i<nRec;i++) {
141     long offset = (char*)ptr-(char *)rec[i].got;
142     if (offset >= 0 && offset < rec[i].size) {
143       memcpy(data+rec[i].off, (void *)rec[i].got, rec[i].size);
144       break;
145     }
146   }
147 }
148
149 CkVec<char *>  _namelist;
150 static int loaded = 0;
151
152 extern "C" int lookup_obj_sym(char *name, unsigned long *val, int *size);
153
154 // read from a file called "globals"
155 static void readGlobals()
156 {
157   if (loaded) return;
158   const char *fname = "globals";
159   printf("Loading globals from file \"%s\" ... \n", fname);
160   FILE *gf = fopen(fname, "r");
161   if (gf == NULL) {
162     CmiAbort("Failed to load globals, file may not exist!");
163   }
164   while (!feof(gf)) 
165   {
166     char name[1024];
167     fscanf(gf, "%s\n", name);
168     _namelist.push_back(strdup(name));
169   }
170   fclose(gf);
171   loaded = 1;
172 }
173
174
175 /**
176   Analyze the current set of global variables, determine 
177   which are user globals and which are system globals, 
178   and store the list of user globals. 
179   */
180 CtgGlobalList::CtgGlobalList() {
181   datalen=0;
182   nRec=0;
183
184   int count;
185   for (count = 0; count < _namelist.size(); count ++) 
186   {
187     unsigned long addr;
188     int size;
189     if (0 > lookup_obj_sym(_namelist[count], &addr, &size)) {
190       fprintf(stderr, "%s: no such symbol\n", _namelist[count]);
191       continue;
192     }
193     void *ptr = (void *)addr;
194     int gSize = ALIGN8(size);
195
196     //#if DEBUG_GOT_MANAGER
197     printf("   -> %s is a user global, of size %d, at %p\n",
198         _namelist[count], size, ptr);
199     //#endif
200
201     rec.push_back(CtgRec(ptr,datalen,size));
202     datalen+=gSize;
203   }
204
205   nRec=rec.size();
206
207 #if DEBUG_GOT_MANAGER   
208   printf("relt has %d entries, %d of which are user globals\n\n", 
209       relt_size,nRec);
210 #endif
211 }
212
213 /****************** Global Variable Storage and Swapping *********************/
214 CpvStaticDeclare(CtgGlobals,_curCtg);
215
216 struct CtgGlobalStruct {
217   public:
218     /* This is set when our data is pointed to by the current GOT */
219     int installed;
220     int inited;
221
222     /* Pointer to our global data segment. */
223     void *data_seg;  
224     int seg_size; /* size in bytes of data segment */
225
226     void allocate(int size, CthThread tid) {
227       seg_size=size;
228       /* global data segment need to be isomalloc */
229       if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
230         data_seg=CmiIsomalloc(seg_size,tid);
231       else
232         data_seg=malloc(seg_size);
233       inited = 0;
234     }
235
236     CtgGlobalStruct(void) {
237       installed=0;
238       data_seg=0;
239     }
240     ~CtgGlobalStruct() {
241       if (!CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC)) {
242         if (data_seg) {
243           free(data_seg);
244         }
245       }
246     }
247
248     void pup(PUP::er &p);
249 };
250
251 void CtgGlobalStruct::pup(PUP::er &p) {
252   p | seg_size;
253   /* global data segment need to be isomalloc pupped */
254   if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
255 #if CMK_USE_MEMPOOL_ISOMALLOC
256     pup_bytes(&p, &data_seg, sizeof(void*));
257 #else
258     CmiIsomallocPup(&p, &data_seg);
259 #endif
260   else {
261     if (p.isUnpacking()) allocate(seg_size, NULL);
262     p((char *)data_seg, seg_size);
263   }
264 }
265
266 /// Singleton object describing our global variables:
267 static CtgGlobalList *_ctgList=NULL;
268 /// Singleton object describing the original values for the globals.
269 static CtgGlobalStruct *_ctgListGlobals=NULL;
270
271 extern "C" int init_symtab(char *exename);
272
273 /** Initialize the globals support (called on each processor). */
274 void CtgInit(void) {
275   CpvInitialize(int, CmiPICMethod);
276   CpvAccess(CmiPICMethod) = 2;
277   CpvInitialize(CtgGlobal,_curCtg);
278
279   if (!_ctgList) 
280   {
281     /*
282        First call on this node: parse out our globals:
283        */
284     readGlobals();
285     init_symtab(CkGetArgv()[0]);
286
287     CtgGlobalList *l=new CtgGlobalList;
288     CtgGlobalStruct *g=new CtgGlobalStruct;
289     if (CmiMyNode()==0) {
290       CmiPrintf("CHARM> -copyglobals enabled\n");
291     }
292
293     g->allocate(l->getSize(),NULL);
294     l->read(g->data_seg);
295     l->install(g->data_seg);
296     _ctgList=l;
297     _ctgListGlobals=g;
298   }
299   /* CmiNodeAllBarrier();  no smp anyway */
300
301   CpvAccess(_curCtg)=_ctgListGlobals;
302 }
303
304 /** Copy the current globals into this new set */
305 CtgGlobals CtgCreate(CthThread tid) {
306   CtgGlobalStruct *g=new CtgGlobalStruct;
307   g->allocate(_ctgList->getSize(), tid);
308   _ctgList->read(g->data_seg);
309   return g;
310 }
311
312 /** PUP this (not currently installed) globals set */
313 CtgGlobals CtgPup(pup_er pv, CtgGlobals g) {
314   PUP::er *p=(PUP::er *)pv;
315   if (p->isUnpacking()) g=new CtgGlobalStruct;
316   if (g->installed) 
317     CmiAbort("CtgPup called on currently installed globals!\n");
318   g->pup(*p);
319   if (g->seg_size!=_ctgList->getSize())
320     CmiAbort("CtgPup: global variable size changed during migration!\n");
321   return g;
322 }
323
324 /** Install this set of globals. If g==NULL, returns to original globals. */
325 void CtgInstall(CtgGlobals g) {
326   CtgGlobals *cur=&CpvAccess(_curCtg);
327   CtgGlobals oldG=*cur;
328   if (g==NULL) g=_ctgListGlobals;
329   if (g == oldG) return;
330   if (oldG) {
331     _ctgList->read(oldG->data_seg);             /* store globals to own copy */
332   }
333   *cur=g;
334   oldG->installed=0;
335   _ctgList->install(g->data_seg);
336   g->installed=1;
337 }
338
339 /** Delete this (not currently installed) set of globals. */
340 void CtgFree(CtgGlobals g) {
341   if (g->installed) CmiAbort("CtgFree called on currently installed globals!\n");
342   delete g;
343 }
344
345 CtgGlobals CtgCurrentGlobals(void){
346   return CpvAccess(_curCtg);
347 }
348
349 void CtgInstall_var(CtgGlobals g, void *ptr) {
350   CtgGlobals *cur=&CpvAccess(_curCtg);
351   CtgGlobals oldG = *cur;
352   if (oldG)
353     _ctgList->read_var(oldG->data_seg, ptr);
354   _ctgList->install_var(g->data_seg, ptr);             /* store globals to own copy */
355 }
356
357 void CtgUninstall_var(CtgGlobals g, void *ptr) {
358   CtgGlobals *cur=&CpvAccess(_curCtg);
359   CtgGlobals oldG = *cur;
360   if (oldG)
361     _ctgList->read_var(g->data_seg, ptr);             /* store globals to own copy */
362   _ctgList->install_var(oldG->data_seg, ptr);             /* store globals to own copy */
363 }
364
365 #else     /* no ELF */
366
367 #include "global-nop.c"
368
369 #endif