1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF. The full HDF copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /* $Id$ */
15
16 /*
17 FILE
18 atom.c - Internal storage routines for handling "atoms"
19
20 REMARKS
21 Atoms are just ID's which allow objects (void *'s currently) to be
22 bundled into "groups" for more general storage.
23
24 DESIGN
25 The groups are stored in an array of pointers to store each group in an
26 element. Each "atomic group" node contains a link to a hash table to
27 manage the atoms in each group. The allowed "atomic groups" are stored
28 in an enum (called group_t) in atom.h.
29
30 BUGS/LIMITATIONS
31 Can't interate over the atoms in a group.
32
33 LOCAL ROUTINES
34 HAIfind_atom - Returns a pointer to an atom_info_t from a atom ID
35 HAIget_atom_node - Gets an atom node (uses the atom free list)
36 HAIrelease_atom_node - Releases an atom node (uses the atom free list)
37 EXPORTED ROUTINES
38 Atom Functions:
39 HAregister_atom - Register an object in a group and get an atom for it
40 HAatom_object - Get the object for an atom
41 HAatom_group - Get the group for an atom
42 HAremove_atom - Remove an atom from a group
43 HAsearch_atom - Search a group for a particular object
44 Atom Group Functions:
45 HAinit_group - Initialize a group to store atoms in
46 HAdestroy_group - Destroy an atomic group
47 Atom Group Cleanup:
48 HAshutdown - Terminate various static buffers.
49
50 AUTHOR
51 Quincey Koziol
52
53 MODIFICATION HISTORY
54 1/3/96 - Starting writing specs & coding prototype
55 1/7/96 - Finished coding prototype
56 */
57
58 #define ATOM_MASTER
59 #include "hdf.h"
60 #include "atom.h"
61 #include <assert.h>
62
63 /* Private function prototypes */
64 static atom_info_t *HAIfind_atom(atom_t atm);
65
66 static atom_info_t *HAIget_atom_node(void);
67
68 static void HAIrelease_atom_node(atom_info_t *atm);
69
70 /******************************************************************************
71 NAME
72 HAinit_group - Initialize an atomic group
73
74 DESCRIPTION
75 Creates a global atomic group to store atoms in. If the group has already
76 been initialized, this routine just increments the count of # of
77 initializations and returns without trying to change the size of the hash
78 table.
79
80 RETURNS
81 Returns SUCCEED if successful and FAIL otherwise
82
83 *******************************************************************************/
HAinit_group(group_t grp,intn hash_size)84 intn HAinit_group(group_t grp, /* IN: Group to initialize */
85 intn hash_size /* IN: Minimum hash table size to use for group */
86 )
87 {
88 CONSTR(FUNC, "HAinit_group"); /* for HERROR */
89 atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
90 intn ret_value=SUCCEED;
91
92 HEclear();
93 if((grp<=BADGROUP || grp>=MAXGROUP) && hash_size>0)
94 HGOTO_ERROR(DFE_ARGS, FAIL);
95
96 #ifdef ATOMS_CACHE_INLINE
97 /* Assertion necessary for faster pointer swapping */
98 assert(sizeof(hdf_pint_t)==sizeof(void *));
99 #endif /* ATOMS_CACHE_INLINE */
100
101 #ifdef HASH_SIZE_POWER_2
102 if(hash_size & (hash_size-1))
103 HGOTO_ERROR(DFE_ARGS, FAIL);
104 #endif /* HASH_SIZE_POWER_2 */
105
106 if(atom_group_list[grp]==NULL)
107 { /* Allocate the group information */
108 grp_ptr=(atom_group_t *)HDcalloc(1,sizeof(atom_group_t));
109 if(grp_ptr==NULL)
110 HGOTO_ERROR(DFE_NOSPACE, FAIL);
111 atom_group_list[grp]=grp_ptr;
112 } /* end if */
113 else /* Get the pointer to the existing group */
114 grp_ptr=atom_group_list[grp];
115
116 if(grp_ptr->count==0)
117 { /* Initialize the atom group structure */
118 grp_ptr->hash_size=hash_size;
119 grp_ptr->atoms=0;
120 grp_ptr->nextid=0;
121 if((grp_ptr->atom_list=(atom_info_t **)HDcalloc(hash_size,sizeof(atom_info_t *)))==NULL)
122 HGOTO_ERROR(DFE_NOSPACE, FAIL);
123 } /* end if */
124
125 /* Increment the count of the times this group has been initialized */
126 grp_ptr->count++;
127
128 done:
129 if(ret_value == FAIL)
130 { /* Error condition cleanup */
131 if(grp_ptr!=NULL)
132 {
133 if(grp_ptr->atom_list!=NULL)
134 HDfree(grp_ptr->atom_list);
135 HDfree(grp_ptr);
136 } /* end if */
137 } /* end if */
138
139 /* Normal function cleanup */
140
141 return ret_value;
142 } /* end HAinit_group() */
143
144 /******************************************************************************
145 NAME
146 HAdestroy_group - Destroy an atomic group
147
148 DESCRIPTION
149 Destroys an atomic group which atoms are stored in. If the group still
150 has atoms which are registered, this routine fails. If there have been
151 multiple initializations of the group, this routine just decrements the
152 count of initializations and does not check the atoms out-standing.
153
154 RETURNS
155 Returns SUCCEED if successful and FAIL otherwise
156
157 *******************************************************************************/
HAdestroy_group(group_t grp)158 intn HAdestroy_group(group_t grp /* IN: Group to destroy */
159 )
160 {
161 CONSTR(FUNC, "HAdestroy_group"); /* for HERROR */
162 atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
163 intn ret_value=SUCCEED;
164
165 HEclear();
166 if(grp<=BADGROUP || grp>=MAXGROUP)
167 HGOTO_ERROR(DFE_ARGS, FAIL);
168
169 grp_ptr=atom_group_list[grp];
170 if(grp_ptr==NULL || grp_ptr->count<=0)
171 HGOTO_ERROR(DFE_INTERNAL, FAIL);
172
173 /* Decrement the number of users of the atomic group */
174 if((--(grp_ptr->count))==0)
175 {
176 #ifdef ATOMS_ARE_CACHED
177 {
178 uintn i;
179
180 for(i=0; i<ATOM_CACHE_SIZE; i++)
181 if(ATOM_TO_GROUP(atom_id_cache[i])==grp)
182 {
183 atom_id_cache[i]=(-1);
184 atom_obj_cache[i]=NULL;
185 } /* end if */
186 } /* end block */
187 #endif /* ATOMS_ARE_CACHED */
188 HDfree(grp_ptr->atom_list);
189 grp_ptr->atom_list = NULL;
190 } /* end if */
191
192 done:
193 if(ret_value == FAIL)
194 { /* Error condition cleanup */
195
196 } /* end if */
197
198 /* Normal function cleanup */
199
200 return ret_value;
201 } /* end HAdestroy_group() */
202
203 /******************************************************************************
204 NAME
205 HAregister_atom - Register an object in a group and get an atom for it.
206
207 DESCRIPTION
208 Registers an object in a group and returns an atom for it. This routine
209 does _not_ check for unique-ness of the objects, if you register an object
210 twice, you will get two different atoms for it. This routine does make
211 certain that each atom in a group is unique. Atoms are created by getting
212 a unique number for the group the atom is in and incorporating the group
213 into the atom which is returned to the user.
214
215 RETURNS
216 Returns atom if successful and FAIL otherwise
217
218 *******************************************************************************/
HAregister_atom(group_t grp,VOIDP object)219 atom_t HAregister_atom(group_t grp, /* IN: Group to register the object in */
220 VOIDP object /* IN: Object to attach to atom */
221 )
222 {
223 CONSTR(FUNC, "HAregister_atom"); /* for HERROR */
224 atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
225 atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
226 atom_t atm_id; /* new atom ID */
227 uintn hash_loc; /* new item's hash table location */
228 atom_t ret_value=SUCCEED;
229
230 HEclear();
231 if(grp<=BADGROUP || grp>=MAXGROUP)
232 HGOTO_ERROR(DFE_ARGS, FAIL);
233
234 grp_ptr=atom_group_list[grp];
235 if(grp_ptr==NULL || grp_ptr->count<=0)
236 HGOTO_ERROR(DFE_INTERNAL, FAIL);
237
238 if((atm_ptr=HAIget_atom_node())==NULL)
239 HGOTO_ERROR(DFE_NOSPACE, FAIL);
240
241 /* Create the atom & it's ID */
242 atm_id=MAKE_ATOM(grp,grp_ptr->nextid);
243 atm_ptr->id=atm_id;
244 atm_ptr->obj_ptr=object;
245 atm_ptr->next=NULL;
246
247 /* hash bucket already full, prepend to front of chain */
248 hash_loc=grp_ptr->nextid%(uintn)grp_ptr->hash_size;
249 if(grp_ptr->atom_list[hash_loc]!=NULL)
250 atm_ptr->next=grp_ptr->atom_list[hash_loc];
251
252 /* Insert into the group */
253 grp_ptr->atom_list[hash_loc]=atm_ptr;
254 grp_ptr->atoms++;
255 grp_ptr->nextid++;
256
257 ret_value=atm_id;
258
259 done:
260 if(ret_value == FAIL)
261 { /* Error condition cleanup */
262
263 } /* end if */
264
265 /* Normal function cleanup */
266
267 return ret_value;
268 } /* end HAregister_atom() */
269
270 /******************************************************************************
271 NAME
272 HAatom_object - Returns to the object ptr for the atom
273
274 DESCRIPTION
275 Retrieves the object ptr which is associated with the atom.
276
277 RETURNS
278 Returns object ptr if successful and NULL otherwise
279
280 *******************************************************************************/
281 #ifdef ATOMS_CACHE_INLINE
HAPatom_object(atom_t atm)282 VOIDP HAPatom_object(atom_t atm /* IN: Atom to retrieve object for */
283 )
284 #else /* ATOMS_CACHE_INLINE */
285 VOIDP HAatom_object(atom_t atm /* IN: Atom to retrieve object for */
286 )
287 #endif /* ATOMS_CACHE_INLINE */
288 {
289 CONSTR(FUNC, "HAatom_object"); /* for HERROR */
290 #ifndef ATOMS_CACHE_INLINE
291 #ifdef ATOMS_ARE_CACHED
292 uintn i; /* local counter */
293 #endif /* ATOMS_ARE_CACHED */
294 #endif /* ATOMS_CACHE_INLINE */
295 atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
296 VOIDP ret_value=NULL;
297
298 HEclear();
299
300 #ifndef ATOMS_CACHE_INLINE
301 #ifdef ATOMS_ARE_CACHED
302 /* Look for the atom in the cache first */
303 for(i=0; i<ATOM_CACHE_SIZE; i++)
304 if(atom_id_cache[i]==atm)
305 {
306 ret_value=atom_obj_cache[i];
307 if(i>0)
308 { /* Implement a simple "move forward" caching scheme */
309 atom_t t_atom=atom_id_cache[i-1];
310 VOIDP t_obj=atom_obj_cache[i-1];
311
312 atom_id_cache[i-1]=atom_id_cache[i];
313 atom_obj_cache[i-1]=atom_obj_cache[i];
314 atom_id_cache[i]=t_atom;
315 atom_obj_cache[i]=t_obj;
316 } /* end if */
317 HGOTO_DONE(ret_value);
318 } /* end if */
319 #endif /* ATOMS_ARE_CACHED */
320 #endif /* ATOMS_CACHE_INLINE */
321
322 /* General lookup of the atom */
323 if((atm_ptr=HAIfind_atom(atm))==NULL)
324 HGOTO_ERROR(DFE_INTERNAL, NULL);
325
326 /* Check if we've found the correct atom */
327 if(atm_ptr!=NULL)
328 ret_value=atm_ptr->obj_ptr;
329
330 done:
331 if(ret_value == NULL)
332 { /* Error condition cleanup */
333
334 } /* end if */
335
336 /* Normal function cleanup */
337
338 return ret_value;
339 } /* end HAatom_object() */
340
341 /******************************************************************************
342 NAME
343 HAatom_group - Returns to the group for the atom
344
345 DESCRIPTION
346 Retrieves the group which is associated with the atom.
347
348 RETURNS
349 Returns group if successful and BADGROUP otherwise
350
351 *******************************************************************************/
HAatom_group(atom_t atm)352 group_t HAatom_group(atom_t atm /* IN: Atom to retrieve group for */
353 )
354 {
355 CONSTR(FUNC, "HAatom_group"); /* for HERROR */
356 group_t ret_value=BADGROUP;
357
358 HEclear();
359 ret_value=ATOM_TO_GROUP(atm);
360 if(ret_value<=BADGROUP || ret_value>=MAXGROUP)
361 HGOTO_ERROR(DFE_ARGS, BADGROUP);
362
363 done:
364 if(ret_value == BADGROUP)
365 { /* Error condition cleanup */
366
367 } /* end if */
368
369 /* Normal function cleanup */
370
371 return ret_value;
372 } /* end HAatom_group() */
373
374 /******************************************************************************
375 NAME
376 HAremove_atom - Removes an atom from a group
377
378 DESCRIPTION
379 Removes an atom from a group.
380
381 RETURNS
382 Returns atom's object if successful and NULL otherwise
383
384 *******************************************************************************/
HAremove_atom(atom_t atm)385 VOIDP HAremove_atom(atom_t atm /* IN: Atom to remove */
386 )
387 {
388 CONSTR(FUNC, "HAremove_atom"); /* for HERROR */
389 atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
390 atom_info_t *curr_atm, /* ptr to the current atom */
391 *last_atm; /* ptr to the last atom */
392 group_t grp; /* atom's atomic group */
393 uintn hash_loc; /* atom's hash table location */
394 #ifdef ATOMS_ARE_CACHED
395 uintn i; /* local counting variable */
396 #endif /* ATOMS_ARE_CACHED */
397 VOIDP ret_value=NULL;
398
399 HEclear();
400 grp=ATOM_TO_GROUP(atm);
401 if(grp<=BADGROUP || grp>=MAXGROUP)
402 HGOTO_ERROR(DFE_ARGS, NULL);
403
404 grp_ptr=atom_group_list[grp];
405 if(grp_ptr==NULL || grp_ptr->count<=0)
406 HGOTO_ERROR(DFE_INTERNAL, NULL);
407
408 /* Get the location in which the atom is located */
409 hash_loc=(uintn)ATOM_TO_LOC(atm,grp_ptr->hash_size);
410 curr_atm=grp_ptr->atom_list[hash_loc];
411 if(curr_atm==NULL)
412 HGOTO_ERROR(DFE_INTERNAL, NULL);
413
414 last_atm=NULL;
415 while(curr_atm!=NULL)
416 {
417 if(curr_atm->id==atm)
418 break;
419 last_atm=curr_atm;
420 curr_atm=curr_atm->next;
421 } /* end while */
422
423 if(curr_atm!=NULL)
424 {
425 if(last_atm==NULL) /* atom is the first the chain */
426 grp_ptr->atom_list[hash_loc]=curr_atm->next;
427 else
428 last_atm->next=curr_atm->next;
429 ret_value=curr_atm->obj_ptr;
430 HAIrelease_atom_node(curr_atm);
431 } /* end if */
432 else /* couldn't find the atom in the proper place */
433 HGOTO_ERROR(DFE_INTERNAL, NULL);
434
435 #ifdef ATOMS_ARE_CACHED
436 /* Delete object from cache */
437 for(i=0; i<ATOM_CACHE_SIZE; i++)
438 if(atom_id_cache[i]==atm)
439 {
440 atom_id_cache[i]=(-1);
441 atom_obj_cache[i]=NULL;
442 break; /* we assume there is only one instance in the cache */
443 } /* end if */
444 #endif /* ATOMS_ARE_CACHED */
445
446 /* Decrement the number of atoms in the group */
447 (grp_ptr->atoms)--;
448
449 done:
450 if(ret_value == NULL)
451 { /* Error condition cleanup */
452
453 } /* end if */
454
455 /* Normal function cleanup */
456
457 return ret_value;
458 } /* end HAremove_atom() */
459
460 /******************************************************************************
461 NAME
462 HAsearch_atom - Search for an object in a group and get it's pointer.
463
464 DESCRIPTION
465 Searchs for an object in a group and returns the pointer to it.
466 This routine calls the function pointer passed in for each object in the
467 group until it finds a match. Currently there is no way to resume a
468 search.
469
470 RETURNS
471 Returns pointer an atom's object if successful and NULL otherwise
472
473 *******************************************************************************/
HAsearch_atom(group_t grp,HAsearch_func_t func,const void * key)474 void * HAsearch_atom(group_t grp, /* IN: Group to search for the object in */
475 HAsearch_func_t func, /* IN: Ptr to the comparison function */
476 const void * key /* IN: pointer to key to compare against */
477 )
478 {
479 CONSTR(FUNC, "HAsearch_atom"); /* for HERROR */
480 atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
481 atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
482 intn i; /* local counting variable */
483 void * ret_value=NULL;
484
485 HEclear();
486 if(grp<=BADGROUP || grp>=MAXGROUP)
487 HGOTO_ERROR(DFE_ARGS, NULL);
488
489 grp_ptr=atom_group_list[grp];
490 if(grp_ptr==NULL || grp_ptr->count<=0)
491 HGOTO_ERROR(DFE_INTERNAL, NULL);
492
493 /* Start at the beginning of the array */
494 for(i=0; i<grp_ptr->hash_size; i++)
495 {
496 atm_ptr=grp_ptr->atom_list[i];
497 while(atm_ptr!=NULL)
498 {
499 if((*func)(atm_ptr->obj_ptr,key))
500 HGOTO_DONE(atm_ptr->obj_ptr); /* found the item we are looking for */
501 atm_ptr=atm_ptr->next;
502 } /* end while */
503 } /* end for */
504
505 done:
506 if(ret_value == NULL)
507 { /* Error condition cleanup */
508
509 } /* end if */
510
511 /* Normal function cleanup */
512
513 return ret_value;
514 } /* end HAsearch_atom() */
515
516 /******************************************************************************
517 NAME
518 HAIfind_atom - Finds a atom in a group
519
520 DESCRIPTION
521 Retrieves the atom ptr which is associated with the atom.
522
523 RETURNS
524 Returns atom ptr if successful and NULL otherwise
525
526 *******************************************************************************/
HAIfind_atom(atom_t atm)527 static atom_info_t *HAIfind_atom(atom_t atm /* IN: Atom to retrieve atom for */
528 )
529 {
530 CONSTR(FUNC, "HAIfind_atom"); /* for HERROR */
531 atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
532 atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
533 group_t grp; /* atom's atomic group */
534 uintn hash_loc; /* atom's hash table location */
535 atom_info_t *ret_value=NULL;
536
537 HEclear();
538 grp=ATOM_TO_GROUP(atm);
539 if(grp<=BADGROUP || grp>=MAXGROUP)
540 HGOTO_ERROR(DFE_ARGS, NULL);
541
542 grp_ptr=atom_group_list[grp];
543 if(grp_ptr==NULL || grp_ptr->count<=0)
544 HGOTO_ERROR(DFE_INTERNAL, NULL);
545
546 /* Get the location in which the atom is located */
547 hash_loc=(uintn)ATOM_TO_LOC(atm,grp_ptr->hash_size);
548 atm_ptr=grp_ptr->atom_list[hash_loc];
549 if(atm_ptr==NULL)
550 HGOTO_ERROR(DFE_INTERNAL, NULL);
551
552 while(atm_ptr!=NULL)
553 {
554 if(atm_ptr->id==atm)
555 break;
556 atm_ptr=atm_ptr->next;
557 } /* end while */
558
559 #ifdef ATOMS_ARE_CACHED
560 if (atm_ptr){
561 /* if found, add it to the end of the cached list */
562 atom_id_cache[ATOM_CACHE_SIZE-1]=atm;
563 atom_obj_cache[ATOM_CACHE_SIZE-1]=atm_ptr->obj_ptr;
564 }
565 #endif /* ATOMS_ARE_CACHED */
566
567 ret_value=atm_ptr;
568
569 done:
570 if(ret_value == NULL)
571 { /* Error condition cleanup */
572
573 } /* end if */
574
575 /* Normal function cleanup */
576
577 return ret_value;
578 } /* end HAIfind_atom() */
579
580 /******************************************************************************
581 NAME
582 HAIget_atom_node - Gets an atom node
583
584 DESCRIPTION
585 Either gets an atom node from the free list (if there is one available)
586 or allocate a node.
587
588 RETURNS
589 Returns atom ptr if successful and NULL otherwise
590
591 *******************************************************************************/
HAIget_atom_node(void)592 static atom_info_t *HAIget_atom_node(void)
593 {
594 CONSTR(FUNC, "HAIget_atom_node"); /* for HERROR */
595 atom_info_t *ret_value=NULL;
596
597 HEclear();
598 if(atom_free_list!=NULL)
599 {
600 ret_value=atom_free_list;
601 atom_free_list=atom_free_list->next;
602 } /* end if */
603 else
604 {
605 if((ret_value=(atom_info_t *)HDmalloc(sizeof(atom_info_t)))==NULL)
606 HGOTO_ERROR(DFE_NOSPACE, NULL);
607 } /* end else */
608
609 done:
610 if(ret_value == NULL)
611 { /* Error condition cleanup */
612
613 } /* end if */
614
615 /* Normal function cleanup */
616
617 return ret_value;
618 } /* end HAIget_atom_node() */
619
620 /******************************************************************************
621 NAME
622 HAIrelease_atom_node - Releases an atom node
623
624 DESCRIPTION
625 Puts an atom node into the free list
626
627 RETURNS
628 No return value
629
630 *******************************************************************************/
HAIrelease_atom_node(atom_info_t * atm)631 static void HAIrelease_atom_node(atom_info_t *atm)
632 {
633 #ifdef LATER
634 CONSTR(FUNC, "HAIrelease_atom_node"); /* for HERROR */
635 #endif /* LATER */
636
637 /* Insert the atom at the beginning of the free list */
638 atm->next=atom_free_list;
639 atom_free_list=atm;
640 } /* end HAIrelease_atom_node() */
641
642 /*--------------------------------------------------------------------------
643 NAME
644 HAshutdown
645 PURPOSE
646 Terminate various static buffers.
647 USAGE
648 intn HAshutdown()
649 RETURNS
650 Returns SUCCEED/FAIL
651 DESCRIPTION
652 Free various buffers allocated in the HA routines.
653 GLOBAL VARIABLES
654 COMMENTS, BUGS, ASSUMPTIONS
655 Should only ever be called by the "atexit" function HDFend
656 EXAMPLES
657 REVISION LOG
658 --------------------------------------------------------------------------*/
659 intn
HAshutdown(void)660 HAshutdown(void)
661 {
662 atom_info_t *curr;
663 intn i;
664
665 /* Release the free-list if it exists */
666 if(atom_free_list!=NULL)
667 {
668 while(atom_free_list!=NULL)
669 {
670 curr=atom_free_list;
671 atom_free_list=atom_free_list->next;
672 HDfree(curr);
673 } /* end while */
674 } /* end if */
675
676 for(i=0; i<(intn)MAXGROUP; i++)
677 if(atom_group_list[i]!=NULL)
678 {
679 HDfree(atom_group_list[i]);
680 atom_group_list[i]=NULL;
681 } /* end if */
682 return (SUCCEED);
683 } /* end HAshutdown() */
684
685