+ Say "returned to the OS" instead of "freed" here, since the latter
[parrot.git] / docs / pmc / struct.pod
blob5210b51b98fa74712867de40e24aa4838fcdb123
1 # Copyright (C) 2001-2005, The Perl Foundation.
2 # $Id$
4 =head1 NAME
6 Structures - Accessing C Structs from Parrot
8 =head1 DESCRIPTION
10 Parrot provides two PMC classes to deal with C structures. These are
11 UnManagedStruct and ManagedStruct. The former has no allocated memory and is
12 typically used to access structures returned by NCI calls, while the latter can
13 be used to define a structure and pass it over to a C function - pointers to
14 structures in both cases of course.
16 =head1 Structure definition
18 The Struct PMCs take an array of triples per structure element, either as
19 initializer or with the B<assign> opcode to define the struct elements.
21 =over 4
23 =item Datatype
25 The datatype is defined by constants declared in F<datatypes.pasm>.
27 =item Array Size
29 The second initializer item, if set to a value greater then 1, defines the
30 struct element to consist of an array of the given data type.
32 =item Byte Offset
34 The third initializer is the byte offset of the data item in the structure.
35 This entry can be 0 if packing of the structure is aligned to the item's sizes
36 or the alignment is the item's size. Otherwise these offsets must be set
37 correctly as Parrot doesn't know how your C compiler packs arbitrary data.
38 Parrot only knows the size of each item.
40 =back
42 =head2 Alignment
44 Parrot tries to do The Right Thing that is currently align items at their size.
46   struct {
47     char c;
48     int  i;
49   }
51 The C<i> above is aligned at 4 (for i386 or such).
53 =head2 Example
55 The C structure
57   struct {
58     double d;
59     float  f;
60     int    i[4];
61     char  *s;
62   };
64 can be declared with this initializer:
66   new P2, 'ResizablePMCArray'
67   .include "datatypes.pasm"
68   push P2, .DATATYPE_DOUBLE
69   push P2, 0    # no array i.e. 1 element
70   push P2, 0    # calculate offset by just adding item size
71   push P2, .DATATYPE_FLOAT
72   push P2, 0
73   push P2, 0
74   push P2, .DATATYPE_INT
75   push P2, 4    # 4 elem array
76   push P2, 0
77   push P2, .DATATYPE_CSTR
78   push P2, 0
79   push P2, 0
81 =head2 Named Structure Elements
83 The initializer can be an OrderedHash PMC too. When all elements are defined in
84 the correct order this can be used to define and access struct elements by name
85 and by index:
87   new P2, 'OrderedHash'
88   .include "datatypes.pasm"
89   set P2["d"], .DATATYPE_DOUBLE
90   push P2, 0    # no array i.e. 1 element
91   push P2, 0    # calculate offset by just adding item size
92   set P2["f"], .DATATYPE_FLOAT
93   ...
95 =head1 Size of a Structure
97 For ManagedStruct (a new structure passed over to a C function) the storage for
98 data items has to be allocated. This is done automatically, when the
99 initializer is attached to the Struct PMC.
101 The size can be obtained by:
103   new P5, 'ManagedStruct', P2   # P2 be some initializer
105   set I0, P5    # allocated size
107 =head1 Accessing Structure Items
109 Setting or getting items is done by keyed access to the Struct PMC. The first
110 key is the structure item, an optional second key can access the n-th array
111 element.
113 =head2 Example
115   set P5[0], N0         # set d
116   set N0, P5[0]         # get d
118   set N0, P5["d"]       # get d if initializer is an OrderedHash
120   set P5[1], N1         # set f
121   set N1, P5[1]         # get f
122   set N1, P5["f"]       # get f if initializer is an OrderedHash
124   set P5[2;0], I2       # set i[0]
125   set I3, P5[2;3]       # get i[3]
127   set P5["i"; 2]        # set i[2] if initializer is an OrderedHash
129   set S0, P5[3]         # get string at *s
130   set S0, P5["s"]       # same
132 =head2 Strings
134 When passing a STRING to a structure that needs a 0-terminated C-string (char
135 *s), then you have to provide the terminating NUL char in the string.
137   struct {
138     ...
139     char *s;
140   };
142   set P5["s"], "a string\x0"
144 Please also note, that the C function currently gets a pointer to string
145 memory, so any code that might trigger GC should be avoided (or GC turned off).
146 Passing constant strings like above is safe though.
148   set P5["s"], S0  # S0 shouldn't move until function call
150 =head2 Callback Functions in the C Library
152 Given a C function that returns a structure containing a callback function like
153 in this example:
155   static struct {
156       int (*f)(char *);
157   } t = {
158        call_back
159   };
160   return &t;
162 The PASM would look like:
164   push P2, .DATATYPE_FUNC_PTR
165   # attach function signature property to this type
166   set P1, P2[-1]
167   new P3, 'String'
168   set P3, "it"
169   setprop P1, "_signature", P3
170   push P2, 0
171   push P2, 0
172   # P5 is the return UnManagedStruct PMC
173   assign P5, P2
174   # now we get a callable NCI PMC
175   set P0, P5[0]
176   set S5, "hello call_back"
177   # call the call_back function
178   invoke
180 =head2 Nested Structures or Pointers to Nested Structures
182 Each contained structure needs its own UnManagedStruct initializer. The
183 UnManagedStruct of the contained structures has to be attached to the structure
184 type PMC as the property B<"_struct">.
186 If a C function returns a pointer to this structure:
188   static struct xt {
189       char x;
190       struct yt {
191           char i;
192           int  j;
193       } _y;
194       char z;
195   } _x;
197 ... access to elements could look like:
199   # the nested structure
200   new P3, 'OrderedHash'
201   set P3["i"], .DATATYPE_CHAR
202   push P3, 0
203   push P3, 0
204   set P3["j"], .DATATYPE_INT
205   push P3, 0
206   push P3, 0
207   new P4, 'UnManagedStruct', P3
209   # outer structure
210   new P2, 'OrderedHash'
211   set P2["x"], .DATATYPE_CHAR
212   push P2, 0
213   push P2, 0
214   set P2["_y"], .DATATYPE_STRUCT
216   # attach the unmanaged struct as property to the type PMC
217   set P1, P2[-1]                # last element
218   setprop P1, "_struct", P4
219   push P2, 0
220   push P2, 0
221   set P2["z"], .DATATYPE_CHAR
222   push P2, 0
223   push P2, 0
225   # attach struct initializer to return value in P5
226   assign P5, P2
228   # now access values
229   set I0, P5[0]         # x
230   set I0, P5[1;0]       # _y.i
231   set I0, P5[1;1]       # _y.j
232   set I0, P5[2]         # z
234   # or by name
235   set I0, P5["x"]
236   set I0, P5["_y"; "i"]
237   set I0, P5["_y"; "j"]
238   set I0, P5["z"]
240 If the structure has a pointer to another structure the datatype is:
242   push P2, .DATATYPE_STRUCT_PTR
244 =head1 Passing A Structure to a C function
246 For a shared library B<libnci_test.so> (or whatever) and a C function
248   typedef struct _dfi_t {
249     double d;
250     float  f;
251     int    i[4];
252   } dfi_t;
254   int nci_ip(dfi_t *p) {}
256 a pointer to the structure is passed with the B<p> signature char:
258   loadlib P1, "libnci_test"
259   dlfunc P0, P1, "nci_ip", "ip"
260   # P5 is ManagedStruct from above
261   invoke
262   # I5 is result
264 =head1 BUGS
266 Not all datatypes are implemented. Alignment is barely tested on different
267 machines. Arrays of structures aren't handled yet. Passing nested structures to
268 C isn't finished.
270 =head1 FILES
272 F<src/pmc/unmanagedstruct.pmc>, F<src/pmc/managedstruct.pmc>
274 =head1 SEE ALSO
276 F<docs/pdds/pdd03_calling_conventions.pod> F<t/pmc/nci.t>, F<src/nci_test.c>
278 =head1 AUTHOR
280 Leopold Toetsch <lt@toetsch.at>