IBR-DTNSuite  0.10
Thread.cpp
Go to the documentation of this file.
1 /*
2  * Thread.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrcommon/config.h"
25 #include "ibrcommon/Logger.h"
26 #include <stdexcept>
27 #include <pthread.h>
28 #include <stdio.h>
29 #include <signal.h>
30 
31 #ifdef _WIN32
32 #include <windows.h>
33 #elif MACOS
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #else
37 #include <unistd.h>
38 #endif
39 
40 #ifdef __DEVELOPMENT_ASSERTIONS__
41 #include <cassert>
42 #endif
43 
44 namespace ibrcommon
45 {
47  {
48 #ifdef WIN32
49  SYSTEM_INFO sysinfo;
50  GetSystemInfo(&sysinfo);
51  return sysinfo.dwNumberOfProcessors;
52 #elif MACOS
53  int nm[2];
54  size_t len = 4;
55  uint32_t count;
56 
57  nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
58  sysctl(nm, 2, &count, &len, NULL, 0);
59 
60  if(count < 1) {
61  nm[1] = HW_NCPU;
62  sysctl(nm, 2, &count, &len, NULL, 0);
63  if(count < 1) { count = 1; }
64  }
65  return count;
66 #else
67  return sysconf(_SC_NPROCESSORS_ONLN);
68 #endif
69  }
70 
71  void* Thread::__execute__(void *obj) throw ()
72  {
73 #ifdef __DEVELOPMENT_ASSERTIONS__
74  // the given object should never be null
75  assert(obj != NULL);
76 #endif
77  // cast the thread object
78  Thread *th = static_cast<Thread *>(obj);
79 
80  // set the state to running
81  th->_state = THREAD_RUNNING;
82 
83  // run threads run routine
84  th->run();
85 
86  // set the state to finalizing, blocking all threads until this is done
87  th->_state = THREAD_FINALIZING;
88 
89  // call the finally method
90  th->finally();
91 
92  // delete the thread-object is requested
93  if (th->_detached) {
94  th->_state = THREAD_FINALIZED;
95  delete th;
96  } else {
97  // set the state to JOINABLE
98  th->_state = THREAD_JOINABLE;
99  }
100 
101  // exit the thread
102  return NULL;
103  }
104 
105  Thread::Thread(size_t size)
106  : _state(THREAD_CREATED, THREAD_FINALIZED), tid(0), stack(size), priority(0), _detached(false)
107  {
108  pthread_attr_init(&attr);
109  }
110 
111  void Thread::yield(void)
112  {
113 #if defined(HAVE_PTHREAD_YIELD_NP)
114  pthread_yield_np();
115 #elif defined(HAVE_PTHREAD_YIELD)
116  pthread_yield();
117 #else
118  sched_yield();
119 #endif
120  }
121 
122  void Thread::concurrency(int level)
123  {
124  #if defined(HAVE_PTHREAD_SETCONCURRENCY)
125  pthread_setconcurrency(level);
126  #endif
127  }
128 
129  void Thread::sleep(time_t timeout)
130  {
131  #if defined(HAVE_PTHREAD_DELAY)
132  timespec ts;
133  ts.tv_sec = timeout / 1000l;
134  ts.tv_nsec = (timeout % 1000l) * 1000000l;
135  pthread_delay(&ts);
136  #elif defined(HAVE_PTHREAD_DELAY_NP)
137  timespec ts;
138  ts.tv_sec = timeout / 1000l;
139  ts.tv_nsec = (timeout % 1000l) * 1000000l;
140  pthread_delay_np(&ts);
141  #else
142  usleep(static_cast<useconds_t>(timeout) * 1000);
143  #endif
144  }
145 
147  {
148  pthread_attr_destroy(&attr);
149  }
150 
152  {
153  if ( _state != THREAD_FINALIZED )
154  throw ThreadException(0, "invalid state for reset");
155 
156  pthread_attr_destroy(&attr);
157 
159  tid = 0;
160  _detached = false;
161 
162  pthread_attr_init(&attr);
163  }
164 
165  int Thread::kill(int sig)
166  {
167  if (tid == 0) return -1;
168  return pthread_kill(tid, sig);
169  }
170 
171  void Thread::cancel() throw ()
172  {
173  // block multiple cancel calls
174  {
176 
177  // if the thread never has been started: exit and deny any further startup
178  if (ls == THREAD_CREATED)
179  {
180  ls = THREAD_FINALIZED;
181  return;
182  }
183 
184  if ((ls == THREAD_CANCELLED) || (ls == THREAD_FINALIZED) || (ls == THREAD_JOINABLE) || (ls == THREAD_FINALIZING)) return;
185 
186  // wait until a state is reached where cancellation is possible
188 
189  // exit if the thread is not running
190  if (ls != THREAD_RUNNING) return;
191 
192  // set state to cancelled
193  ls = THREAD_CANCELLED;
194  }
195 
196  // run custom cancellation
197  __cancellation();
198  }
199 
200  bool Thread::equal(pthread_t t1, pthread_t t2)
201  {
202  return (pthread_equal(t1, t2) != 0);
203  }
204 
205  bool Thread::isFinalized() throw ()
206  {
207  return _state == THREAD_FINALIZED;
208  }
209 
211  : Thread(size)
212  {
213  }
214 
216  {
217 #ifdef __DEVELOPMENT_ASSERTIONS__
218  // every thread should be joined, when the destructor is called.
219  if ( _state != THREAD_FINALIZED )
220  {
221  std::cerr << "FAILURE: Thread not finalized before! Current state:" << _state.get() << std::endl;
222  assert( _state != THREAD_FINALIZED );
223  }
224 #endif
225  join();
226  }
227 
229  {
230  int ret;
231 
232  // switch to STARTED only if this is a fresh thread
233  {
235 
236  // only start once
237  if (ls != THREAD_CREATED) return;
238 
239  // set the thread state to STARTED
240  ls = THREAD_STARTED;
241  }
242 
243  // set priority
244  priority = adj;
245 
246  // call the setup method
247  setup();
248 
249  // set the state to running
250  _state = THREAD_INITIALIZED;
251 
252 #ifndef __PTH__
253  // modify the threads attributes - set as joinable thread
254  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
255 
256 #ifndef ANDROID
257  // ignore scheduling policy and use the same as the parent
258  pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
259 #endif
260 #endif
261  // we typically use "stack 1" for min stack...
262 #ifdef PTHREAD_STACK_MIN
263  // if the given stack size is too small...
264  if(stack && stack < PTHREAD_STACK_MIN)
265  {
266  // set it to the min stack size
267  stack = PTHREAD_STACK_MIN;
268  }
269 #else
270  // if stack size if larger than zero and smaller than two...
271  if (stack && stack < 2)
272  {
273  // set it to zero (we will not set the stack size)
274  stack = 0;
275  }
276 #endif
277 
278 #ifdef __PTH__
279  // spawn a new thread
280  tid = pth_spawn(PTH_ATTR_DEFAULT, &Thread::__execute__, this);
281 #else
282  // if the stack size is specified (> 0)
283  if (stack)
284  {
285  // set the stack size attribute
286  pthread_attr_setstacksize(&attr, stack);
287  }
288 
289  // spawn a new thread
290  ret = pthread_create(&tid, &attr, &Thread::__execute__, this);
291 
292  switch (ret)
293  {
294  case EAGAIN:
295  _state = THREAD_FINALIZED;
296  throw ThreadException(ret, "The system lacked the necessary resources to create another thread, or the system-imposed limit on the total number of threads in a process PTHREAD_THREADS_MAX would be exceeded.");
297  case EINVAL:
298  _state = THREAD_FINALIZED;
299  throw ThreadException(ret, "The value specified by attr is invalid.");
300  case EPERM:
301  _state = THREAD_FINALIZED;
302  throw ThreadException(ret, "The caller does not have appropriate permission to set the required scheduling parameters or scheduling policy.");
303  }
304 #endif
305  }
306 
307  void JoinableThread::stop() throw ()
308  {
309  Thread::cancel();
310  }
311 
313  {
315 
316  // if the thread never has been started: exit and deny any further startup
317  if (ls == THREAD_CREATED)
318  {
319  ls = THREAD_FINALIZED;
320  return;
321  }
322 
323  // wait until the finalized state is reached
325 
326  // if the thread has been joined already: exit
327  if (ls == THREAD_FINALIZED) return;
328 
329  // get the thread-id of the calling thread
330  pthread_t self = pthread_self();
331 
332 #ifdef __DEVELOPMENT_ASSERTIONS__
333  // never try to join our own thread, check this here
334  assert( !equal(tid, self) );
335 #endif
336 
337  // if the thread has been started, do join
338  int ret = 0;
339  if ((ret = pthread_join(tid, NULL)) == 0)
340  {
341  // set the state to joined
342  ls = THREAD_FINALIZED;
343  }
344  else
345  {
346  throw ThreadException(ret, "Join on a thread failed");
347  }
348  }
349 
351  {
352  }
353 
355  {
356  }
357 
359  {
360  int ret = 0;
361 
362  // switch to STARTED only if this is a fresh thread
363  {
365 
366  // only start once
367  if (ls != THREAD_CREATED) return;
368 
369  // set the thread state to STARTED
370  ls = THREAD_STARTED;
371  }
372 
373  // set the priority
374  priority = adj;
375 
376  // call the setup method
377  setup();
378 
379  // set the state to running
380  _state = THREAD_INITIALIZED;
381 
382 #ifndef __PTH__
383  // modify the threads attributes - set as detached thread
384  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
385 
386 #ifndef ANDROID
387  // ignore scheduling policy and use the same as the parent
388  pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
389 #endif
390 #endif
391  // we typically use "stack 1" for min stack...
392 #ifdef PTHREAD_STACK_MIN
393  // if the given stack size is too small...
394  if(stack && stack < PTHREAD_STACK_MIN)
395  {
396  // set it to the min stack size
397  stack = PTHREAD_STACK_MIN;
398  }
399 #else
400  // if stack size if larger than zero and smaller than two...
401  if (stack && stack < 2)
402  {
403  // set it to zero (we will not set the stack size)
404  stack = 0;
405  }
406 #endif
407 
408 #ifdef __PTH__
409  // spawn a new thread
410  tid = pth_spawn(PTH_ATTR_DEFAULT, &Thread::__execute__, this);
411 #else
412  // if the stack size is specified (> 0)
413  if (stack)
414  {
415  // set the stack size attribute
416  pthread_attr_setstacksize(&attr, stack);
417  }
418 
419  // set this thread as detached
420  _detached = true;
421 
422  // spawn a new thread
423  ret = pthread_create(&tid, &attr, &Thread::__execute__, this);
424 
425  // check for errors
426  switch (ret)
427  {
428  case EAGAIN:
429  _state = THREAD_FINALIZED;
430  throw ThreadException(ret, "The system lacked the necessary resources to create another thread, or the system-imposed limit on the total number of threads in a process PTHREAD_THREADS_MAX would be exceeded.");
431  case EINVAL:
432  _state = THREAD_FINALIZED;
433  throw ThreadException(ret, "The value specified by attr is invalid.");
434  case EPERM:
435  _state = THREAD_FINALIZED;
436  throw ThreadException(ret, "The caller does not have appropriate permission to set the required scheduling parameters or scheduling policy.");
437  }
438 #endif
439  }
440 
442  {
443  Thread::cancel();
444  }
445 }