source: trunk/third/ORBit/docs/orbit-mem.txt @ 15271

Revision 15271, 12.4 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15270, which included commits to RCS files with non-trunk default branches.
Line 
1To: orbit-list@cuc.edu
2Subject: CORBA memory allcoation
3From: Owen Taylor <otaylor@gtk.org>
4Date: 17 Jun 1998 20:19:53 -0400
5In-Reply-To: Elliot Lee's message of Wed, 17 Jun 1998 17:14:40 -0400 (EDT)
6Message-ID: <lzemwnv9w6.fsf@cu-dialup-1518.cit.cornell.edu>
7Lines: 192
8
9
10The descriptions of memory management issues in the CORBA
11spec are just horrible. I've been reading at them recently
12and am somewhat confused. But I'm pretty sure what is currently
13in ORBit isn't right.
14
15If people agree with what I say below, I'll try to write up
16a coherent description for docs/
17
18The basic problem is the nature of CORBA free. Here's
19what the standard says.
20
21  [...]
22  The client may use and retain that storage indefinitely, and
23  must indicate when the value is no longer needed by calling
24  the procedure CORBA_free, whose signature is:
25
26  /* C */ extern
27  void CORBA_free(void *storage);
28
29  The parameter to CORBA_free() is the pointer used to return
30  the out parameter. CORBA_free() releases the ORB-allocated
31  storage occupied by the out parameter, including storage
32  indirectly referenced, such as in the case of a sequence of
33  strings or array of object reference. If a client does not
34  call CORBA_free() before reusing the pointers that reference
35  the out parameters, that storage might be wasted. Passing a
36  null pointer to CORBA_free() is allowed; CORBA_free() simply
37  ignores it and returns without error.
38
39Note the portion beginning "including storage indirectly
40referenced.."  CORBA_free() is not like free() or
41g_free(). It needs to know about the nature of the thing it
42is freeing. (ILU's C mapping gets this wrong, but mostly
43gets away with it because it doesn't have Anys)
44
45
46To look at a specific example, take CORBA_any. The
47complication for Any's and sequences is the set_release()
48function. For CORBA_any_set_release () the standard says:
49
50  /* C */
51  void CORBA_any_set_release (CORBA_any*, CORBA_boolean);
52  CORBA_boolean CORBA_any_get_release(CORBA_any*);
53
54  CORBA_any_set_release can be used to set the state of the
55  release flag. If the flag is set to TRUE, the any
56  effectively "owns" the storage pointed to by _value; if
57  FALSE, the programmer is responsible for the storage. If,
58  for example, an any is returned from an operation with its
59  release flag set to FALSE, calling CORBA_free() on the
60  returned any* will not deallocate the memory pointed to by
61  _value.
62
63That is the allocation functions for CORBA_any look like:
64
65======
66typedef void (*ORBit_free_func)(void *);
67
68typedef struct {
69  void (*free)(void *, CORBA_ULong);
70  void *data;
71} ORBit_mem_info;
72
73typedef struct {
74  CORBA_any any;
75  CORBA_boolean release;
76} CORBA_any_private;
77
78void
79CORBA_free (void *ptr)
80{
81  ORBit_mem_info *mem_info = ((ORBit_mem_info *)ptr) - 1;
82  mem_info->free (ptr, mem_info->data);
83}
84
85void
86CORBA_any_free (void *ptr, CORBA_ULong length)
87{
88  CORBA_any_private *private = ptr;
89  if (private->release)
90    CORBA_free (private->_value);
91}
92
93CORBA_any *
94CORBA_any_alloc (void)
95{
96  ORBit_mem_info *mem_info;
97  CORBA_any_private *private;
98
99  mem_info = (ORBit_mem_info *)
100      malloc(sizeof(ORBit_mem_info) + sizeof(CORBA_any_private));
101  private = (CORBA_any_private *)(mem_info + 1);
102 
103  mem_info->free = CORBA_any_free;
104  private->release = FALSE;
105
106  return &private->any;
107}
108======
109
110With each thing we alloc, we store information about how
111to free it. the 'data' member is there mainly to support
112somebody doing:
113
114  COBRA_free (any->_value)
115
116If we demarshalled the any off the wire, the only way
117we may be able to free _value is by walking its TypeCode.
118So the CORBA_free call needs to have a pointer to the
119TypeCode.
120
121[
122This situation is what the next (very confusing) statement
123in the standard refers to:
124
125  Before calling CORBA_free() on the _value member of
126  an any directly, the programmer should check the release
127  flag using CORBA_any_get_release. If it returns FALSE, the
128  programmer should not invoke CORBA_free() on the _value
129  member; doing so produces undefined behavior.
130
131This is refers to is the case when the programmer modifying
132an existing any to point to another buffer. 
133]
134
135===
136
137Sequences work pretty similiarly. But the examples in the
138section on sequences, if taken to be authoritative, show
139that the above division into CORBA_any_private and
140CORBA_any is not possible. Here's why:
141
142Here's what standard says about an INOUT sequence parameter.
143
144  [...] Consider the following OMG IDL declaration:
145
146  // IDL
147  typedef sequence<long,10> vec10;
148
149  In C, this is converted to:
150
151  /* C */
152  typedef struct {
153    CORBA_unsigned_long _maximum;
154    CORBA_unsigned_long _length;
155    CORBA_long *_buffer;
156  } vec10;
157
158  An instance of this type is declared as follows:
159
160  /* C */
161  vec10 x = {10L, 0L, (CORBA_long *)NULL);
162
163Since we've stack allocated the sequence, the vec10
164structure better have really looked like:
165
166typedef struct {
167  CORBA_unsigned_long _maximum;
168  CORBA_unsigned_long _length;
169  CORBA_long *_buffer;
170  CORBA_boolean _release;
171} vec10;
172
173Or the _release flag will point into invalid memory. Perhaps
174the in such circumstances the release flag is never supposed
175to be examined? No - becaues shortly after we have:
176
177  Prior to passing &x as an inout parameter, the programmer
178  must set the _buffer member to point to a CORBA_long array
179  of 10 elements. The _length member must be set to the actual
180  number of elements to transmit. Upon successful return from
181  the invocation, the _length member will contain the number
182  of values that were copied into the buffer pointed to by the
183  _buffer member. If more data must be returned than the
184  original buffer can hold, the callee can deallocate the
185  original _buffer member using CORBA_free() (honoring the
186  release flag) and assign _buffer to point to new storage.
187
188====
189
190Finally, Note the typo on page 19-12:
191
192  char *CORBA_string_alloc();
193
194The correct definition appears on page 19-17:
195
196  CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);
197
198
199Regards,
200                                        Owen
201
202Date: Thu, 18 Jun 1998 13:36:02 -0400 (EDT)
203From: Elliot Lee <sopwith@redhat.com>
204To: orbit-list@cuc.edu
205Subject: Re: CORBA memory allcoation
206In-Reply-To: <lzemwnv9w6.fsf@cu-dialup-1518.cit.cornell.edu>
207Message-ID: <Pine.LNX.3.96.980618131957.15045F-100000@lacrosse.redhat.com>
208
209On 17 Jun 1998, Owen Taylor wrote:
210
211> Note the portion beginning "including storage indirectly
212> referenced.."  CORBA_free() is not like free() or
213> g_free(). It needs to know about the nature of the thing it
214> is freeing.
215
216Err, I guess we have to write our own memory allocation/freeing wrappers.
217This is seriously depressing... :)
218
219> With each thing we alloc, we store information about how
220> to free it. the 'data' member is there mainly to support
221> somebody doing:
222>
223>   COBRA_free (any->_value)
224>
225> If we demarshalled the any off the wire, the only way
226> we may be able to free _value is by walking its TypeCode.
227> So the CORBA_free call needs to have a pointer to the
228> TypeCode.
229
230So... We'll need info on how to recursively descend all values, not just
231ones that we generated off the wire. You're right, TypeCode's are the
232obvious way to do it.
233
234For sequences & any's we need to store the _release flag as well - might
235as well store it as part of the ORBit_mem_info structure (perhaps as the
236bottom-most bit of the 'free' function pointer, which is going to be
237aligned to a paragraph or something).
238
239We also need to cope with arrays of structures - i.e. a sequence<any>
240translates roughly into
241
242typedef struct {
243        CORBA_unsigned_long _maximum, _length;
244        CORBA_any *_buffer;
245} CORBA_sequence_any;
246
247('typedef struct CORBA_any_struct CORBA_any;' is the way the header files
248are set up currently - if all typedefs are supposed to be pointers to
249structs then someone should say something quickly :)
250
251If someone tries to free _buffer, it needs to free all the
252CORBA_any->_value's, but free the array memory as one big piece.
253
254We could make this work by storing a "valcount" member in ORBit_mem_info
255structures that tells how many consecutive values there are in the memory
256region. Or is there a better way?
257
258> Finally, Note the typo on page 19-12:
259>
260>   char *CORBA_string_alloc();
261>
262> The correct definition appears on page 19-17:
263>
264>   CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);
265
266Yea, got that fixed already in the sources.
267
268Thanks,
269-- Elliot
270When I die, I want to die peacefully in my sleep like my grandfather...
271        ...not yelling and screaming like the people in the back of the
272           plane he was flying.
273
274To: orbit-list@cuc.edu
275Subject: Re: CORBA memory allcoation
276From: Owen Taylor <otaylor@gtk.org>
277Date: 19 Jun 1998 11:15:59 -0400
278In-Reply-To: Elliot Lee's message of Thu, 18 Jun 1998 13:36:02 -0400 (EDT)
279Message-ID: <lz4sxhwhg0.fsf@cu-dialup-1725.cit.cornell.edu>
280
281
282Elliot Lee <sopwith@redhat.com> writes:
283
284> On 17 Jun 1998, Owen Taylor wrote:
285>
286> > Note the portion beginning "including storage indirectly
287> > referenced.."  CORBA_free() is not like free() or
288> > g_free(). It needs to know about the nature of the thing it
289> > is freeing.
290>
291> Err, I guess we have to write our own memory allocation/freeing wrappers.
292> This is seriously depressing... :)
293>
294> > With each thing we alloc, we store information about how
295> > to free it. the 'data' member is there mainly to support
296> > somebody doing:
297> >
298> >   COBRA_free (any->_value)
299> >
300> > If we demarshalled the any off the wire, the only way
301> > we may be able to free _value is by walking its TypeCode.
302> > So the CORBA_free call needs to have a pointer to the
303> > TypeCode.
304>
305> So... We'll need info on how to recursively descend all values, not just
306> ones that we generated off the wire. You're right, TypeCode's are the
307> obvious way to do it.
308
309I think long-term we want to restrict Typecode descent to values
310we get off the wire. For values we know about statically, the descent
311can be done by emitting __free() functions along with the __alloc()
312functions. For instance:
313
314 struct Foo {
315    short a;
316    sequence <long>b;
317 }
318
319 void Foo__free (void *ptr)
320 {
321   Foo *val = (Foo *)ptr;
322   CORBA_free (val->b);
323   g_free (ptr);
324 }
325
326For sequences, we need a __freebuf() to go along with __allocbuf().
327
328Then we just stick the pointer to the correct free function in
329the mem_info structure during the allocation.
330
331> For sequences & any's we need to store the _release flag as well - might
332> as well store it as part of the ORBit_mem_info structure (perhaps as the
333> bottom-most bit of the 'free' function pointer, which is going to be
334> aligned to a paragraph or something).
335
336I think this needs to be actually in the structure definition. The
337example I quoted in my last definition shows that it is expected
338that you can access the release flag for a stack-allocated any
339or sequence. So hiding it doesn't work.
340
341We don't need to worry about the release flag when the user does
342
343 CORBA_free (sequence->_buffer);
344
345In that case, the user is responsible for checking the _release
346flag for the sequence. (via _get_release())
347
348> We also need to cope with arrays of structures - i.e. a sequence<any>
349> translates roughly into
350>
351> typedef struct {
352>       CORBA_unsigned_long _maximum, _length;
353>       CORBA_any *_buffer;
354> } CORBA_sequence_any;
355>
356> ('typedef struct CORBA_any_struct CORBA_any;' is the way the header files
357> are set up currently - if all typedefs are supposed to be pointers to
358> structs then someone should say something quickly :)
359
360What the header files have is correct. I think only object references
361(and pseudo-object references) hide the '*' within the typedef.
362>
363> If someone tries to free _buffer, it needs to free all the
364> CORBA_any->_value's, but free the array memory as one big piece.
365>
366> We could make this work by storing a "valcount" member in ORBit_mem_info
367> structures that tells how many consecutive values there are in the memory
368> region. Or is there a better way?
369
370I think this is the right way. But we can make it a union with
371the ->data part of mem_info; because the sequence is homogenous -
372we either:
373
374 - Free the buffer with a single g_free()
375or,
376 - Call CORBA_free on each element, then g_free() the buf.
377
378So we just need to know the length of the sequence and pass
379it to the free() function.
380
381Regards,
382                                        Owen
383
384-----------------------------------------------------------------------
385Requirements:
386        When a pointer is passed to CORBA_free(), it must free any
387        stuff "contained" in that region.
388Examples:
389        structs/arrays/unions/sequences/exceptions
390
391IDLN_TYPE_FIXED
392IDLN_TYPE_ANY
393IDLN_TYPE_OBJECT
394IDLN_TYPE_SEQUENCE
395IDLN_TYPE_ARRAY
396IDLN_TYPE_STRUCT
397IDLN_TYPE_UNION
Note: See TracBrowser for help on using the repository browser.