#include<pthread.h>
#include<stdarg.h>
#include<stdio.h>
+#include<stdlib.h>
extern int verbose_flag;
extern pthread_t logging_thread;
+extern pthread_mutex_t logging_mutex;
enum log_level {
LOG_LEVEL_SILENT = 0, /* suppresses all output */
LOG_LEVEL_VERBOSE = 3 /* logging and debugging info */
};
-#define log_err(...) log_enqueue(LOG_LEVEL_ERRORS,stderr,__VA_ARGS__)
-#define log_info(...) log_enqueue(LOG_LEVEL_VERBOSE,stdout,__VA_ARGS__)
-#define log_msg(...) log_enqueue(LOG_LEVEL_DEFAULT,stdout,__VA_ARGS__)
+#define log_err(...) log_message(LOG_LEVEL_ERRORS,stderr,__VA_ARGS__)
+#define log_info(...) log_message(LOG_LEVEL_VERBOSE,stdout,__VA_ARGS__)
+#define log_msg(...) log_message(LOG_LEVEL_DEFAULT,stdout,__VA_ARGS__)
+
+#define LOG_FLUSH_MESSAGE "flushing log queue...\n"
+
+#define LOG_ENTRY_MAX_LENGTH 100
+#define LOG_QUEUE_SIZE 100
struct log_entry {
enum log_level level;
char buf[LOG_ENTRY_MAX_LENGTH];
FILE *out_stream;
+ struct log_entry *next;
+};
+
+struct log_helper {
+ void *p;
+ struct log_entry *start;
+ struct log_entry *end;
+ size_t next;
};
-void log_enqueue(enum log_level,FILE*,const char*,...);
+struct log_entry *log_dequeue();
+void log_enqueue(struct log_entry*);
+int log_entries_init();
+void log_entries_clean();
+void log_flush();
+void log_print(struct log_entry*);
void log_message(enum log_level,FILE*,const char*,...);
void log_poll();
int verbose_flag = LOG_LEVEL_DEFAULT;
-void log_enqueue(enum log_level level, FILE *out_stream, const char *format,...) {
- va_list args;
- va_start(args,format);
-// vsnprintf(buf,format,args);
- va_end(args);
+struct log_helper helper;
+
+struct log_entry *log_dequeue() {
+ struct log_entry *p;
+
+ pthread_mutex_lock(&logging_mutex);
+
+ if(NULL==helper.start) {
+ p = NULL;
+ } else {
+ p = helper.start;
+ helper.start = p->next;
+ }
+
+ pthread_mutex_unlock(&logging_mutex);
+
+ return p;
+}
+
+void log_enqueue(struct log_entry *p) {
+ pthread_mutex_lock(&logging_mutex);
+
+ if(NULL==helper.start) {
+ helper.start = p;
+ helper.end = p;
+ } else {
+ helper.end->next = p;
+ helper.end = p;
+ }
+
+ pthread_mutex_unlock(&logging_mutex);
+}
+
+int log_entries_init() {
+ helper.start = NULL;
+ helper.end = NULL;
+ helper.next = 0;
+
+ helper.p = malloc(sizeof(struct log_entry(*))*LOG_QUEUE_SIZE+(sizeof(struct log_entry)*LOG_QUEUE_SIZE));
+ if(NULL==helper.p) {
+ perror("malloc");
+ return -1;
+ }
+
+ return 1;
+}
+
+void log_entries_clean() {
+ free(helper.p);
+}
+
+void log_flush() {
+ log_err(LOG_FLUSH_MESSAGE);
+
+ pthread_mutex_lock(&logging_mutex);
+
+ while(helper.start!=NULL) {
+ log_print(helper.start);
+ helper.start = helper.start->next;
+ }
+
+ helper.start = NULL;
+ helper.end = NULL;
+ helper.next = 0;
+
+ pthread_mutex_unlock(&logging_mutex);
+}
+
+void log_print(struct log_entry *p) {
+ fputs(p->out_stream,p->buf);
}
void log_message(enum log_level level, FILE *out_stream, const char *format,...) {
if(level>verbose_flag) { return; }
va_list args;
-
+ va_start(args,format);
if(0==pthread_equal(pthread_self(),logging_thread)) {
- log_enqueue(level,out_stream,format,...);
+ // not on logging_thread
+
+ struct log_entry *p;
+ size_t offset;
+
+ offset = LOG_QUEUE_SIZE;
+ while(offset>=LOG_QUEUE_SIZE) {
+ pthread_mutex_lock(&logging_mutex);
+
+ offset = helper.next;
+ helper.next++;
+
+ pthread_mutex_unlock(&logging_mutex);
+
+ // out of queue entries
+ if(offset>=LOG_QUEUE_SIZE) {
+ log_flush();
+ }
+ }
+
+ p = &(helper.p[offset*sizeof(struct log_entry)]);
+
+ p->level = level;
+ p->out_stream = out_stream;
+ p->next = NULL;
+ vsnprintf(p->buf,LOG_ENTRY_MAX_LENGTH,format,args);
+
+ log_enqueue(p);
} else {
- va_start(args,format);
vfprintf(out_stream,format,args);
}