--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "memory.h"
+#include "log.h"
+
+#define ALIGN(len, s) (((len)+(s)-1)/(s)*(s))
+
+#if LOGDBG
+static void dump_logarea (void)
+{
+ struct logmsg * msg;
+
+ logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
+ la->start, la->end);
+ logdbg(stderr, "|addr |next |prio|msg\n");
+
+ for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
+ msg = msg->next)
+ logdbg(stderr, "|%p |%p |%i |%s\n", (void *)msg, msg->next,
+ msg->prio, (char *)&msg->str);
+
+ logdbg(stderr, "|%p |%p |%i |%s\n", (void *)msg, msg->next,
+ msg->prio, (char *)&msg->str);
+
+ logdbg(stderr, "\n\n");
+}
+#endif
+
+static int logarea_init (int size)
+{
+ logdbg(stderr,"enter logarea_init\n");
+ la = (struct logarea *)MALLOC(sizeof(struct logarea));
+
+ if (!la)
+ return 1;
+
+ if (size < MAX_MSG_SIZE)
+ size = DEFAULT_AREA_SIZE;
+
+ la->start = MALLOC(size);
+ memset(la->start, 0, size);
+
+ if (!la->start) {
+ FREE(la);
+ return 1;
+ }
+
+ la->empty = 1;
+ la->end = la->start + size;
+ la->head = la->start;
+ la->tail = la->start;
+
+ la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
+
+ if (!la->buff) {
+ FREE(la->start);
+ FREE(la);
+ return 1;
+ }
+ return 0;
+
+}
+
+int log_init(char *program_name, int size)
+{
+ logdbg(stderr,"enter log_init\n");
+ openlog(program_name, 0, LOG_DAEMON);
+
+ if (logarea_init(size))
+ return 1;
+
+ return 0;
+}
+
+void free_logarea (void)
+{
+ FREE(la->start);
+ FREE(la->buff);
+ FREE(la);
+ return;
+}
+
+void log_close (void)
+{
+ free_logarea();
+ closelog();
+
+ return;
+}
+
+int log_enqueue (int prio, const char * fmt, va_list ap)
+{
+ int len, fwd;
+ char buff[MAX_MSG_SIZE];
+ struct logmsg * msg;
+ struct logmsg * lastmsg;
+
+ lastmsg = (struct logmsg *)la->tail;
+
+ if (!la->empty) {
+ fwd = sizeof(struct logmsg) +
+ strlen((char *)&lastmsg->str) * sizeof(char) + 1;
+ la->tail += ALIGN(fwd, sizeof(void *));
+ }
+ vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
+ len = ALIGN(sizeof(struct logmsg) + strlen(buff) * sizeof(char) + 1,
+ sizeof(void *));
+
+ /* not enough space on tail : rewind */
+ if (la->head <= la->tail && len > (la->end - la->tail)) {
+ logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
+ la->tail = la->start;
+
+ if (la->empty)
+ la->head = la->start;
+ }
+
+ /* not enough space on head : drop msg */
+ if (la->head > la->tail && len >= (la->head - la->tail)) {
+ logdbg(stderr, "enqueue: log area overrun, drop msg\n");
+
+ if (!la->empty)
+ la->tail = lastmsg;
+
+ return 1;
+ }
+
+ /* ok, we can stage the msg in the area */
+ la->empty = 0;
+ msg = (struct logmsg *)la->tail;
+ msg->prio = prio;
+ memcpy((void *)&msg->str, buff, strlen(buff));
+ lastmsg->next = la->tail;
+ msg->next = la->head;
+
+ logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
+ msg->prio, (char *)&msg->str);
+
+#if LOGDBG
+ dump_logarea();
+#endif
+ return 0;
+}
+
+int log_dequeue (void * buff)
+{
+ struct logmsg * src = (struct logmsg *)la->head;
+ struct logmsg * dst = (struct logmsg *)buff;
+ struct logmsg * lst = (struct logmsg *)la->tail;
+
+ if (la->empty)
+ return 1;
+
+ int len = strlen((char *)&src->str) * sizeof(char) +
+ sizeof(struct logmsg) + 1;
+
+ dst->prio = src->prio;
+ memcpy(dst, src, len);
+
+ if (la->tail == la->head)
+ la->empty = 1; /* we purge the last logmsg */
+ else {
+ la->head = src->next;
+ lst->next = la->head;
+ }
+ logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
+ (void *)src, src->next, src->prio, (char *)&src->str);
+
+ memset((void *)src, 0, len);
+
+ return la->empty;
+}
+
+/*
+ * this one can block under memory pressure
+ */
+void log_syslog (void * buff)
+{
+ struct logmsg * msg = (struct logmsg *)buff;
+
+ syslog(msg->prio, "%s", (char *)&msg->str);
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <sys/mman.h>
+
+#include <memory.h>
+
+#include "log_pthread.h"
+#include "log.h"
+
+void log_safe (int prio, char * fmt, va_list ap)
+{
+ pthread_mutex_lock(logq_lock);
+ //va_start(ap, fmt);
+ log_enqueue(prio, fmt, ap);
+ va_end(ap);
+ pthread_mutex_unlock(logq_lock);
+
+ pthread_mutex_lock(logev_lock);
+ pthread_cond_signal(logev_cond);
+ pthread_mutex_unlock(logev_lock);
+}
+
+static void flush_logqueue (void)
+{
+ int empty;
+
+ do {
+ pthread_mutex_lock(logq_lock);
+ empty = log_dequeue(la->buff);
+ pthread_mutex_unlock(logq_lock);
+ log_syslog(la->buff);
+ } while (empty == 0);
+}
+
+static void * log_thread (void * et)
+{
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+ logdbg(stderr,"enter log_thread\n");
+
+ while (1) {
+ pthread_mutex_lock(logev_lock);
+ pthread_cond_wait(logev_cond, logev_lock);
+ pthread_mutex_unlock(logev_lock);
+
+ flush_logqueue();
+ }
+}
+
+void log_thread_start (void)
+{
+ pthread_attr_t attr;
+
+ logdbg(stderr,"enter log_thread_start\n");
+
+ logq_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+ logev_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+ logev_cond = (pthread_cond_t *) malloc(sizeof(pthread_cond_t));
+
+ pthread_mutex_init(logq_lock, NULL);
+ pthread_mutex_init(logev_lock, NULL);
+ pthread_cond_init(logev_cond, NULL);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 64 * 1024);
+
+ if (log_init("multipathd", 0)) {
+ fprintf(stderr,"can't initialize log buffer\n");
+ exit(1);
+ }
+ pthread_create(&log_thr, &attr, log_thread, NULL);
+
+ return;
+}
+
+void log_thread_stop (void)
+{
+ logdbg(stderr,"enter log_thread_stop\n");
+
+ pthread_mutex_lock(logq_lock);
+ pthread_cancel(log_thr);
+ pthread_mutex_unlock(logq_lock);
+
+ flush_logqueue();
+
+ pthread_mutex_destroy(logq_lock);
+ pthread_mutex_destroy(logev_lock);
+ pthread_cond_destroy(logev_cond);
+
+ free_logarea();
+}