RPi Locator and Display Services
skn_signal_manager.c
Go to the documentation of this file.
1 /*
2  * skn_signal_manager.c
3  *
4  * Created on: Jul 25, 2015
5  * Author: jscott
6  */
7 
8 #include "skn_network_helpers.h"
9 
10 
11 
12 static int skn_signal_manager_process_signals(siginfo_t *signal_info);
13 static void *skn_signal_manager_handler_thread(void *l_thread_complete);
14 
15 /*
16  * process_signals()
17  *
18  * Handle/Process linux signals for the whole multi-threaded application.
19  *
20  * Params:
21  * sig -- current linux signal
22  *
23  * Returns/Affects:
24  * returns current value of the atomic int gi_exit_flag
25  * returns true (or current value) if nothing needs done
26  * returns 0 or false if exit is required
27  */
28 static int skn_signal_manager_process_signals(siginfo_t *signal_info) {
29  int rval = gi_exit_flag; /* use existing value */
30  int sig = 0;
31  char *pch = "<unknown>";
32 
33  assert(signal_info != NULL);
34 
35  sig = signal_info->si_signo;
36 
37  /*
38  * look to see what signal has been caught
39  */
40  switch (sig) {
41  case SIGHUP: /* often used to reload configuration */
42 // rval = 33; /* flag a reload of the ip address info */
43  skn_logger(SD_NOTICE, "%s received: Requesting IP Address Info reload => [pid=%d, uid=%d]", strsignal(sig), signal_info->si_pid,
44  signal_info->si_uid);
45  break;
46  case SIGUSR1: /* Any user function */
47  switch (signal_info->si_code) {
48  case SI_USER:
49  pch = "kill(2) or raise(3)";
50  break;
51  case SI_KERNEL:
52  pch = "Sent by the kernel.";
53  break;
54  case SI_QUEUE:
55  pch = "sigqueue(2)";
56  break;
57  case SI_TIMER:
58  pch = "POSIX timer expired";
59  break;
60  case SI_MESGQ:
61  pch = "POSIX message queue state changed";
62  break;
63  case SI_ASYNCIO:
64  pch = "AIO completed";
65  break;
66  case SI_SIGIO:
67  pch = "queued SIGIO";
68  break;
69  case SI_TKILL:
70  pch = "tkill(2) or tgkill(2)";
71  break;
72  default:
73  pch = "<unknown>";
74  break;
75  }
76  skn_logger(SD_NOTICE, "%s received from => %s ?[pid=%d, uid=%d] signaling application shutdown.", strsignal(sig), pch, signal_info->si_pid, signal_info->si_uid);
77  rval = sig;
78  break;
79  case SIGCHLD: /* some child ended */
80  switch (signal_info->si_code) {
81  case CLD_EXITED:
82  pch = "child has exited";
83  break;
84  case CLD_KILLED:
85  pch = "child was killed";
86  break;
87  case CLD_DUMPED:
88  pch = "child terminated abnormally";
89  break;
90  case CLD_TRAPPED:
91  pch = "traced child has trapped";
92  break;
93  case CLD_STOPPED:
94  pch = "child has stopped";
95  break;
96  case CLD_CONTINUED:
97  pch = "stopped child has continued";
98  break;
99  default:
100  pch = "<unknown>";
101  break;
102  }
103  skn_logger(SD_NOTICE, "%s received for pid => %d, w/rc => %d for this reason => %s {Ignored}", strsignal(sig), signal_info->si_pid,
104  signal_info->si_status, pch);
105  break;
106  case SIGQUIT: /* often used to signal an orderly shutdown */
107  case SIGINT: /* often used to signal an orderly shutdown */
108  case SIGPWR: /* Power Failure */
109  case SIGKILL: /* Fatal Exit flag */
110  case SIGTERM: /* Immediately Fatal Exit flag */
111  default:
112  switch (signal_info->si_code) {
113  case SI_USER:
114  pch = "kill(2) or raise(3)";
115  break;
116  case SI_KERNEL:
117  pch = "Sent by the kernel.";
118  break;
119  case SI_QUEUE:
120  pch = "sigqueue(2)";
121  break;
122  case SI_TIMER:
123  pch = "POSIX timer expired";
124  break;
125  case SI_MESGQ:
126  pch = "POSIX message queue state changed";
127  break;
128  case SI_ASYNCIO:
129  pch = "AIO completed";
130  break;
131  case SI_SIGIO:
132  pch = "queued SIGIO";
133  break;
134  case SI_TKILL:
135  pch = "tkill(2) or tgkill(2)";
136  break;
137  default:
138  pch = "<unknown>";
139  break;
140  }
141  skn_logger(SD_NOTICE, "%s received from => %s ?[pid=%d, uid=%d]{Exiting}", strsignal(sig), pch, signal_info->si_pid, signal_info->si_uid);
142  rval = sig;
143  break;
144  } /* end switch */
145 
146  return rval;
147 }
148 
161 static void *skn_signal_manager_handler_thread(void *l_thread_complete) {
162  sigset_t signal_set;
163  siginfo_t signal_info;
164 // struct timespec timeout;
165  int sig = 0;
166  int rval = 0;
167  long *threadC = (long *)l_thread_complete;
168 
169  *threadC = 1;
170 
171 // timeout.tv_nsec = 0;
172 // timeout.tv_sec = 8;
173  sigfillset(&signal_set);
174  skn_logger(SD_NOTICE, "SignalManager: Startup Successful...");
175 
176  while (gi_exit_flag == SKN_RUN_MODE_RUN) {
177  /* wait for any and all signals */
178  /* OLD: sigwait (&signal_set, &sig); */
179  sig = sigwaitinfo(&signal_set, &signal_info);
180  if (sig == PLATFORM_ERROR) {
181  if (errno == EAGAIN) {
182  continue;
183  }
184  skn_logger(SD_WARNING, "SignalManager: sigwaitinfo() returned an error => {%s}", strerror(errno));
186  break;
187  }
188  /* when we get this far, we've caught a signal */
189  rval = skn_signal_manager_process_signals(&signal_info);
190  gi_exit_flag = rval;
191 
192  } /* end-while */
193 
194  pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
195 
196  skn_logger(SD_NOTICE, "SignalManager: Thread Shutdown Complete.");
197 
198  *threadC = 0;
199 
200  pthread_exit((void *) (long int) sig);
201 
202  return NULL;
203 }
204 
209 int skn_signal_manager_shutdown(pthread_t sig_thread, sigset_t *psignal_set, long *l_thread_complete) {
210  void *trc = NULL;
211  int rc = EXIT_SUCCESS;
212 
214  gi_exit_flag = SKN_RUN_MODE_STOP; /* shut down the system -- work is done */
215  // need to force theads down or interrupt them
216  skn_logger(SD_WARNING, "shutdown caused by application!");
217  sleep(1);
218  if (*l_thread_complete != 0) {
219  pthread_cancel(sig_thread);
220  sleep(1);
221  }
222  skn_logger(SD_WARNING, "Collecting (cleanup) threads.");
223  pthread_join(sig_thread, &trc);
224  } else {
225  rc = EXIT_FAILURE;
226  skn_logger(SD_NOTICE, "Collecting signal thread's return code.");
227  pthread_join(sig_thread, &trc);
228  skn_logger(SD_NOTICE, "Signal thread was ended by a %d:%s signal.", gi_exit_flag, strsignal((int) (long int) trc));
229  }
230  pthread_sigmask(SIG_UNBLOCK, psignal_set, NULL);
231 
232  return rc;
233 }
234 
238 int skn_signal_manager_startup(pthread_t *psig_thread, sigset_t *psignal_set, long *l_thread_complete) {
239  int i_thread_rc = 0; // EXIT_SUCCESS
240 
241  sigfillset(psignal_set);
242  pthread_sigmask(SIG_BLOCK, psignal_set, NULL);
243 
244  i_thread_rc = pthread_create(psig_thread, NULL, skn_signal_manager_handler_thread, (void*) l_thread_complete);
245  if (i_thread_rc == PLATFORM_ERROR) {
246  skn_logger(SD_ERR, "Create signal thread failed: %d:%s", errno, strerror(errno));
247  pthread_sigmask(SIG_UNBLOCK, psignal_set, NULL);
248  i_thread_rc = EXIT_FAILURE;
249  }
250  sleep(1); // give thread a chance to start
251 
252  return i_thread_rc;
253 }
#define PLATFORM_ERROR
Definition: cmdDC.c:63
static int skn_signal_manager_process_signals(siginfo_t *signal_info)
#define SKN_RUN_MODE_STOP
int skn_signal_manager_startup(pthread_t *psig_thread, sigset_t *psignal_set, long *l_thread_complete)
static void * skn_signal_manager_handler_thread(void *l_thread_complete)
#define SD_ERR
#define SD_WARNING
int skn_signal_manager_shutdown(pthread_t sig_thread, sigset_t *psignal_set, long *l_thread_complete)
#define SKN_RUN_MODE_RUN
sig_atomic_t gi_exit_flag
#define SD_NOTICE