ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cooja-loader-factory.cc
Go to the documentation of this file.
1 #define _GNU_SOURCE 1
2 #include "cooja-loader-factory.h"
3 #include "elf-cache.h"
4 #include "elf-dependencies.h"
5 #include "ns3/log.h"
6 #ifdef DCE_MPI
7 #include "ns3/mpi-interface.h"
8 #endif
9 #include <string.h>
10 #include <dlfcn.h>
11 #include <elf.h>
12 #include <link.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <sys/mman.h>
18 #include <list>
19 #include <errno.h>
20 
21 namespace {
23 {
24  void *handle;
26  void *data_buffer;
28  uint32_t buffer_size;
29  uint32_t id;
30  uint32_t refcount;
31  std::list<struct SharedModule *> deps;
32 };
33 }
34 
35 namespace ns3 {
36 
37 NS_LOG_COMPONENT_DEFINE ("CoojaLoaderFactory");
38 NS_OBJECT_ENSURE_REGISTERED (CoojaLoaderFactory);
39 
41 {
42  SharedModules ();
43  ~SharedModules ();
45  std::list<struct SharedModule *> modules;
46 };
47 
48 class CoojaLoader : public Loader
49 {
50 public:
51  CoojaLoader ();
52 private:
53  struct Module
54  {
55  struct SharedModule *module;
56  std::list<struct Module *> deps;
57  uint32_t refcount;
58  void *buffer;
59  };
60 
61  virtual ~CoojaLoader ();
62  virtual void NotifyStartExecute (void);
63  virtual void NotifyEndExecute (void);
64  virtual Loader * Clone (void);
65  virtual void UnloadAll (void);
66  virtual void * Load (std::string filename, int flag);
67  virtual void Unload (void *module);
68  virtual void * Lookup (void *module, std::string symbol);
69 
70  static struct SharedModules * Peek (void);
71  struct CoojaLoader::Module * SearchModule (uint32_t id);
72  struct SharedModule * SearchSharedModule (uint32_t id);
73  struct CoojaLoader::Module * LoadModule (std::string filename, int flag);
74  void UnrefSharedModule (SharedModule *search);
75 
76  std::list<struct Module *> m_modules;
77 };
78 
80 #ifdef DCE_MPI
81  : cache ("elf-cache", MpiInterface::GetSystemId ())
82 #else
83  : cache ("elf-cache", 0)
84 #endif
85 {
86 }
87 
89 {
90  for (std::list<struct SharedModule *>::iterator i = modules.begin ();
91  i != modules.end (); ++i)
92  {
93  struct SharedModule *module = *i;
94  NS_LOG_DEBUG ("delete shared module " << module);
95  free (module->template_buffer);
96  dlclose (module->handle);
97  delete module;
98  }
99  modules.clear ();
100 }
101 
102 struct SharedModules *
104 {
105  static SharedModules modules;
106  return &modules;
107 }
108 
109 void
111 {
112  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
113  {
114  const struct Module *module = *i;
115  if (module->buffer == module->module->current_buffer)
116  {
117  continue;
118  }
119  if (module->module->current_buffer != 0)
120  {
121  // save the previous one
122  memcpy (module->module->current_buffer,
123  module->module->data_buffer,
124  module->module->buffer_size);
125  }
126  // restore our own
127  memcpy (module->module->data_buffer,
128  module->buffer,
129  module->module->buffer_size);
130  // remember what we did
131  module->module->current_buffer = module->buffer;
132  }
133 }
134 void
136 {
137 }
138 
139 Loader *
141 {
142  CoojaLoader *clone = new CoojaLoader ();
143  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
144  {
145  struct Module *module = *i;
146  struct Module *clonedModule = new Module ();
147  clonedModule->module = module->module;
148  clonedModule->module->refcount++;
149  clonedModule->refcount = module->refcount;
150  clonedModule->buffer = malloc (module->module->buffer_size);
151  memcpy (clonedModule->buffer,
152  module->module->data_buffer,
153  clonedModule->module->buffer_size);
154  // setup deps.
155  for (std::list<struct Module *>::iterator j = module->deps.begin ();
156  j != module->deps.end (); ++j)
157  {
158  struct Module *dep = *j;
159  struct Module *cloneDep = clone->SearchModule (dep->module->id);
160  cloneDep->refcount++;
161  clonedModule->deps.push_back (cloneDep);
162  }
163  NS_LOG_DEBUG ("add " << clonedModule->module->id);
164  clone->m_modules.push_back (clonedModule);
165  }
166  return clone;
167 }
168 
169 void *
170 CoojaLoader::Load (std::string filename, int flag)
171 {
172  struct Module *module = LoadModule (filename, flag);
173 
174  // acquire ref for client
175  module->refcount++;
176  return module->module->handle;
177 }
178 
179 struct CoojaLoader::Module *
181 {
182  for (std::list<struct Module *>::iterator i = m_modules.begin (); i != m_modules.end (); ++i)
183  {
184  struct Module *module = *i;
185  if (module->module->id == id)
186  {
187  // already in, ignore.
188  return module;
189  }
190  }
191  return 0;
192 }
193 
194 struct SharedModule *
196 {
197  struct SharedModules *ns = Peek ();
198  for (std::list<struct SharedModule *>::iterator i = ns->modules.begin ();
199  i != ns->modules.end (); ++i)
200  {
201  if ((*i)->id == id)
202  {
203  return *i;
204  }
205  }
206  return 0;
207 }
208 
209 #define ROUND_DOWN(addr, align) \
210  (((unsigned long)addr) - (((unsigned long)(addr)) % (align)))
211 
212 struct CoojaLoader::Module *
213 CoojaLoader::LoadModule (std::string filename, int flag)
214 {
215  NS_LOG_FUNCTION (this << filename << flag);
216  struct SharedModules *modules = Peek ();
217  ElfDependencies deps = ElfDependencies (filename);
218  struct Module *module = 0;
219  for (ElfDependencies::Iterator i = deps.Begin (); i != deps.End (); ++i)
220  {
221  ElfCache::ElfCachedFile cached = modules->cache.Add (i->found);
222  struct SharedModule *sharedModule = SearchSharedModule (cached.id);
223  if (sharedModule == 0)
224  {
225  void *handle = dlopen (cached.cachedFilename.c_str (),
226  RTLD_LAZY | RTLD_DEEPBIND | RTLD_LOCAL);
227  NS_ASSERT_MSG (handle != 0, "Could not open " << cached.cachedFilename << " " << dlerror ());
228  struct link_map *link_map;
229  dlinfo (handle, RTLD_DI_LINKMAP, &link_map);
230 
231  sharedModule = new SharedModule ();
232  NS_LOG_DEBUG ("create shared module=" << sharedModule <<
233  " file=" << cached.cachedFilename <<
234  " id=" << cached.id);
235  sharedModule->refcount = 0;
236  sharedModule->id = cached.id;
237  sharedModule->handle = handle;
238  sharedModule->buffer_size = cached.data_p_memsz;
239  sharedModule->template_buffer = malloc (cached.data_p_memsz);
240  sharedModule->data_buffer = (void *)(link_map->l_addr + cached.data_p_vaddr);
241  memcpy (sharedModule->template_buffer,
242  sharedModule->data_buffer,
243  sharedModule->buffer_size);
244  sharedModule->current_buffer = 0;
245  for (std::vector<uint32_t>::const_iterator j = cached.deps.begin ();
246  j != cached.deps.end (); ++j)
247  {
248  struct SharedModule *dep = SearchSharedModule (*j);
249  dep->refcount++;
250  sharedModule->deps.push_back (dep);
251  }
252  modules->modules.push_back (sharedModule);
253  }
254  module = SearchModule (sharedModule->id);
255  if (module == 0)
256  {
257  module = new Module ();
258  NS_LOG_DEBUG ("Create module for " << sharedModule->handle <<
259  " " << cached.cachedFilename);
260  module->module = sharedModule;
261  sharedModule->refcount++;
262  module->refcount = 0;
263  module->buffer = malloc (sharedModule->buffer_size);
264  if (sharedModule->current_buffer != 0)
265  {
266  // save the previous one
267  memcpy (module->module->current_buffer,
268  module->module->data_buffer,
269  module->module->buffer_size);
270  }
271  // make sure we re-initialize the data section with the template
272  memcpy (sharedModule->data_buffer,
273  sharedModule->template_buffer,
274  sharedModule->buffer_size);
275  // record current buffer to ensure that it is saved later
276  sharedModule->current_buffer = module->buffer;
277  // setup deps.
278  for (std::vector<uint32_t>::const_iterator j = cached.deps.begin ();
279  j != cached.deps.end (); ++j)
280  {
281  struct Module *dep = SearchModule (*j);
282  dep->refcount++;
283  module->deps.push_back (dep);
284  }
285  NS_LOG_DEBUG ("add " << module);
286  m_modules.push_back (module);
287  }
288  }
289  return module;
290 }
291 void
292 CoojaLoader::UnrefSharedModule (SharedModule *search)
293 {
294  NS_LOG_FUNCTION (this << search << search->refcount);
295  struct SharedModules *ns = Peek ();
296  for (std::list<struct SharedModule *>::iterator i = ns->modules.begin ();
297  i != ns->modules.end (); ++i)
298  {
299  struct SharedModule *module = *i;
300  if (module == search)
301  {
302  module->refcount--;
303  if (module->refcount == 0)
304  {
305  NS_LOG_DEBUG ("delete shared module " << module);
306  for (std::list<struct SharedModule *>::iterator j = module->deps.begin ();
307  j != module->deps.end (); ++j)
308  {
309  struct SharedModule *dep = *j;
310  UnrefSharedModule (dep);
311  }
312  dlclose (module->handle);
313  free (module->template_buffer);
314  delete module;
315  ns->modules.erase (i);
316  }
317  break;
318  }
319  }
320 }
321 void
323 {
324  NS_LOG_FUNCTION (this);
325  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
326  {
327  struct Module *module = *i;
328  NS_LOG_DEBUG ("Delete module " << module);
329  if (module->module->current_buffer == module->buffer)
330  {
331  module->module->current_buffer = 0;
332  }
333  UnrefSharedModule (module->module);
334  free (module->buffer);
335  delete module;
336  }
337  m_modules.clear ();
338 }
339 void
340 CoojaLoader::Unload (void *handle)
341 {
342  NS_LOG_FUNCTION (this << handle);
343  for (std::list<struct Module *>::iterator i = m_modules.begin (); i != m_modules.end (); ++i)
344  {
345  struct Module *module = *i;
346  if (module->module->handle == handle)
347  {
348  module->refcount--;
349  if (module->refcount == 0)
350  {
351  m_modules.erase (i);
352  for (std::list<struct Module *>::iterator j = module->deps.begin ();
353  j != module->deps.end (); ++j)
354  {
355  struct Module *dep = *j;
356  Unload (dep->module->handle);
357  }
358  // close only after unloading the deps.
359  NS_LOG_DEBUG ("Delete module for " << module->module->handle);
360  if (module->module->current_buffer == module->buffer)
361  {
362  module->module->current_buffer = 0;
363  }
364  UnrefSharedModule (module->module);
365  free (module->buffer);
366  delete module;
367  }
368  break;
369  }
370  }
371 }
372 void *
373 CoojaLoader::Lookup (void *module, std::string symbol)
374 {
375  NS_LOG_FUNCTION (this << module << symbol);
376  void *p = dlsym (module, symbol.c_str ());
377  return p;
378 }
379 
381 {
382  NS_LOG_FUNCTION (this);
383 }
384 
386 {
387  NS_LOG_FUNCTION (this);
388  UnloadAll ();
389 }
390 
391 
392 TypeId
394 {
395  static TypeId tid = TypeId ("ns3::CoojaLoaderFactory")
396  .SetParent<LoaderFactory> ()
397  .AddConstructor<CoojaLoaderFactory> ()
398  ;
399  return tid;
400 }
402 {
403 }
405 {
406 }
407 Loader *
408 CoojaLoaderFactory::Create (int argc, char **argv, char **envp)
409 {
410  CoojaLoader *loader = new CoojaLoader ();
411  return loader;
412 }
413 
414 } // namespace ns3