source: rtems/cpukit/score/src/object.c @ 55b8fef2

4.104.114.84.95
Last change on this file since 55b8fef2 was f4a8ee1, checked in by Joel Sherrill <joel.sherrill@…>, on 03/17/99 at 16:01:03

Unlimited objects patch from Chris Johns <ccj@…>. Email follows:

First, the unlimited patch. I have compiled the unlmited patch for the
Linux posix BSP only and it seems to work cleanly. I would like a really
major application run on this change before commiting as the changes are
very core and significant. I am currently building all the tests to run.

I have no targets suitable to test on at the moment.

I have tested the patch for inline functions and macros.

Turning macros on has found some core bugs. I have fixed these but have
not run all the tests. Please review the patch for these changes. They
are:

1) The conditional compilation for MP support broke the core messages
code. You cannot embed a conditional macro in another macro. The Send
and Urgent Send calls are macros.

2) User extensions handler initialisation now has two parameters. I have
updated the macros to support the extra parameter.

The patch also contains the gcc-target-default.cfg fix required to build
the kernel. More of a by product than a fix for you.

  • Property mode set to 100644
File size: 22.9 KB
Line 
1/*
2 *  Object Handler
3 *
4 *
5 *  COPYRIGHT (c) 1989-1998.
6 *  On-Line Applications Research Corporation (OAR).
7 *  Copyright assigned to U.S. Government, 1994.
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.OARcorp.com/rtems/license.html.
12 *
13 *  $Id$
14 */
15
16#include <rtems/system.h>
17#include <rtems/score/address.h>
18#include <rtems/score/chain.h>
19#include <rtems/score/object.h>
20#if defined(RTEMS_MULTIPROCESSING)
21#include <rtems/score/objectmp.h>
22#endif
23#include <rtems/score/thread.h>
24#include <rtems/score/wkspace.h>
25#include <rtems/score/sysstate.h>
26#include <rtems/score/isr.h>
27
28/*PAGE
29 *
30 *  _Objects_Handler_initialization
31 *
32 *  This routine initializes the object handler.
33 *
34 *  Input parameters:
35 *    node                   - local node
36 *    maximum_nodes          - number of nodes in the system
37 *    maximum_global_objects - number of configured global objects
38 *
39 *  Output parameters:  NONE
40 */
41
42void _Objects_Handler_initialization(
43  unsigned32 node,
44  unsigned32 maximum_nodes,
45  unsigned32 maximum_global_objects
46)
47{
48  if ( node < 1 || node > maximum_nodes )
49    _Internal_error_Occurred(
50      INTERNAL_ERROR_CORE,
51      TRUE,
52      INTERNAL_ERROR_INVALID_NODE
53    );
54
55  _Objects_Local_node    = node;
56  _Objects_Maximum_nodes = maximum_nodes;
57
58#if defined(RTEMS_MULTIPROCESSING)
59  _Objects_MP_Handler_initialization(
60    node,
61    maximum_nodes,
62    maximum_global_objects
63  );
64#endif
65}
66
67/*PAGE
68 *
69 *  _Objects_Extend_information
70 *
71 *  This routine extends all object information related data structures.
72 *
73 *  Input parameters:
74 *    information     - object information table
75 *
76 *  Output parameters:  NONE
77 */
78
79void _Objects_Extend_information(
80  Objects_Information *information
81)
82{
83  Objects_Control  *the_object;
84  void             *name_area;
85  Chain_Control     Inactive;
86  unsigned32        block_count;
87  unsigned32        block;
88  unsigned32        index_base;
89  unsigned32        minimum_index;
90  unsigned32        index;
91
92  /*
93   *  Search for a free block of indexes. The block variable ends up set
94   *  to block_count + 1 if the table needs to be extended.
95   */
96
97  minimum_index = _Objects_Get_index( information->minimum_id );
98  index_base = minimum_index;
99  block = 0;
100 
101  if (information->maximum < minimum_index)
102    block_count = 0;
103  else {
104    block_count = information->maximum / information->allocation_size;
105 
106    for ( ; block < block_count; block++ ) {
107      if ( information->object_blocks[ block ] == NULL )
108        break;
109      else
110        index_base += information->allocation_size;
111    }
112  }
113
114  /*
115   *  If the index_base is the maximum we need to grow the tables.
116   */
117
118  if (index_base >= information->maximum ) {
119    ISR_Level         level;
120    void            **object_blocks;
121    Objects_Name     *name_table;
122    unsigned32       *inactive_per_block;
123    Objects_Control **local_table;
124    unsigned32        maximum;
125    void             *old_tables;   
126   
127    /*
128     *  Growing the tables means allocating a new area, doing a copy and updating
129     *  the information table.
130     *
131     *  If the maximum is minimum we do not have a table to copy. First time through.
132     *
133     *  The allocation has :
134     *
135     *      void            *objects[block_count];
136     *      unsiged32        inactive_count[block_count];
137     *      Objects_Name    *name_table[block_count];
138     *      Objects_Control *local_table[maximum];
139     *
140     *  This is the order in memory. Watch changing the order. See the memcpy
141     *  below.
142     */
143
144    /*
145     *  Up the block count and maximum
146     */
147
148    block_count++;
149   
150    maximum = information->maximum + information->allocation_size;
151
152    /*
153     *  Allocate the tables and break it up.
154     */
155   
156    if ( information->auto_extend ) {
157      object_blocks = (void**)
158        _Workspace_Allocate(
159          block_count * (sizeof(void *) + sizeof(unsigned32) + sizeof(Objects_Name *)) +
160          ((maximum + minimum_index) * sizeof(Objects_Control *))
161          );
162
163      if ( !object_blocks )
164        return;
165    }
166    else {
167      object_blocks = (void**)
168        _Workspace_Allocate_or_fatal_error(
169          block_count * (sizeof(void *) + sizeof(unsigned32) + sizeof(Objects_Name *)) +
170          ((maximum + minimum_index) * sizeof(Objects_Control *))
171        );
172    }
173
174    /*
175     *  Break the block into the various sections.
176     *
177     */
178     
179    inactive_per_block =
180      (unsigned32 *) _Addresses_Add_offset( object_blocks, block_count * sizeof(void*) );
181    name_table =
182        (Objects_Name *) _Addresses_Add_offset( inactive_per_block,
183                                                block_count * sizeof(unsigned32) );
184    local_table =
185      (Objects_Control **) _Addresses_Add_offset( name_table,
186                                                  block_count * sizeof(Objects_Name *) );
187   
188    /*
189     *  Take the block count down. Saves all the (block_count - 1) in the copies.
190     */
191
192    block_count--;
193   
194    if ( information->maximum > minimum_index ) {
195     
196      /*
197       *  Copy each section of the table over. This has to be performed as
198       *  separate parts as size of each block has changed.
199       */
200   
201      memcpy( object_blocks,
202              information->object_blocks,
203              block_count * sizeof(void*) );
204      memcpy( inactive_per_block,
205              information->inactive_per_block,
206              block_count * sizeof(unsigned32) );
207      memcpy( name_table,
208              information->name_table,
209              block_count * sizeof(Objects_Name *) );
210      memcpy( local_table,
211              information->local_table,
212              (information->maximum + minimum_index) * sizeof(Objects_Control *) );
213    }
214    else {
215
216      /*
217       *  Deal with the special case of the 0 to minimum_index
218       */
219      for ( index = 0; index < minimum_index; index++ ) {
220        local_table[ index ] = NULL;
221      }
222    }
223   
224    /*
225     *  Initialise the new entries in the table.
226     */
227   
228    object_blocks[block_count] = NULL;
229    inactive_per_block[block_count] = 0;
230    name_table[block_count] = NULL;
231
232    for ( index=index_base ;
233          index < ( information->allocation_size + index_base );
234          index++ ) {
235      local_table[ index ] = NULL;
236    }
237   
238    _ISR_Disable( level );
239
240    old_tables = information->object_blocks;
241   
242    information->object_blocks = object_blocks;
243    information->inactive_per_block = inactive_per_block;
244    information->name_table = name_table;
245    information->local_table = local_table;
246    information->maximum = maximum;
247    information->maximum_id =
248      _Objects_Build_id(
249        information->the_class, _Objects_Local_node, information->maximum
250      );
251
252    _ISR_Enable( level );
253
254    if ( old_tables )
255      _Workspace_Free( old_tables );
256   
257    block_count++;
258  }
259           
260  /*
261   *  Allocate the name table, and the objects
262   */
263
264  if ( information->auto_extend ) {
265    information->object_blocks[ block ] =
266      _Workspace_Allocate(
267        (information->allocation_size * information->name_length) +
268        (information->allocation_size * information->size)
269      );
270
271    if ( !information->object_blocks[ block ] )
272      return;
273  }
274  else {
275    information->object_blocks[ block ] =
276      _Workspace_Allocate_or_fatal_error(
277        (information->allocation_size * information->name_length) +
278        (information->allocation_size * information->size)
279      );
280  }
281 
282  name_area = (Objects_Name *) information->object_blocks[ block ];
283  information->name_table[ block ] = name_area;
284
285  /*
286   *  Initialize objects .. add to a local chain first.
287   */
288
289  _Chain_Initialize(
290    &Inactive,
291    _Addresses_Add_offset( information->object_blocks[ block ],
292                           (information->allocation_size * information->name_length) ),
293    information->allocation_size,
294    information->size
295  );
296
297  /*
298   *  Move from the local chain, initialise, then append to the inactive chain
299   */
300
301  index = index_base;
302 
303  while ( (the_object = (Objects_Control *) _Chain_Get( &Inactive ) ) != NULL ) {
304   
305    the_object->id =
306      _Objects_Build_id(
307        information->the_class, _Objects_Local_node, index
308      );
309     
310    the_object->name = (void *) name_area;
311
312    name_area = _Addresses_Add_offset( name_area, information->name_length );
313
314    _Chain_Append( &information->Inactive, &the_object->Node );
315
316    index++;
317  }
318 
319  information->inactive_per_block[ block ] = information->allocation_size;
320  information->inactive += information->allocation_size;
321}
322
323/*PAGE
324 *
325 *  _Objects_Shrink_information
326 *
327 *  This routine shrinks object information related data structures.
328 *  The object's name and object space are released. The local_table
329 *  etc block does not shrink. The InActive list needs to be scanned
330 *  to find the objects are remove them.
331 *  Input parameters:
332 *    information     - object information table
333 *    the_block       - the block to remove
334 *
335 *  Output parameters:  NONE
336 */
337
338void _Objects_Shrink_information(
339  Objects_Information *information
340)
341{
342  Objects_Control  *the_object;
343  Objects_Control  *extract_me;
344  unsigned32        block_count;
345  unsigned32        block;
346  unsigned32        index_base;
347  unsigned32        index;
348
349  /*
350   * Search the list to find block or chunnk with all objects inactive.
351   */
352
353  index_base = _Objects_Get_index( information->minimum_id );
354  block_count = ( information->maximum - index_base ) / information->allocation_size;
355 
356  for ( block = 0; block < block_count; block++ ) {
357    if ( information->inactive_per_block[ block ] == information->allocation_size ) {
358
359      /*
360       * XXX - Not to sure how to use a chain where you need to iterate and
361       *       and remove elements.
362       */
363     
364      the_object = (Objects_Control *) information->Inactive.first;
365
366      /*
367       *  Assume the Inactive chain is never empty at this point
368       */
369
370      do {
371        index = _Objects_Get_index( the_object->id );
372
373        if ((index >= index_base) &&
374            (index < (index_base + information->allocation_size))) {
375         
376          /*
377           *  Get the next node before the node is extracted
378           */
379         
380          extract_me = the_object;
381
382          if ( !_Chain_Is_last( &the_object->Node ) )
383            the_object = (Objects_Control *) the_object->Node.next;
384          else
385            the_object = NULL;
386         
387          _Chain_Extract( &extract_me->Node );
388        }
389        else {
390          the_object = (Objects_Control *) the_object->Node.next;
391        }
392      }
393      while ( the_object && !_Chain_Is_last( &the_object->Node ) );
394
395      /*
396       *  Free the memory and reset the structures in the object' information
397       */
398
399      _Workspace_Free( information->object_blocks[ block ] );
400      information->name_table[ block ] = NULL;
401      information->object_blocks[ block ] = NULL;
402      information->inactive_per_block[ block ] = 0;
403
404      information->inactive -= information->allocation_size;
405     
406      return;
407    }
408   
409    index_base += information->allocation_size;
410  }
411}
412
413/*PAGE
414 *
415 *  _Objects_Initialize_information
416 *
417 *  This routine initializes all object information related data structures.
418 *
419 *  Input parameters:
420 *    information     - object information table
421 *    the_class       - object class
422 *    supports_global - TRUE if this is a global object class
423 *    maximum         - maximum objects of this class
424 *    is_string       - TRUE if names for this object are strings
425 *    size            - size of this object's control block
426 *    is_thread       - TRUE if this class is threads
427 *
428 *  Output parameters:  NONE
429 */
430
431void _Objects_Initialize_information(
432  Objects_Information *information,
433  Objects_Classes      the_class,
434  boolean              supports_global,
435  unsigned32           maximum,
436  unsigned32           size,
437  boolean              is_string,
438  unsigned32           maximum_name_length,
439  boolean              is_thread
440)
441{
442  unsigned32       minimum_index;
443  unsigned32       index;
444  unsigned32       name_length;
445
446  information->the_class          = the_class;
447  information->is_string          = is_string;
448  information->is_thread          = is_thread;
449 
450  information->local_table        = 0;
451  information->name_table         = 0;
452  information->inactive_per_block = 0;
453  information->object_blocks      = 0;
454 
455  information->inactive           = 0;
456 
457  /*
458   *  Set the entry in the object information table.
459   */
460
461  _Objects_Information_table[ the_class ] = information;
462
463  /*
464   *  Set the size of the object
465   */
466
467  information->size = size;
468 
469  /*
470   *  Are we operating in unlimited, or auto-extend mode
471   */
472
473  information->auto_extend = (maximum & OBJECTS_UNLIMITED_OBJECTS) ? TRUE : FALSE;
474  maximum &= ~OBJECTS_UNLIMITED_OBJECTS;
475 
476  /*
477   *  The allocation unit is the maximum value
478   */
479
480  information->allocation_size = maximum;
481
482  /*
483   *  Calculate minimum and maximum Id's
484   */
485
486  if ( maximum == 0 ) minimum_index = 0;
487  else                minimum_index = 1;
488
489  information->minimum_id =
490    _Objects_Build_id( the_class, _Objects_Local_node, minimum_index );
491
492  /*
493   *  Calculate the maximum name length
494   */
495
496  name_length = maximum_name_length;
497
498  if (name_length & (OBJECTS_NAME_ALIGNMENT-1))
499    name_length = (name_length + OBJECTS_NAME_ALIGNMENT) &
500                  ~(OBJECTS_NAME_ALIGNMENT-1);
501
502  information->name_length = name_length;
503
504  _Chain_Initialize_empty( &information->Inactive );
505   
506  /*
507   *  Initialize objects .. if there are any
508   */
509
510  if ( maximum ) {
511
512    /*
513     *  Reset the maximum value. It will be updated when the information is
514     *  extended.
515     */
516   
517    information->maximum = 0;
518   
519    /*
520     *  Always have the maximum size available so the current performance
521     *  figures are create are met.  If the user moves past the maximum
522     *  number then a performance hit is taken.
523     */
524   
525    _Objects_Extend_information( information );
526   
527  }
528
529  /*
530   *  Take care of multiprocessing
531   */
532
533  if ( supports_global == TRUE && _System_state_Is_multiprocessing ) {
534
535    information->global_table =
536      (Chain_Control *) _Workspace_Allocate_or_fatal_error(
537        (_Objects_Maximum_nodes + 1) * sizeof(Chain_Control)
538      );
539
540    for ( index=1; index <= _Objects_Maximum_nodes ; index++ )
541      _Chain_Initialize_empty( &information->global_table[ index ] );
542   }
543   else
544     information->global_table = NULL;
545}
546
547/*PAGE
548 *
549 *  _Objects_Allocate
550 *
551 *  DESCRIPTION:
552 *
553 *  This function allocates a object control block from
554 *  the inactive chain of free object control blocks.
555 */
556
557Objects_Control *_Objects_Allocate(
558  Objects_Information *information
559)
560{
561  Objects_Control *the_object = 
562    (Objects_Control *) _Chain_Get( &information->Inactive );
563
564  if ( information->auto_extend ) {
565    /*
566     *  If the list is empty then we are out of objects and need to
567     *  extend information base.
568     */
569 
570    if ( !the_object ) {
571      _Objects_Extend_information( information );
572      the_object =  (Objects_Control *) _Chain_Get( &information->Inactive );
573    }
574 
575    if ( the_object ) {
576      unsigned32 block;
577   
578      block =
579        _Objects_Get_index( the_object->id ) - _Objects_Get_index( information->minimum_id );
580      block /= information->allocation_size;
581     
582      information->inactive_per_block[ block ]--;
583      information->inactive--;
584    }
585  }
586 
587  return the_object;
588}
589
590/*PAGE
591 *
592 *  _Objects_Free
593 *
594 *  DESCRIPTION:
595 *
596 *  This function frees a object control block to the
597 *  inactive chain of free object control blocks.
598 */
599
600void _Objects_Free(
601  Objects_Information *information,
602  Objects_Control     *the_object
603)
604{
605  unsigned32  allocation_size = information->allocation_size;
606
607  _Chain_Append( &information->Inactive, &the_object->Node );
608
609  if ( information->auto_extend ) {
610    unsigned32  block;
611   
612    block =
613      _Objects_Get_index( the_object->id ) - _Objects_Get_index( information->minimum_id );
614    block /= information->allocation_size;
615     
616    information->inactive_per_block[ block ]++;
617    information->inactive++;
618 
619    /*
620     *  Check if the threshold level has been met of
621     *  1.5 x allocation_size are free.
622     */
623
624    if ( information->inactive > ( allocation_size + ( allocation_size >> 1 ) ) ) {
625      _Objects_Shrink_information( information );
626    }
627  }
628}
629
630/*PAGE
631 *
632 *  _Objects_Clear_name
633 *
634 *  XXX
635 */
636
637void _Objects_Clear_name(
638  void       *name,
639  unsigned32  length
640)
641{
642  unsigned32  index;
643  unsigned32  maximum = length / OBJECTS_NAME_ALIGNMENT;
644  unsigned32 *name_ptr = (unsigned32 *) name;
645
646  for ( index=0 ; index < maximum ; index++ )
647    *name_ptr++ = 0;
648}
649 
650/*PAGE
651 *
652 *  _Objects_Copy_name_string
653 *
654 *  XXX
655 */
656 
657void _Objects_Copy_name_string(
658  void       *source,
659  void       *destination
660)
661{
662  unsigned8 *source_p = (unsigned8 *) source;
663  unsigned8 *destination_p = (unsigned8 *) destination;
664 
665  do {
666    *destination_p++ = *source_p;
667  } while ( *source_p++ );
668}
669
670/*PAGE
671 *
672 *  _Objects_Copy_name_raw
673 *
674 *  XXX
675 */
676 
677void _Objects_Copy_name_raw(
678  void       *source,
679  void       *destination,
680  unsigned32  length
681)
682{
683  unsigned32 *source_p = (unsigned32 *) source;
684  unsigned32 *destination_p = (unsigned32 *) destination;
685  unsigned32  tmp_length = length / OBJECTS_NAME_ALIGNMENT;
686 
687  while ( tmp_length-- )
688    *destination_p++ = *source_p++;
689}
690
691/*PAGE
692 *
693 *  _Objects_Compare_name_string
694 *
695 *  XXX
696 */
697 
698boolean _Objects_Compare_name_string(
699  void       *name_1,
700  void       *name_2,
701  unsigned32  length
702)
703{
704  unsigned8 *name_1_p = (unsigned8 *) name_1;
705  unsigned8 *name_2_p = (unsigned8 *) name_2;
706  unsigned32 tmp_length = length;
707 
708  do {
709    if ( *name_1_p++ != *name_2_p++ )
710      return FALSE;
711    if ( !tmp_length-- )
712      return FALSE;
713  } while ( *name_1_p );
714
715  return TRUE;
716}
717 
718/*PAGE
719 *
720 *  _Objects_Compare_name_raw
721 *
722 *  XXX
723 */
724 
725boolean _Objects_Compare_name_raw(
726  void       *name_1,
727  void       *name_2,
728  unsigned32  length
729)
730{
731  unsigned32 *name_1_p = (unsigned32 *) name_1;
732  unsigned32 *name_2_p = (unsigned32 *) name_2;
733  unsigned32  tmp_length = length / OBJECTS_NAME_ALIGNMENT;
734 
735  while ( tmp_length-- )
736    if ( *name_1_p++ != *name_2_p++ )
737      return FALSE;
738
739  return TRUE;
740}
741
742
743/*PAGE
744 *
745 *  _Objects_Name_to_id
746 *
747 *  These kernel routines search the object table(s) for the given
748 *  object name and returns the associated object id.
749 *
750 *  Input parameters:
751 *    information - object information
752 *    name        - user defined object name
753 *    node        - node indentifier (0 indicates any node)
754 *    id          - address of return ID
755 *
756 *  Output parameters:
757 *    id                 - object id
758 *    OBJECTS_SUCCESSFUL - if successful
759 *    error code         - if unsuccessful
760 */
761
762Objects_Name_to_id_errors _Objects_Name_to_id(
763  Objects_Information *information,
764  Objects_Name         name,
765  unsigned32           node,
766  Objects_Id          *id
767)
768{
769  boolean                    search_local_node;
770  Objects_Control           *the_object;
771  unsigned32                 index;
772  unsigned32                 name_length;
773  Objects_Name_comparators   compare_them;
774
775  if ( name == 0 )
776    return OBJECTS_INVALID_NAME;
777
778  search_local_node = FALSE;
779
780  if ( information->maximum != 0 &&
781      (node == OBJECTS_SEARCH_ALL_NODES || node == OBJECTS_SEARCH_LOCAL_NODE ||
782      _Objects_Is_local_node( node ) ) )
783   search_local_node = TRUE;
784
785  if ( search_local_node ) {
786    name_length = information->name_length;
787
788    if ( information->is_string ) compare_them = _Objects_Compare_name_string;
789    else                          compare_them = _Objects_Compare_name_raw;
790
791    for ( index = 1; index <= information->maximum; index++ ) {
792
793      the_object = information->local_table[ index ];
794
795      if ( !the_object || !the_object->name )
796        continue;
797
798      if ( (*compare_them)( name, the_object->name, name_length ) ) {
799        *id = the_object->id;
800        return OBJECTS_SUCCESSFUL;
801      }
802    }
803  }
804
805  if ( _Objects_Is_local_node( node ) || node == OBJECTS_SEARCH_LOCAL_NODE )
806    return OBJECTS_INVALID_NAME;
807
808#if defined(RTEMS_MULTIPROCESSING)
809  return ( _Objects_MP_Global_name_search( information, name, node, id ) );
810#else
811  return OBJECTS_INVALID_NAME;
812#endif
813}
814
815/*PAGE
816 *
817 * _Objects_Get
818 *
819 * This routine sets the object pointer for the given
820 * object id based on the given object information structure.
821 *
822 * Input parameters:
823 *   information - pointer to entry in table for this class
824 *   id          - object id to search for
825 *   location    - address of where to store the location
826 *
827 * Output parameters:
828 *   returns - address of object if local
829 *   location    - one of the following:
830 *                  OBJECTS_ERROR  - invalid object ID
831 *                  OBJECTS_REMOTE - remote object
832 *                  OBJECTS_LOCAL  - local object
833 */
834
835Objects_Control *_Objects_Get(
836  Objects_Information *information,
837  Objects_Id           id,
838  Objects_Locations   *location
839)
840{
841  Objects_Control *the_object;
842  unsigned32       index;
843
844  index = _Objects_Get_index( id );
845
846  if ( information->maximum >= index ) {
847    _Thread_Disable_dispatch();
848    if ( (the_object = _Objects_Get_local_object( information, index )) != NULL ) {
849      *location = OBJECTS_LOCAL;
850      return( the_object );
851    }
852    _Thread_Enable_dispatch();
853    *location = OBJECTS_ERROR;
854    return( NULL );
855  }
856  *location = OBJECTS_ERROR;
857#if defined(RTEMS_MULTIPROCESSING)
858  _Objects_MP_Is_remote( information, id, location, &the_object );
859  return the_object;
860#else
861  return NULL;
862#endif
863}
864
865
866/*PAGE
867 *
868 * _Objects_Get_next
869 *
870 * Like _Objects_Get, but considers the 'id' as a "hint" and
871 * finds next valid one after that point.
872 * Mostly used for monitor and debug traversal of an object.
873 *
874 * Input parameters:
875 *   information - pointer to entry in table for this class
876 *   id          - object id to search for
877 *   location    - address of where to store the location
878 *   next_id     - address to store next id to try
879 *
880 * Output parameters:
881 *   returns     - address of object if local
882 *   location    - one of the following:
883 *                  OBJECTS_ERROR  - invalid object ID
884 *                  OBJECTS_REMOTE - remote object
885 *                  OBJECTS_LOCAL  - local object
886 *   next_id     - will contain a reasonable "next" id to continue traversal
887 *
888 * NOTE:
889 *      assumes can add '1' to an id to get to next index.
890 */
891
892Objects_Control *
893_Objects_Get_next(
894    Objects_Information *information,
895    Objects_Id           id,
896    Objects_Locations   *location_p,
897    Objects_Id          *next_id_p
898)
899{
900    Objects_Control *object;
901    Objects_Id       next_id;
902   
903    if (_Objects_Get_index(id) == OBJECTS_ID_INITIAL_INDEX)
904        next_id = information->minimum_id;
905    else
906        next_id = id;
907
908    do {
909        /* walked off end of list? */
910        if (_Objects_Get_index(next_id) > information->maximum)
911        {
912            *location_p = OBJECTS_ERROR;
913            goto final;
914        }
915       
916        /* try to grab one */
917        object = _Objects_Get(information, next_id, location_p);
918
919        next_id++;
920
921    } while (*location_p != OBJECTS_LOCAL);
922
923    *next_id_p = next_id;
924    return object;
925
926final:
927    *next_id_p = OBJECTS_ID_FINAL;
928    return 0;
929}
930
Note: See TracBrowser for help on using the repository browser.