File: log_pthread.c

package info (click to toggle)
multipath-tools 0.13.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,992 kB
  • sloc: ansic: 63,788; perl: 1,622; makefile: 729; sh: 647; pascal: 150
file content (159 lines) | stat: -rw-r--r-- 3,247 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Copyright (c) 2005 Christophe Varoqui
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <syslog.h>
#include <pthread.h>
#include <sys/mman.h>

#include "log_pthread.h"
#include "log.h"
#include "lock.h"
#include "util.h"

static pthread_t log_thr;

/* logev_lock must not be taken with logq_lock held */
static pthread_mutex_t logev_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t logev_cond = PTHREAD_COND_INITIALIZER;

static int logq_running;
static int log_messages_pending;

void log_safe (int prio, const char * fmt, va_list ap)
{
	bool running;

	if (prio > LOG_DEBUG)
		prio = LOG_DEBUG;

	/*
	 * logev_lock protects logq_running. By holding it, we avoid a race
	 * with log_thread_stop() -> log_close(), which would free the logarea.
	 */
	pthread_mutex_lock(&logev_lock);
	pthread_cleanup_push(cleanup_mutex, &logev_lock);
	running = logq_running;

	if (running) {
		log_enqueue(prio, fmt, ap);

		log_messages_pending = 1;
		pthread_cond_signal(&logev_cond);
	}
	pthread_cleanup_pop(1);

	if (!running)
		vsyslog(prio, fmt, ap);
}

static void flush_logqueue (void)
{
	int empty;

	do {
		empty = log_dequeue(la->buff);
		if (!empty)
			log_syslog(la->buff);
	} while (empty == 0);
}

static void cleanup_log_thread(__attribute__((unused)) void *arg)
{
	logdbg(stderr, "log thread exiting");
	pthread_mutex_lock(&logev_lock);
	logq_running = 0;
	pthread_mutex_unlock(&logev_lock);
}

static void * log_thread (__attribute__((unused)) void * et)
{
	int running;

	pthread_mutex_lock(&logev_lock);
	running = logq_running;
	if (!running)
		logq_running = 1;
	pthread_cond_signal(&logev_cond);
	pthread_mutex_unlock(&logev_lock);
	if (running)
		/* already started */
		return NULL;
	pthread_cleanup_push(cleanup_log_thread, NULL);

	mlockall(MCL_CURRENT | MCL_FUTURE);
	logdbg(stderr,"enter log_thread\n");

	while (1) {
		pthread_mutex_lock(&logev_lock);
		pthread_cleanup_push(cleanup_mutex, &logev_lock);
		while (!log_messages_pending)
			/* this is a cancellation point */
			pthread_cond_wait(&logev_cond, &logev_lock);
		log_messages_pending = 0;
		pthread_cleanup_pop(1);

		flush_logqueue();
	}
	pthread_cleanup_pop(1);
	return NULL;
}

void log_thread_start (pthread_attr_t *attr)
{
	int running = 0;

	logdbg(stderr,"enter log_thread_start\n");

	if (log_init("multipathd", 0)) {
		fprintf(stderr,"can't initialize log buffer\n");
		exit(1);
	}

	pthread_mutex_lock(&logev_lock);
	pthread_cleanup_push(cleanup_mutex, &logev_lock);
	if (!pthread_create(&log_thr, attr, log_thread, NULL))
		while (!(running = logq_running))
			pthread_cond_wait(&logev_cond, &logev_lock);
	pthread_cleanup_pop(1);

	if (!running) {
		fprintf(stderr,"can't start log thread\n");
		exit(1);
	}

	return;
}

void log_thread_reset (void)
{
	logdbg(stderr,"resetting log\n");
	log_reset("multipathd");
}

void log_thread_stop (void)
{
	int running;

	if (!la)
		return;

	logdbg(stderr,"enter log_thread_stop\n");

	pthread_mutex_lock(&logev_lock);
	pthread_cleanup_push(cleanup_mutex, &logev_lock);
	running = logq_running;
	if (running) {
		pthread_cancel(log_thr);
		pthread_cond_signal(&logev_cond);
	}
	pthread_cleanup_pop(1);

	if (running)
		pthread_join(log_thr, NULL);

	flush_logqueue();
	log_close();
}