|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <stdio.h> |
|
19 #include <stdlib.h> |
|
20 #include <wchar.h> |
|
21 #include <glib.h> |
|
22 |
|
23 #include <exception> |
|
24 |
|
25 #include "cpixsyncpool.h" |
|
26 |
|
27 #include "cpixerror.h" |
|
28 #include "cpixthreadlocaldata.h" |
|
29 #include "common/cpixlog.h" |
|
30 #include "initparams.h" |
|
31 |
|
32 #include "CLucene.h" |
|
33 |
|
34 |
|
35 wchar_t ET_STD_CPP_EXC_NAME[] = L"Std C++ exception"; |
|
36 wchar_t ET_CPIX_EXC_NAME[] = L"CPix exception"; |
|
37 wchar_t ET_CLUCENE_EXC_NAME[] = L"CLucene exception"; |
|
38 wchar_t ET_UNKNOWN_EXC_NAME[] = L"Unknown exception"; |
|
39 wchar_t ET_CPTSYNTAX_EXC_NAME[] = L"Syntax exception"; |
|
40 wchar_t ET_CPT_EXC_NAME[] = L"Cpt exception"; |
|
41 wchar_t ET_OS_EXC_NAME[] = L"OS exception"; |
|
42 |
|
43 const wchar_t * GetErrorTypeName(cpix_ErrorType errorType) |
|
44 { |
|
45 wchar_t |
|
46 * rv = ET_UNKNOWN_EXC_NAME; |
|
47 |
|
48 if (errorType & ET_STD_CPP_EXC) |
|
49 { |
|
50 rv = ET_STD_CPP_EXC_NAME; |
|
51 } |
|
52 else if (errorType & ET_CPIX_EXC) |
|
53 { |
|
54 rv = ET_CPIX_EXC_NAME; |
|
55 } |
|
56 else if (errorType & ET_CLUCENE_EXC) |
|
57 { |
|
58 rv = ET_CLUCENE_EXC_NAME; |
|
59 } |
|
60 else if (errorType == ET_CPTSYNTAX_EXC) |
|
61 { |
|
62 rv = ET_CPTSYNTAX_EXC_NAME; |
|
63 } |
|
64 else if (errorType & ET_CPT_EXC) |
|
65 { |
|
66 rv = ET_CPT_EXC_NAME; |
|
67 } |
|
68 else if (errorType & ET_OS_EXC) |
|
69 { |
|
70 rv = ET_OS_EXC_NAME; |
|
71 } |
|
72 |
|
73 return rv; |
|
74 } |
|
75 |
|
76 |
|
77 |
|
78 /** |
|
79 * This class is used for relaying error messages for asynchronous |
|
80 * calls. It derives from cpix_Error, and thus IS-A a cpix_Error, and |
|
81 * can be used with the rest of the API. |
|
82 * |
|
83 * Rationale: an error status / message must be available as long as |
|
84 * the client does not collect the results of an async call (or has |
|
85 * cancelled it). |
|
86 */ |
|
87 struct ErrorInfo : public cpix_Error |
|
88 { |
|
89 private: |
|
90 // |
|
91 // private members |
|
92 // |
|
93 wchar_t buf_[Cpix::ERRORMSG_BUFSIZE]; |
|
94 |
|
95 |
|
96 public: |
|
97 // |
|
98 // public operators |
|
99 // |
|
100 |
|
101 /** |
|
102 * Sets the error type (type_ in parent class) to the given type |
|
103 * and the message (msg_ in parent class) to NULL. |
|
104 * |
|
105 * @param errorType the error type to set |
|
106 */ |
|
107 void setInfo(cpix_ErrorType errorType) |
|
108 { |
|
109 setInfo(errorType, |
|
110 static_cast<const wchar_t*>(NULL)); |
|
111 } |
|
112 |
|
113 |
|
114 /** |
|
115 * Sets the error type (type_ in parent class) to the given type |
|
116 * and message (msg_ in parent class) to the given message. |
|
117 * |
|
118 * |
|
119 * @param errorType the error type to set |
|
120 * |
|
121 * @param msg the detailed message of the error |
|
122 */ |
|
123 void setInfo(cpix_ErrorType errorType, |
|
124 const wchar_t * msg) |
|
125 { |
|
126 type_ = errorType; |
|
127 if (msg == NULL) |
|
128 { |
|
129 msg_ = NULL; |
|
130 } |
|
131 else |
|
132 { |
|
133 wcsncpy(buf_, |
|
134 msg, |
|
135 sizeof(buf_)/sizeof(wchar_t) - 1); |
|
136 buf_[sizeof(buf_)/sizeof(wchar_t) - 1] |
|
137 = wchar_t(0); |
|
138 msg_ = buf_; |
|
139 } |
|
140 impl_ = this; |
|
141 } |
|
142 |
|
143 |
|
144 /** |
|
145 * Same as overloaded method, but for char instead of wchar_t. |
|
146 */ |
|
147 void setInfo(cpix_ErrorType errorType, |
|
148 const char * msg) |
|
149 { |
|
150 type_ = errorType; |
|
151 if (msg == NULL) |
|
152 { |
|
153 msg_ = NULL; |
|
154 } |
|
155 else |
|
156 { |
|
157 mbstowcs(buf_, |
|
158 msg, |
|
159 sizeof(buf_)/sizeof(wchar_t) - 1); |
|
160 buf_[sizeof(buf_)/sizeof(wchar_t) - 1] |
|
161 = wchar_t(0); |
|
162 msg_ = buf_; |
|
163 } |
|
164 impl_ = this; |
|
165 } |
|
166 |
|
167 |
|
168 /** |
|
169 * Constructor (default). In fact, it initializes the public |
|
170 * members of the super class (which is a C struct part of the |
|
171 * public API). |
|
172 */ |
|
173 ErrorInfo() |
|
174 { |
|
175 type_ = ET_UNKNOWN_EXC; |
|
176 msg_ = NULL; |
|
177 impl_ = this; |
|
178 } |
|
179 }; |
|
180 |
|
181 |
|
182 |
|
183 /** |
|
184 * This error info instance is used with ALL synchronous API calls, |
|
185 * but never with asynchronous API calls. |
|
186 * |
|
187 * NOTE: This C++ instance has in practice a problem getting |
|
188 * constructed properly with the ARM rvctc 2.2 compiler, but it should |
|
189 * not matter - an error info should be set up (setInfo) before use. |
|
190 */ |
|
191 ErrorInfo SyncErrorInfo; |
|
192 |
|
193 |
|
194 /** |
|
195 * A singleton pool of ErrorInfo objects that are used only with |
|
196 * asynchronous calls, never with synchronous calls. |
|
197 * |
|
198 * TODO as a debug measure, set a max limit, and warn/assert when it |
|
199 * is exceeded, to pinpoint leaking error infos. |
|
200 */ |
|
201 class ErrorInfoPool : public Cpt::SyncPool<ErrorInfo> |
|
202 { |
|
203 private: |
|
204 // |
|
205 // private members |
|
206 // |
|
207 |
|
208 static ErrorInfoPool * instance_; |
|
209 |
|
210 public: |
|
211 // |
|
212 // public operators |
|
213 // |
|
214 ErrorInfoPool() |
|
215 : Cpt::SyncPool<ErrorInfo>(Cpix::MIN_ERRORINFO_COUNT) |
|
216 { |
|
217 ; |
|
218 } |
|
219 |
|
220 |
|
221 static ErrorInfoPool * instance() |
|
222 { |
|
223 if (instance_ == NULL) |
|
224 { |
|
225 instance_ = new ErrorInfoPool; |
|
226 } |
|
227 |
|
228 return instance_; |
|
229 } |
|
230 |
|
231 static void shutdown() |
|
232 { |
|
233 delete instance_; |
|
234 instance_ = NULL; |
|
235 } |
|
236 |
|
237 }; |
|
238 |
|
239 namespace Cpix { |
|
240 |
|
241 void InitErrorInfoPool() |
|
242 { |
|
243 ErrorInfoPool::instance(); |
|
244 } |
|
245 |
|
246 |
|
247 void ShutdownErrorInfoPool() |
|
248 { |
|
249 ErrorInfoPool::shutdown(); |
|
250 } |
|
251 } |
|
252 |
|
253 |
|
254 |
|
255 ErrorInfoPool * ErrorInfoPool::instance_ = NULL; |
|
256 |
|
257 |
|
258 |
|
259 ErrorInfo * AcquireErrorInfo() |
|
260 { |
|
261 bool |
|
262 isSlaveThread = false; |
|
263 |
|
264 void |
|
265 * key = pthread_getspecific(Cpix::ThreadLocalDataKey); |
|
266 |
|
267 if (key == NULL) |
|
268 { |
|
269 logMsg(CPIX_LL_ERROR, |
|
270 "No ThreadLocalData in this thread (cpix_init() not called?)"); |
|
271 } |
|
272 else |
|
273 { |
|
274 Cpix::ThreadLocalData |
|
275 * tld = reinterpret_cast<Cpix::ThreadLocalData*>(key); |
|
276 isSlaveThread = tld->isSlaveThread(); |
|
277 } |
|
278 |
|
279 ErrorInfo |
|
280 * rv = NULL; |
|
281 |
|
282 if (isSlaveThread) |
|
283 { |
|
284 // for slave threads (async api), we must use an error |
|
285 // info instance from the pool that noone else is using |
|
286 rv = ErrorInfoPool::instance()->acquire(); |
|
287 } |
|
288 else |
|
289 { |
|
290 // for master thread (sync api), we must use the global |
|
291 // instance |
|
292 rv = & SyncErrorInfo; |
|
293 } |
|
294 |
|
295 return rv; |
|
296 } |
|
297 |
|
298 |
|
299 void ReleaseErrorInfo(ErrorInfo * errorInfo) |
|
300 { |
|
301 if (errorInfo != &SyncErrorInfo) |
|
302 { |
|
303 ErrorInfoPool::instance()->release(errorInfo); |
|
304 } |
|
305 else |
|
306 { |
|
307 ; // SyncErrorInfo is static, nothing to release about it |
|
308 } |
|
309 } |
|
310 |
|
311 |
|
312 |
|
313 cpix_Error * CreateError(cpix_ErrorType errorType, |
|
314 const wchar_t * msg) |
|
315 { |
|
316 ErrorInfo |
|
317 * errorInfo = NULL; |
|
318 |
|
319 try |
|
320 { |
|
321 errorInfo = AcquireErrorInfo(); |
|
322 errorInfo->setInfo(errorType, |
|
323 msg); |
|
324 } |
|
325 catch (...) |
|
326 { |
|
327 logMsg(CPIX_LL_ERROR, |
|
328 "!!! Failed to create error struct for type %d ...", |
|
329 errorType); |
|
330 logMsg(CPIX_LL_ERROR, |
|
331 "!!! ... (cont'd) msg: %S. Will report CPIX error.", |
|
332 msg == NULL ? L"(null)" : msg); |
|
333 |
|
334 errorInfo = & SyncErrorInfo; |
|
335 errorInfo->setInfo(ET_CPIX_EXC); |
|
336 } |
|
337 |
|
338 cpix_Error |
|
339 * rv = static_cast<cpix_Error*>(errorInfo); |
|
340 |
|
341 return rv; |
|
342 } |
|
343 |
|
344 |
|
345 |
|
346 cpix_Error * CreateError(cpix_ErrorType errorType, |
|
347 const char * msg) |
|
348 { |
|
349 ErrorInfo |
|
350 * errorInfo = NULL; |
|
351 |
|
352 try |
|
353 { |
|
354 errorInfo = AcquireErrorInfo(); |
|
355 errorInfo->setInfo(errorType, |
|
356 msg); |
|
357 } |
|
358 catch (...) |
|
359 { |
|
360 logMsg(CPIX_LL_ERROR, |
|
361 "!!! Failed to create error struct for type %d ...", |
|
362 errorType); |
|
363 logMsg(CPIX_LL_ERROR, |
|
364 "!!! ... (cont'd) msg: %s. Will report CPIX error.", |
|
365 msg == NULL ? "(null)" : msg); |
|
366 |
|
367 errorInfo = & SyncErrorInfo; |
|
368 errorInfo->setInfo(ET_CPIX_EXC); |
|
369 } |
|
370 |
|
371 cpix_Error |
|
372 * rv = static_cast<cpix_Error*>(errorInfo); |
|
373 |
|
374 return rv; |
|
375 } |
|
376 |
|
377 |
|
378 |
|
379 void cpix_Error_report(cpix_Error * thisError, |
|
380 wchar_t * target, |
|
381 size_t targetLength) |
|
382 { |
|
383 |
|
384 if (thisError != NULL) |
|
385 { |
|
386 const wchar_t |
|
387 * errorTypeName = GetErrorTypeName(thisError->type_); |
|
388 const wchar_t |
|
389 * detail = thisError->msg_; |
|
390 |
|
391 if (detail == NULL) |
|
392 { |
|
393 detail = L"No details"; |
|
394 } |
|
395 |
|
396 snwprintf(target, |
|
397 targetLength, |
|
398 L"Error type: %S. %S\n", |
|
399 errorTypeName, |
|
400 detail); |
|
401 } |
|
402 else |
|
403 { |
|
404 *target = 0; |
|
405 } |
|
406 } |
|
407 |
|
408 |
|
409 |
|
410 cpix_Error * cpix_Error_destroy(cpix_Error * thisError) |
|
411 { |
|
412 if (thisError != NULL) |
|
413 { |
|
414 ReleaseErrorInfo(reinterpret_cast<ErrorInfo*>(thisError->impl_)); |
|
415 } |
|
416 |
|
417 return NULL; |
|
418 } |
|
419 |