Newer
Older
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX(a, b) ((a) < (b) ? (b) : (a))
static FILE *errfile = NULL;
static FILE *verbfile = NULL;
static FILE *logfile = NULL;
static void init_files(FILE *efile, FILE *vfile)
{
errfile = efile;
verbfile = vfile;
}
static char fail_buf[1024] = "FATAL Error. Exiting\n";
static void default_fatal_fun()
ret = write(STDOUT_FILENO, fail_buf, strlen(fail_buf) + 1);
if (logfile)
fputs(fail_buf, logfile);
}
/* Optional function to call when fatal error encountered */
static void (*fatal_fun)() = default_fatal_fun;
void set_verblevel(int level)
{
verblevel = level;
}
bool set_logfile(const char *file_name)
{
logfile = fopen(file_name, "w");
return logfile != NULL;
}
void report_event(message_t msg, char *fmt, ...)
{
va_list ap;
bool fatal = msg == MSG_FATAL;
"WARNING",
"ERROR",
"FATAL ERROR",
};
char *msg_name = msg_name_text[2];
if (msg < N_MSG)
msg_name = msg_name_text[msg];
int level = N_MSG - msg - 1;
va_start(ap, fmt);
fprintf(errfile, "%s: ", msg_name);
vfprintf(errfile, fmt, ap);
fprintf(errfile, "\n");
fflush(errfile);
va_end(ap);
if (logfile) {
va_start(ap, fmt);
fprintf(logfile, "Error: ");
vfprintf(logfile, fmt, ap);
fprintf(logfile, "\n");
fflush(logfile);
va_end(ap);
fclose(logfile);
}
if (fatal) {
if (fatal_fun)
fatal_fun();
exit(1);
}
}
void report(int level, char *fmt, ...)
{
if (!verbfile)
init_files(stdout, stdout);
va_start(ap, fmt);
vfprintf(verbfile, fmt, ap);
fprintf(verbfile, "\n");
fflush(verbfile);
va_end(ap);
if (logfile) {
va_start(ap, fmt);
vfprintf(logfile, fmt, ap);
fprintf(logfile, "\n");
fflush(logfile);
va_end(ap);
}
va_start(ap, fmt);
vsnprintf(buffer, BUF_SIZE, fmt, ap);
va_end(ap);
}
int len = strlen(buffer);
buffer[len] = '\n';
buffer[len + 1] = '\0';
}
}
void report_noreturn(int level, char *fmt, ...)
{
if (!verbfile)
init_files(stdout, stdout);
va_start(ap, fmt);
vfprintf(verbfile, fmt, ap);
fflush(verbfile);
va_end(ap);
if (logfile) {
va_start(ap, fmt);
vfprintf(logfile, fmt, ap);
fflush(logfile);
va_end(ap);
}
va_start(ap, fmt);
vsnprintf(buffer, BUF_SIZE, fmt, ap);
va_end(ap);
}
if (web_connfd)
web_send(web_connfd, buffer);
}
/* Functions denoting failures */
/* Need to be able to print without using malloc */
static void fail_fun(const char *format, const char *msg)
snprintf(fail_buf, sizeof(fail_buf), format, msg);
/* Tack on return */
fail_buf[strlen(fail_buf)] = '\n';
/* Use write to avoid any buffering issues */
ret = write(STDOUT_FILENO, fail_buf, strlen(fail_buf) + 1);
if (logfile) {
/* Don't know file descriptor for logfile */
fputs(fail_buf, logfile);
}
exit(1);
}
/* Maximum number of megabytes that application can use (0 = unlimited) */
/* Keeping track of memory allocation */
static size_t allocate_cnt = 0;
static size_t allocate_bytes = 0;
static size_t free_cnt = 0;
static size_t free_bytes = 0;
/* Counters giving peak memory usage */
static size_t peak_bytes = 0;
static size_t last_peak_bytes = 0;
static size_t current_bytes = 0;
static void check_exceed(size_t new_bytes)
{
size_t limit_bytes = (size_t) mblimit << 20;
size_t request_bytes = new_bytes + current_bytes;
if (mblimit > 0 && request_bytes > limit_bytes) {
report_event(MSG_FATAL,
"Exceeded memory limit of %u megabytes with %lu bytes",
mblimit, request_bytes);
}
}
/* Call malloc & exit if fails */
void *malloc_or_fail(size_t bytes, const char *fun_name)
{
check_exceed(bytes);
void *p = malloc(bytes);
if (!p) {
fail_fun("Malloc returned NULL in %s", fun_name);
return NULL;
}
allocate_cnt++;
allocate_bytes += bytes;
current_bytes += bytes;
peak_bytes = MAX(peak_bytes, current_bytes);
last_peak_bytes = MAX(last_peak_bytes, current_bytes);
return p;
}
/* Call calloc returns NULL & exit if fails */
void *calloc_or_fail(size_t cnt, size_t bytes, const char *fun_name)
{
check_exceed(cnt * bytes);
void *p = calloc(cnt, bytes);
if (!p) {
fail_fun("Calloc returned NULL in %s", fun_name);
return NULL;
}
allocate_cnt++;
allocate_bytes += cnt * bytes;
current_bytes += cnt * bytes;
peak_bytes = MAX(peak_bytes, current_bytes);
last_peak_bytes = MAX(last_peak_bytes, current_bytes);
return p;
}
char *strsave_or_fail(const char *s, const char *fun_name)
size_t len = strlen(s);
check_exceed(len + 1);
char *ss = malloc(len + 1);
allocate_cnt++;
allocate_bytes += len + 1;
current_bytes += len + 1;
peak_bytes = MAX(peak_bytes, current_bytes);
last_peak_bytes = MAX(last_peak_bytes, current_bytes);
}
/* Free block, as from malloc, realloc, or strsave */
void free_block(void *b, size_t bytes)
{
report_event(MSG_ERROR, "Attempting to free null block");
free(b);
free_cnt++;
free_bytes += bytes;
current_bytes -= bytes;
}
/* Free array, as from calloc */
void free_array(void *b, size_t cnt, size_t bytes)
{
report_event(MSG_ERROR, "Attempting to free null block");
free(b);
free_cnt++;
free_bytes += cnt * bytes;
current_bytes -= cnt * bytes;
}
/* Free string saved by strsave_or_fail */
void free_string(char *s)
{
report_event(MSG_ERROR, "Attempting to free null block");
free_block((void *) s, strlen(s) + 1);
}
/* Initialization of timers */
void init_time(double *timep)
{
(void) delta_time(timep);
}
double delta_time(double *timep)
{
struct timeval tv;
gettimeofday(&tv, NULL);
double current_time = tv.tv_sec + 1.0E-6 * tv.tv_usec;
double delta = current_time - *timep;
*timep = current_time;
return delta;