ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dce-pthread.cc
Go to the documentation of this file.
1 #include "dce-pthread.h"
2 #include "dce-signal.h"
3 #include "dce-unistd.h"
4 #include "dce-manager.h"
5 #include "process.h"
6 #include "utils.h"
7 #include "dce-cxa.h"
8 #include "dce-stdio.h"
9 #include "loader-factory.h"
10 #include "task-manager.h"
11 #include "kingsley-alloc.h"
12 #include "ns3/log.h"
13 #include "ns3/simulator.h"
14 #include <errno.h>
15 #include <signal.h>
16 #include <list>
17 
18 NS_LOG_COMPONENT_DEFINE ("SimuPthread");
19 
20 using namespace ns3;
21 
22 static uint16_t
23 PthreadToTid (pthread_t thread_handle)
24 {
25  NS_ASSERT (sizeof (pthread_t) >= 4);
26  return (thread_handle >> 16) & 0xffff;
27 }
28 
29 static uint16_t
30 PthreadToPid (pthread_t thread_handle)
31 {
32  NS_ASSERT (sizeof (pthread_t) >= 4);
33  return thread_handle & 0xffff;
34 }
35 
36 static pthread_t
37 PidTidToPthread (uint16_t pid, uint16_t tid)
38 {
39  NS_ASSERT (sizeof (pthread_t) >= 4);
40  uint32_t th = tid;
41  th <<= 16;
42  th |= pid;
43  return th;
44 }
45 
46 static void
48 {
49  Thread *current = Current ();
50  // From this function, we perform process cleanup which _requires_
51  // a user context. here delete the keys of each thread which might
52  // require calling a key destructor in the process.
53  for (std::list<ThreadKeyValue>::iterator j = current->keyValues.begin ();
54  j != current->keyValues.end (); ++j)
55  {
56  NS_LOG_DEBUG ("destroy key " << j->key << " " << j->destructor << " " << j->value);
57  if (j->destructor != 0 && j->value != 0)
58  {
59  void *v = j->value;
60  // according to the posix spec, we must
61  // set the value to zero before invoking the
62  // destructor.
63  j->value = 0;
64  j->destructor (v);
65  }
66  }
67  current->keyValues.clear ();
68 }
69 
70 void dce_exit (int status)
71 {
72  Thread *current = Current ();
73  std::ostringstream oss;
74  std::string line;
75 
76  NS_LOG_FUNCTION (current << UtilsGetNodeId () << status);
77  NS_ASSERT (current != 0);
80  dce_fflush (0);
81  current->process->timing.exitValue = __W_EXITCODE (status, WTERMSIG (current->process->timing.exitValue));
82  current->process->timing.ns3End = Now ().GetNanoSeconds ();
83  current->process->timing.realEnd = time (0);
84 
85  current->task->SetSwitchNotifier (0, 0);
86  current->process->loader->UnloadAll ();
87 
88  oss << "Exit (" << status << ")";
89  line = oss.str ();
90  DceManager::AppendStatusFile (current->process->pid, current->process->nodeId, line);
92 
95 }
96 
98 {
99  void *(*start_routine)(void*);
100  void *arg;
101 };
102 
103 static void pthread_do_start (void *context)
104 {
105  struct PthreadStartContext *pctx = (struct PthreadStartContext *)context;
106  struct PthreadStartContext ctx = *pctx;
107  delete pctx;
108  void *retval = ctx.start_routine (ctx.arg);
109  dce_pthread_exit (retval);
110 }
111 
112 static void PthreadTaskSwitch (enum Task::SwitchType type, void *context)
113 {
114  Process *process = (Process *) context;
115  switch (type)
116  {
117  case Task::TO:
118  process->loader->NotifyStartExecute ();
119  process->alloc->SwitchTo ();
120  break;
121  case Task::FROM:
122  process->loader->NotifyEndExecute ();
123  break;
124  }
125 }
126 
127 int dce_pthread_create (pthread_t *thread_handle,
128  const pthread_attr_t *attr,
129  void *(*start_routine)(void*),
130  void *arg)
131 {
132  Thread *current = Current ();
133  NS_LOG_FUNCTION (current << UtilsGetNodeId () << arg);
134  NS_ASSERT (current != 0);
135  Thread *thread = current->process->manager->CreateThread (current->process);
136  *thread_handle = PidTidToPthread (thread->process->pid, thread->tid);
137  TaskManager *manager = TaskManager::Current ();
138  PthreadStartContext *startContext = new PthreadStartContext ();
139  startContext->start_routine = start_routine;
140  startContext->arg = arg;
141  uint32_t mainStackSize = manager->GetStackSize (current->process->threads[0]->task);
142  Task *task = manager->Start (&pthread_do_start, startContext, mainStackSize);
143  task->SetContext (thread);
144  task->SetSwitchNotifier (&PthreadTaskSwitch, current->process);
145  thread->task = task;
146  manager->Yield ();
147  return 0;
148 }
149 void dce_pthread_exit (void *arg)
150 {
151  Thread *current = Current ();
152  NS_LOG_FUNCTION (current << UtilsGetNodeId () << arg);
153  NS_ASSERT (current != 0);
154  Process *process = current->process;
155  if (process->threads.size () == 1)
156  {
157  // call below does not return
158  dce_exit (0);
159  }
161  if (!current->isDetached)
162  {
163  current->hasExitValue = true;
164  current->exitValue = arg;
165  if (current->joinWaiter != 0)
166  {
167  current->process->manager->Wakeup (current->joinWaiter);
168  }
169  // thread will be deleted by joining thread.
170  // but we clear this up to make sure that DeleteThread
171  // does not try to 'Stop' the task because the call to
172  // Exit below will effectively delete the task.
173  current->task = 0;
174  }
175  else
176  {
177  current->process->manager->DeleteThread (current);
178  }
179  TaskManager::Current ()->Exit ();
180 }
181 int dce_pthread_join (pthread_t thread_handle, void **value_ptr)
182 {
183  Thread *current = Current ();
184  NS_LOG_FUNCTION (current << UtilsGetNodeId () << PthreadToPid (thread_handle) << PthreadToTid (thread_handle));
185  NS_ASSERT (current != 0);
186  NS_ASSERT (current->process->pid == PthreadToPid (thread_handle));
187  if (current->tid == PthreadToTid (thread_handle))
188  {
189  return EDEADLK;
190  }
191 
192  Thread *thread = current->process->manager->SearchThread (PthreadToPid (thread_handle),
193  PthreadToTid (thread_handle));
194  if (thread == 0)
195  {
196  return ESRCH;
197  }
198  if (thread->isDetached || thread->joinWaiter != 0)
199  {
200  /* If someone has already joined this thread, we do not
201  * allow joining it again.
202  */
203  return EINVAL;
204  }
205 
206  while (!thread->hasExitValue)
207  {
208  thread->joinWaiter = current;
209  current->process->manager->Wait ();
210  thread->joinWaiter = 0;
211  }
212  NS_ASSERT (!thread->isDetached);
213  NS_ASSERT (thread->hasExitValue);
214  if (value_ptr != NULL)
215  {
216  *value_ptr = thread->exitValue;
217  }
218  thread->isDetached = true;
219  current->process->manager->DeleteThread (thread);
220  return 0;
221 }
222 int dce_pthread_detach (pthread_t thread_handle)
223 {
224  Thread *current = Current ();
225  NS_LOG_FUNCTION (current << UtilsGetNodeId () << PthreadToPid (thread_handle) << PthreadToTid (thread_handle));
226  NS_ASSERT (current != 0);
227  Thread *thread = current->process->manager->SearchThread (PthreadToPid (thread_handle),
228  PthreadToTid (thread_handle));
229  if (thread == 0)
230  {
231  return ESRCH;
232  }
233  if (thread->isDetached)
234  {
235  return EINVAL;
236  }
237  if (thread->joinWaiter != 0)
238  {
239  // the standard does not specify what should happen in this case
240  // but this is the behavior chosen by nptl so, we mimick it
241  // to minimize application behavior changes.
242  return 0;
243  }
244  thread->isDetached = true;
245  return 0;
246 }
247 int dce_pthread_cancel (pthread_t thread)
248 {
249  // XXX
250  return 0;
251 }
252 pthread_t dce_pthread_self (void)
253 {
254  Thread *current = Current ();
255  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
256  NS_ASSERT (current != 0);
257  return PidTidToPthread (current->process->pid, current->tid);
258 }
259 
260 int dce_pthread_once (pthread_once_t *once_control, void (*init_routine)(void))
261 {
262  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << once_control << init_routine);
263  NS_ASSERT (Current () != 0);
264  if (once_control == 0 || init_routine == 0)
265  {
266  return EINVAL;
267  }
268  if (*once_control == 1)
269  {
270  return 0;
271  }
272  *once_control = 1;
273  (*init_routine)();
274  return 0;
275 }
276 
277 static bool
278 IsKeyValid (pthread_key_t key)
279 {
280  Thread *current = Current ();
281  for (std::list<struct ThreadKeyValue>::const_iterator i = current->keyValues.begin ();
282  i != current->keyValues.end (); ++i)
283  {
284  if (i->key == key)
285  {
286  return true;
287  }
288  }
289  return false;
290 }
291 void * dce_pthread_getspecific (pthread_key_t key)
292 {
293  Thread *current = Current ();
294  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key);
295  NS_ASSERT (current != 0);
296  for (std::list<struct ThreadKeyValue>::const_iterator i = current->keyValues.begin ();
297  i != current->keyValues.end (); ++i)
298  {
299  if (i->key == key)
300  {
301  return i->value;
302  }
303  }
304  return 0;
305 }
306 int dce_pthread_setspecific (pthread_key_t key, const void *value)
307 {
308  Thread *current = Current ();
309  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key << value);
310  NS_ASSERT (current != 0);
311  for (std::list<struct ThreadKeyValue>::iterator i = current->keyValues.begin ();
312  i != current->keyValues.end (); ++i)
313  {
314  if (i->key == key)
315  {
316  i->value = const_cast<void *> (value);
317  return 0;
318  }
319  }
320  // invalid key
321  return EINVAL;
322 }
323 int dce_pthread_key_create (pthread_key_t *key, void (*destructor)(void*))
324 {
325  Thread *current = Current ();
326  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key << destructor);
327  NS_ASSERT (current != 0);
328  pthread_key_t tmp = 2;
329  // this is a totally arbitrary limit on the total number of thread keys per process.
330  while (tmp < 100000)
331  {
332  if (!IsKeyValid (tmp))
333  {
334  struct ThreadKeyValue value;
335  value.key = tmp;
336  value.destructor = destructor;
337  value.value = 0;
338  // store the key in each thread of the process.
339  struct Process *process = current->process;
340  for (std::vector<struct Thread *>::const_iterator i = process->threads.begin ();
341  i != process->threads.end (); ++i)
342  {
343  struct Thread *thread = *i;
344  thread->keyValues.push_back (value);
345  }
346  *key = tmp;
347  return 0;
348  }
349  tmp++;
350  }
351  return EAGAIN;
352 }
353 int dce_pthread_key_delete (pthread_key_t key)
354 {
355  Thread *current = Current ();
356  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key);
357  NS_ASSERT (current != 0);
358  if (!IsKeyValid (key))
359  {
360  return EINVAL;
361  }
362  struct Process *process = current->process;
363  for (std::vector<struct Thread *>::const_iterator i = process->threads.begin ();
364  i != process->threads.end (); ++i)
365  {
366  struct Thread *thread = *i;
367  bool found = false;
368  for (std::list<struct ThreadKeyValue>::iterator j = thread->keyValues.begin ();
369  j != thread->keyValues.end (); ++j)
370  {
371  if (j->key == key)
372  {
373  found = true;
374  thread->keyValues.erase (j);
375  break;
376  }
377  }
378  NS_ASSERT (found);
379  }
380  return 0;
381 }
382 int dce_pthread_kill (pthread_t th, int sig)
383 {
384  Thread *current = Current ();
385  NS_LOG_FUNCTION (current << UtilsGetNodeId () << PthreadToPid (th) << PthreadToTid (th) << sig);
386  NS_ASSERT (current != 0);
387  Thread *thread = current->process->manager->SearchThread (PthreadToPid (th),
388  PthreadToTid (th));
389  if (thread == 0)
390  {
391  return ESRCH;
392  }
393 
394  sigaddset (&thread->pendingSignals, sig);
395  if (sigismember (&thread->signalMask, sig) == 0)
396  {
397  // signal not blocked by thread.
398  if (thread->task->IsBlocked ())
399  {
400  thread->process->manager->Wakeup (thread);
401  }
402  }
403 
404  return 0;
405 }
406 #if 0
407 int dce_pthread_sigmask (int how, const sigset_t *restrict set,
408  sigset_t *restrict oset)
409 {
410  // XXX implement
411  return 0;
412 }
413 int dce_sigprocmask (int how, const sigset_t *restrict set,
414  sigset_t *restrict oset)
415 {
416  // XXX implement
417  return 0;
418 }
419 #endif