Make log_pthread more robust
[multipath-tools/.git] / libmultipath / log_pthread.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <pthread.h>
8 #include <sys/mman.h>
9
10 #include <memory.h>
11
12 #include "log_pthread.h"
13 #include "log.h"
14 #include "lock.h"
15
16 pthread_t log_thr;
17
18 pthread_mutex_t logq_lock;
19 pthread_mutex_t logev_lock;
20 pthread_cond_t logev_cond;
21
22 int logq_running;
23
24 static void
25 sigusr1 (int sig)
26 {
27         pthread_mutex_lock(&logq_lock);
28         log_reset("multipathd");
29         pthread_mutex_unlock(&logq_lock);
30 }
31
32 void log_safe (int prio, const char * fmt, va_list ap)
33 {
34         sigset_t old;
35
36         if (log_thr == (pthread_t)0) {
37                 syslog(prio, fmt, ap);
38                 return;
39         }
40
41         block_signal(SIGUSR1, &old);
42         block_signal(SIGHUP, NULL);
43
44         pthread_mutex_lock(&logq_lock);
45         log_enqueue(prio, fmt, ap);
46         pthread_mutex_unlock(&logq_lock);
47
48         pthread_mutex_lock(&logev_lock);
49         pthread_cond_signal(&logev_cond);
50         pthread_mutex_unlock(&logev_lock);
51
52         pthread_sigmask(SIG_SETMASK, &old, NULL);
53 }
54
55 static void flush_logqueue (void)
56 {
57         int empty;
58
59         do {
60                 pthread_mutex_lock(&logq_lock);
61                 empty = log_dequeue(la->buff);
62                 pthread_mutex_unlock(&logq_lock);
63                 if (!empty)
64                         log_syslog(la->buff);
65         } while (empty == 0);
66 }
67
68 static void * log_thread (void * et)
69 {
70         struct sigaction sig;
71         int running;
72
73         sig.sa_handler = sigusr1;
74         sigemptyset(&sig.sa_mask);
75         sig.sa_flags = 0;
76         if (sigaction(SIGUSR1, &sig, NULL) < 0)
77                 logdbg(stderr, "Cannot set signal handler");
78
79         pthread_mutex_lock(&logev_lock);
80         logq_running = 1;
81         pthread_mutex_unlock(&logev_lock);
82
83         mlockall(MCL_CURRENT | MCL_FUTURE);
84         logdbg(stderr,"enter log_thread\n");
85
86         while (1) {
87                 pthread_mutex_lock(&logev_lock);
88                 pthread_cond_wait(&logev_cond, &logev_lock);
89                 running = logq_running;
90                 pthread_mutex_unlock(&logev_lock);
91                 if (!running)
92                         break;
93                 log_thread_flush();
94         }
95         return NULL;
96 }
97
98 void log_thread_start (pthread_attr_t *attr)
99 {
100         logdbg(stderr,"enter log_thread_start\n");
101
102         pthread_mutex_init(&logq_lock, NULL);
103         pthread_mutex_init(&logev_lock, NULL);
104         pthread_cond_init(&logev_cond, NULL);
105
106         if (log_init("multipathd", 0)) {
107                 fprintf(stderr,"can't initialize log buffer\n");
108                 exit(1);
109         }
110         if (pthread_create(&log_thr, attr, log_thread, NULL)) {
111                 fprintf(stderr,"can't start log thread\n");
112                 exit(1);
113         }
114
115         return;
116 }
117
118 void log_thread_stop (void)
119 {
120         logdbg(stderr,"enter log_thread_stop\n");
121
122         pthread_mutex_lock(&logev_lock);
123         logq_running = 0;
124         pthread_cond_signal(&logev_cond);
125         pthread_mutex_unlock(&logev_lock);
126
127         pthread_mutex_lock(&logq_lock);
128         pthread_cancel(log_thr);
129         pthread_mutex_unlock(&logq_lock);
130         pthread_join(log_thr, NULL);
131         log_thr = (pthread_t)0;
132
133         flush_logqueue();
134
135         pthread_mutex_destroy(&logq_lock);
136         pthread_mutex_destroy(&logev_lock);
137         pthread_cond_destroy(&logev_cond);
138
139         log_close();
140 }