2586952632e69818e848cd8c41306eda07e04b43
[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 <babeltrace/compat/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 bt_stream_pos *destp,
100 struct definition_float *dest_definition,
101 struct bt_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 bt_stream_pos *ppos, struct bt_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 bt_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, NULL, -1, O_RDWR);
201 mmap_align_set_addr(&mma, (char *) u.bits);
202 destp.base_mma = &mma;
203 destp.content_size = destp.packet_size = sizeof(u) * CHAR_BIT;
204 if (!ctf_align_pos(pos, float_declaration->p.alignment)) {
205 ret = -EFAULT;
206 goto end_unref;
207 }
208 ret = _ctf_float_copy(&destp.parent, tmpfloat, ppos, float_definition);
209 switch (float_declaration->mantissa->len + 1) {
210 case FLT_MANT_DIG:
211 float_definition->value = u.vf;
212 break;
213 case DBL_MANT_DIG:
214 float_definition->value = u.vd;
215 break;
216 default:
217 ret = -EINVAL;
218 goto end_unref;
219 }
220
221 end_unref:
222 bt_definition_unref(tmpdef);
223 end:
224 float_unlock();
225 return ret;
226 }
227
228 int ctf_float_write(struct bt_stream_pos *ppos, struct bt_definition *definition)
229 {
230 struct definition_float *float_definition =
231 container_of(definition, struct definition_float, p);
232 const struct declaration_float *float_declaration =
233 float_definition->declaration;
234 struct ctf_stream_pos *pos = ctf_pos(ppos);
235 union doubleIEEE754 u;
236 struct bt_definition *tmpdef;
237 struct definition_float *tmpfloat;
238 struct ctf_stream_pos srcp = { { 0 } };
239 struct mmap_align mma;
240 int ret;
241
242 float_lock();
243 switch (float_declaration->mantissa->len + 1) {
244 case FLT_MANT_DIG:
245 tmpdef = static_float_declaration->p.definition_new(
246 &static_float_declaration->p,
247 NULL, 0, 0, "__tmpfloat");
248 break;
249 case DBL_MANT_DIG:
250 tmpdef = static_double_declaration->p.definition_new(
251 &static_double_declaration->p,
252 NULL, 0, 0, "__tmpfloat");
253 break;
254 default:
255 ret = -EINVAL;
256 goto end;
257 }
258 tmpfloat = container_of(tmpdef, struct definition_float, p);
259 ctf_init_pos(&srcp, NULL, -1, O_RDONLY);
260 mmap_align_set_addr(&mma, (char *) u.bits);
261 srcp.base_mma = &mma;
262 srcp.content_size = srcp.packet_size = sizeof(u) * CHAR_BIT;
263 switch (float_declaration->mantissa->len + 1) {
264 case FLT_MANT_DIG:
265 u.vf = float_definition->value;
266 break;
267 case DBL_MANT_DIG:
268 u.vd = float_definition->value;
269 break;
270 default:
271 ret = -EINVAL;
272 goto end_unref;
273 }
274 if (!ctf_align_pos(pos, float_declaration->p.alignment)) {
275 ret = -EFAULT;
276 goto end_unref;
277 }
278 ret = _ctf_float_copy(ppos, float_definition, &srcp.parent, tmpfloat);
279
280 end_unref:
281 bt_definition_unref(tmpdef);
282 end:
283 float_unlock();
284 return ret;
285 }
286
287 double bt_get_float(const struct bt_definition *field)
288 {
289 struct definition_float *definition =
290 container_of(field, struct definition_float, p);
291
292 return definition->value;
293 }
294
295 static
296 void __attribute__((constructor)) ctf_float_init(void)
297 {
298 static_float_declaration =
299 bt_float_declaration_new(FLT_MANT_DIG,
300 sizeof(float) * CHAR_BIT - FLT_MANT_DIG,
301 BYTE_ORDER,
302 __alignof__(float));
303 static_double_declaration =
304 bt_float_declaration_new(DBL_MANT_DIG,
305 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
306 BYTE_ORDER,
307 __alignof__(double));
308 }
309
310 static
311 void __attribute__((destructor)) ctf_float_fini(void)
312 {
313 bt_declaration_unref(&static_float_declaration->p);
314 bt_declaration_unref(&static_double_declaration->p);
315 }
This page took 0.03483 seconds and 3 git commands to generate.