ONPOSIX  2.0
 All Classes Namespaces Files Functions Variables Enumerator Friends Macros Pages
AbstractThread.cpp
Go to the documentation of this file.
1 /*
2  * AbstractThread.cpp
3  *
4  * Copyright (C) 2012 Evidence Srl - www.evidence.eu.com
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "AbstractThread.hpp"
22 #include <unistd.h>
23 #include <csignal>
24 #include <strings.h>
25 #include "Logger.hpp"
26 #include <stdexcept>
27 
28 
29 namespace onposix {
30 
31 /**
32  * \brief The static function representing the code executed in the thread context.
33  *
34  * This function just calls the run() function of the subclass.
35  * We need this level of indirection because pthread_create() cannot accept
36  * a method which is non static or virtual.
37  * @param param The pointer to the concrete subclass.
38  * @return Always zero.
39  */
40 void *AbstractThread::Execute(void* param)
41 {
42  AbstractThread* th = reinterpret_cast<AbstractThread*>(param);
43  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
44  th->run();
45  return 0;
46 }
47 
48 /**
49  * \brief Constructor. Initialize the class attributes.
50  */
52  isStarted_(false)
53 {
54 }
55 
56 
57 /**
58  * \brief Destructor.
59  *
60  * In case the thread is running, it stops the thread and prints an error
61  * message.
62  */
64  if (isStarted_){
65  WARNING("Killing a running thread!");
66  stop();
67  }
68 }
69 
70 /**
71  * \brief Starts execution of the thread by calling run().
72  *
73  * If the thread is
74  * already started this function does nothing.
75  * @return true if the thread is started or it has been previously started;
76  * false if an error occurs when starting the thread.
77  */
79 {
80  if (isStarted_)
81  return true;
82 
83  if (pthread_create(&handle_, NULL, AbstractThread::Execute,
84  (void*)this) == 0)
85  isStarted_ = true;
86 
87  return isStarted_;
88 }
89 
90 /**
91  * \brief Stops the running thread.
92  *
93  * @return true on success; false if an error occurs or the thread
94  * is not running (i.e., it has not been started or it has been already stopped)
95  */
97 {
98  if (!isStarted_){
99  DEBUG("Thread already stopped");
100  return false;
101  }
102 
103  DEBUG("Cancelling thread...");
104  isStarted_ = false;
105  if (pthread_cancel(handle_) == 0){
106  DEBUG("Thread succesfully canceled.");
107  return true;
108  }
109  return false;
110 }
111 
112 /**
113  * \brief Blocks the calling thread until the thread is finished.
114  *
115  * This method blocks the calling thread until the thread associated with
116  * the AbstractThread object has finished execution
117  * @return true on success, false if an error occurs.
118  */
120 {
121  if (pthread_join(handle_, NULL) == 0){
122  DEBUG("Thread succesfully joined.");
123  isStarted_ = false;
124  return true;
125  }
126  return false;
127 }
128 
129 /**
130  * \brief Masks a specific signal on this thread
131  *
132  * This method allows to block a specific signal
133  * The list of signals is available on /usr/include/bits/signum.h
134  * @param sig the signal to be blocked
135  * @return true on success; false if some error occurred
136  */
138 {
139  sigset_t m;
140  sigemptyset(&m);
141  sigaddset(&m, sig);
142  if (pthread_sigmask(SIG_BLOCK, &m, NULL) != 0) {
143  ERROR("Can't mask signal " << sig);
144  return false;
145  }
146  return true;
147 }
148 
149 /**
150  * \brief Unmasks a signal previously masked
151  *
152  * This method allows to unblock a specific signal previously blocked
153  * through blockSignal().
154  * The list of signals is available on /usr/include/bits/signum.h
155  * @param sig the signal to be unblocked
156  * @return true on success; false if some error occurred
157  */
159 {
160  sigset_t m;
161  sigemptyset(&m);
162  sigaddset(&m, sig);
163  if (pthread_sigmask(SIG_UNBLOCK, &m, NULL) != 0) {
164  ERROR("Can't unmask signal " << sig);
165  return false;
166  }
167  return true;
168 }
169 
170 /**
171  * \brief Sends a signal to the thread
172  *
173  * This method allows to send a signal from one thread to another thread
174  * The list of signals is available on /usr/include/bits/signum.h
175  * @param sig the signal to be sent
176  * @return true on success; false if some error occurred
177  */
179 {
180  if (pthread_kill(handle_, sig) != 0){
181  ERROR("Can't send signal " << sig);
182  return false;
183  }
184  return true;
185 }
186 
187 /**
188  * \brief Set a handler for a specific signal
189  *
190  * This method allows to manually set a handler for handling a
191  * specific signal.
192  * The list of signals is available on /usr/include/bits/signum.h
193  * Use signals less as possible, mainly for standard situations.
194  * During the execution of the handler other signals may arrive.
195  * This can lead
196  * to inconsistent states. The handler must be short.
197  * It must just update the internal state and/or kill the application.
198  * Not all library functions can be called inside the handler without having
199  * strange behaviors (see man signal). In particular, it's not safe calling
200  * functions of the standard library, like printf() or exit(), or other
201  * functions defined inside the application itself. The access to global
202  * variables is not safe either, unless they have been defined as volatile.
203  * @param sig the signal to be sent
204  * @return true on success; false if some error occurred
205  */
206 bool AbstractThread::setSignalHandler(int sig, void (*handler) (int))
207 {
208  bool ret = true;
209  sigset_t oldset, set;
210  struct sigaction sa;
211  /* mask all signals until the handlers are installed */
212  sigfillset(&set);
213  sigprocmask(SIG_SETMASK, &set, &oldset);
214  bzero( &sa, sizeof(sa) );
215  sa.sa_handler = handler;
216  if (sigaction(sig, &sa, NULL) < 0) {
217  ERROR("Can't set signal " << sig);
218  ret = false;
219  }
220  /* remove the mask */
221  sigprocmask(SIG_SETMASK, &oldset,NULL);
222  return ret;
223 }
224 
225 
226 /**
227  * \brief Set scheduling policy and priority
228  *
229  * @param policy: policy (SCHED_FIFO, SCHED_RR or SCHED_OTHER)
230  * @param priority: scheduling priority
231  * @return true in case of success; false in case of error
232  */
233 bool AbstractThread::setSchedParam(int policy, int priority)
234 {
235  struct sched_param p;
236  p.sched_priority = priority;
237  if (pthread_setschedparam(handle_, policy, &p) == 0)
238  return true;
239  else
240  return false;
241 }
242 
243 /**
244  * \brief Get current scheduling policy and priority
245  *
246  * @param policy: policy (SCHED_FIFO, SCHED_RR or SCHED_OTHER)
247  * @param priority: scheduling priority; it has a meaning only for SCHED_FIFO
248  * and SCHED_RR
249  * @return true in case of success; false in case of error
250  */
251 bool AbstractThread::getSchedParam(int* policy, int* priority)
252 {
253  struct sched_param p;
254  int ret = pthread_getschedparam(handle_, policy, &p);
255  *priority = p.sched_priority;
256  if (ret == 0)
257  return true;
258  else
259  return false;
260 }
261 
262 
263 #if defined(ONPOSIX_LINUX_SPECIFIC) && defined(__GLIBC__) && \
264  ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ > 3)))
265 /**
266  * \brief Set CPU affinity
267  *
268  * Example of usage:
269  * \code
270  * std::vector<bool> v (2);
271  * v[0] = true;
272  * v[1] = false;
273  * setAffinity(v);
274  * \endcode
275  * @param v: vector of booleans containing the affinity (true/false)
276  * @exception std::runtime_error in case affinity cannot be set
277  */
278 void AbstractThread::setAffinity(const std::vector<bool>& v)
279 {
280  cpu_set_t s;
281  CPU_ZERO(&s);
282  for (unsigned int i = 0; (i < v.size()) && (i < CPU_SETSIZE); ++i)
283  if (v[i])
284  CPU_SET(i, &s);
285 
286  if ((pthread_setaffinity_np(handle_, sizeof(s), &s) != 0))
287  throw std::runtime_error ("Set affinity error");
288 }
289 
290 /**
291  * \brief Get CPU affinity
292  *
293  * Example of usage:
294  * \code
295  * std::vector<bool> v (2);
296  * getAffinity(&v);
297  * std::cout << "Affinity: " << v[0] << " " << v[1] << std::endl;
298  * \endcode
299  * @param v: vector of booleans containing the current affinity (true/false)
300  * @exception std::runtime_error in case affinity cannot be get
301  */
302 void AbstractThread::getAffinity(std::vector<bool>* v)
303 {
304  cpu_set_t s;
305  CPU_ZERO(&s);
306 
307  if ((pthread_getaffinity_np(handle_, sizeof(s), &s) != 0))
308  throw std::runtime_error ("Get affinity error");
309 
310  for (unsigned int j = 0; (j < CPU_SETSIZE) && (j < v->size()); ++j) {
311  if (CPU_ISSET(j, &s))
312  (*v)[j] = true;
313  else
314  (*v)[j] = false;
315  }
316 }
317 #endif /* ONPOSIX_LINUX_SPECIFIC && GLIBC */
318 
319 
320 
321 } /* onposix */