comparison Isolated/tErrorLib.c @ 38:71b465ff0622

Added support files.
author Eric Wing <ewing@anscamobile.com>
date Thu, 28 Apr 2011 16:22:30 -0700
parents
children c07dbd386ded
comparison
equal deleted inserted replaced
37:b346b6608eab 38:71b465ff0622
1 /* See header file for license information. */
2
3 #include "tErrorLib.h"
4 #include <stdlib.h> /* for malloc */
5 #include <string.h>
6 #include <stdarg.h> /* for vasprintf */
7 #include <stdio.h> /* also for vasprintf and for printf family */
8 #include <stddef.h> /* size_t */
9
10 /**
11 * For string-only based usage, this implementation
12 * still expects an actual error number to be set.
13 * I am defining 1 as that error value. This might be changable,
14 * but it is untested. If you change this value, you must recompile
15 * the entire library. This can really be any integer except what
16 * TERROR_NOERROR_VALUE (in header) is set to.
17 */
18 #define TERROR_ERROR_VALUE 1
19
20 #ifdef DONT_USE_VASPRINT
21 #define TERROR_DEFAULT_STRING_LENGTH 128
22 /* Visual Studio doesn't define snprintf but _snprintf */
23 #ifdef _MSC_VER
24 #define snprintf _snprintf
25 #define vsnprintf _vsnprintf
26 #endif
27 #endif
28
29
30 #if defined(_WIN32) && !defined(__CYGWIN32__)
31 #include <windows.h>
32 #include <winbase.h> /* For CreateMutex(), LockFile() */
33
34 static void* Internal_CreateMutex()
35 {
36 return((void*)CreateMutex(NULL, FALSE, NULL));
37 }
38 static void Internal_DestroyMutex(void* mutex)
39 {
40 if(NULL != mutex)
41 {
42 CloseHandle( (HANDLE)mutex );
43 }
44 }
45 /* This will return true if locking is successful, false if not.
46 */
47 static int Internal_LockMutex(void* mutex)
48 {
49 return(
50 WaitForSingleObject(
51 (HANDLE)mutex,
52 INFINITE
53 ) != WAIT_FAILED
54 );
55 }
56 static void Internal_UnlockMutex(void* mutex)
57 {
58 ReleaseMutex(
59 (HANDLE)mutex
60 );
61 }
62 size_t Internal_PlatformPlatformGetThreadID(void)
63 {
64 return((size_t)GetCurrentThreadId());
65 }
66 #else /* Assuming POSIX...maybe not a good assumption. */
67 #include <pthread.h>
68 static void* Internal_CreateMutex()
69 {
70 int ret_val;
71 pthread_mutex_t* m = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
72 if(NULL == m)
73 {
74 return NULL;
75 }
76 ret_val = pthread_mutex_init(m, NULL);
77 if(0 != ret_val)
78 {
79 free(m);
80 return NULL;
81 }
82 return((void*)m);
83 }
84 static void Internal_DestroyMutex(void* mutex)
85 {
86 if(NULL != mutex)
87 {
88 pthread_mutex_destroy((pthread_mutex_t*) (mutex));
89 free(mutex);
90 }
91 }
92 /* This will return true if locking is successful, false if not.
93 * (This is the opposite of pthread_mutex_lock which returns
94 * 0 for success.)
95 */
96 static int Internal_LockMutex(void* mutex)
97 {
98 return(
99 pthread_mutex_lock(
100 (pthread_mutex_t*)mutex
101 ) == 0
102 );
103 }
104 static void Internal_UnlockMutex(void* mutex)
105 {
106 pthread_mutex_unlock(
107 (pthread_mutex_t*)mutex
108 );
109 }
110
111 size_t Internal_PlatformGetThreadID()
112 {
113 /* Basically, we need to convert a pthread_t into an id number. */
114 return (size_t)pthread_self();
115 }
116 #endif
117
118
119 /**
120 * Copies a source string, potentially to a target string, and returns
121 * the pointer to the copied string.
122 * This function is a intended to be an efficient string copy function.
123 * It's purpose is to copy a string into a string with preallocated memory
124 * and avoid dynamic memory allocation if possible. If memory must
125 * be allocated, then the old string will be destroyed.
126 *
127 * This is only to be used where target_string was created with dynamic
128 * memory. This function will destroy the memory and allocate new memory
129 * if there is not enough space in the target string.
130 *
131 * @param target_string This is the string you would like to try
132 * to copy into. If there is not enough space, a new string will
133 * be created and the target_string will be freed. This string
134 * must have been created dynamically. This may be NULL if you
135 * wish for this function to dynamically create a new string
136 * for you.
137 *
138 * @param target_max_buffer_size This is a pointer that points to
139 * an address containing the size of the preallocated target_string.
140 * This size is the maximum buffer length which includes the '\\0'
141 * character as part of that count. This pointer may not be NULL.
142 * If you pass in NULL for the target_string (indicating you want
143 * a new string allocated for you), then the size should be set to 0.
144 * When the function completes, the size will be set to the new
145 * max buffer size of the string if the string needed to be reallocated.
146 *
147 * @param source_string This is the string you want to copy. If it's NULL,
148 * the target_string will have it's memory freed.
149 *
150 * @return Will return a pointer to the duplicated string. Be aware
151 * of several things:
152 * - The returned pointer address may not be the same address as the
153 * target string passed in (due to a possible reallocation).
154 * - If the pointer to the source and target string
155 * are the same, the pointer to the target string will be returned.
156 * - If the source string is NULL, the target string
157 * will be freed and will return NULL.
158 * - If an error occurs, NULL will be returned.
159 *
160 * Also note that the value at the address target_max_buffer_size points
161 * to will be filled with the new max buffer size for the string.
162 *
163 * Example:
164 * @code
165 *
166 * int main()
167 * {
168 * const char* original1 = "Hello World";
169 * const char* original2 = "Smaller";
170 * const char* original3 = "Good-Bye World";
171 * char* ret_val;
172 * char* target = NULL;
173 * size_t target_max_buffer_size = 0;
174 *
175 * ret_val = CopyDynamicString(target, &target_max_buffer_size, original1);
176 *
177 * if(ret_val)
178 * {
179 * fprintf(stderr, "Target is '%s' with max size = %d\n", ret_val, target_max_buffer_size);
180 * }
181 * else
182 * {
183 * fprintf(stderr, "Error in function\n");
184 * }
185 * target = ret_val;
186 *
187 * ret_val = CopyDynamicString(target, &target_max_buffer_size, original2);
188 * fprintf(stderr, "Target is '%s' with max size = %d\n", ret_val, target_max_buffer_size);
189 *
190 * target = ret_val; *
191 * ret_val = CopyDynamicString(target, &target_max_buffer_size, original3);
192 * fprintf(stderr, "Target is '%s' with max size = %d\n", ret_val, target_max_buffer_size);
193 *
194 * return 0;
195 * }
196 * @endcode
197 * This outputs:
198 * @code
199 * Target is 'Hello World' with max size = 12
200 * Target is 'Smaller' with max size = 12
201 * Target is 'Good-Bye World' with max size = 15
202 * @endcode
203 */
204 static char* Internal_CopyDynamicString(char* target_string, size_t* target_max_buffer_size, const char* source_string)
205 {
206 /* If the pointers are the same, no copy is needed. */
207 if(source_string == target_string)
208 {
209 /* I don't feel like asserting if the sizes are the same. */
210 /* Return 1 instead of 0 because maybe this isn't an error?
211 */
212 return target_string;
213 }
214
215 /* Make sure the size pointer is valid. */
216 if(NULL == target_max_buffer_size)
217 {
218 return NULL;
219 }
220
221 /* Yikes, if the string is NULL, should we make the target string NULL?
222 * For now, yes, we destroy the string. If you change this, realize that
223 * their is code that depends on this behavior.
224 */
225 if(NULL == source_string)
226 {
227 *target_max_buffer_size = 0;
228 free(target_string);
229 target_string = NULL;
230 return NULL;
231 }
232
233 /* If target_string is NULL, the *target_max_buffer_size should also be 0.
234 * Technically, the user should set this and this would be an error,
235 * but I'll be nice for now. An alternate implementation might suggest
236 * that the size would be the desired size the user wants for a new string.
237 */
238 if( (NULL == target_string) && (0 != *target_max_buffer_size) )
239 {
240 *target_max_buffer_size = 0;
241 }
242
243 /* If there is not enough preallocated memory in the target string,
244 * then we need to reallocate enough memory.
245 */
246 if( *target_max_buffer_size < (strlen(source_string) + 1) )
247 {
248 *target_max_buffer_size = 0;
249 if(NULL != target_string)
250 {
251 free(target_string);
252 }
253 target_string = (char*)calloc( (strlen(source_string) + 1), sizeof(char) );
254 if(NULL == target_string)
255 {
256 return NULL;
257 }
258 *target_max_buffer_size = strlen(source_string) + 1;
259 }
260
261 /* At this point, there should be enough preallocated
262 * memory to call strncpy.
263 */
264 strncpy(target_string, source_string, *target_max_buffer_size);
265
266 return target_string;
267 }
268
269 /**
270 * This is a structure that contains everything needed for an
271 * error message entry (per thread). The linked list stuff
272 * is fused in with it because I didn't want to write an entire
273 * linked list class.
274 */
275 typedef struct TErrorMessageStructType
276 {
277 size_t threadID; /** ThreadID for associated message. */
278 int errorAvailable; /** 1 if an error has been set and not been checked. */
279 int errorNumber; /**< For the user error number. */
280 char* errorString; /**< For the user error message. */
281 size_t errorMaxStringLength; /**< Max size of string buffer including \\0. */
282 struct TErrorMessageStructType* nextItem; /**< Pointer to next error message in list. */
283 } TErrorMessage;
284
285 /**
286 * This is a private struct that contains all private data for an
287 * ErrorPool. Currently it is a linked list containing all error message
288 * structs for every thread.
289 */
290 typedef struct
291 {
292 TErrorMessage* errorMessageListHead; /**< Head of the error list. */
293 TErrorMessage* lastErrorMessage; /**< Points to the last set element in the list for GetLastError. */
294 /* Mutex */
295 } TErrorPoolOpaqueData;
296
297 /**
298 * This is a private helper function that creates a new TErrorMessage
299 * and initializes all its values.
300 * @return Returns a pointer to a newly allocated and initialized
301 * TErrorMessage or NULL on failure.
302 */
303 static TErrorMessage* Internal_CreateErrorMessageStructure()
304 {
305 TErrorMessage* new_message;
306 /* Use calloc to create a fully cleared structure,
307 * so I don't have to set/clear each member.
308 */
309 new_message = (TErrorMessage*)calloc(1, sizeof(TErrorMessage));
310 if(NULL == new_message)
311 {
312 /* Very bad, but not sure what to do. */
313 return NULL;
314 }
315 new_message->errorNumber = TERROR_NOERROR_VALUE;
316 return new_message;
317 }
318
319 /**
320 * This is a private helper function that frees a TErrorMessage.
321 *
322 * @param err_mesg The pointer to the TErrorMessage to be freed.
323 */
324 static void Internal_FreeErrorMessageStructure(TErrorMessage* err_mesg)
325 {
326 if(NULL == err_mesg)
327 {
328 return;
329 }
330 if(NULL != err_mesg->errorString)
331 {
332 free(err_mesg->errorString);
333 err_mesg->errorString = NULL;
334 }
335 err_mesg->nextItem = NULL;
336 free(err_mesg);
337 }
338
339 /**
340 * This is a private helper function that will search the error pool
341 * for the last set error message structure in the Linked list.
342 * If the last error message was on a different thread, the error
343 * data will be copied to the current thread's memory and the
344 * lastErrorMessage pointer will be set to the current thread's message.
345 * (This is because I expect this message to be marked as cleared/read.)
346 * This function does its own mutex locking.
347 *
348 * @param err_pool The error pool to be used.
349 * @return Returns the a pointer to the TErrorMessage if found,
350 * NULL if not found.
351 */
352 static TErrorMessage* Internal_GetLastError(TErrorPool* err_pool)
353 {
354 size_t thread_id;
355 TErrorMessage* current_thread_err_mesg;
356 TErrorPoolOpaqueData* err_pool_data;
357
358 thread_id = Internal_PlatformGetThreadID();
359
360 Internal_LockMutex(err_pool->mutexLock);
361
362 err_pool_data = err_pool->opaqueData;
363
364 if(NULL == err_pool_data->errorMessageListHead)
365 {
366 Internal_UnlockMutex(err_pool->mutexLock);
367 return NULL;
368 }
369
370 /* I think this is actually an assertion failure.
371 * I do the check here so I don't have to keep checking below.
372 */
373 if(NULL == err_pool_data->lastErrorMessage)
374 {
375 Internal_UnlockMutex(err_pool->mutexLock);
376 return NULL;
377 }
378
379 /* We need to determine if the lastMessage pointer is pointing
380 * to data on the current thread. If it is we can just return it.
381 * Otherwise, we need to copy the message to the current thread's
382 * error message memory area.
383 * We should also update the lastMessage pointer to point
384 * to this message since it will likely be marked cleared once read.
385 */
386 if(thread_id == err_pool_data->lastErrorMessage->threadID)
387 {
388 /* Not copy is needed. The last error message already
389 * points to the memory on the current thread.
390 * We can short-circuit and return.
391 */
392 Internal_UnlockMutex(err_pool->mutexLock);
393 return err_pool_data->lastErrorMessage;
394 }
395
396 /* Sigh, I really should have a dedicated linked list structure,
397 * but I don't feel like writing it right now.
398 */
399 for(current_thread_err_mesg = err_pool_data->errorMessageListHead; current_thread_err_mesg != NULL; current_thread_err_mesg = current_thread_err_mesg->nextItem)
400 {
401 /* First find the message (memory) for the current thread. */
402 if(thread_id == current_thread_err_mesg->threadID)
403 {
404 /* Now we need to copy the message data from the lastErrorMessage
405 * to this thread's message (memory).
406 */
407 current_thread_err_mesg->errorNumber = err_pool_data->lastErrorMessage->errorNumber;
408 current_thread_err_mesg->errorAvailable = err_pool_data->lastErrorMessage->errorAvailable;
409 /* This will copy the string and set the new errorMaxStringLength as needed. */
410 current_thread_err_mesg->errorString = Internal_CopyDynamicString(current_thread_err_mesg->errorString, &current_thread_err_mesg->errorMaxStringLength, err_pool_data->lastErrorMessage->errorString);
411
412
413 /* Finally, change the last error message to point to
414 * the current thread since I expect the message to be
415 * marked cleared and we don't want to accidentally refetched
416 * the stale, uncleared entry.
417 */
418 err_pool_data->lastErrorMessage = current_thread_err_mesg;
419
420 Internal_UnlockMutex(err_pool->mutexLock);
421 return current_thread_err_mesg;
422 }
423 }
424 Internal_UnlockMutex(err_pool->mutexLock);
425 return NULL;
426 }
427
428 /**
429 * This is a private helper function that will search the error pool
430 * for an error message structure in the Linked list (by thread ID)
431 * and return the pointer if found. This function does its own mutex
432 * locking.
433 * @param err_pool The error pool to be used.
434 * @return Returns the a pointer to the TErrorMessage if found,
435 * NULL if not found.
436 */
437 static TErrorMessage* Internal_GetErrorOnCurrentThread(TErrorPool* err_pool)
438 {
439 size_t thread_id;
440 TErrorMessage* current_err_mesg;
441 TErrorPoolOpaqueData* err_pool_data;
442
443 thread_id = Internal_PlatformGetThreadID();
444
445 Internal_LockMutex(err_pool->mutexLock);
446
447 err_pool_data = err_pool->opaqueData;
448
449 if(NULL == err_pool_data->errorMessageListHead)
450 {
451 Internal_UnlockMutex(err_pool->mutexLock);
452 return NULL;
453 }
454
455 /* Sigh, I really should have a dedicated linked list structure,
456 * but I don't feel like writing it right now.
457 */
458 for(current_err_mesg = err_pool_data->errorMessageListHead; current_err_mesg != NULL; current_err_mesg = current_err_mesg->nextItem)
459 {
460 if(thread_id == current_err_mesg->threadID)
461 {
462 Internal_UnlockMutex(err_pool->mutexLock);
463 return current_err_mesg;
464 }
465 }
466 Internal_UnlockMutex(err_pool->mutexLock);
467 return NULL;
468 }
469
470 /**
471 * Given a specific TErrorMessage*, will set the lastErrorMessage pointer to
472 * the provided error message.
473 * This function locks.
474 *
475 * @param err_pool The error pool to be used.
476 * @param error_message The error message to set the lastErrorMessage pointer to
477 */
478 static void Internal_SetLastErrorMessagePointerToErrorMessage(TErrorPool* err_pool, TErrorMessage* error_message)
479 {
480 TErrorPoolOpaqueData* err_pool_data;
481 Internal_LockMutex(err_pool->mutexLock);
482 err_pool_data = err_pool->opaqueData;
483 err_pool_data->lastErrorMessage = error_message;
484 Internal_UnlockMutex(err_pool->mutexLock);
485 }
486
487
488 /**
489 * This is a private helper function that creates a new error message
490 * structure for the current thread.
491 * This currently does not check if an error already exists
492 * before creating a new entry. Call GetErrorOnCurrentThread first
493 * to make sure nothing exists or duplicate entries will be created.
494 * This function does its own mutex locking.
495 *
496 * @param err_pool The error pool to be used.
497 * @return Returns the a pointer to the TErrorMessage if found,
498 * NULL if there was an allocation error.
499 */
500 static TErrorMessage* Internal_CreateErrorOnCurrentThread(TErrorPool* err_pool)
501 {
502 TErrorMessage* new_err_mesg;
503 TErrorPoolOpaqueData* err_pool_data;
504
505 new_err_mesg = Internal_CreateErrorMessageStructure();
506 if(NULL == new_err_mesg)
507 {
508 /* Serious problem, not sure what to do. */
509 return NULL;
510 }
511 /* Copy the thread id so we can distinguish between entries. */
512 new_err_mesg->threadID = Internal_PlatformGetThreadID();
513
514 Internal_LockMutex(err_pool->mutexLock);
515
516 err_pool_data = err_pool->opaqueData;
517 /* Add the new message to the top of the list by making
518 * its next pointer point to the head of the current list.
519 * (A formal linked list implementation would make this feel
520 * less hacky.)
521 * This also (should) handle the case where errorMessageListHead
522 * is NULL.
523 */
524 new_err_mesg->nextItem = err_pool_data->errorMessageListHead;
525 /* Now set the head of the list to the new message.
526 */
527 err_pool_data->errorMessageListHead = new_err_mesg;
528
529 Internal_UnlockMutex(err_pool->mutexLock);
530
531 return new_err_mesg;
532 }
533
534 /**
535 * This is a private helper function that will clean up all the
536 * error message structures in the list. This function does its
537 * own locking.
538 * @param err_pool The error pool to be used.
539 */
540 static void Internal_FreeErrorMessageList(TErrorPool* err_pool)
541 {
542 TErrorMessage* current_message = NULL;
543 TErrorMessage* next_message = NULL;
544 TErrorPoolOpaqueData* err_pool_data;
545
546 Internal_LockMutex(err_pool->mutexLock);
547
548 err_pool_data = err_pool->opaqueData;
549
550 if(NULL == err_pool_data->errorMessageListHead)
551 {
552 Internal_UnlockMutex(err_pool->mutexLock);
553 return;
554 }
555
556 /* Sigh, I really should have a dedicated linked list structure,
557 * but I don't feel like writing it right now.
558 */
559 for(current_message = err_pool_data->errorMessageListHead;
560 current_message != NULL;
561 current_message = next_message
562 )
563 {
564 next_message = current_message->nextItem;
565 Internal_FreeErrorMessageStructure(current_message);
566 }
567 err_pool_data->errorMessageListHead = NULL;
568 err_pool_data->lastErrorMessage = NULL;
569
570 Internal_UnlockMutex(err_pool->mutexLock);
571 }
572
573 /*
574 * API functions start below.
575 *
576 */
577
578
579 void TError_DeleteEntryOnCurrentThread(TErrorPool* err_pool)
580 {
581 TErrorMessage* prev_message = NULL;
582 TErrorMessage* current_message = NULL;
583 TErrorMessage* next_message = NULL;
584 size_t thread_id;
585 TErrorPoolOpaqueData* err_pool_data;
586
587 thread_id = Internal_PlatformGetThreadID();
588
589 Internal_LockMutex(err_pool->mutexLock);
590
591 err_pool_data = err_pool->opaqueData;
592
593 if(NULL == err_pool_data->errorMessageListHead)
594 {
595 Internal_UnlockMutex(err_pool->mutexLock);
596 return;
597 }
598
599 /* Sigh, I really should have a dedicated linked list structure,
600 * but I don't feel like writing it right now.
601 */
602 for(current_message = err_pool_data->errorMessageListHead;
603 current_message != NULL;
604 /* I'm not going to increment here because I
605 * may delete the item below which would probably
606 * cause bad things to happen here.
607 */
608 /* current_message = current_message->nextItem */
609 )
610 {
611 next_message = current_message->nextItem;
612
613 if(thread_id == current_message->threadID)
614 {
615 /* Special case, current is only item in list:
616 * Both next and prev are NULL in this case.
617 * We should delete the item and set the errorMessageListHead
618 * to NULL.
619 */
620 if((NULL == prev_message) && (NULL == next_message))
621 {
622 Internal_FreeErrorMessageStructure(current_message);
623 current_message = NULL;
624 err_pool_data->errorMessageListHead = NULL;
625 err_pool_data->lastErrorMessage = NULL;
626 }
627 /* Special case, current is at head:
628 * Prev is NULL but next is not NULL in this case.
629 * We should delete the item and set the errorMessageListHead
630 * to point to next.
631 * (The code for the above case would probably work for
632 * this case too, but for clarity, this remains.)
633 */
634 else if(NULL == prev_message)
635 {
636 /* If the current message happened to be the last message
637 * set, we need to change the lastErrorMessage pointer
638 * so it is not dangling.
639 */
640 if(current_message == err_pool_data->lastErrorMessage)
641 {
642 err_pool_data->lastErrorMessage = NULL;
643 }
644 Internal_FreeErrorMessageStructure(current_message);
645 current_message = NULL;
646 err_pool_data->errorMessageListHead = next_message;
647 }
648 /* Special case, current is at tail.
649 * Prev is not NULL, but next is NULL in this case.
650 * We should delete the item and set prev->next to NULL.
651 */
652 else if(NULL == next_message)
653 {
654 /* If the current message happened to be the last message
655 * set, we need to change the lastErrorMessage pointer
656 * so it is not dangling.
657 */
658 if(current_message == err_pool_data->lastErrorMessage)
659 {
660 err_pool_data->lastErrorMessage = NULL;
661 }
662 Internal_FreeErrorMessageStructure(current_message);
663 current_message = NULL;
664 prev_message->nextItem = NULL;
665 }
666 /* Normal case, current is somewhere in the middle of the list.
667 * The item should be deleted and
668 * the prev_message->next should connect to
669 * the next_message.
670 */
671 else
672 {
673 /* If the current message happened to be the last message
674 * set, we need to change the lastErrorMessage pointer
675 * so it is not dangling.
676 */
677 if(current_message == err_pool_data->lastErrorMessage)
678 {
679 err_pool_data->lastErrorMessage = NULL;
680 }
681 Internal_FreeErrorMessageStructure(current_message);
682 current_message = NULL;
683 prev_message->nextItem = next_message;
684 }
685 }
686 /* It's not this thread, so increment everything for the next loop. */
687 else
688 {
689 prev_message = current_message;
690 current_message = next_message;
691 }
692 } /* End for-loop */
693
694 Internal_UnlockMutex(err_pool->mutexLock);
695 }
696
697
698 void TError_GetLinkedVersion(TErrorVersion* ver)
699 {
700 /* Check the pointer */
701 if(NULL == ver)
702 {
703 /* Do nothing */
704 return;
705 }
706 ver->major = TERROR_MAJOR_VERSION;
707 ver->minor = TERROR_MINOR_VERSION;
708 ver->patch = TERROR_PATCH_VERSION;
709 }
710
711
712 #if 0
713 /* This is for global initialization, not pool initialization. */
714 int TError_Init()
715 {
716 /* initialize platform? */
717 /* initialize mutexes? */
718
719 }
720 #endif
721
722 TErrorPool* TError_CreateErrorPool()
723 {
724 TErrorPool* err_pool;
725 TErrorPoolOpaqueData* err_pool_data;
726
727 err_pool = (TErrorPool*)calloc(1, sizeof(TErrorPool));
728 if(NULL == err_pool)
729 {
730 /* Very bad, but not sure what to do here. */
731 return NULL;
732 }
733 err_pool_data = (TErrorPoolOpaqueData*)calloc(1, sizeof(TErrorPoolOpaqueData));
734 if(NULL == err_pool_data)
735 {
736 /* Very bad, but not sure what to do here. */
737 free(err_pool);
738 return NULL;
739 }
740
741 /* Create mutex */
742 err_pool->mutexLock = Internal_CreateMutex();
743
744 if(NULL == err_pool->mutexLock)
745 {
746 /* Very bad, but not sure what to do here. */
747 free(err_pool_data);
748 free(err_pool);
749 return NULL;
750 }
751
752 /* Attach the opaque data to the error pool. */
753 err_pool->opaqueData = err_pool_data;
754
755 /* The OpaqueData will hold the error message list, but it is
756 * allowed to be NULL for an empty list so we don't have to allocate
757 * it here.
758 */
759
760 return err_pool;
761 }
762
763 /* There better not be any contention when this is called. */
764 void TError_FreeErrorPool(TErrorPool* err_pool)
765 {
766 if(NULL == err_pool)
767 {
768 return;
769 }
770 /* Free all the error messages for each thread.
771 * This locks and unlocks as it needs.
772 */
773 Internal_FreeErrorMessageList(err_pool);
774
775 /* Free opaque data structure. */
776 free(err_pool->opaqueData);
777
778 /* Delete mutex after all locking functions. */
779 Internal_DestroyMutex(err_pool->mutexLock);
780
781 /* Free main data structure. */
782 free(err_pool);
783 }
784
785 void TError_SetError(TErrorPool* err_pool, int err_num, const char* err_str, ...)
786 {
787 va_list argp;
788 va_start(argp, err_str);
789 TError_SetErrorv(err_pool, err_num, err_str, argp);
790 va_end(argp);
791 }
792
793 void TError_SetErrorv(TErrorPool* err_pool, int err_num, const char* err_str, va_list argp)
794 {
795 TErrorMessage* error_message;
796 int ret_num_chars;
797
798 if(NULL == err_pool)
799 {
800 return;
801 }
802
803 error_message = Internal_GetErrorOnCurrentThread(err_pool);
804 /* If no error message was found, that means we must allocate
805 * a new entry for this entry.
806 */
807 if(NULL == error_message)
808 {
809 error_message = Internal_CreateErrorOnCurrentThread(err_pool);
810 /* If this fails, this is bad...not sure what to do though. */
811 if(NULL == error_message)
812 {
813 return;
814 }
815 }
816
817 /*
818 * I don't think I have to lock here. The [Get|Create]ErrorOnCurrentThread
819 * functions lock err_pool as they need access. Here, I don't access
820 * err_pool (which is shared) and error_message should be unique for
821 * each thread so I don't think there is any contention. (Remember that
822 * simultaneous calls to SetError would only happen if they are in
823 * different threads.)
824 * There *might* be a problem with library calls (strncpy, calloc).
825 * I'm not sure if the various platforms are reentrant.
826 * I guess for now, I will assume they won't bite me.
827 */
828
829 /* If the err_str is NULL, we need to free our current string
830 * for consistency. More aggressive optimizations to hold the
831 * memory might be considered in the future.
832 */
833 if(NULL == err_str)
834 {
835 if(NULL != error_message->errorString)
836 {
837 free(error_message->errorString);
838 error_message->errorString = NULL;
839 error_message->errorMaxStringLength = 0;
840 }
841 }
842 /* Else, copy the string */
843 else
844 {
845 /* I am using vasprintf which is a GNU extension so it is not
846 * portable. However, vasprintf makes certain things possible
847 * which would not be otherwise, which is the reason for my
848 * use. The main benefit of asprintf/vasprintf is that you can
849 * create a string using printf style formatters without
850 * worrying about the buffer size. sprintf should never be
851 * used because of potential buffer overflows. snprintf
852 * is safer, but you are limited to a fixed size string
853 * which from time-to-time, I have exceeded unless you make
854 * the number really big.
855 * Furthermore, snprintf itself is not currently terribly portable
856 * because it is specified only for C99 which some compilers
857 * still have not have embraced.
858 * If you can't use the vasprintf implementation,
859 * you must add -DDONT_USE_VASPRINTF to your compile flags.
860 */
861 #ifdef DONT_USE_VASPRINTF
862 /* This implementation uses vsnprintf instead of
863 * vasprintf. It is strongly recommended you use
864 * the vasprintf implmententation instead.
865 * Never use vsprintf unless you like
866 * buffer overflows and security exploits.
867 */
868
869 /* If the string was set to NULL, we must reallocate memory first. */
870 if(NULL == error_message->errorString)
871 {
872 error_message->errorString = (char*)calloc(TERROR_DEFAULT_STRING_LENGTH, sizeof(char));
873 if(NULL == error_message->errorString)
874 {
875 /* Very bad...what should I do?
876 */
877 error_message->errorMaxStringLength = 0;
878 }
879 else
880 {
881 error_message->errorMaxStringLength = TERROR_DEFAULT_STRING_LENGTH;
882 }
883 }
884 /* Because of the "Very Bad" situation directly above,
885 * I need to check again to make sure the string isn't NULL.
886 * This will let the very bad situation continue on so va_end
887 * can be called and the error_number still has a chance to be set.
888 */
889 if(NULL != error_message->errorString)
890 {
891 ret_num_chars = vsnprintf(error_message->errorString,
892 error_message->errorMaxStringLength,
893 err_str,
894 argp
895 );
896 }
897
898 #else /* DONT_USE_VASPRINTF */
899 /* You might be wondering why the #ifdef logic assumes
900 * asprintf is available instead of requiring an explicit
901 * #define for that. The reason is because asprintf is the
902 * better option and I want you to realize that you are not
903 * using it. Typically, nobody knows or understands the build
904 * system and/or files get copied into new projects with a
905 * entirely new build system, so it is easy to forget to
906 * add a -D flag. So if you compile without asprintf,
907 * you are encouraged to explicitly know this.
908 */
909 /* There may be a slight performance advantage to using snprintf
910 * over asprintf depending how asprintf is written. But this
911 * implementation will completely destroy and reallocate a
912 * string regardless if a string is set to NULL, so there will
913 * actually be no performance gains for these cases.
914 * (This could be optimized but some additional bookkeeping
915 * might be needed which might not be worth the effort and
916 * code clutter.)
917 * As for memory allocation safety, because new messages for
918 * different threads must be allocated dynamically, there is no
919 * way for this library to use purely static memory.
920 * So I don't believe there is anything to be gained using
921 * snprintf over asprintf and you lose out on arbitrary lengthed
922 * error messages.
923 * If memory allocation must be minimized, I recommend just
924 * using the error number interface by itself which
925 * will always keep the strings at NULL, and don't mess
926 * with the asprintf/sprintf code.
927 */
928
929 ret_num_chars = vasprintf(&error_message->errorString, err_str, argp);
930 /* vasprintf returns -1 as an error */
931 if(-1 == ret_num_chars)
932 {
933 /* Very bad, but not sure what to do here. */
934 if(NULL != error_message->errorString)
935 {
936 free(error_message->errorString);
937 error_message->errorString = NULL;
938 error_message->errorMaxStringLength = 0;
939 /* Don't return here. Still need to va_end, and
940 * there is a chance that the err_num might work.
941 * Plus the availability needs to be set.
942 */
943 }
944 }
945 /* else vasprint returns the number of characters in the string
946 * not including the \0 character.
947 */
948 else
949 {
950 /* I actually don't know how much memory vasprintf allocated
951 * for the string. But it is at least ret_num_chars+1, so
952 * I will use that as my max string length (which is
953 * mainly used by CopyDynamicString() for efficiency
954 * which is becoming less used in this code).
955 */
956 error_message->errorMaxStringLength = ret_num_chars+1;
957 }
958 #endif /* DONT_USE_VASPRINTF */
959 }
960
961 /* I'm allowing for a user to explicitly clear an error message by
962 * clearing both attributes.
963 */
964 if((TERROR_NOERROR_VALUE == err_num) && (NULL == err_str))
965 {
966 error_message->errorNumber = TERROR_NOERROR_VALUE;
967 error_message->errorAvailable = 0;
968 }
969 /* This is the normal case, copy the error number
970 * and mark the error as unread.
971 */
972 else
973 {
974 error_message->errorNumber = err_num;
975 error_message->errorAvailable = 1;
976 }
977
978 /* Now that the data is set, we also want to denote that this
979 * thread is the last error message. We need to lock for this
980 * since the lastError pointer is shared across threads.
981 */
982 Internal_SetLastErrorMessagePointerToErrorMessage(err_pool, error_message);
983 }
984
985 void TError_SetErrorNoFormat(TErrorPool* err_pool, int err_num, const char* err_str)
986 {
987 TErrorMessage* error_message;
988 if(NULL == err_pool)
989 {
990 return;
991 }
992
993 error_message = Internal_GetErrorOnCurrentThread(err_pool);
994 /* If no error message was found, that means we must allocate
995 * a new entry for this entry.
996 */
997 if(NULL == error_message)
998 {
999 error_message = Internal_CreateErrorOnCurrentThread(err_pool);
1000 /* If this fails, this is bad...not sure what to do though. */
1001 if(NULL == error_message)
1002 {
1003 return;
1004 }
1005 }
1006
1007 /*
1008 * I don't think I have to lock here. The [Get|Create]ErrorOnCurrentThread
1009 * functions lock err_pool as they need access. Here, I don't access
1010 * err_pool (which is shared) and error_message should be unique for
1011 * each thread so I don't think there is any contention. (Remember that
1012 * simultaneous calls to SetError would only happen if they are in
1013 * different threads.)
1014 * There *might* be a problem with library calls (strncpy, calloc).
1015 * I'm not sure if the various platforms are reentrant.
1016 * I guess for now, I will assume they won't bite me.
1017 */
1018 error_message->errorNumber = err_num;
1019 /* This will copy the string and set the new errorMaxStringLength as needed. */
1020 error_message->errorString = Internal_CopyDynamicString(error_message->errorString, &error_message->errorMaxStringLength, err_str);
1021 /* I'm allowing for a user to explicitly clear an error message by
1022 * clearing both attributes.
1023 */
1024 if((TERROR_NOERROR_VALUE == err_num) && (NULL == err_str))
1025 {
1026 error_message->errorAvailable = 0;
1027 }
1028 else
1029 {
1030 error_message->errorAvailable = 1;
1031 }
1032
1033 /* Now that the data is set, we also want to denote that this
1034 * thread is the last error message. We need to lock for this
1035 * since the lastError pointer is shared across threads.
1036 */
1037 Internal_SetLastErrorMessagePointerToErrorMessage(err_pool, error_message);
1038 }
1039
1040 void TError_SetErrorNum(TErrorPool* err_pool, int err_num)
1041 {
1042 TError_SetErrorNoFormat(err_pool, err_num, NULL);
1043 }
1044
1045 void TError_SetErrorStr(TErrorPool* err_pool, const char* err_str, ...)
1046 {
1047 va_list argp;
1048 va_start(argp, err_str);
1049 if(NULL == err_str)
1050 {
1051 TError_SetErrorv(err_pool, TERROR_NOERROR_VALUE, err_str, argp);
1052 }
1053 else
1054 {
1055 TError_SetErrorv(err_pool, TERROR_ERROR_VALUE, err_str, argp);
1056 }
1057 va_end(argp);
1058 }
1059
1060 void TError_SetErrorStrv(TErrorPool* err_pool, const char* err_str, va_list argp)
1061 {
1062 if(NULL == err_str)
1063 {
1064 TError_SetErrorv(err_pool, TERROR_NOERROR_VALUE, err_str, argp);
1065 }
1066 else
1067 {
1068 TError_SetErrorv(err_pool, TERROR_ERROR_VALUE, err_str, argp);
1069 }
1070 }
1071
1072 /* If a NULL string is set, then it is presumed no error actually occurred
1073 * and this is a reset. So the err_num will be implicitly set to 0. Otherwise
1074 * the err_num will be set to 1 (for internal consistency and conventions).
1075 */
1076 void TError_SetErrorStrNoFormat(TErrorPool* err_pool, const char* err_str)
1077 {
1078 if(NULL == err_str)
1079 {
1080 TError_SetErrorNoFormat(err_pool, TERROR_NOERROR_VALUE, err_str);
1081 }
1082 else
1083 {
1084 TError_SetErrorNoFormat(err_pool, TERROR_ERROR_VALUE, err_str);
1085 }
1086 }
1087
1088 /* This currently returns 0 as a "no error found" value.
1089 * This could potentially conflict with a user. For now, users
1090 * shouldn't use 0 to represent an error. If this becomes a
1091 * problem, we could introduce a magic number like -999999 and
1092 * define TERROR_NO_ERROR_FOUND.
1093 */
1094 int TError_GetErrorNumOnCurrentThread(TErrorPool* err_pool)
1095 {
1096 TErrorMessage* error_message;
1097
1098 error_message = Internal_GetErrorOnCurrentThread(err_pool);
1099
1100 /* If no error message was found for the thread. */
1101 if(NULL == error_message)
1102 {
1103 return 0;
1104 }
1105 /* If an error message was found for the thread, but
1106 * it has already been read/cleared.
1107 */
1108 if(0 == error_message->errorAvailable)
1109 {
1110 return 0;
1111 }
1112 /* We found a legitimate error message, clear it and return it. */
1113 error_message->errorAvailable = 0;
1114 return error_message->errorNumber;
1115 }
1116
1117 const char* TError_GetErrorStrOnCurrentThread(TErrorPool* err_pool)
1118 {
1119 TErrorMessage* error_message;
1120
1121 error_message = Internal_GetErrorOnCurrentThread(err_pool);
1122
1123 /* If no error message was found for the thread. */
1124 if(NULL == error_message)
1125 {
1126 return 0;
1127 }
1128 /* If an error message was found for the thread, but
1129 * it has already been read/cleared.
1130 */
1131 if(0 == error_message->errorAvailable)
1132 {
1133 return 0;
1134 }
1135 /* We found a legitimate error message, clear it and return it. */
1136 error_message->errorAvailable = 0;
1137 return error_message->errorString;
1138 }
1139
1140 TErrorStatus TError_GetErrorOnCurrentThread(TErrorPool* err_pool)
1141 {
1142 TErrorMessage* error_message;
1143 TErrorStatus error_container;
1144 error_container.errorNumber = TERROR_NOERROR_VALUE;
1145 error_container.errorString = NULL;
1146
1147 error_message = Internal_GetErrorOnCurrentThread(err_pool);
1148
1149 /* If no error message was found for the thread. */
1150 if(NULL == error_message)
1151 {
1152 return error_container;
1153 }
1154 /* If an error message was found for the thread, but
1155 * it has already been read/cleared.
1156 */
1157 if(0 == error_message->errorAvailable)
1158 {
1159 return error_container;
1160 }
1161 /* We found a legitimate error message, clear it and return it. */
1162 error_message->errorAvailable = 0;
1163
1164 error_container.errorNumber = error_message->errorNumber;
1165 error_container.errorString = error_message->errorString;
1166 return error_container;
1167 }
1168
1169 /* This function is for alternative usage where you just want one error
1170 * for all threads. The backend will still work the same, but when you
1171 * call this function, it will look up the last set error, copy (with locking)
1172 * the last error to the current thread's memory, and return the object.
1173 * As always, since the returned object is only accessed on this thread, you
1174 * don't have to worry about locking.
1175 */
1176 TErrorStatus TError_GetLastError(TErrorPool* err_pool)
1177 {
1178
1179 // Lock the error pool to get the lastMessage pointer
1180 // if the lastMessage pointer is pointing to data on the current thread,
1181 // we can just return it.
1182 // Otherwise, we need to copy the message
1183
1184 TErrorMessage* error_message;
1185 TErrorStatus error_container;
1186 error_container.errorNumber = TERROR_NOERROR_VALUE;
1187 error_container.errorString = NULL;
1188
1189 error_message = Internal_GetLastError(err_pool);
1190
1191 /* If no error message was found for the thread. */
1192 if(NULL == error_message)
1193 {
1194 return error_container;
1195 }
1196 /* If an error message was found for the thread, but
1197 * it has already been read/cleared.
1198 */
1199 if(0 == error_message->errorAvailable)
1200 {
1201 return error_container;
1202 }
1203 /* We found a legitimate error message, clear it and return it. */
1204 error_message->errorAvailable = 0;
1205
1206 error_container.errorNumber = error_message->errorNumber;
1207 error_container.errorString = error_message->errorString;
1208 return error_container;
1209 }
1210
1211 /* This currently returns 0 as a "no error found" value.
1212 * This could potentially conflict with a user. For now, users
1213 * shouldn't use 0 to represent an error. If this becomes a
1214 * problem, we could introduce a magic number like -999999 and
1215 * define TERROR_NO_ERROR_FOUND.
1216 */
1217 int TError_GetLastErrorNum(TErrorPool* err_pool)
1218 {
1219 TErrorMessage* error_message;
1220
1221 error_message = Internal_GetLastError(err_pool);
1222
1223 /* If no error message was found for the thread. */
1224 if(NULL == error_message)
1225 {
1226 return 0;
1227 }
1228 /* If an error message was found for the thread, but
1229 * it has already been read/cleared.
1230 */
1231 if(0 == error_message->errorAvailable)
1232 {
1233 return 0;
1234 }
1235 /* We found a legitimate error message, clear it and return it. */
1236 error_message->errorAvailable = 0;
1237 return error_message->errorNumber;
1238 }
1239
1240 const char* TError_GetLastErrorStr(TErrorPool* err_pool)
1241 {
1242 TErrorMessage* error_message;
1243
1244 error_message = Internal_GetLastError(err_pool);
1245
1246 /* If no error message was found for the thread. */
1247 if(NULL == error_message)
1248 {
1249 return 0;
1250 }
1251 /* If an error message was found for the thread, but
1252 * it has already been read/cleared.
1253 */
1254 if(0 == error_message->errorAvailable)
1255 {
1256 return 0;
1257 }
1258 /* We found a legitimate error message, clear it and return it. */
1259 error_message->errorAvailable = 0;
1260 return error_message->errorString;
1261 }
1262
1263
1264