ONPOSIX  2.0
 All Classes Namespaces Files Functions Variables Enumerator Friends Macros Pages
Process.cpp
Go to the documentation of this file.
1 /*
2  * Process.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 <stdexcept>
22 #include <sched.h>
23 #include <sys/wait.h>
24 #include <strings.h>
25 #include <signal.h>
26 
27 #include <iostream>
28 
29 #include "Process.hpp"
30 #include "Logger.hpp"
31 
32 namespace onposix {
33 
34 /**
35  * \brief Create a process
36  *
37  * This function creates a new process through fork().
38  * This function is not meant to be called explicitly,
39  * but it is automatically called by the constructors.
40  * @exception std::runtime_error in case the process cannot
41  * be created.
42  */
44 {
45  pid_ = fork();
46  if (pid_ == -1) {
47  running_ = false;
48  ERROR("Cannot start process");
49  throw std::runtime_error ("Async error");
50  }
51 
52  if (pid_ == 0) {
53  // Child
54  pid_ = getpid();
55  is_child_ = true;
56  } else {
57  // Parent
58  is_child_ = false;
59  }
60  running_ = true;
61 }
62 
63 /**
64  * \brief Constructor to run a specific function
65  *
66  * This constructor creates a new process that will run the
67  * function given as argument.
68  * @param function: pointer to the function that must be run
69  */
70 Process::Process(void (*function)(void)):
71  is_child_(false),
72  running_(false),
73  status_(0)
74 {
75  createProcess();
76  if (is_child_ && running_){
77  (*function)();
78  }
79 }
80 
81 /**
82  * \brief Constructor to run a specific program
83  *
84  * This constructor creates a new process that will run the
85  * program given as argument. This contructor invokes fork()+execvp().
86  * @param program: name of the program to be run
87  * @args args: list of arguments
88  */
89 Process::Process(const std::string& program,
90  const std::vector<std::string>& args):
91  is_child_(false),
92  running_(false),
93  status_(0)
94 {
95  createProcess();
96  if (is_child_ && running_){
97  char* c_args [20];
98  c_args[0] = const_cast<char*> (program.c_str());
99  for (unsigned int i = 0; i < args.size(); ++i){
100  c_args[i+1] = const_cast<char*> (args[i].c_str());
101  }
102  c_args[args.size()+1] = (char*) NULL;
103 
104  execvp(program.c_str(), c_args);
105  }
106 }
107 
108 /**
109  * \brief Function to wait the termination of the process
110  *
111  * To avoid deadlocks, this function can be called only by the parent
112  * and not by the child itself.
113  * @return false in case the function is called by the child or in
114  * case of abnormal termination; true in case of normal termination
115  */
117 {
118  if (is_child_)
119  return false;
120  waitpid(pid_, &status_, 1);
121  running_ = false;
122  if (WIFEXITED(status_))
123  return true;
124  else
125  return false;
126 }
127 
128 /**
129  * \brief Function to check if the child has terminated correctly
130  *
131  * This function must be invoked after waitForTermination() and
132  * allows to inspect the termination status of the child.
133  * @return true in case of normal termination; false otherwise
134  */
136 {
137  if (is_child_)
138  return false;
139  if (WIFEXITED(status_))
140  return true;
141  else
142  return false;
143 }
144 
145 /**
146  * \brief Function to check if the child has terminated for a signal
147  *
148  * This function must be invoked after waitForTermination() and
149  * allows to inspect the termination status of the child.
150  * @return true in case the child has terminated due to a signal;
151  * false otherwise
152  */
154 {
155  if (is_child_)
156  return false;
157  if (WIFSIGNALED(status_))
158  return true;
159  else
160  return false;
161 }
162 
163 
164 
165 /**
166  * \brief Function to send a signal to the process
167  *
168  * This method allows to send a signal to the process related to
169  * this instance of Process. This function wraps the classical kill()
170  * function.
171  * The list of signals is available on /usr/include/bits/signum.h
172  * @param sig the signal to be sent
173  * @return true on success; false if some error occurred
174  */
175 bool Process::sendSignal(int sig)
176 {
177  if (kill(pid_, sig) != 0){
178  ERROR("Can't send signal " << sig);
179  return false;
180  }
181  return true;
182 }
183 
184 /**
185  * \brief Set a handler for a specific signal
186  *
187  * This method allows to manually set a handler for handling a specific signal.
188  * The list of signals is available on /usr/include/bits/signum.h
189  * Use signals less as possible, mainly for standard situations.
190  * During the execution of the handler other signals may arrive. This can lead
191  * to inconsistent states. The handler must be short.
192  * It must just update the internal state and/or kill the application.
193  * Not all library functions can be called inside the handler without having
194  * strange behaviors (see man signal). In particular, it's not safe calling
195  * functions of the standard library, like printf() or exit(), or other
196  * functions defined inside the application itself. The access to global
197  * variables is not safe either, unless they have been defined as volatile.
198  * @param sig the signal to be sent
199  * @return true on success; false if some error occurred
200  */
201 bool Process::setSignalHandler(int sig, void (*handler) (int))
202 {
203  bool ret = true;
204  sigset_t oldset, set;
205  struct sigaction sa;
206  /* mask all signals until the handlers are installed */
207  sigfillset(&set);
208  sigprocmask(SIG_SETMASK, &set, &oldset);
209  bzero( &sa, sizeof(sa) );
210  sa.sa_handler = handler;
211  if (sigaction(sig, &sa, NULL) < 0) {
212  ERROR("Can't set signal " << sig);
213  ret = false;
214  }
215  /* remove the mask */
216  sigprocmask(SIG_SETMASK, &oldset,NULL);
217  return ret;
218 }
219 
220 
221 
222 /**
223  * \brief Set scheduling policy and priority
224  *
225  * @param policy: policy (SCHED_FIFO, SCHED_RR or SCHED_OTHER)
226  * @param priority: scheduling priority
227  * @return true in case of success; false in case of error
228  */
229 bool Process::setSchedParam(int policy, int priority)
230 {
231  struct sched_param p;
232  p.sched_priority = priority;
233  if (sched_setscheduler(pid_, policy, &p) == 0)
234  return true;
235  else
236  return false;
237 }
238 
239 
240 
241 /**
242  * \brief Get current scheduling policy and priority
243  *
244  * @param policy: policy (SCHED_FIFO, SCHED_RR or SCHED_OTHER)
245  * @param priority: scheduling priority; it has a meaning only for SCHED_FIFO
246  * and SCHED_RR
247  * @return true in case of success; false in case of error
248  */
249 bool Process::getSchedParam(int* policy, int* priority)
250 {
251  struct sched_param p;
252  int ret = sched_getparam(pid_, &p);
253  *priority = p.sched_priority;
254  *policy = sched_getscheduler(pid_);
255  if ((*policy < 0) || (ret < 0))
256  return false;
257  else
258  return true;
259 }
260 
261 
262 #if defined(ONPOSIX_LINUX_SPECIFIC) && defined(__GLIBC__) && \
263  ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ > 3)))
264 /**
265  * \brief Set CPU affinity
266  *
267  * Example of usage:
268  * \code
269  * std::vector<bool> v (2);
270  * v[0] = true;
271  * v[1] = false;
272  * setAffinity(v);
273  * \endcode
274  * @param v: vector of booleans containing the affinity (true/false)
275  * @exception std::runtime_error in case affinity cannot be set
276  */
277 void Process::setAffinity(const std::vector<bool>& v)
278 {
279  cpu_set_t s;
280  CPU_ZERO(&s);
281  for (unsigned int i = 0; (i < v.size()) && (i < CPU_SETSIZE); ++i)
282  if (v[i])
283  CPU_SET(i, &s);
284 
285  if ((sched_setaffinity(pid_, sizeof(s), &s) != 0))
286  throw std::runtime_error ("Set affinity error");
287 }
288 
289 /**
290  * \brief Get CPU affinity
291  *
292  * Example of usage:
293  * \code
294  * std::vector<bool> v (2);
295  * getAffinity(&v);
296  * std::cout << "Affinity: " << v[0] << " " << v[1] << std::endl;
297  * \endcode
298  * @param v: vector of booleans containing the current affinity (true/false)
299  * @exception std::runtime_error in case affinity cannot be get
300  */
301 void Process::getAffinity(std::vector<bool>* v)
302 {
303  cpu_set_t s;
304  CPU_ZERO(&s);
305 
306  if ((sched_getaffinity(pid_, sizeof(s), &s) != 0))
307  throw std::runtime_error ("Get affinity error");
308 
309  for (unsigned int j = 0; (j < CPU_SETSIZE) && (j < v->size()); ++j) {
310  if (CPU_ISSET(j, &s))
311  (*v)[j] = true;
312  else
313  (*v)[j] = false;
314  }
315 }
316 #endif /* ONPOSIX_LINUX_SPECIFIC && GLIBC */
317 
318 
319 } /* onposix */