summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1085/pgm/messages.c
blob: 9fa281b636a48d5c1c0bf6f13ea988b8bbb0492f (plain) (blame)
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
 *
 * basic message reporting.
 *
 * Copyright (c) 2010 Miru Limited.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdarg.h>
#include <stdio.h>
#include <impl/framework.h>


/* globals */

/* bit mask for trace role modules */
int pgm_log_mask PGM_GNUC_READ_MOSTLY		= 0xffff;
int pgm_min_log_level PGM_GNUC_READ_MOSTLY	= PGM_LOG_LEVEL_NORMAL;


/* locals */

static const char log_levels[8][6] = {
	"Uknown",
	"Debug",
	"Trace",
	"Minor",
	"Info",
	"Warn",
	"Error",
	"Fatal"
};

static volatile uint32_t	messages_ref_count = 0;
static pgm_mutex_t		messages_mutex;
static pgm_log_func_t 		log_handler PGM_GNUC_READ_MOSTLY = NULL;
static void* 			log_handler_closure PGM_GNUC_READ_MOSTLY = NULL;

static inline const char* log_level_text (const int) PGM_GNUC_PURE;


static inline
const char*
log_level_text (
	const int	log_level
	)
{
	switch (log_level) {
	default:			return log_levels[0];
	case PGM_LOG_LEVEL_DEBUG:	return log_levels[1];
	case PGM_LOG_LEVEL_TRACE:	return log_levels[2];
	case PGM_LOG_LEVEL_MINOR:	return log_levels[3];
	case PGM_LOG_LEVEL_NORMAL:	return log_levels[4];
	case PGM_LOG_LEVEL_WARNING:	return log_levels[5];
	case PGM_LOG_LEVEL_ERROR:	return log_levels[6];
	case PGM_LOG_LEVEL_FATAL:	return log_levels[7];
	}
}

/* reference counted init and shutdown
 */

void
pgm_messages_init (void)
{
	if (pgm_atomic_exchange_and_add32 (&messages_ref_count, 1) > 0)
		return;

	pgm_mutex_init (&messages_mutex);

	const char* log_mask = getenv ("PGM_LOG_MASK");
	if (NULL != log_mask) {
		unsigned int value = 0;
		if (1 == sscanf (log_mask, "0x%4x", &value))
			pgm_log_mask = value;
	}
	const char *min_log_level = getenv ("PGM_MIN_LOG_LEVEL");
	if (NULL != min_log_level) {
		switch (min_log_level[0]) {
		case 'D':	pgm_min_log_level = PGM_LOG_LEVEL_DEBUG; break;
		case 'T':	pgm_min_log_level = PGM_LOG_LEVEL_TRACE; break;
		case 'M':	pgm_min_log_level = PGM_LOG_LEVEL_MINOR; break;
		case 'N':	pgm_min_log_level = PGM_LOG_LEVEL_NORMAL; break;
		case 'W':	pgm_min_log_level = PGM_LOG_LEVEL_WARNING; break;
		case 'E':	pgm_min_log_level = PGM_LOG_LEVEL_ERROR; break;
		case 'F':	pgm_min_log_level = PGM_LOG_LEVEL_FATAL; break;
		default: break;
		}
	}
}

void
pgm_messages_shutdown (void)
{
	pgm_return_if_fail (pgm_atomic_read32 (&messages_ref_count) > 0);

	if (pgm_atomic_exchange_and_add32 (&messages_ref_count, (uint32_t)-1) != 1)
		return;

	pgm_mutex_free (&messages_mutex);
}

/* set application handler for log messages, returns previous value,
 * default handler value is NULL.
 */

pgm_log_func_t
pgm_log_set_handler (
	pgm_log_func_t		handler,
	void*			closure
	)
{
	pgm_log_func_t previous_handler;
	pgm_mutex_lock (&messages_mutex);
	previous_handler	= log_handler;
	log_handler		= handler;
	log_handler_closure	= closure;
	pgm_mutex_unlock (&messages_mutex);
	return previous_handler;
}

void
pgm__log (
	const int		log_level,
	const char*		format,
	...
	)
{
	va_list args;

	va_start (args, format);
	pgm__logv (log_level, format, args);
	va_end (args);
}

void
pgm__logv (
	const int		log_level,
	const char*		format,
	va_list			args
	)
{
	char tbuf[ 1024 ];

	pgm_mutex_lock (&messages_mutex);
	const int offset = sprintf (tbuf, "%s: ", log_level_text (log_level));
	vsnprintf (tbuf+offset, sizeof(tbuf)-offset, format, args);
	tbuf[ sizeof(tbuf) ] = '\0';
	if (log_handler)
		log_handler (log_level, tbuf, log_handler_closure);
	else {
/* ignore return value */
		write (STDOUT_FILENO, tbuf, strlen (tbuf));
		write (STDOUT_FILENO, "\n", 1);
	}
		
	pgm_mutex_unlock (&messages_mutex);
}

/* eof */