ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dce-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005,2008 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "dce-manager.h"
21 #include "process.h"
22 #include "task-manager.h"
23 #include "libc-dce.h"
24 #include "unix-fd.h"
25 #include "unix-file-fd.h"
26 #include "utils.h"
27 #include "kingsley-alloc.h"
28 #include "dce-stdio.h"
29 #include "dce-unistd.h"
30 #include "dce-pthread.h"
31 #include "dce-fcntl.h"
32 #include "sys/dce-stat.h"
33 #include "loader-factory.h"
34 #include "ns3/node.h"
35 #include "ns3/log.h"
36 #include "ns3/simulator.h"
37 #include "ns3/ipv4-address.h"
38 #include "ns3/packet.h"
39 #include "ns3/ptr.h"
40 #include "ns3/uinteger.h"
41 #include "ns3/boolean.h"
42 #include "ns3/trace-source-accessor.h"
43 #include "ns3/enum.h"
44 #include "file-usage.h"
45 #include "wait-queue.h"
46 #include "waiter.h"
47 #include "dce-dirent.h"
48 #include "exec-utils.h"
49 
50 #include <errno.h>
51 #include <dlfcn.h>
52 #include <arpa/inet.h>
53 #include <sys/types.h>
54 #include <dirent.h>
55 #include <sys/stat.h>
56 #include <netdb.h>
57 #include <signal.h>
58 #include <fcntl.h>
59 #include <stdlib.h>
60 
61 NS_LOG_COMPONENT_DEFINE ("DceManager");
62 
63 namespace ns3 {
64 
65 NS_OBJECT_ENSURE_REGISTERED (DceManager);
66 
67 class Waiter;
68 
69 TypeId
71 {
72  static TypeId tid = TypeId ("ns3::DceManager")
73  .SetParent<Object> ()
74  .AddConstructor<DceManager> ()
75  .AddTraceSource ("Exit", "A process has exited",
76  MakeTraceSourceAccessor (&DceManager::m_processExit))
77  .AddAttribute ("FirstPid", "The PID used by default when creating a process in this manager.",
78  UintegerValue (1),
79  MakeUintegerAccessor (&DceManager::m_nextPid),
80  MakeUintegerChecker<uint16_t> ())
81  .AddAttribute ("MinimizeOpenFiles", "For each DCE virtual process running it exists 3 files opened (stdin,stdout and stderr),"
82  " if you enable this flag, the 2 files stderr and stdout will be closed between each write in order to "
83  " minimize the number of opened files and then maximize the number of DCE virtual process running at the same time.",
84  BooleanValue (false),
85  MakeBooleanAccessor (&DceManager::m_minimizeFiles),
86  MakeBooleanChecker ())
87  ;
88  return tid;
89 }
90 
92 {
93  NS_LOG_FUNCTION (this);
94 }
96 {
97  NS_LOG_FUNCTION (this);
98 }
99 void
101 {
102  NS_LOG_FUNCTION (this);
103  struct Process *tmp;
104  std::map<uint16_t, Process*> mapCopy = m_processes;
105 
106  m_processes.clear ();
107  for (std::map<uint16_t, Process*>::iterator it = mapCopy.begin (); it != mapCopy.end (); it++)
108  {
109  tmp = it->second;
110  std::string statusWord = "Never ended.";
111  AppendStatusFile (tmp->pid, tmp->nodeId, statusWord);
112  DeleteProcess (tmp, PEC_NS3_END);
113  }
114  mapCopy.clear ();
116 }
117 
118 struct ::Libc *
120 {
121  static struct ::Libc *libc = 0;
122  if (libc != 0)
123  {
124  return libc;
125  }
126  libc_dce (&libc);
127  return libc;
128 }
129 
130 void
131 DceManager::EnsureDirectoryExists (struct Thread *current, std::string dirName)
132 {
133  int fd = dce_open (dirName.c_str (), O_DIRECTORY | O_RDONLY, 0);
134  if (fd != -1)
135  {
136  dce_close (fd);
137  }
138  else if (current->err == ENOENT)
139  {
140  int status = dce_mkdir (dirName.c_str (), S_IRWXU | S_IRWXG);
141  if (status == -1)
142  {
143  NS_FATAL_ERROR ("Could not create directory " << dirName
144  << ": " << strerror (current->err));
145  }
146  }
147  else
148  {
149  NS_FATAL_ERROR ("Could not open \"" << dirName << "\"");
150  }
151 }
152 
153 int
154 DceManager::CreatePidFile (struct Thread *current, std::string filename)
155 {
156  EnsureDirectoryExists (current, "/var");
157  EnsureDirectoryExists (current, "/var/log");
158  std::ostringstream oss;
159  oss << "/var/log/" << current->process->pid;
160  std::string pidDirName = oss.str ();
161  EnsureDirectoryExists (current, oss.str ());
162  oss << "/" << filename;
163  std::string s = oss.str ();
164  int fd = dce_creat (s.c_str (), S_IWUSR | S_IRUSR);
165  return fd;
166 }
167 int (*DceManager::PrepareDoStartProcess (Thread * current)) (int, char **)
168 {
169  // Note : this preparing process is out of method DoStartProcess in order to
170  // free all local variable in particular the std library ones before the main execution
171  // because main call will reset allocation counters of std library then we must not free std::string
172  // after the main call !
173  int err = 0;
174  int (*main)(int, char **) = 0;
175  GetLibc ();
176  UnixFd *unixFd = 0;
177 
178  if (current->process->stdinFilename.length () > 0)
179  {
180  std::string fullpath = UtilsGetRealFilePath (current->process->stdinFilename);
181  int realFd = ::open (fullpath.c_str (), O_RDONLY, 0);
182 
183  if (-1 == realFd)
184  {
185  NS_FATAL_ERROR ("Unable to open stdin file : " << current->process->stdinFilename);
186  }
187  unixFd = new UnixFileFd (realFd);
188  }
189  else
190  {
191  unixFd = new TermUnixFileFd (0);
192  }
193  // create fd 0
194  unixFd->IncFdCount ();
195  current->process->openFiles[0] = new FileUsage (0, unixFd);
196 
197  // create fd 1
198  int fd = CreatePidFile (current, "stdout");
199  NS_ASSERT (fd == 1);
200  // create fd 2
201  fd = CreatePidFile (current, "stderr");
202  NS_ASSERT (fd == 2);
203 
204  fd = CreatePidFile (current, "cmdline");
205  NS_ASSERT (fd == 3);
206  for (int i = 0; i < current->process->originalArgc; i++)
207  {
208  char *cur = current->process->originalArgv[i];
209  dce_write (fd, cur, strlen (cur));
210  dce_write (fd, " ", 1);
211  current->process->timing.cmdLine += cur;
212  if (i < (current->process->originalArgc - 1))
213  {
214  current->process->timing.cmdLine += ' ';
215  }
216  }
217  dce_write (fd, "\n", 1);
218  dce_close (fd);
219 
220  fd = CreatePidFile (current, "status");
221  NS_ASSERT (fd == 3);
222  {
223  std::ostringstream oss;
224  oss << "Start Time: " << GetTimeStamp () << std::endl;
225  std::string tmp = oss.str ();
226  const char *str = tmp.c_str ();
227  dce_write (fd, str, strlen (str));
228  dce_close (fd);
229  }
230  std::string vpath = "";
231  char *pvpath = seek_env ("PATH", current->process->originalEnvp);
232  if (pvpath)
233  {
234  vpath = std::string (pvpath);
235  }
236  int errNo = 0;
237  std::string exeFullPath = SearchExecFile (current->process->originalArgv[0], vpath, getuid (), getgid (), &errNo);
238 
239  if (exeFullPath.length () <= 0)
240  {
241  std::string line = "Executable '";
242  line += current->process->originalArgv[0];
243  line += "' not found ! Please check your DCE_PATH and DCE_ROOT environment variables.";
244  AppendStatusFile (current->process->pid, current->process->nodeId, line);
245  NS_ASSERT_MSG (exeFullPath.length () > 0, line.c_str ());
246  dce_exit (-1);
247  return 0;
248  }
249 
250  main = (int (*) (int, char **))LoadMain (current->process->loader,
251  exeFullPath,
252  current->process,
253  err);
254 
255  if (!main)
256  {
257  std::string line = "No main method found in executable file '";
258  line += exeFullPath;
259  line += "'.";
260  AppendStatusFile (current->process->pid, current->process->nodeId, line);
261  NS_ASSERT_MSG (!main, line.c_str ());
262  }
263  else
264  {
265  std::string line = "Starting: " + exeFullPath;
266  AppendStatusFile (current->process->pid, current->process->nodeId, line);
267  }
268 
269  return main;
270 }
271 void
273 {
274  Thread *current = (Thread *)context;
275  int (*main)(int, char **) = PrepareDoStartProcess (current);
276  int retval = 127;
277 
278  if (main)
279  {
281  retval = main (current->process->originalArgc, current->process->originalArgv);
282  }
283  dce_exit (retval);
284 }
285 
286 void
288 {
289 }
290 
291 struct Process *
292 DceManager::CreateProcess (std::string name, std::string stdinfilename, std::vector<std::string> args,
293  std::vector<std::pair<std::string,std::string> > envs, int pid)
294 {
295  struct Process *process = new Process ();
296  process->euid = 0;
297  process->ruid = 0;
298  process->suid = 0;
299  process->egid = 0;
300  process->rgid = 0;
301  process->sgid = 0;
302  process->alloc = new KingsleyAlloc ();
303  process->originalArgv = 0;
304  process->originalArgc = 0;
305  process->originalEnvp = 0;
306  SetArgv (process, name, args);
307  SetEnvp (process, envs);
308  Ptr<LoaderFactory> loaderFactory = this->GetObject<LoaderFactory> ();
309  process->loader = loaderFactory->Create (process->originalArgc, process->originalArgv,
310  process->originalEnvp);
311  process->timing.exitValue = 0;
312  process->timing.ns3Start = Now ().GetNanoSeconds ();
313  process->timing.realStart = time (0);
314  process->timing.ns3End = 0;
315  process->timing.realEnd = 0;
316  process->timing.cmdLine = "";
317 
318  process->name = name;
319  process->ppid = 0;
320  process->pgid = 0;
321  process->pid = pid ? pid : AllocatePid ();
322  process->manager = this;
323  sigemptyset (&process->pendingSignals);
324 
326 
327  // we reserve 0 for the mutex initialized with PTHREAD_MUTEX_INITIALIZER
328  // we reserve 2 for a destroyed mutex
329  // 1 is such a common value that we try to avoid it.
330  // we unfortunately cannot avoid the value 0 because we
331  // have to be compatible with the system PHREAD_MUTEX_INITIALIZER
332  // which uses the value 0.
333  process->nextMid = 3;
334  // we reserve 2 for a destroyed mutex
335  // 0 and 1 are such common values that we avoid them.
336  process->nextSid = 3;
337  // we reserve 2 for a destroyed condition variable
338  // 0 and 1 are such common values that we avoid them.
339  process->nextCid = 3;
340  process->cwd = "/";
341  process->pstdin = 0;
342  process->pstdout = 0;
343  process->pstderr = 0;
344  process->penvp = 0;
345 
346  process->uMask = 022;
347 
348  process->stdinFilename = stdinfilename;
349 
350  //"seeding" random variable
351  process->rndVarible = UniformVariable (0, RAND_MAX);
352 
353  process->nodeId = UtilsGetNodeId ();
354 
355  process->minimizeFiles = (m_minimizeFiles ? 1 : 0);
356 
357  if (!pid)
358  {
359  m_processes[process->pid] = process;
360  }
361 
362  return process;
363 }
364 void
365 DceManager::TaskSwitch (enum Task::SwitchType type, void *context)
366 {
367  Process *process = (Process *)context;
368  switch (type)
369  {
370  case Task::TO:
371  process->loader->NotifyStartExecute ();
372  process->alloc->SwitchTo ();
373  break;
374  case Task::FROM:
375  process->loader->NotifyEndExecute ();
376  break;
377  }
378 }
379 uint16_t
380 DceManager::Start (std::string name, std::string stdinfilename, std::vector<std::string> args,
381  std::vector<std::pair<std::string,std::string> > envs,
382  uid_t uid, uid_t euid, uid_t gid, uid_t egid)
383 {
384  NS_LOG_FUNCTION (this << name << args.size ());
385  struct Process *process = CreateProcess (name, stdinfilename, args, envs, 0);
386  process->ruid = uid;
387  process->euid = euid;
388  process->rgid = gid;
389  process->egid = egid;
390  struct Thread *thread = CreateThread (process);
391  Task *task = TaskManager::Current ()->Start (&DceManager::DoStartProcess, thread);
392  task->SetContext (thread);
393  task->SetSwitchNotifier (&DceManager::TaskSwitch, process);
394  thread->task = task;
395  return process->pid;
396 }
397 uint16_t
398 DceManager::Start (std::string name, std::string stdinfilename, uint32_t stackSize,
399  std::vector<std::string> args,
400  std::vector<std::pair<std::string,std::string> > envs,
401  uid_t uid, uid_t euid, uid_t gid, uid_t egid)
402 {
403  NS_LOG_FUNCTION (this << name << stackSize << args.size () << envs.size ());
404  struct Process *process = CreateProcess (name, stdinfilename, args, envs, 0);
405  process->ruid = uid;
406  process->euid = euid;
407  process->rgid = gid;
408  process->egid = egid;
409  struct Thread *thread = CreateThread (process);
410  Task *task = TaskManager::Current ()->Start (&DceManager::DoStartProcess, thread, stackSize);
411  task->SetContext (thread);
412  task->SetSwitchNotifier (&DceManager::TaskSwitch, process);
413  thread->task = task;
414  return process->pid;
415 }
416 uint16_t
418 {
419  std::vector<std::string> nullargs;
420  std::vector<std::pair<std::string,std::string> > nullenvs;
421  struct Process *process = CreateProcess ("internal", "dummy-stdin", nullargs, nullenvs, 0);
422  struct Thread *thread = CreateThread (process);
423  Task *task = new Task ();
424  task->SetContext (thread);
425  return process->pid;
426 }
427 uint16_t
429 {
430  std::vector<std::string> nullargs;
431  std::vector<std::pair<std::string,std::string> > envs;
432  struct Process *process = CreateProcess ("dummy", "dummy-stdin", nullargs, envs, 0);
433  struct Thread *thread = CreateThread (process);
434  Task *task = new Task ();
435  task->SetContext (thread);
436  thread->task = task;
437  NS_LOG_FUNCTION (this << process->pid << thread << TaskManager::Current ()->CurrentTask ());
438  TaskManager::Current ()->EnterHiTask (task);
439  return process->pid;
440 }
441 
442 void
444 {
445  Process *process = SearchProcess (pid);
446  Thread *thread = process->threads.front ();
447  NS_LOG_FUNCTION (this << process->pid << thread << thread->task << TaskManager::Current ()->CurrentTask ());
448  TaskManager::Current ()->EnterHiTask (thread->task);
449  return;
450 }
451 
452 void
454 {
455  Process *process = SearchProcess (pid);
456  Thread *thread = process->threads.front ();
457  NS_LOG_FUNCTION (this << process->pid << TaskManager::Current ()->CurrentTask ());
458  TaskManager::Current ()->LeaveHiTask (thread->task);
459  return;
460 }
461 void
463 {
464  NS_LOG_FUNCTION (this);
465  Process *process = SearchProcess (pid);
466  Thread *thread = process->threads.front ();
467  Task *task = thread->task;
468  DeleteProcess (process, PEC_EXIT);
469  NS_LOG_FUNCTION (this << process->pid << TaskManager::Current ()->CurrentTask ());
470  TaskManager::Current ()->LeaveHiTask (task);
471  return;
472 }
473 
474 uint16_t
476 {
477  // Note that this function purposedly never allocates pid 0
478  // to make it useable in the kernel stack layer for kernel-level
479  // special tasks (which thus all share the same pid)
480  NS_LOG_FUNCTION (this);
481  for (uint16_t i = 0; i < 0xffff; i++)
482  {
483  uint16_t candidatePid = (m_nextPid + i) & 0xffff;
484  if (candidatePid > 1 && SearchProcess (candidatePid) == 0)
485  {
486  m_nextPid = (candidatePid + 1) & 0xffff;
487  return candidatePid;
488  }
489  }
490  NS_FATAL_ERROR ("Too many processes");
491  return 0; // quiet compiler
492 }
493 uint16_t
494 DceManager::AllocateTid (const struct Process *process) const
495 {
496  for (uint16_t tid = 0; tid < 0xffff; tid++)
497  {
498  bool found = false;
499  for (std::vector<struct Thread *>::const_iterator i = process->threads.begin (); i != process->threads.end (); ++i)
500  {
501  struct Thread *tmp = *i;
502  if (tmp->tid == tid)
503  {
504  found = true;
505  break;
506  }
507  }
508  if (!found)
509  {
510  return tid;
511  }
512  }
513  NS_FATAL_ERROR ("We attempted to allocate a new tid for this process but none were available: "
514  "too many threads created at the same time.");
515  // quiet compiler
516  return 0;
517 }
518 struct Thread *
520 {
521  NS_LOG_FUNCTION (this << process);
522  struct Thread *thread = new Thread ();
523  NS_LOG_DEBUG ("Create " << thread);
524  thread->err = 0;
525  thread->tid = AllocateTid (process);
526  thread->process = process;
527  thread->isDetached = false;
528  thread->hasExitValue = false;
529  thread->joinWaiter = 0;
530  thread->lastTime = Time (0);
531  thread->childWaiter = 0;
532  thread->pollTable = 0;
533  thread->ioWait = std::make_pair ((UnixFd*)0,(WaitQueueEntry*)0);
534  sigemptyset (&thread->signalMask);
535  if (!process->threads.empty ())
536  {
537  // copy all key values.
538  Thread *tmp = process->threads.front ();
539  thread->keyValues = tmp->keyValues;
540  // reset all values to NULL
541  for (std::list<struct ThreadKeyValue>::iterator i = thread->keyValues.begin ();
542  i != thread->keyValues.end (); ++i)
543  {
544  i->value = 0;
545  }
546  }
547  process->threads.push_back (thread);
548  return thread;
549 }
550 
551 void
553 {
554  TaskManager::Current ()->Exit ();
555 }
556 
557 bool
559 {
560  if (!thread)
561  {
562  return false;
563  }
564  if (!thread->process)
565  {
566  return false;
567  }
568 
569  Process *process = thread->process;
570 
571  for (std::vector<Thread *>::const_iterator j = process->threads.begin ();
572  j != process->threads.end (); ++j)
573  {
574  Thread *cur = *j;
575  if (cur == thread)
576  {
577  return true;
578  }
579  }
580 
581  return false;
582 }
583 
584 uint16_t
586 {
587  NS_LOG_FUNCTION (this << thread);
588  Process *clone = new Process ();
589  clone->euid = 0;
590  clone->ruid = 0;
591  clone->suid = 0;
592  clone->egid = 0;
593  clone->rgid = 0;
594  clone->sgid = 0;
595  // XXX setup
596  clone->originalArgv = 0;
597  clone->originalArgc = 0;
598  clone->originalEnvp = 0;
599  clone->timing.exitValue = 0;
600  clone->timing.ns3Start = Now ().GetNanoSeconds ();
601  clone->timing.realStart = time (0);
602  clone->timing.ns3End = 0;
603  clone->timing.realEnd = 0;
604  clone->name = thread->process->name;
605  clone->ppid = thread->process->pid;
606  clone->pgid = thread->process->pgid;
607  clone->pid = AllocatePid ();
608  thread->process->children.insert (clone->pid);
609  // dup each file descriptor.
610  for (std::map <int, FileUsage*>::iterator i = thread->process->openFiles.begin ();
611  i != thread->process->openFiles.end (); ++i)
612  {
613  int fd = i->first;
614  FileUsage* fu = i->second;
615 
616  if (fu && fu->GetFile ())
617  {
618  fu->GetFile ()->IncFdCount ();
619  fu->GetFile ()->Ref ();
620  clone->openFiles[fd] = new FileUsage (fd, fu->GetFile ());
621  }
622  }
623  // don't copy threads, semaphores, mutexes, condition vars
624  // XXX: what about file streams ?
625  clone->manager = this;
626  sigemptyset (&clone->pendingSignals);
627 
629 
630  clone->nextMid = thread->process->nextMid;
631  clone->nextSid = thread->process->nextSid;
632  clone->nextCid = thread->process->nextCid;
633  clone->cwd = thread->process->cwd;
634  clone->pstdin = thread->process->pstdin;
635  clone->pstdout = thread->process->pstdout;
636  clone->pstderr = thread->process->pstderr;
637  clone->penvp = thread->process->penvp;
638 
639  //"seeding" random variable
640  clone->rndVarible = UniformVariable (0, RAND_MAX);
641  m_processes[clone->pid] = clone;
642  Thread *cloneThread = CreateThread (clone);
643 
644  clone->loader = thread->process->loader->Clone ();
645  clone->alloc = thread->process->alloc->Clone ();
646  Task *task = TaskManager::Current ()->Clone (thread->task);
647  if (task != 0)
648  {
649  // parent. complete setup. return.
650  task->SetContext (cloneThread);
652  cloneThread->task = task;
653  return clone->pid;
654  }
655  // child.
656  return 0;
657 }
658 
659 void
661 {
662  TaskManager::Current ()->Yield ();
663 }
664 
665 void
667 {
668  TaskManager::Current ()->Sleep ();
669 }
670 
671 Time
672 DceManager::Wait (Time timeout)
673 {
674  return TaskManager::Current ()->Sleep (timeout);
675 }
676 
677 void
679 {
680  NS_ASSERT (ThreadExists (thread));
681  return TaskManager::Current ()->Wakeup (thread->task);
682 }
683 
684 void
685 DceManager::SetFinishedCallback (uint16_t pid, Callback<void,uint16_t,int> cb)
686 {
687  Process *process = SearchProcess (pid);
688  if (process == 0)
689  {
690  return;
691  }
692  process->finished = cb;
693 }
694 void
695 DceManager::Stop (uint16_t pid)
696 {
697  NS_LOG_FUNCTION (this << pid);
698 
699  Process *process = SearchProcess (pid);
700  if (process == 0)
701  {
702  return;
703  }
704  std::string statusWord = "Stopped by NS3.";
705  AppendStatusFile (process->pid, process->nodeId, statusWord);
706  DeleteProcess (process, PEC_NS3_STOP);
707 }
708 void
710 {
711  NS_ASSERT (signal == SIGKILL);
712  dce_exit (-1);
713 }
714 void
716 {
717  NS_ASSERT (signal == SIGABRT);
718  dce_exit (-2);
719 }
720 void
722 {
723  if (thread->ioWait.first != 0 && thread->ioWait.second != 0)
724  {
725  thread->ioWait.first->RemoveWaitQueue (thread->ioWait.second, false);
726  if (thread->ioWait.second)
727  {
728  delete thread->ioWait.second;
729  }
730  thread->ioWait = std::make_pair ((UnixFd*)0,(WaitQueueEntry*)0);
731  }
732  if (thread->pollTable != 0)
733  {
734  PollTable *lb = thread->pollTable;
735  thread->pollTable = 0;
736  lb->FreeWait ();
737  delete lb;
738  lb = 0;
739  }
740 }
741 
742 void
744 {
745  NS_LOG_FUNCTION (this << thread);
746  if (thread->task != 0)
747  {
748  // the task could be 0 if it was Exited by
749  // pthread_exit and it was not pthread_detached.
750  GetObject<TaskManager> ()->Stop (thread->task);
751  }
752  thread->task = 0;
753  for (std::vector<Thread *>::iterator i = thread->process->threads.begin ();
754  i != thread->process->threads.end (); ++i)
755  {
756  if (*i == thread)
757  {
758  thread->process->threads.erase (i);
759  break;
760  }
761  }
762  if (0 != thread->childWaiter)
763  {
764  Waiter *lb = thread->childWaiter;
765  thread->childWaiter = 0;
766  delete lb;
767  }
768  delete thread;
769 }
770 
771 void
773 {
774  NS_LOG_FUNCTION (this << process << "pid" << std::dec << process->pid << "ppid" << process->ppid);
775 
776  // Remove Threads Waiters
777  struct Thread *tmp;
778  std::vector<Thread *> threads = process->threads;
779 
780  // First remove from wait queues: I am not more interressed of IO on Files
781  while (!threads.empty ())
782  {
783  tmp = threads.back ();
784  threads.pop_back ();
785  CleanupThread (tmp);
786  tmp = 0;
787  }
788 
789  if (type == PEC_EXIT)
790  {
791  // We have a Current so we can call dce_close !
792  std::map<int,FileUsage *> openFiles = process->openFiles;
793 
794  for (std::map <int, FileUsage*>::iterator i = openFiles.begin ();
795  i != openFiles.end (); ++i)
796  {
797  int fd = i->first;
798  FileUsage* fu = i->second;
799 
800  if (fu)
801  {
802  // Nullify count of thread using this file.
803  fu->NullifyUsage ();
804  // Close my files and eventually wake up others processes.
805  dce_close (fd);
806  }
807  }
808  openFiles.clear ();
809  }
810 
811  // Close all streams opened
812  for (uint32_t i = 0; i < process->openStreams.size (); i++)
813  {
814  // Note that, while this code might look straightforward,
815  // it is not so. Specifically, we call here the system fclose
816  // function which will call indirectly system_close in
817  // system-wrappers.cc which will call dce_close in dce-fd.cc
818  // which will return -1 because it is called without a 'current'
819  // thread
821  }
822  process->openStreams.clear ();
823 
824  // Close all DIR opened
825  for (uint32_t i = 0; i < process->openDirs.size (); i++)
826  {
827  dce_internalClosedir (process->openDirs[i], 0);
828  }
829  process->openDirs.clear ();
830 
831  if (!process->finished.IsNull ())
832  {
833  process->finished (process->pid, process->timing.exitValue);
834  }
835  // stop itimer timers if there are any.
836  process->itimer.Cancel ();
837  // Delete File References Memory
838  std::map<int,FileUsage *> openFiles = process->openFiles;
839  process->openFiles.clear ();
840  for (std::map <int, FileUsage*>::iterator i = openFiles.begin ();
841  i != openFiles.end (); ++i)
842  {
843  FileUsage* fu = i->second;
844 
845  if (fu)
846  {
847  delete fu;
848  }
849  }
850  openFiles.clear ();
851 
852  // finally, delete remaining threads
853  while (!process->threads.empty ())
854  {
855  tmp = process->threads.back ();
856  process->threads.pop_back ();
857  DeleteThread (tmp);
858  }
859  // delete all mutexes
860  for (uint32_t i = 0; i < process->mutexes.size (); ++i)
861  {
862  struct Mutex *mutex = process->mutexes[i];
863  // XXX: do some error checking here to ensure that no thread is
864  // blocked in a critical section.
865  delete mutex;
866  }
867  process->mutexes.clear ();
868  // delete all semaphores
869  for (uint32_t i = 0; i < process->semaphores.size (); ++i)
870  {
871  struct Semaphore *semaphore = process->semaphores[i];
872  // XXX: do some error checking here to ensure that no thread is
873  // blocked in a critical section.
874  delete semaphore;
875  }
876  // delete all extra buffers
877  while (!process->allocated.empty ())
878  {
879  void *buffer = process->allocated.back ();
880  process->allocated.pop_back ();
881  free (buffer);
882  }
883 
884  int ppid = process->ppid;
885 
886  if ((type == PEC_EXIT)||(type == PEC_NS3_STOP))
887  {
888  // Re-parent children
889  std::set<uint16_t> children = process->children;
890  process->children.clear ();
891  std::set<uint16_t>::iterator it;
892 
893  for (it = children.begin (); it != children.end (); it++)
894  {
895  Process *child = SearchProcess (*it);
896 
897  if (child)
898  {
899  child->ppid = 1;
900  if ((child->pid > 1) && !child->loader && !child->alloc)
901  {
902  m_processes.erase (child->pid);
903  delete child;
904  }
905  }
906  }
907  m_processExit (process->pid, process->timing.exitValue);
908  }
909  delete process->loader;
910  process->loader = 0;
911  if (type == PEC_EXIT)
912  {
913  // Only dispose from good context
914  process->alloc->Dispose ();
915  }
916  delete process->alloc;
917  process->alloc = 0;
918 
919  if ((type == PEC_EXIT)||(type == PEC_NS3_STOP))
920  {
921  if (ppid > 1)
922  {
923  // Warn father
924  ChildFinished (process->pid);
925  }
926  else
927  {
928  // ppid == 0 have no father, perhaps DCE, else ppid = 1 init : have lost it's real father.
929  // remove ourselves from list of processes
930  m_processes.erase (process->pid);
931  // delete process data structure.
932  delete process;
933  }
934  }
935  else
936  {
937  delete process;
938  }
939 
940 }
941 
942 bool
944 {
945  return TaskManager::Current () != 0 && TaskManager::Current ()->CurrentTask () != 0;
946 }
947 
948 Thread *
949 DceManager::SearchThread (uint16_t pid, uint16_t tid)
950 {
951  NS_LOG_FUNCTION (this << pid << tid);
952  NS_ASSERT (CheckProcessContext ());
953  Process *process = SearchProcess (pid);
954  if (process == 0)
955  {
956  return 0;
957  }
958  for (std::vector<Thread *>::const_iterator j = process->threads.begin ();
959  j != process->threads.end (); ++j)
960  {
961  Thread *thread = *j;
962  if (thread->tid == tid)
963  {
964  return thread;
965  }
966  }
967  return 0;
968 }
969 Process *
971 {
972  NS_LOG_FUNCTION (this << pid);
973 
974  std::map<uint16_t, Process *>::iterator it = m_processes.find (pid);
975 
976  if (it != m_processes.end ())
977  {
978  return it->second;
979  }
980  return 0;
981 }
982 
983 void
984 DceManager::SetArgv (struct Process *process, std::string filename, std::vector<std::string> args)
985 {
986  NS_ASSERT (process->originalArgv == 0);
987  int argc = args.size () + 1;
988  char **argv = (char **)malloc (sizeof (char *) * (argc + 1));
989  process->allocated.push_back (argv);
990  argv[0] = strdup (filename.c_str ());
991  process->allocated.push_back (argv[0]);
992  for (uint32_t i = 0; i < args.size (); ++i)
993  {
994  char *arg = strdup (args[i].c_str ());
995  NS_LOG_DEBUG ("argc=" << argc << " i=" << i << " v=" << arg);
996  argv[i + 1] = arg;
997  process->allocated.push_back (arg);
998  }
999  argv[argc] = 0;
1000  process->originalArgv = argv;
1001  process->originalArgc = argc;
1002  process->originalProgname = argv[0];
1003 }
1004 
1005 void
1006 DceManager::SetEnvp (struct Process *process,
1007  std::vector<std::pair<std::string,std::string> > envs)
1008 {
1009  int envpc = envs.size ();
1010  char **envp = (char **)malloc (sizeof (char *) * (envpc + 1));
1011  process->allocated.push_back (envp);
1012  for (uint32_t i = 0; i < envs.size (); ++i)
1013  {
1014  int size = envs[i].first.size () + envs[i].second.size () + 1;
1015  envp[i] = (char*)malloc (size + 1);
1016  process->allocated.push_back (envp[i]);
1017  memcpy (envp[i], envs[i].first.c_str (), envs[i].first.size ());
1018  envp[i][envs[i].first.size ()] = '=';
1019  memcpy (envp[i] + envs[i].first.size () + 1, envs[i].second.c_str (), envs[i].second.size ());
1020  envp[i][size] = 0;
1021  NS_LOG_DEBUG ("envpc=" << envpc << " i=" << i << " v=" << envp[i]);
1022  }
1023  envp[envpc] = 0;
1024  process->originalEnvp = envp;
1025 }
1026 
1027 void
1028 DceManager::AppendStatusFile (uint16_t pid, uint32_t nodeId, std::string &line)
1029 {
1030  std::ostringstream oss;
1031  oss << "files-" << nodeId << "/var/log/" << pid << "/status";
1032  std::string s = oss.str ();
1033 
1034  int fd = ::open (s.c_str (), O_WRONLY | O_APPEND, 0);
1035 
1036  if (fd >= 0) // XXX: When fork is used the pid directory is not created, I plan to fix it when I will work on fork/exec/wait...
1037  {
1038  oss.str ("");
1039  oss.clear ();
1040  oss << " Time: " << GetTimeStamp () << " --> " << line << std::endl;
1041  std::string wholeLine = oss.str ();
1042  int l = wholeLine.length ();
1043  const char *str = wholeLine.c_str ();
1044  ::write (fd, str, l);
1045  ::close (fd);
1046  }
1047 }
1048 void
1050 {
1051  if (!p)
1052  {
1053  return;
1054  }
1055  std::ostringstream oss;
1056  int fd = ::open ("exitprocs", O_WRONLY | O_APPEND | O_CREAT, 0644);
1057 
1058  if (fd >= 0)
1059  {
1060  struct stat st;
1061  if ((!fstat (fd, &st)) && (0 == st.st_size))
1062  {
1063  const char *header = "NODE EXIT-CODE PID NS3-START-TIME NS3-END-TIME REAL-START-TIME REAL-END-TIME NS3-DURATION REAL-DURATION CMDLINE\n";
1064 
1065  ::write (fd, header, strlen (header));
1066  }
1067 
1068  oss << p->nodeId
1069  << ' ' << p->timing.exitValue
1070  << ' ' << p->pid
1071  << ' ' << p->timing.ns3Start
1072  << ' ' << p->timing.ns3End
1073  << ' ' << p->timing.realStart
1074  << ' ' << p->timing.realEnd
1075  << ' ' << ((p->timing.ns3End - p->timing.ns3Start) / (double) 1000000000)
1076  << ' ' << (p->timing.realEnd - p->timing.realStart)
1077  << ' ' << p->timing.cmdLine << std::endl;
1078  std::string wholeLine = oss.str ();
1079  int l = wholeLine.length ();
1080  const char *str = wholeLine.c_str ();
1081  ::write (fd, str, l);
1082  ::close (fd);
1083  }
1084 }
1085 
1086 std::map<uint16_t, Process *>
1088 {
1089  return m_processes;
1090 }
1091 
1092 void
1094 {
1095  // Get pid process.
1096  Process *child = SearchProcess (pid);
1097  NS_ASSERT (child);
1098  Process *p = SearchProcess (child->ppid);
1099  NS_ASSERT (p);
1100  WakeupChildWaiters (p);
1101  if (!true) // IF WAIT DONE !
1102  {
1103  std::set<uint16_t>::iterator it = p->children.find (pid);
1104  if (it != p->children.end ())
1105  {
1106  p->children.erase (it);
1107  }
1108  m_processes.erase (pid);
1109  delete child;
1110  }
1111 }
1112 bool
1114 {
1115  bool ret = false;
1116  std::vector<Thread *> tt = p->threads;
1117 
1118  for (std::vector<Thread*>::iterator it = tt.begin (); it != tt.end (); it++)
1119  {
1120  Thread *t = *it;
1121  if (t && t->childWaiter)
1122  {
1123  t->childWaiter->Wakeup ();
1124  }
1125  }
1126 
1127  return ret;
1128 }
1129 void
1131 {
1132  // A wait success on this proc
1133  Process *child = SearchProcess (pid);
1134  if (child)
1135  {
1136  m_processes.erase (pid);
1137  delete child;
1138  }
1139 }
1140 std::vector<std::string>
1141 DceManager::CopyArgs (char *const argv[])
1142 {
1143  std::vector<std::string> args;
1144 
1145  // Copy argv
1146  if (0 != argv)
1147  {
1148  char **v = (char **) argv;
1149  if (*v)
1150  {
1151  v++; // Ignore argv[0]
1152  }
1153  while (*v)
1154  {
1155  char *s = *v++;
1156  args.push_back (s);
1157  }
1158  }
1159  return args;
1160 }
1161 int
1162 DceManager::CopyEnv (char *const envp[], std::vector<std::pair<std::string,std::string> > &envs)
1163 {
1164  if (0 != envp)
1165  {
1166  char **e = (char **) envp;
1167 
1168  while (*e)
1169  {
1170  char *s = *e++;
1171  char *c = s;
1172 
1173  while ((*c != 0) && (*c != '='))
1174  {
1175  c++;
1176  }
1177 
1178  if (('=' != *c) || (s == c))
1179  {
1180  Current ()->err = EINVAL;
1181  return -1;
1182  }
1183  std::string key = std::string (s, c);
1184  std::string val = std::string (1 + c);
1185  envs.push_back (std::make_pair (key, val));
1186  }
1187  }
1188 
1189  return 0;
1190 }
1191 void*
1192 DceManager::LoadMain (Loader *ld, std::string filename, Process *proc, int &err)
1193 {
1194  void *h = ld->Load ("libc-ns3.so", RTLD_GLOBAL);
1195  void *symbol = 0;
1196  struct ::Libc *libc = GetLibc ();
1197 
1198  if (h == 0)
1199  {
1200  err = ENOMEM;
1201  return 0;
1202  }
1203  else
1204  {
1205  symbol = ld->Lookup (h, "libc_setup");
1206  if (symbol == 0)
1207  {
1208  NS_FATAL_ERROR ("This is not our fake libc !");
1209  }
1210  // construct the libc now
1211  void (*libc_setup)(const struct Libc *fn);
1212  libc_setup = (void (*) (const struct Libc *))(symbol);
1213  libc_setup (libc);
1214 
1215  h = ld->Load ("libpthread-ns3.so", RTLD_GLOBAL);
1216  if (h == 0)
1217  {
1218  err = ENOMEM;
1219  return 0;
1220  }
1221  else
1222  {
1223  symbol = ld->Lookup (h, "libpthread_setup");
1224  if (symbol == 0)
1225  {
1226  NS_FATAL_ERROR ("This is not our fake libpthread !");
1227  }
1228  // construct libpthread now
1229  void (*libpthread_setup)(const struct Libc *fn);
1230  libpthread_setup = (void (*) (const struct Libc *))(symbol);
1231  libpthread_setup (libc);
1232 
1233  h = ld->Load ("librt-ns3.so", RTLD_GLOBAL);
1234  if (h == 0)
1235  {
1236  err = ENOMEM;
1237  return 0;
1238  }
1239  symbol = ld->Lookup (h, "librt_setup");
1240  if (symbol == 0)
1241  {
1242  NS_FATAL_ERROR ("This is not our fake librt !");
1243  }
1244  // construct librt now
1245  void (*librt_setup)(const struct Libc *fn);
1246  librt_setup = (void (*) (const struct Libc *))(symbol);
1247  librt_setup (libc);
1248 
1249  h = ld->Load ("libm-ns3.so", RTLD_GLOBAL);
1250  if (h == 0)
1251  {
1252  err = ENOMEM;
1253  return 0;
1254  }
1255  symbol = ld->Lookup (h, "libm_setup");
1256  if (symbol == 0)
1257  {
1258  NS_FATAL_ERROR ("This is not our fake libm !");
1259  }
1260  // construct libm now
1261  void (*libm_setup)(const struct Libc *fn);
1262  libm_setup = (void (*) (const struct Libc *))(symbol);
1263  libm_setup (libc);
1264 
1265  // finally, call into 'main'.
1266  h = ld->Load (filename, RTLD_GLOBAL);
1267 
1268  if (h == 0)
1269  {
1270  err = EACCES;
1271  return 0;
1272  }
1273  else
1274  {
1275  proc->mainHandle = h;
1276  symbol = ld->Lookup (h, "main");
1277  err = (0 != symbol) ? 0 : ENOEXEC;
1278  }
1279  }
1280  }
1281  return symbol;
1282 }
1283 void
1285 {
1286  int (*main)(int, char **) = (int (*) (int, char **))c;
1287  Thread *current = Current ();
1288 
1290 
1291  int retval = main (current->process->originalArgc, current->process->originalArgv);
1292  dce_exit (retval);
1293 }
1294 void
1295 DceManager::SetDefaultSigHandler (std::vector<SignalHandler> &signalHandlers)
1296 {
1297  // setup a signal handler for SIGKILL which calls dce_exit.
1298  struct SignalHandler handler;
1299  handler.signal = SIGKILL;
1300  handler.flags = 0;
1301  sigemptyset (&handler.mask);
1303  signalHandlers.push_back (handler);
1304 
1305  // setup a signal handler for SIGABRT which calls dce_exit.
1306  handler.signal = SIGABRT;
1307  handler.flags = 0;
1308  sigemptyset (&handler.mask);
1310  signalHandlers.push_back (handler);
1311 }
1312 int
1313 DceManager::Execve (const char *path, const char *argv0, char *const argv[], char *const envp[])
1314 {
1315  Process pTemp;
1316  Process *process = Current ()->process;
1317  std::vector<std::pair<std::string,std::string> > envs;
1318  memset (&pTemp, 0, sizeof (Process));
1319 
1320  // Parse Verify environnement and arguments
1321  if (CopyEnv (envp, envs))
1322  {
1323  return -1;
1324  }
1325  std::ostringstream interpreter, optArgs;
1326  std::string filename = std::string (path);
1327  if (CheckShellScript (path, interpreter, optArgs))
1328  {
1329  std::vector<std::string> args, lasts = CopyArgs (argv);
1330  std::string opt = optArgs.str ();
1331  std::string shell = interpreter.str ();
1332 
1333  if (opt.length () > 0)
1334  {
1335  args.push_back (opt);
1336  }
1337  args.push_back (argv0);
1338 
1339  if (lasts.size () > 0)
1340  {
1341  args.insert (args.end (), lasts.begin (), lasts.end ());
1342  }
1343 
1344  SetArgv (&pTemp, argv0, args);
1345 
1346  std::string vpath = "";
1347  char *pvpath = seek_env ("PATH", *process->penvp);
1348  if (pvpath)
1349  {
1350  vpath = std::string (pvpath);
1351  }
1352  filename = SearchExecFile (shell, vpath, getuid (), getgid (), &(Current ()->err));
1353  if (filename.length () <= 0)
1354  {
1355  return -1;
1356  }
1357  }
1358  else
1359  {
1360  SetArgv (&pTemp, path, CopyArgs (argv));
1361  }
1362  SetEnvp (&pTemp, envs);
1363  envs.clear ();
1364 
1365  std::ostringstream oss;
1366  oss << "EXEC: ";
1367  for (int i = 0; i < pTemp.originalArgc; i++)
1368  {
1369  oss << pTemp.originalArgv[i] << ' ';
1370  }
1371  std::string line = oss.str ();
1372  AppendStatusFile (process->pid, process->nodeId, line);
1373 
1374  // Try to load the code and find a MAIN
1375  Ptr<LoaderFactory> loaderFactory = this->GetObject<LoaderFactory> ();
1376  pTemp.loader = loaderFactory->Create (pTemp.originalArgc, pTemp.originalArgv, pTemp.originalEnvp);
1377 
1378  int err = 0;
1379 
1380  FILE **pstdin = process->pstdin;
1381  FILE **pstdout = process->pstdout;
1382  FILE **pstderr = process->pstderr;
1383  char ***penvp = process->penvp;
1384  char *originalProgname = process->originalProgname;
1385 
1386  std::vector<FILE *> openStreams = process->openStreams;
1387  process->openStreams.clear ();
1388  process->pstdin = 0;
1389  process->pstdout = 0;
1390  process->pstderr = 0;
1391  process->penvp = 0;
1392  process->originalProgname = pTemp.originalProgname;
1393 
1394  void *main = LoadMain (pTemp.loader, filename, &pTemp, err);
1395 
1396  if (!main)
1397  {
1398  process->pstdin = pstdin;
1399  process->pstdout = pstdout;
1400  process->pstderr = pstderr;
1401  process->penvp = penvp;
1402  process->openStreams = openStreams;
1403  process->originalProgname = originalProgname;
1404  delete pTemp.loader;
1405  pTemp.loader = 0;
1406  // delete all extra buffers
1407  while (!pTemp.allocated.empty ())
1408  {
1409  void *buffer = pTemp.allocated.back ();
1410  pTemp.allocated.pop_back ();
1411  free (buffer);
1412  }
1413  Current ()->err = err;
1414  line = "EXEC FAILED";
1415  AppendStatusFile (process->pid, process->nodeId, line);
1416  return -1;
1417  }
1418 
1419  while (!openStreams.empty ())
1420  {
1421  FILE *f = openStreams.back ();
1422  openStreams.pop_back ();
1423  if (f)
1424  {
1425  dce_fclose_onexec (f);
1426  }
1427  }
1428 
1429  // save old threads.
1430  std::vector<Thread *> Oldthreads = process->threads;
1431  process->threads.clear ();
1432 
1433  struct Thread *thread = CreateThread (process);
1434 
1435  Task *task = TaskManager::Current ()->Start (&DceManager::DoExecProcess, main,
1436  TaskManager::Current ()->GetStackSize (Current ()->task));
1437  task->SetContext (thread);
1438  task->SetSwitchNotifier (&DceManager::TaskSwitch, process);
1439  thread->task = task;
1440 
1441  // Review Process to release old stuff and put new stuff in place
1442  delete process->loader;
1443 
1444  // delete all extra buffers
1445  while (!process->allocated.empty ())
1446  {
1447  void *buffer = process->allocated.back ();
1448  process->allocated.pop_back ();
1449  free (buffer);
1450  }
1451  process->allocated = pTemp.allocated;
1452 
1453  process->loader = pTemp.loader;
1454  process->originalArgc = pTemp.originalArgc;
1455  process->originalArgv = pTemp.originalArgv;
1456  process->originalEnvp = pTemp.originalEnvp;
1457  *process->penvp = process->originalEnvp;
1458  process->name = std::string (path);
1459  process->signalHandlers.clear ();
1461  process->atExitHandlers.clear ();
1462  process->nextMid = process->nextSid = process->nextCid = 0;
1463  process->mainHandle = pTemp.mainHandle;
1464 
1465  // Remove Threads Waiters
1466  struct Thread *tmp;
1467  std::vector<Thread *> threads = Oldthreads;
1468 
1469  // First remove from wait queues: I am not more interressed of IO on Files
1470  while (!threads.empty ())
1471  {
1472  tmp = threads.back ();
1473  threads.pop_back ();
1474  CleanupThread (tmp);
1475  tmp = 0;
1476  }
1477  threads.clear ();
1478  threads = Oldthreads;
1479  // finally, delete remaining threads
1480  while (!threads.empty ())
1481  {
1482  tmp = threads.back ();
1483  threads.pop_back ();
1484  DeleteThread (tmp);
1485  }
1486  threads.clear ();
1487  Oldthreads.clear ();
1488  process->alloc->Dispose ();
1489  delete process->alloc;
1490  process->alloc = new KingsleyAlloc ();
1491 
1492  while (!process->mutexes.empty ())
1493  {
1494  Mutex * m = process->mutexes.back ();
1495  process->mutexes.pop_back ();
1496  if (m)
1497  {
1498  delete m;
1499  }
1500  }
1501 
1502  while (!process->semaphores.empty ())
1503  {
1504  Semaphore * s = process->semaphores.back ();
1505  process->semaphores.pop_back ();
1506  if (s)
1507  {
1508  delete s;
1509  }
1510  }
1511 
1512  while (!process->conditions.empty ())
1513  {
1514  Condition * c = process->conditions.back ();
1515  process->conditions.pop_back ();
1516  if (c)
1517  {
1518  delete c;
1519  }
1520  }
1521 
1522  line = "EXEC SUCCESS";
1523  AppendStatusFile (process->pid, process->nodeId, line);
1524  TaskManager::Current ()->Exit ();
1525  // NEVER REACHED
1526  return -1;
1527 }
1528 void
1530 {
1531  m_virtualPath = p;
1532 }
1533 std::string
1535 {
1536  return m_virtualPath;
1537 }
1538 } // namespace ns3