blob: fa444e5f9cb93bbf3cab197c3c4730fb17a4eb23 [file] [log] [blame]
// Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include "cm.h"
#define MAX_EXIT_CB_CNT 8
typedef void (*exit_cb_t)(int);
static int signal_active = 0;
static exit_cb_t exit_cb_list[MAX_EXIT_CB_CNT];
static int control_signals[] = {
#if 0
SIGKILL,
SIGQUIT,
SIGTSTP,
SIGABRT,
SIGTERM,
SIGSEGV,
#endif
SIGINT
};
static int ignore_signals[] = {
SIGPIPE
};
int register_exit_cb(void (*cb)(int sig))
{
exit_cb_t *cb_list = exit_cb_list;
int i;
for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
if (cb_list[i] == cb)
return -1;
}
for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
if (NULL == cb_list[i]) {
cb_list[i] = (void *)cb;
return 0;
}
}
assert(0);
return -1;
}
int unregister_exit_cb(void (*cb)(int sig))
{
exit_cb_t *cb_list = exit_cb_list;
int i;
for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
if (cb_list[i] == cb) {
cb_list[i] = NULL;
return 0;
}
}
return -1;
}
static void __do_exit_cb(int sig)
{
exit_cb_t *cb_list = exit_cb_list;
int nr_sigs = sizeof(control_signals)/sizeof(control_signals[0]);
int i;
for (i = 0; i < nr_sigs; i++) {
if (control_signals[i] == sig)
break;
}
assert(!sig || i < nr_sigs);
if (0 == signal_active) {
signal_active = 1;
for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
if (cb_list[i]) {
cb_list[i](sig);
cb_list[i] = NULL;
}
}
if (sig > 0) {
cm_printf("signal(%d) issued\n", sig);
exit(0);
}
signal_active = 0;
}
}
static void __ignore_signal_cb(int sig)
{
cm_printf("signal(%d) ignored\n", sig);
}
static void __exit_cb(void)
{
if (!signal_active)
cm_printf("exit() called\n");
}
void init_exit_cb(void)
{
struct sigaction act;
int i;
atexit(__exit_cb);
memset(exit_cb_list, 0, sizeof(exit_cb_list));
memset(&act, 0, sizeof(act));
sigemptyset(&act.sa_mask);
act.sa_handler = __do_exit_cb;
for (i = 0; i < sizeof(control_signals)/sizeof(control_signals[0]); i++)
if (sigaction(control_signals[i], &act, NULL) < 0)
cm_eprintf("sigaction(%d) error %s(%d)\n", control_signals[i], strerror(errno), errno);
act.sa_handler = __ignore_signal_cb;
act.sa_flags = SA_RESTART;
for (i = 0; i < sizeof(ignore_signals)/sizeof(ignore_signals[0]); i++)
if (sigaction(ignore_signals[i], &act, NULL) < 0)
cm_eprintf("sigaction(%d) error %s(%d)\n", ignore_signals[i], strerror(errno), errno);
}
void process_exit_cb(void)
{
__do_exit_cb(0);
}