namespace definition_ref and definition_unref
[babeltrace.git] / formats / ctf / types / float.c
1 /*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 * Reference: ISO C99 standard 5.2.4
29 */
30
31 #include <babeltrace/ctf/types.h>
32 #include <glib.h>
33 #include <float.h> /* C99 floating point definitions */
34 #include <limits.h> /* C99 limits */
35 #include <babeltrace/endian.h>
36 #include <pthread.h>
37
38 /*
39 * This library is limited to binary representation of floating point values.
40 * We use hardware support for conversion between 32 and 64-bit floating
41 * point values.
42 */
43
44 /*
45 * Aliasing float/double and unsigned long is not strictly permitted by strict
46 * aliasing, but in practice declaration prunning is well supported, and this permits
47 * us to use per-word read/writes rather than per-byte.
48 */
49
50 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
51 #define HAS_TYPE_PRUNING
52 #endif
53
54 #if (FLT_RADIX != 2)
55
56 #error "Unsupported floating point radix"
57
58 #endif
59
60 union doubleIEEE754 {
61 double vd;
62 float vf;
63 #ifdef HAS_TYPE_PRUNING
64 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
65 #else
66 unsigned char bits[sizeof(double)];
67 #endif
68 };
69
70 /*
71 * This mutex protects the static temporary float and double
72 * declarations (static_float_declaration and static_double_declaration).
73 */
74 static pthread_mutex_t float_mutex = PTHREAD_MUTEX_INITIALIZER;
75
76 static struct declaration_float *static_float_declaration,
77 *static_double_declaration;
78
79 struct pos_len {
80 size_t len;
81 };
82
83 static void float_lock(void)
84 {
85 int ret;
86
87 ret = pthread_mutex_lock(&float_mutex);
88 assert(!ret);
89 }
90
91 static void float_unlock(void)
92 {
93 int ret;
94
95 ret = pthread_mutex_unlock(&float_mutex);
96 assert(!ret);
97 }
98
99 static int _ctf_float_copy(struct stream_pos *destp,
100 struct definition_float *dest_definition,
101 struct stream_pos *srcp,
102 const struct definition_float *src_definition)
103 {
104 int ret;
105
106 /* We only support copy of same-size floats for now */
107 assert(src_definition->declaration->sign->len ==
108 dest_definition->declaration->sign->len);
109 assert(src_definition->declaration->exp->len ==
110 dest_definition->declaration->exp->len);
111 assert(src_definition->declaration->mantissa->len ==
112 dest_definition->declaration->mantissa->len);
113 /* Read */
114 if (src_definition->declaration->byte_order == LITTLE_ENDIAN) {
115 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
116 if (ret)
117 return ret;
118 ret = ctf_integer_read(srcp, &src_definition->exp->p);
119 if (ret)
120 return ret;
121 ret = ctf_integer_read(srcp, &src_definition->sign->p);
122 if (ret)
123 return ret;
124 } else {
125 ret = ctf_integer_read(srcp, &src_definition->sign->p);
126 if (ret)
127 return ret;
128 ret = ctf_integer_read(srcp, &src_definition->exp->p);
129 if (ret)
130 return ret;
131 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
132 if (ret)
133 return ret;
134 }
135
136 dest_definition->mantissa->value._unsigned =
137 src_definition->mantissa->value._unsigned;
138 dest_definition->exp->value._signed =
139 src_definition->exp->value._signed;
140 dest_definition->sign->value._unsigned =
141 src_definition->sign->value._unsigned;
142
143 /* Write */
144 if (dest_definition->declaration->byte_order == LITTLE_ENDIAN) {
145 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
146 if (ret)
147 return ret;
148 ret = ctf_integer_write(destp, &dest_definition->exp->p);
149 if (ret)
150 return ret;
151 ret = ctf_integer_write(destp, &dest_definition->sign->p);
152 if (ret)
153 return ret;
154 } else {
155 ret = ctf_integer_write(destp, &dest_definition->sign->p);
156 if (ret)
157 return ret;
158 ret = ctf_integer_write(destp, &dest_definition->exp->p);
159 if (ret)
160 return ret;
161 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
162 if (ret)
163 return ret;
164 }
165 return 0;
166 }
167
168 int ctf_float_read(struct stream_pos *ppos, struct definition *definition)
169 {
170 struct definition_float *float_definition =
171 container_of(definition, struct definition_float, p);
172 const struct declaration_float *float_declaration =
173 float_definition->declaration;
174 struct ctf_stream_pos *pos = ctf_pos(ppos);
175 union doubleIEEE754 u;
176 struct definition *tmpdef;
177 struct definition_float *tmpfloat;
178 struct ctf_stream_pos destp;
179 struct mmap_align mma;
180 int ret;
181
182 float_lock();
183 switch (float_declaration->mantissa->len + 1) {
184 case FLT_MANT_DIG:
185 tmpdef = static_float_declaration->p.definition_new(
186 &static_float_declaration->p,
187 NULL, 0, 0, "__tmpfloat");
188 break;
189 case DBL_MANT_DIG:
190 tmpdef = static_double_declaration->p.definition_new(
191 &static_double_declaration->p,
192 NULL, 0, 0, "__tmpfloat");
193 break;
194 default:
195 ret = -EINVAL;
196 goto end;
197 }
198 tmpfloat = container_of(tmpdef, struct definition_float, p);
199 memset(&destp, 0, sizeof(destp));
200 ctf_init_pos(&destp, -1, O_RDWR);
201 mmap_align_set_addr(&mma, (char *) u.bits);
202 destp.base_mma = &mma;
203 destp.packet_size = sizeof(u) * CHAR_BIT;
204 ctf_align_pos(pos, float_declaration->p.alignment);
205 ret = _ctf_float_copy(&destp.parent, tmpfloat, ppos, float_definition);
206 switch (float_declaration->mantissa->len + 1) {
207 case FLT_MANT_DIG:
208 float_definition->value = u.vf;
209 break;
210 case DBL_MANT_DIG:
211 float_definition->value = u.vd;
212 break;
213 default:
214 ret = -EINVAL;
215 goto end_unref;
216 }
217
218 end_unref:
219 bt_definition_unref(tmpdef);
220 end:
221 float_unlock();
222 return ret;
223 }
224
225 int ctf_float_write(struct stream_pos *ppos, struct definition *definition)
226 {
227 struct definition_float *float_definition =
228 container_of(definition, struct definition_float, p);
229 const struct declaration_float *float_declaration =
230 float_definition->declaration;
231 struct ctf_stream_pos *pos = ctf_pos(ppos);
232 union doubleIEEE754 u;
233 struct definition *tmpdef;
234 struct definition_float *tmpfloat;
235 struct ctf_stream_pos srcp;
236 struct mmap_align mma;
237 int ret;
238
239 float_lock();
240 switch (float_declaration->mantissa->len + 1) {
241 case FLT_MANT_DIG:
242 tmpdef = static_float_declaration->p.definition_new(
243 &static_float_declaration->p,
244 NULL, 0, 0, "__tmpfloat");
245 break;
246 case DBL_MANT_DIG:
247 tmpdef = static_double_declaration->p.definition_new(
248 &static_double_declaration->p,
249 NULL, 0, 0, "__tmpfloat");
250 break;
251 default:
252 ret = -EINVAL;
253 goto end;
254 }
255 tmpfloat = container_of(tmpdef, struct definition_float, p);
256 ctf_init_pos(&srcp, -1, O_RDONLY);
257 mmap_align_set_addr(&mma, (char *) u.bits);
258 srcp.base_mma = &mma;
259 srcp.packet_size = sizeof(u) * CHAR_BIT;
260 switch (float_declaration->mantissa->len + 1) {
261 case FLT_MANT_DIG:
262 u.vf = float_definition->value;
263 break;
264 case DBL_MANT_DIG:
265 u.vd = float_definition->value;
266 break;
267 default:
268 ret = -EINVAL;
269 goto end_unref;
270 }
271 ctf_align_pos(pos, float_declaration->p.alignment);
272 ret = _ctf_float_copy(ppos, float_definition, &srcp.parent, tmpfloat);
273
274 end_unref:
275 bt_definition_unref(tmpdef);
276 end:
277 float_unlock();
278 return ret;
279 }
280
281 static
282 void __attribute__((constructor)) ctf_float_init(void)
283 {
284 static_float_declaration =
285 float_declaration_new(FLT_MANT_DIG,
286 sizeof(float) * CHAR_BIT - FLT_MANT_DIG,
287 BYTE_ORDER,
288 __alignof__(float));
289 static_double_declaration =
290 float_declaration_new(DBL_MANT_DIG,
291 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
292 BYTE_ORDER,
293 __alignof__(double));
294 }
295
296 static
297 void __attribute__((destructor)) ctf_float_fini(void)
298 {
299 bt_declaration_unref(&static_float_declaration->p);
300 bt_declaration_unref(&static_double_declaration->p);
301 }
This page took 0.034187 seconds and 4 git commands to generate.