1 /* ncbiprop.c
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name: ncbiprop.c
27 *
28 * Author: Schuler
29 *
30 * Version Creation Date: 06-04-93
31 *
32 * $Revision: 6.4 $
33 *
34 * File Description: Application Property Functions.
35 *
36 * Application properties were introduced to allow the NCBI Toolbox
37 * to be implemented as a dynamic link library (DLL). Under Windows,
38 * global variables located in the DLL are not instantiated for each
39 * application instance, but instead shared by all applications having
40 * a run-time linkage. Values that might ordinarily be stored in
41 * global variables can instead be saved as application properties
42 * (unless sharing is desired, of course). An application property
43 * is simply a pointer (or other value cast to a pointer) that is
44 * identified by a string key. Properties are kept in a linked list
45 * (sorted by key) whose head is stored in an application context block.
46 * The application context block is created on-demand and marked
47 * with the process ID of the calling application (or it's creation
48 * can be forced by calling InitAppContext() at the beginning of your
49 * program. The linked list of (smallish) application context
50 * structures is the only thing allocated from the DLL's data space,
51 * all other memory is owned by the application that called the DLL
52 * is automatically freed by the system when the application terminates.
53 *
54 * If this code is not actually compiled as a DLL, but bound at link
55 * time to a single application in the normal way, the behavior of all
56 * functions will be the same. The only difference being that the
57 * list of application context structures will contain exactly one item.
58 *
59 * Modifications:
60 * --------------------------------------------------------------------------
61 * $Log: ncbiprop.c,v $
62 * Revision 6.4 2008/04/29 13:40:53 kans
63 * fixes for warnings caught by mingw cross-compiler
64 *
65 * Revision 6.3 2001/03/02 19:52:34 vakatov
66 * Do not use "pid" in the app.context anymore.
67 * It was needed for 16-bit MS-Win DLLs, a long time ago, and now it's
68 * just eating resources...
69 *
70 * Revision 6.2 1998/08/24 17:42:02 kans
71 * fixed old style function definition warnings
72 *
73 * Revision 6.1 1997/10/29 02:44:20 vakatov
74 * Type castings to pass through the C++ compiler
75 *
76 * Revision 6.0 1997/08/25 18:16:56 madden
77 * Revision changed to 6.0
78 *
79 * Revision 5.6 1997/01/28 21:19:12 kans
80 * <Desk.h>, <OSEvents.h> and <GestaltEqu.h> are obsolete in CodeWarrior
81 *
82 * Revision 5.5 1997/01/08 22:55:36 shavirin
83 * Added threads comparison through NlmThreadCompare
84 *
85 * Revision 5.4 1996/12/03 21:48:33 vakatov
86 * Adopted for 32-bit MS-Windows DLLs
87 *
88 * Revision 5.3 1996/11/25 19:05:30 vakatov
89 * Made Get/ReleaseAppContext() MT-safe
90 *
91 * Revision 5.2 1996/07/16 19:58:01 vakatov
92 * Nlm_GetScratchBuffer() now has a "size" parameter and has a variable
93 * size -- thus it works as an fast and smart "ad hoc" memory allocator.
94 * Added "corelib.h" header; thread_id argum. added to new_AppContext(...);
95 * delete_AppContext(): new cleaning funcs ReleaseApp{Err|Msg}Info called.
96 * Added a code to test error posting functions(they use the ScratchBuffer
97 * and Properties intensively) for multiple concurrent threads.
98 *
99 * Revision 5.1 1996/06/12 20:18:29 shavirin
100 * Added multy-thread ability of toolkit to handle error posting
101 * ==========================================================================
102 */
103
104 #include "corepriv.h"
105
106
107
108 /* ----------------------------------------------------------------------
109 * new_AppProperty allocates/constructs an AppProperty struct
110 * delete_AppProperty deallocates/destructs an AppProperty struct
111 *
112 * Created:
113 * 06-04-93 Schuler
114 * Modified:
115 * 00-00-00 YourName What changes did you make?
116 * ---------------------------------------------------------------------- */
117
118 typedef struct _AppProperty_
119 {
120 struct _AppProperty_ *next;
121 char *key;
122 void *data;
123 }
124 AppProperty;
125
126 static AppProperty * new_AppProperty PROTO((const char *key, void *data));
127 static void delete_AppProperty PROTO((AppProperty *prop));
128
new_AppProperty(const char * key,void * data)129 static AppProperty * new_AppProperty (const char *key, void *data)
130 {
131 AppProperty *prop = (AppProperty *)Calloc(1, sizeof(AppProperty));
132 ASSERT_HARD(key != NULL);
133 ASSERT_HARD(*key != '\0');
134
135 if (prop != NULL)
136 {
137 if ( (prop->key = StrSave(key)) == NULL )
138 {
139 Free(prop);
140 prop = NULL;
141 }
142 else
143 prop->data = data;
144 }
145
146 return prop;
147 }
148
149
delete_AppProperty(AppProperty * prop)150 static void delete_AppProperty (AppProperty *prop)
151 {
152 ASSERT_HARD(prop != NULL);
153 MemFree(prop->key);
154 MemFill(prop, '\xFF', sizeof(*prop));
155 Free(prop);
156 }
157
158
159
160 /* ----------------------------------------------------------------------
161 * new_AppContext allocates/constructs an AppContext struct
162 * delete_AppContext deallocates/destructs an AppContext struct
163 *
164 * Notes: (1) If a valid context cannot be created, the application halts.
165 * (2) The memory allocated for the AppContext struct is owned by
166 * the DLL and the scratch buffer is owned by the application.
167 * (3) It is important that this function NOT call TRACE, Message,
168 * or ErrPost (or anything else that could result in any of these
169 * being called) as they use the applicaion context's scratch buffer.
170 *
171 * For every non-thread capable platform tid == 0
172 *
173 * Created:
174 * 06-04-93 Schuler
175 * Modified:
176 * 00-00-00 YourName What changes did you make?
177 06-12-96 Shavirin Added TNlmThread tid element to
178 distinguish contexes belong to diffrent threads
179 * ---------------------------------------------------------------------- */
180
181 /*
182 #define SCRATCH_SIZE_DEFAULT (2*KBYTE)
183 */
184
185 typedef struct _AppContext_
186 {
187 struct _AppContext_ *next;
188 struct _AppProperty_ *proplist;
189 TNlmThread tid;
190
191 unsigned enums :15; /* number of nested enumerations in-progress */
192 unsigned lock :1; /* if TRUE, property list is locked */
193 size_t scratch_size;
194 void *scratch;
195 }
196 AppContext;
197
198 /* this is the only global variable in this file: */
199 static AppContext * g_appList; /* Application Context List */
200
201 static AppContext * new_AppContext(TNlmThread thread_id);
202 static void delete_AppContext PROTO((AppContext *prop));
203 INLINE static void AppContext_Lock PROTO((AppContext *context));
204 INLINE static void AppContext_Unlock PROTO((AppContext *context));
205 INLINE static unsigned AppContext_IsLocked PROTO((AppContext *context));
206
207
new_AppContext(TNlmThread thread_id)208 static AppContext * new_AppContext(TNlmThread thread_id)
209 {
210 AppContext *context = (AppContext *)dll_Malloc(sizeof(AppContext));
211
212 if (context == NULL)
213 AbnormalExit(1);
214
215 memset((void*)context,0,sizeof(struct _AppContext_));
216 context->tid = thread_id; /* thread id for thread-capable OS */
217 context->scratch_size = 0;
218 context->scratch = NULL;
219 return context;
220 }
221
delete_AppContext(AppContext * context)222 static void delete_AppContext (AppContext *context)
223 {
224 AppProperty *p1, *p2;
225
226 ASSERT_HARD(context != NULL);
227
228 ReleaseAppErrInfo();
229 ReleaseAppMsgInfo();
230
231 for (p1=context->proplist; p1; p1=p2)
232 {
233 p2 = p1->next;
234 delete_AppProperty(p1);
235 }
236
237 Nlm_GetScratchBuffer( 0 );
238 dll_Free(context);
239 }
240
AppContext_Lock(AppContext * context)241 static INLINE void AppContext_Lock (AppContext *context)
242 {
243 ASSERT(context->lock==0);
244 context->lock = 1;
245 }
246
AppContext_Unlock(AppContext * context)247 static INLINE void AppContext_Unlock (AppContext *context)
248 {
249 ASSERT(context->lock==1);
250 context->lock = 0;
251 }
252
AppContext_IsLocked(AppContext * context)253 static INLINE unsigned AppContext_IsLocked (AppContext *context)
254 {
255 return context->lock;
256 }
257
258
259
260 /* ----------------------------------------------------------------------
261 * InitAppContext -- Initializes a context struct for current application.
262 *
263 * Notes:
264 * If a valid context cannot be created, the application halts.
265 * Although it is not strictly necessary to call InitAppContext() as
266 * contexts are created on-demand, calling it once at the beginning
267 * of the program may reduce heap fragmentation.
268 *
269 * Created:
270 * 06-04-93 Schuler
271 * Modified:
272 * 06-12-96 Shavirin Added multy-thread ability of context handling
273 *
274 *
275 * ---------------------------------------------------------------------- */
276
277 /* helper functions for internal use only */
278
GetAppContext(void)279 static AppContext *GetAppContext (void)
280 {
281 AppContext *p1, *p2;
282 AppContext *app;
283 TNlmThread thread_id = NlmThreadSelf(); /* thread ID */
284
285 NlmMutexLockEx( &corelibMutex );
286
287 /*
288 * First we scan the list of contexts for one with the current
289 * application's process ID.
290 */
291 for (p1=g_appList,p2=NULL; p1; p1=p1->next)
292 {
293 if ( NlmThreadCompare(p1->tid, thread_id) )
294 {
295 NlmMutexUnlock( corelibMutex );
296 return p1;
297 }
298 p2 = p1;
299 }
300
301 /*
302 * If we reach this point, the context for current does not
303 * exist yet, so we need to create one and link it into the list.
304 */
305 app = new_AppContext(thread_id);
306
307 if (p2 == NULL)
308 g_appList = app;
309 else
310 p2->next = app;
311 app->next = p1;
312
313 NlmMutexUnlock( corelibMutex );
314
315 return app;
316 }
317
318
Nlm_InitAppContext(void)319 NLM_EXTERN void LIBCALL Nlm_InitAppContext (void)
320 {
321 GetAppContext ();
322 }
323
324
Nlm_GetScratchBuffer(size_t size)325 NLM_EXTERN char * LIBCALL Nlm_GetScratchBuffer(size_t size)
326 {
327 AppContext *context = GetAppContext();
328 if (context == NULL)
329 abort();
330
331 if ((size == 0 || context->scratch_size < size) &&
332 context->scratch != NULL)
333 {
334 /* reset scratch buffer */
335 Free( context->scratch );
336 context->scratch_size = 0;
337 context->scratch = NULL;
338 }
339
340 /* nothing but reset */
341 if (size == 0)
342 return NULL;
343
344 /* do we have enough allocated memory already? */
345 if (context->scratch_size >= size)
346 return (char *) context->scratch;
347
348 /* allocate new buffer */
349 size = (size + 15) / 16;
350 size *= 16;
351 if ((context->scratch = (char *) Malloc( size )) == NULL)
352 return NULL;
353
354 context->scratch_size = size;
355 return (char *) context->scratch;
356 }
357
358
359
360 /* ----------------------------------------------------------------------
361 * ReleaseAppContext -- frees application context struct for current app.
362 *
363 * Notes:
364 * For most platforms, memory will be recovered automatically by the
365 * operating system. However, since we cannot guarantee this for
366 * all systems, it might be wise to call ReleaseAppContext() once
367 * just before the application exits.
368 *
369 * Created:
370 * 06-04-93 Schuler
371 * Modified:
372 * 06-12-96 Shavirin Added multi-thread ability of context handling
373 *
374 *
375 * ---------------------------------------------------------------------- */
376
Nlm_ReleaseAppContext(void)377 NLM_EXTERN void LIBCALL Nlm_ReleaseAppContext (void)
378 {
379 AppContext *p1, *p2;
380 TNlmThread thread_id = NlmThreadSelf();
381
382 NlmMutexLockEx( &corelibMutex );
383
384 /*
385 * Scan the list for the context of the current app
386 */
387 for (p1=g_appList,p2=NULL; p1; p1=p1->next)
388 {
389 if ( NlmThreadCompare(p1->tid, thread_id) )
390 break;
391 p2 = p1;
392 }
393 /*
394 * Adjust links and release memory
395 */
396 if (p1 != NULL)
397 {
398 AppContext *next = p1->next;
399 delete_AppContext( p1 );
400
401 if (p2 == NULL)
402 g_appList = next;
403 else
404 p2->next = next;
405 }
406
407 NlmMutexUnlock( corelibMutex );
408 }
409
410
411
412 /* ----------------------------------------------------------------------
413 * SetAppProperty -- Sets a data item int the application context's
414 * property list, replacing the existing one or creating a new
415 * one if no property with that key exists.
416 *
417 * Parameters:
418 * key: key identifying the property
419 * value: pointer to arbitrary data
420 *
421 * Return value:
422 * Previous value of the property, if any, or NULL otherwise.
423 *
424 * Created:
425 * 06-08-93 Schuler
426 * Modified:
427 * 00-00-00 YourName What changes did you make?
428 * ---------------------------------------------------------------------- */
429
Nlm_SetAppProperty(const char * key,void * data)430 NLM_EXTERN void * LIBCALL Nlm_SetAppProperty (const char *key, void *data)
431 {
432 if (key && *key)
433 {
434 AppContext *context = GetAppContext();
435 AppProperty *p1, *p2, *prop;
436 void *prev;
437 int d;
438
439 for (p1=context->proplist, p2=NULL; p1; p1=p1->next)
440 {
441 d = strcmp(key,p1->key);
442 if (d < 0) break;
443 if (d==0)
444 {
445 prev = p1->data;
446 p1->data = data;
447 return prev; /* previous value */
448 }
449 p2 = p1;
450 }
451
452 /*
453 * If we reach here, a property with the given key does not exist, so
454 * let's create a new one and link it into the list.
455 */
456
457 if (AppContext_IsLocked(context))
458 {
459 TRACE("SetAppProperty: ** property list is locked **\n");
460 }
461 else
462 {
463 AppContext_Lock(context);
464 if ((prop = new_AppProperty(key,data)) != NULL)
465 {
466 if (p2 == NULL)
467 context->proplist = prop;
468 else
469 p2->next = prop;
470 prop->next = p1;
471 }
472 AppContext_Unlock(context);
473 }
474 }
475 return NULL; /* no previous value */
476 }
477
478
479
480 /* ----------------------------------------------------------------------
481 * GetAppProperty -- Retrieves data value that was set with SetAppProperty.
482 *
483 * Parameters:
484 * key: key identifying the property
485 *
486 * Return value:
487 * Value that was set with SetAppProperty or NULL if no property with
488 * that key exists.
489 *
490 * Created:
491 * 06-08-93 Schuler
492 * Modified:
493 * 00-00-00 YourName What changes did you make?
494 *
495 * ---------------------------------------------------------------------- */
496
Nlm_GetAppProperty(const char * key)497 NLM_EXTERN void * LIBCALL Nlm_GetAppProperty (const char *key)
498 {
499 if (key && *key)
500 {
501 AppContext *context = GetAppContext();
502 AppProperty *prop;
503
504 for (prop=context->proplist; prop; prop=prop->next)
505 {
506 if (strcmp(prop->key,key) == 0)
507 return prop->data;
508 }
509 }
510 return NULL;
511 }
512
513
514
515 /* ----------------------------------------------------------------------
516 * RemoveAppProperty -- Removes a property from the application context's
517 * property list (if it exists) and returns the data value that was
518 * set with SetAppParam().
519 *
520 * Parameters:
521 * key: key identifying the property
522 *
523 * Return value:
524 * Value that was set with SetAppProperty or NULL if no property with
525 * that key exists.
526 *
527 * Notes:
528 * It is the responsibiliy of the caller to free whatever resources
529 * the property's data (return value) may happen to point to.
530 *
531 * Created:
532 * 06-08-93 Schuler
533 * Modified:
534 * 00-00-00 YourName What changes did you make?
535 *
536 * ---------------------------------------------------------------------- */
537
Nlm_RemoveAppProperty(const char * key)538 NLM_EXTERN void * LIBCALL Nlm_RemoveAppProperty (const char *key)
539 {
540 if (key && *key)
541 {
542 AppContext *context = GetAppContext();
543
544 if (AppContext_IsLocked(context))
545 {
546 TRACE("RemoveAppProperty: ** property list is locked **\n");
547 }
548 else
549 {
550 AppProperty *p1, *p2;
551 int d;
552
553 AppContext_Lock(context);
554 for (p1=context->proplist, p2=NULL; p1; p1=p1->next)
555 {
556 d = strcmp(key,p1->key);
557 if (d < 0) break;
558 if (d==0)
559 {
560 void *data = p1->data;
561 if (p2 == NULL)
562 context->proplist = p1->next;
563 else
564 p2->next = p1->next;
565 delete_AppProperty(p1);
566 AppContext_Unlock(context);
567 return data; /* success */
568 }
569 p2 = p1;
570 }
571 AppContext_Unlock(context);
572 }
573 }
574 return NULL; /* failure */
575 }
576
577
578
579 /* ----------------------------------------------------------------------
580 * EnumAppProperties -- Enumerates all application properties, calling
581 * a caller-supplied callback function with the key and data for
582 * each one.
583 *
584 * Parameters:
585 * Pointer to the enumeration callback procedure.
586 *
587 * Return value:
588 * Number of properties enumerated.
589 *
590 * Callback function:
591 *
592 * int LIBCALLBACK MyEmumProc (const char *key, void *value)
593 * {
594 * //--- insert your code here ---
595 *
596 * // for example:
597 * if (strcmp(key,"MyBigBuffer") ==0)
598 * {
599 * SetAppProperty(key,NULL);
600 * MemFree(data)
601 * return FALSE; // FALSE to stop enumeration at this point
602 * }
603 * return TRUE; // TRUE to continue the enumeration.
604 * }
605 *
606 * Notes:
607 * It is OK to call SetAppProperty() from within the callback function,
608 * but _only_ to change the value of an existing property. Any attempt
609 * to alter the property list, either by calling SetAppProperty() with
610 * a new key or calling RemoveAppProperty() will fail while an enumera-
611 * tion is in progress.
612 *
613 * Created:
614 * 06-09-93 Schuler
615 * Modified:
616 * 00-00-00 YourName What changes did you make?
617 *
618 * ---------------------------------------------------------------------- */
619
Nlm_EnumAppProperties(Nlm_AppPropEnumProc proc)620 NLM_EXTERN int LIBCALL Nlm_EnumAppProperties (Nlm_AppPropEnumProc proc)
621 {
622 int count = 0;
623 if (proc != NULL)
624 {
625 AppContext *context = GetAppContext();
626 AppProperty *prop;
627
628 if (context->enums==0)
629 AppContext_Lock(context);
630 context->enums++;
631 for (prop=context->proplist; prop; prop=prop->next)
632 {
633 count ++;
634 if ( ! (*proc)(prop->key,prop->data) )
635 break;
636 }
637 context->enums--;
638 if (context->enums==0)
639 AppContext_Unlock(context);
640 }
641 return count;
642 }
643
644
645 /* ----------------------------------------------------------------------
646 * GetAppProcessID [Schuler, 06-04-93]
647 *
648 * Returns an identifier for the current application instance.
649 *
650 * Notes:
651 * On the Macintosh, the process ID is a 64-bit value, which is being
652 * condensed down to 32-bits here by XORing the high and low halves
653 * of the value. I can't guarantee it will be unique (although it
654 * seems to be in practice), but this code is not being dynamically
655 * linked on the Mac, so it doesn't matter.
656 *
657 * MODIFICATIONS
658 * 04-10-93 Schuler Added Macintosh version.
659 * 12-16-93 Schuler Added Borland version contributed by M.Copperwhite
660 * ---------------------------------------------------------------------- */
661
662 #define USE_GETPID
663
664 /* (insert other platform-specific versions here as necessary and #undef USE_GETPID) */
665
666
667 /* ----- Macintosh Version ----- */
668 #ifdef OS_MAC
669 #include <Processes.h>
670 #include <Gestalt.h>
671
Nlm_GetAppProcessID(void)672 NLM_EXTERN long LIBCALL Nlm_GetAppProcessID (void)
673 {
674 long gval;
675 ProcessSerialNumber psn; /* a 64-bit value*/
676
677 if (Gestalt (gestaltSystemVersion, &gval) == noErr && (short) gval >= 7 * 256) {
678 GetCurrentProcess(&psn);
679 return (psn.highLongOfPSN ^ psn.lowLongOfPSN); /* merge to 32-bits */
680 } else {
681 return 1;
682 }
683 }
684
685 #undef USE_GETPID
686 #endif
687
688
689 /* ----- NCBIDLL mod Borland DLL version - call Windows API to get PSP ----- */
690 #ifdef _WINDLL
691 #ifdef COMP_BOR
692
Nlm_GetAppProcessID(void)693 NLM_EXTERN long LIBCALL Nlm_GetAppProcessID (void)
694 {
695 return GetCurrentPDB();
696 }
697
698 #undef USE_GETPID
699 #endif
700 #endif
701
702
703 /* ----- Generic Version ----- */
704 #ifdef USE_GETPID
705 #if defined(COMP_MSC) || defined(COMP_BOR) || defined(COMP_MINGW)
706 #include <process.h>
707 #endif
708
Nlm_GetAppProcessID(void)709 NLM_EXTERN long LIBCALL Nlm_GetAppProcessID (void)
710 {
711 return getpid();
712 }
713
714 #endif
715
716
717
718 #ifdef TEST_MODULE_NCBIPROP
719
720 /***********************************************************************
721 * TEST
722 ***********************************************************************/
723
724 #include <stdio.h>
725 #include <ncbistd.h>
726 #include <tsprintf.h>
727
728 FILE *STDOUT = (FILE *)stdout;
729 FILE *STDERR = (FILE *)stderr;
730
TEST__MyThread(Nlm_VoidPtr arg)731 static Nlm_VoidPtr TEST__MyThread(Nlm_VoidPtr arg)
732 {
733 Nlm_Int4 thread_no = (Nlm_Int4) arg;
734 Nlm_Int4 n, i;
735 Nlm_CharPtr str = NULL;
736 const Nlm_Char PNTR s = NULL;
737
738 fprintf(STDOUT, "TEST__MyThread(): Thread #%ld(%ld) started\n",
739 (long)NlmThreadSelf(), (long)thread_no);
740
741 n = (thread_no + 1) * 20;
742 str = (Nlm_CharPtr)Nlm_MemNew( n );
743 for (i = 10; i < n; i += 10)
744 {
745 Nlm_MemSet(str, 'a', i);
746 str[i] = '\0';
747 s = TSPrintf("TEST__MyThread() #%ld: %u %d %e %g %f %p %s +++\n",
748 (long)thread_no, (unsigned int)i, (int)i, (double)i,
749 (double)i, (double)i, (void *)&i, str);
750 fprintf(STDOUT, "%p %ld: %s\n", (void *)s, Nlm_StrLen( s ), s);
751 }
752
753 Nlm_MemFree( str );
754
755 #if defined (OS_UNIX)
756 sleep(thread_no + 1);
757 #elif defined (WIN32)
758 Sleep(1000 * (thread_no + 1));
759 #endif
760
761
762 fprintf(STDOUT, "TEST__MyThread() after sleep #%ld: %p %ld: %s\n",
763 (long)thread_no, (void *)s, Nlm_StrLen( s ), s);
764
765 switch (thread_no % 4)
766 {
767 case 0:
768 Nlm_Message(MSG_OKC,
769 "TEST__MyThread() #%ld: Nlm_Message(MSG_OKC)\n",
770 (long)thread_no);
771 break;
772
773 case 1:
774 Nlm_MsgAlert (MSG_YN, MSG_POST,
775 "Nlm_MsgAlert(): Caption\n",
776 "TEST__MyThread() #%ld: Nlm_MsgAlert(MSG_YN,MSG_POST)\n",
777 (long)thread_no);
778 break;
779
780 case 2:
781 Nlm_ErrPost (CTX_DEBUG/*CTX_UNKNOWN*/, 1,
782 "TEST__MyThread() #%ld: Nlm_ErrPost(CTX_DEBUG,1)\n",
783 (long)thread_no);
784 break;
785
786 case 3:
787 Nlm_ErrPostEx (SEV_ERROR, 1, 2,
788 "TEST__MyThread() #%ld: Nlm_ErrPostEx(0,1,2)\n",
789 (long)thread_no);
790 break;
791 }
792
793 return NULL;
794 }
795
796
MyExitMessage(Nlm_VoidPtr arg)797 static void MyExitMessage(Nlm_VoidPtr arg)
798 {
799 fprintf(STDERR, "\n%s\n", (Nlm_CharPtr)arg);
800 Nlm_MemFree( arg );
801 }
802
TEST__scratch(Nlm_Int4 n_threads)803 static Nlm_Int4 TEST__scratch(Nlm_Int4 n_threads)
804 {
805 Nlm_Int4 t;
806 Nlm_Int4 err_code = 0;
807 TNlmThread *threads = Nlm_MemNew(n_threads * sizeof(TNlmThread));
808
809 for (t = 0; t < n_threads; t++)
810 {
811 switch (t % 2)
812 {
813 case 0:
814 threads[t] = NlmThreadCreate(TEST__MyThread, (Nlm_VoidPtr)t,
815 THR_RUN);
816 break;
817 case 1:
818 {
819 Nlm_CharPtr exit_message = Nlm_MemNew( 64 );
820 sprintf(exit_message, "Exit Message, thread #%d", (int)t);
821 threads[t] = NlmThreadCreateEx(
822 TEST__MyThread, (Nlm_VoidPtr)t, THR_RUN,
823 MyExitMessage, (Nlm_VoidPtr)exit_message);
824 break;
825 }
826 }
827 fprintf(STDOUT, "TEST__scratch(): Starting thread #%ld\n",
828 (long)threads[t]);
829 }
830
831 for (t = 0; t < n_threads; t++)
832 {
833 Nlm_VoidPtr status;
834 err_code += NlmThreadJoin(threads[t], &status);
835 if (err_code != 0)
836 {
837 fprintf(STDOUT, "TEST__scratch(): Cannot join thread #%ld; \
838 error code = %ld\n",
839 (long)threads[t], (long)err_code);
840 break;
841 }
842
843 fprintf(STDOUT, "TEST__scratch(): Thread #%ld joined; \
844 terminated, exit status = %p\n",
845 (long)threads[t], status);
846 }
847
848 Nlm_MemFree( threads );
849
850 fprintf(STDOUT, "TEST__scratch(): FINISHED\n");
851 return err_code;
852 }
853
854
Nlm_Main(void)855 Nlm_Int2 Nlm_Main( void )
856 {
857 #if defined(WIN32) && defined(_WINDOWS)
858 (FILE *)STDOUT = freopen("stdout.w95", "w", stdout);
859 (FILE *)STDERR = freopen("stderr.w95", "w", stderr);
860 if (!STDOUT || !STDERR)
861 abort();
862 #endif
863
864 return (Nlm_Int2)TEST__scratch( 10 );
865 }
866
867 #endif /* TEST_MODULE_NCBIPROP */
868