~ubuntu-branches/ubuntu/warty/ncbi-tools6/warty

« back to all changes in this revision

Viewing changes to corelib/ncbiprop.c

  • Committer: Bazaar Package Importer
  • Author(s): Aaron M. Ucko
  • Date: 2002-04-04 22:13:09 UTC
  • Revision ID: james.westby@ubuntu.com-20020404221309-vfze028rfnlrldct
Tags: upstream-6.1.20011220a
ImportĀ upstreamĀ versionĀ 6.1.20011220a

Show diffs side-by-side

added added

removed removed

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