ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ucontext-fiber-manager.cc
Go to the documentation of this file.
1 #define _GNU_SOURCE 1
3 #include "ns3/fatal-error.h"
4 #include "ns3/assert.h"
5 #include <ucontext.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <stdint.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <malloc.h>
14 #include <sys/mman.h>
15 #include <link.h>
16 
17 #ifdef HAVE_VALGRIND_H
18 # include "valgrind/valgrind.h"
19 #else
20 # define VALGRIND_STACK_REGISTER(start,end) (0)
21 # define VALGRIND_STACK_DEREGISTER(id)
22 #endif
23 
24 
25 namespace ns3 {
26 
28 std::list<unsigned long> UcontextFiberManager::g_guardPages;
29 
30 struct UcontextFiber : public Fiber
31 {
32  uint8_t *stack;
33  uint32_t stackSize;
34  ucontext_t context;
35  unsigned int vgId;
36 };
37 void
38 UcontextFiberManager::SegfaultHandler (int sig, siginfo_t *si, void *unused)
39 {
40  int pagesize = sysconf (_SC_PAGE_SIZE);
41  if (pagesize == -1)
42  {
43  NS_FATAL_ERROR ("Unable to query page size");
44  }
45  unsigned long page = (unsigned long) si->si_addr;
46  page = page - (page % pagesize);
47  for (std::list<unsigned long>::iterator i = g_guardPages.begin ();
48  i != g_guardPages.end (); ++i)
49  {
50  if (*i == page)
51  {
52  // This is a stack overflow: all we can do is print some error message
53  {
54  char message[] = "Stack overflow !";
55  write (2, message, strlen (message));
56  }
57  break;
58  }
59  }
60 }
61 
62 void
64 {
66 }
67 
68 void
70 {
71  static bool alreadySetup = false;
72  if (alreadySetup)
73  {
74  return;
75  }
76  alreadySetup = true;
77 
78  stack_t ss;
79 
86  ss.ss_sp = malloc (SIGSTKSZ);
87  ss.ss_size = SIGSTKSZ;
88  ss.ss_flags = 0;
89  int status = sigaltstack (&ss, NULL);
90  if (status == -1)
91  {
92  NS_FATAL_ERROR ("Unable to setup an alternate signal stack handler, errno="
93  << strerror (errno));
94  }
95  g_alternateSignalStack = ss.ss_sp;
96 
97  atexit (&FreeAlternateSignalStack);
98 
99  struct sigaction sa;
100  sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESETHAND;
101  sigemptyset (&sa.sa_mask);
102  sa.sa_sigaction = &UcontextFiberManager::SegfaultHandler;
103  status = sigaction (SIGSEGV, &sa, NULL);
104  if (status == -1)
105  {
106  NS_FATAL_ERROR ("Unable to setup page fault handler, errno="
107  << strerror (errno));
108  }
109 }
110 
111 uint32_t
113 {
114  int pagesize = sysconf (_SC_PAGE_SIZE);
115  if (pagesize == -1)
116  {
117  NS_FATAL_ERROR ("Unable to query page size");
118  }
119 
120  if ((size % pagesize) == 0)
121  {
122  return size + 2 * pagesize;
123  }
124  else
125  {
126  return size + (pagesize - (size % pagesize)) + 2 * pagesize;
127  }
128 }
129 
130 uint8_t *
132 {
133  int pagesize = sysconf (_SC_PAGE_SIZE);
134  if (pagesize == -1)
135  {
136  NS_FATAL_ERROR ("Unable to query page size");
137  }
138 
140 
141  uint32_t realSize = CalcStackSize (size);
142  void *map = mmap (0, realSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
143  if (map == MAP_FAILED)
144  {
145  NS_FATAL_ERROR ("Unable to allocate stack pages: size=" << size <<
146  ", alloced=" << realSize <<
147  ", errno=" << strerror (errno));
148  }
149  uint8_t *stack = (uint8_t *)map;
150  int status = mprotect (stack + pagesize, realSize - 2 * pagesize, PROT_READ | PROT_WRITE);
151  if (status == -1)
152  {
153  NS_FATAL_ERROR ("Unable to protect bottom of stack space, errno=" << strerror (errno));
154  }
155  g_guardPages.push_back ((unsigned long)stack);
156  return stack + pagesize;
157 }
158 void
160  uint32_t stackSize)
161 {
162  int pagesize = sysconf (_SC_PAGE_SIZE);
163  if (pagesize == -1)
164  {
165  NS_FATAL_ERROR ("Unable to query page size, errno=" << strerror (errno));
166  }
167  uint32_t realSize = CalcStackSize (stackSize);
168  int status = munmap (buffer - pagesize, realSize);
169  if (status == -1)
170  {
171  NS_FATAL_ERROR ("Unable to unmap stack, errno=" << strerror (errno));
172  }
173  unsigned long guard = (unsigned long)(buffer - pagesize);
174  g_guardPages.remove (guard);
175 }
176 
178  : m_notifySwitch (0)
179 {
180 }
182 {
183 }
184 
185 void
186 UcontextFiberManager::Trampoline (int a0, int a1, int a2, int a3)
187 {
188  NS_ASSERT (sizeof(int) >= 4);
189  uint64_t fn = 0;
190  fn |= (uint32_t)a0;
191  fn <<= 32;
192  fn |= (uint32_t)a1;
193  uint64_t ctx = 0;
194  ctx |= (uint32_t)a2;
195  ctx <<= 32;
196  ctx |= (uint32_t)a3;
197 
198  void (*cb)(void *) = (void (*) (void*))fn;
199  cb ((void*)ctx);
200 }
201 
202 struct Fiber *
203 UcontextFiberManager::Create (void (*callback)(void *),
204  void *context,
205  uint32_t stackSize)
206 {
207  struct UcontextFiber *fiber = new struct UcontextFiber ();
208  uint8_t *stack;
209  int retval;
210 
211  stack = AllocateStack (stackSize);
212  fiber->vgId = VALGRIND_STACK_REGISTER (stack,stack + stackSize);
213  fiber->stack = stack;
214  fiber->stackSize = stackSize;
215 
216  retval = getcontext (&fiber->context);
217  NS_ASSERT (retval != -1);
218  fiber->context.uc_stack.ss_sp = stack;
219  fiber->context.uc_stack.ss_size = stackSize;
220  // make sure the thread exits when it completes.
221  fiber->context.uc_link = NULL;
222 
223  uint64_t cb = (uint64_t)callback;
224  uint64_t ctx = (uint64_t)context;
225  uint32_t a0 = cb >> 32;
226  uint32_t a1 = cb & 0xffffffff;
227  uint32_t a2 = ctx >> 32;
228  uint32_t a3 = ctx & 0xffffffff;
229  void (*fn)() = (void (*) ()) & UcontextFiberManager::Trampoline;
230  makecontext (&fiber->context, fn, 4, a0, a1, a2, a3);
231 
232  return fiber;
233 }
234 
235 struct Fiber *
237 {
238  struct UcontextFiber *fiber = new struct UcontextFiber ();
239  fiber->stack = 0;
240  fiber->stackSize = 0;
241  return fiber;
242 }
243 
244 void
246 {
247  struct UcontextFiber *fiber = (struct UcontextFiber *)fib;
249  if (fiber->stack != 0)
250  {
251  DeallocateStack (fiber->stack, fiber->stackSize);
252  }
253  fiber->stack = 0;
254  fiber->stackSize = 0xdeadbeaf;
255  delete fiber;
256 }
257 
258 void
260  const struct Fiber *toFiber)
261 {
262  struct UcontextFiber *from = (struct UcontextFiber *)fromFiber;
263  struct UcontextFiber *to = (struct UcontextFiber *)toFiber;
264  swapcontext (&from->context, &to->context);
265  if (m_notifySwitch != 0)
266  {
267  m_notifySwitch ();
268  }
269 }
270 
271 uint32_t
273 {
274  struct UcontextFiber *fiber = (struct UcontextFiber *)fib;
275  return fiber->stackSize;
276 }
277 
278 void
280 {
281  m_notifySwitch = fn;
282 }
283 
284 
285 
286 } // namespace ns3