ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dce-pthread-mutex.cc
Go to the documentation of this file.
1 #include "dce-pthread.h"
2 #include "utils.h"
3 #include "process.h"
4 #include "dce-manager.h"
5 #include "ns3/assert.h"
6 #include "ns3/log.h"
7 #include <stdint.h>
8 #include <errno.h>
9 
10 NS_LOG_COMPONENT_DEFINE ("PthreadMutex");
11 
12 using namespace ns3;
13 
15 {
16  uint8_t type;
17 };
18 
19 static uint32_t
20 MutexToMid (const pthread_mutex_t *mutex)
21 {
22  NS_ASSERT (sizeof (pthread_mutex_t) >= 4);
23  if (mutex != 0)
24  {
25  const uint32_t *pmid = (const uint32_t *)mutex;
26  return *pmid;
27  }
28  return 0;
29 }
30 static void
31 MidToMutex (uint32_t mid, pthread_mutex_t *mutex)
32 {
33  uint32_t *pmid = (uint32_t *)mutex;
34  *pmid = mid;
35 }
36 
37 static void
38 PthreadMutexInitStatic (pthread_mutex_t *mutex)
39 {
40  Thread *current = Current ();
41  NS_LOG_FUNCTION (mutex);
42  // This method initializes the mutex fully when it has been
43  // initialized with PTHREAD_MUTEX_INITIALIZER.
44  struct Mutex *mtx = new Mutex ();
45  switch (mutex->__data.__kind)
46  {
47  case PTHREAD_MUTEX_RECURSIVE:
48  NS_LOG_DEBUG ("recursive");
49  mtx->type = Mutex::RECURSIVE;
50  break;
51  default:
52  NS_LOG_DEBUG ("normal");
53  mtx->type = Mutex::NORMAL;
54  break;
55  }
56  mtx->mid = current->process->nextMid;
57  current->process->nextMid++;
58  mtx->count = 0;
59  mtx->waiting.clear ();
60  mtx->current = 0;
61  current->process->mutexes.push_back (mtx);
62  MidToMutex (mtx->mid, mutex);
63 }
64 
65 static struct Mutex *
66 SearchMutex (pthread_mutex_t *mutex)
67 {
68  Thread *current = Current ();
69  if (mutex == 0)
70  {
71  return 0;
72  }
73  if (MutexToMid (mutex) == 0)
74  {
75  // this is a mutex initialized with PTHREAD_MUTEX_INITIALIZER
76  PthreadMutexInitStatic (mutex);
77  }
78  uint32_t mid = MutexToMid (mutex);
79  for (uint32_t i = 0; i < current->process->mutexes.size (); ++i)
80  {
81  struct Mutex *mtx = current->process->mutexes[i];
82  if (mtx->mid == mid)
83  {
84  return mtx;
85  }
86  }
87  return 0;
88 }
89 
90 int dce_pthread_mutex_init (pthread_mutex_t *mutex,
91  const pthread_mutexattr_t *attribute)
92 {
93  Thread *current = Current ();
94  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex << attribute);
95  NS_ASSERT (current != 0);
96  if (mutex == 0)
97  {
98  return EINVAL;
99  }
100  struct PthreadMutexAttr *attr = (struct PthreadMutexAttr *)attribute;
101  if (attr != 0
102  && attr->type != PTHREAD_MUTEX_RECURSIVE
103  && attr->type != PTHREAD_MUTEX_NORMAL)
104  {
105  return EINVAL;
106  }
107  /* Note: there is no way to detect a second attempt to initialize
108  * a mutex because there is no way to detect the difference between
109  * a mutex initialized correctly and a mutex un-initialized but filled
110  * with random garbage which happens to look like correctly-initialized
111  * data. So, we don't even try to return EBUSY.
112  */
113  struct Mutex *mtx = new Mutex ();
114  mtx->mid = current->process->nextMid;
115  current->process->nextMid++;
116  if (attr == 0 || attr->type != PTHREAD_MUTEX_RECURSIVE)
117  {
118  mtx->type = Mutex::NORMAL;
119  }
120  else if (attr != 0 || attr->type == PTHREAD_MUTEX_RECURSIVE)
121  {
122  mtx->type = Mutex::RECURSIVE;
123  }
124  else
125  {
126  NS_ASSERT (false);
127  }
128  mtx->count = 0;
129  mtx->waiting.clear ();
130  mtx->current = 0;
131  current->process->mutexes.push_back (mtx);
132 
133  MidToMutex (mtx->mid, mutex);
134 
135  return 0;
136 }
137 int dce_pthread_mutex_destroy (pthread_mutex_t *mutex)
138 {
139  Thread *current = Current ();
140  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
141  NS_ASSERT (current != 0);
142  struct Mutex *mtx = SearchMutex (mutex);
143  if (mtx == 0)
144  {
145  return EINVAL;
146  }
147  if (mtx->current != 0 || !mtx->waiting.empty ())
148  {
149  /* Someone (potentially us) is holding this mutex
150  * or someone is waiting for this mutex.
151  */
152  return EBUSY;
153  }
154  // If no one is holding this mutex, its count should be zero.
155  NS_ASSERT (mtx->count == 0);
156 
157  for (std::vector<struct Mutex *>::iterator i = current->process->mutexes.begin ();
158  i != current->process->mutexes.end (); ++i)
159  {
160  if (mtx == *i)
161  {
162  delete mtx;
163  mtx = 0;
164  current->process->mutexes.erase (i);
165  break;
166  }
167  }
168  NS_ASSERT (mtx == 0);
169  MidToMutex (2, mutex);
170 
171  return 0;
172 }
173 int dce_pthread_mutex_lock (pthread_mutex_t *mutex)
174 {
175  Thread *current = Current ();
176  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
177  NS_ASSERT (current != 0);
178  struct Mutex *mtx = SearchMutex (mutex);
179  if (mtx == 0)
180  {
181  return EINVAL;
182  }
183  if (current == mtx->current)
184  {
185  if (mtx->type == Mutex::RECURSIVE)
186  {
187  mtx->count++;
188  return 0;
189  }
190  else if (mtx->type == Mutex::NORMAL)
191  {
192  return EDEADLK;
193  }
194  else
195  {
196  NS_ASSERT (false);
197  }
198  }
199  while (mtx->current != 0)
200  {
201  mtx->waiting.push_back (current);
202  current->process->manager->Wait ();
203  mtx->waiting.remove (current);
204  }
205  NS_ASSERT (mtx->current == 0);
206  mtx->current = current;
207  mtx->count++;
208 
209  return 0;
210 }
211 int dce_pthread_mutex_trylock (pthread_mutex_t *mutex)
212 {
213  Thread *current = Current ();
214  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
215  NS_ASSERT (current != 0);
216  struct Mutex *mtx = SearchMutex (mutex);
217  if (mtx == 0)
218  {
219  return EINVAL;
220  }
221  if (mtx->type == Mutex::RECURSIVE)
222  {
223  if (mtx->current == 0)
224  {
225  mtx->current = current;
226  mtx->count++;
227  return 0;
228  }
229  else if (mtx->current == current)
230  {
231  mtx->count++;
232  return 0;
233  }
234  else
235  {
236  return EBUSY;
237  }
238  }
239  else if (mtx->type == Mutex::NORMAL)
240  {
241  if (mtx->current == 0)
242  {
243  mtx->count++;
244  mtx->current = current;
245  return 0;
246  }
247  else
248  {
249  // even if mtx->current == current
250  // according to IEEE Std 1003.1, 2004
251  return EBUSY;
252  }
253  }
254  else
255  {
256  NS_ASSERT (false);
257  }
258  // quiet compiler.
259  return 0;
260 }
261 int dce_pthread_mutex_unlock (pthread_mutex_t *mutex)
262 {
263  Thread *current = Current ();
264  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
265  NS_ASSERT (current != 0);
266  struct Mutex *mtx = SearchMutex (mutex);
267  if (mtx == 0)
268  {
269  return EINVAL;
270  }
271  if (mtx->current == 0
272  || mtx->current != current)
273  {
274  return EPERM;
275  }
276  mtx->count--;
277  if (mtx->count == 0)
278  {
279  mtx->current = 0;
280  // Now, we tell the first waiting thread that
281  // it can potentially take the lock. Note that
282  // there are lots of different possible policies
283  // here. We could wake up everybody and let the
284  // process scheduler pick the highest priority
285  // thread, we could attempt to find a better candidate
286  // here locally to avoid waking up lots of threads only
287  // to bring them back to sleep after they wake up because
288  // they just realized that someone stole the lock from
289  // them, etc. What we do, instead, is implement the simplest
290  // "fair" policy by ensuring that every thread
291  // is woken up in FIFO order.
292  Thread *waiting = mtx->waiting.front ();
293  if (waiting != 0)
294  {
295  current->process->manager->Wakeup (waiting);
296  // give them a chance to run.
297  current->process->manager->Yield ();
298  }
299  }
300  return 0;
301 }
302 int dce_pthread_mutexattr_init (pthread_mutexattr_t *attribute)
303 {
304  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << attribute);
305  NS_ASSERT (Current () != 0);
306  if (attribute == 0)
307  {
308  return EINVAL;
309  }
310  NS_ASSERT (sizeof(struct PthreadMutexAttr) <= sizeof (pthread_mutexattr_t));
311  struct PthreadMutexAttr *attr = (struct PthreadMutexAttr *)attribute;
312  attr->type = PTHREAD_MUTEX_NORMAL;
313  return 0;
314 }
315 int dce_pthread_mutexattr_destroy (pthread_mutexattr_t *attribute)
316 {
317  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << attribute);
318  NS_ASSERT (Current () != 0);
319  if (attribute == 0)
320  {
321  return EINVAL;
322  }
323  return 0;
324 }
325 int dce_pthread_mutexattr_settype (pthread_mutexattr_t *attribute, int kind)
326 {
327  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << attribute << kind);
328  NS_ASSERT (Current () != 0);
329  if (attribute == 0)
330  {
331  return EINVAL;
332  }
333  struct PthreadMutexAttr *attr = (struct PthreadMutexAttr *)attribute;
334  attr->type = kind;
335  return 0;
336 }