]> code.delx.au - pulseaudio/blob - src/pulsecore/core-error.c
044bea124039463fa1e924587be9257eaccd5d84
[pulseaudio] / src / pulsecore / core-error.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
13
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #ifdef HAVE_PTHREAD
35 #include <pthread.h>
36 #endif
37
38 #ifdef HAVE_WINDOWS_H
39 #include <windows.h>
40 #endif
41
42 #include <pulse/utf8.h>
43 #include <pulse/xmalloc.h>
44
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/native-common.h>
47
48 #include "core-error.h"
49
50 #ifdef HAVE_PTHREAD
51
52 static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT;
53 static pthread_key_t tlsstr_key;
54
55 static void inittls(void) {
56 int ret;
57
58 ret = pthread_key_create(&tlsstr_key, pa_xfree);
59 if (ret) {
60 fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno);
61 exit(-1);
62 }
63 }
64
65 #elif HAVE_WINDOWS_H
66
67 static DWORD tlsstr_key = TLS_OUT_OF_INDEXES;
68 static DWORD monitor_key = TLS_OUT_OF_INDEXES;
69
70 static void inittls(void) {
71 HANDLE mutex;
72 char name[64];
73
74 sprintf(name, "pulse%d", (int)GetCurrentProcessId());
75
76 mutex = CreateMutex(NULL, FALSE, name);
77 if (!mutex) {
78 fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError());
79 exit(-1);
80 }
81
82 WaitForSingleObject(mutex, INFINITE);
83
84 if (tlsstr_key == TLS_OUT_OF_INDEXES) {
85 tlsstr_key = TlsAlloc();
86 monitor_key = TlsAlloc();
87 if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) {
88 fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError());
89 exit(-1);
90 }
91 }
92
93 ReleaseMutex(mutex);
94
95 CloseHandle(mutex);
96 }
97
98 /*
99 * This is incredibly brain dead, but this is necessary when dealing with
100 * the hell that is Win32.
101 */
102 struct monitor_data {
103 HANDLE thread;
104 void *data;
105 };
106
107 static DWORD WINAPI monitor_thread(LPVOID param) {
108 struct monitor_data *data;
109
110 data = (struct monitor_data*)param;
111 assert(data);
112
113 WaitForSingleObject(data->thread, INFINITE);
114
115 CloseHandle(data->thread);
116 pa_xfree(data->data);
117 pa_xfree(data);
118
119 return 0;
120 }
121
122 static void start_monitor(void) {
123 HANDLE thread;
124 struct monitor_data *data;
125
126 data = pa_xnew(struct monitor_data, 1);
127 assert(data);
128
129 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
130 GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS);
131
132 thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL);
133 assert(thread);
134
135 TlsSetValue(monitor_key, data);
136
137 CloseHandle(thread);
138 }
139
140 #else
141
142 /* Unsafe, but we have no choice */
143 static char *tlsstr;
144
145 #endif
146
147 const char* pa_cstrerror(int errnum) {
148 const char *origbuf;
149
150 #ifdef HAVE_STRERROR_R
151 char errbuf[128];
152 #endif
153
154 #ifdef HAVE_PTHREAD
155 char *tlsstr;
156
157 pthread_once(&cstrerror_once, inittls);
158
159 tlsstr = pthread_getspecific(tlsstr_key);
160 #elif defined(HAVE_WINDOWS_H)
161 char *tlsstr;
162 struct monitor_data *data;
163
164 inittls();
165
166 tlsstr = TlsGetValue(tlsstr_key);
167 if (!tlsstr)
168 start_monitor();
169 data = TlsGetValue(monitor_key);
170 #endif
171
172 if (tlsstr)
173 pa_xfree(tlsstr);
174
175 #ifdef HAVE_STRERROR_R
176
177 #ifdef __GLIBC__
178 origbuf = strerror_r(errnum, errbuf, sizeof(errbuf));
179 if (origbuf == NULL)
180 origbuf = "";
181 #else
182 if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) {
183 origbuf = errbuf;
184 errbuf[sizeof(errbuf) - 1] = '\0';
185 } else
186 origbuf = "";
187 #endif
188
189 #else
190 /* This might not be thread safe, but we hope for the best */
191 origbuf = strerror(errnum);
192 #endif
193
194 tlsstr = pa_locale_to_utf8(origbuf);
195 if (!tlsstr) {
196 fprintf(stderr, "Unable to convert, filtering\n");
197 tlsstr = pa_utf8_filter(origbuf);
198 }
199
200 #ifdef HAVE_PTHREAD
201 pthread_setspecific(tlsstr_key, tlsstr);
202 #elif defined(HAVE_WINDOWS_H)
203 TlsSetValue(tlsstr_key, tlsstr);
204 data->data = tlsstr;
205 #endif
206
207 return tlsstr;
208 }