782f72bfef514433303a9c232188e86bee4f4e80
[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 * Reference: ISO C99 standard 5.2.4
21 */
22
23 #include <babeltrace/ctf/types.h>
24 #include <glib.h>
25 #include <float.h> /* C99 floating point definitions */
26 #include <limits.h> /* C99 limits */
27 #include <babeltrace/endian.h>
28 #include <pthread.h>
29
30 /*
31 * This library is limited to binary representation of floating point values.
32 * We use hardware support for conversion between 32 and 64-bit floating
33 * point values.
34 */
35
36 /*
37 * Aliasing float/double and unsigned long is not strictly permitted by strict
38 * aliasing, but in practice declaration prunning is well supported, and this permits
39 * us to use per-word read/writes rather than per-byte.
40 */
41
42 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
43 #define HAS_TYPE_PRUNING
44 #endif
45
46 #if (FLT_RADIX != 2)
47
48 #error "Unsupported floating point radix"
49
50 #endif
51
52 union doubleIEEE754 {
53 double vd;
54 float vf;
55 #ifdef HAS_TYPE_PRUNING
56 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
57 #else
58 unsigned char bits[sizeof(double)];
59 #endif
60 };
61
62 /*
63 * This mutex protects the static temporary float and double
64 * declarations (static_float_declaration and static_double_declaration).
65 */
66 static pthread_mutex_t float_mutex = PTHREAD_MUTEX_INITIALIZER;
67
68 static struct declaration_float *static_float_declaration,
69 *static_double_declaration;
70
71 struct pos_len {
72 size_t len;
73 };
74
75 static void float_lock(void)
76 {
77 int ret;
78
79 ret = pthread_mutex_lock(&float_mutex);
80 assert(!ret);
81 }
82
83 static void float_unlock(void)
84 {
85 int ret;
86
87 ret = pthread_mutex_unlock(&float_mutex);
88 assert(!ret);
89 }
90
91 int _ctf_float_copy(struct stream_pos *destp,
92 struct definition_float *dest_definition,
93 struct stream_pos *srcp,
94 const struct definition_float *src_definition)
95 {
96 int ret;
97
98 /* We only support copy of same-size floats for now */
99 assert(src_definition->declaration->sign->len ==
100 dest_definition->declaration->sign->len);
101 assert(src_definition->declaration->exp->len ==
102 dest_definition->declaration->exp->len);
103 assert(src_definition->declaration->mantissa->len ==
104 dest_definition->declaration->mantissa->len);
105 /* Read */
106 if (src_definition->declaration->byte_order == LITTLE_ENDIAN) {
107 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
108 if (ret)
109 return ret;
110 ret = ctf_integer_read(srcp, &src_definition->exp->p);
111 if (ret)
112 return ret;
113 ret = ctf_integer_read(srcp, &src_definition->sign->p);
114 if (ret)
115 return ret;
116 } else {
117 ret = ctf_integer_read(srcp, &src_definition->sign->p);
118 if (ret)
119 return ret;
120 ret = ctf_integer_read(srcp, &src_definition->exp->p);
121 if (ret)
122 return ret;
123 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
124 if (ret)
125 return ret;
126 }
127
128 dest_definition->mantissa->value._unsigned =
129 src_definition->mantissa->value._unsigned;
130 dest_definition->exp->value._signed =
131 src_definition->exp->value._signed;
132 dest_definition->sign->value._unsigned =
133 src_definition->sign->value._unsigned;
134
135 /* Write */
136 if (dest_definition->declaration->byte_order == LITTLE_ENDIAN) {
137 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
138 if (ret)
139 return ret;
140 ret = ctf_integer_write(destp, &dest_definition->exp->p);
141 if (ret)
142 return ret;
143 ret = ctf_integer_write(destp, &dest_definition->sign->p);
144 if (ret)
145 return ret;
146 } else {
147 ret = ctf_integer_write(destp, &dest_definition->sign->p);
148 if (ret)
149 return ret;
150 ret = ctf_integer_write(destp, &dest_definition->exp->p);
151 if (ret)
152 return ret;
153 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
154 if (ret)
155 return ret;
156 }
157 return 0;
158 }
159
160 int ctf_float_read(struct stream_pos *ppos, struct definition *definition)
161 {
162 struct definition_float *float_definition =
163 container_of(definition, struct definition_float, p);
164 const struct declaration_float *float_declaration =
165 float_definition->declaration;
166 struct ctf_stream_pos *pos = ctf_pos(ppos);
167 union doubleIEEE754 u;
168 struct definition *tmpdef;
169 struct definition_float *tmpfloat;
170 struct ctf_stream_pos destp;
171 struct mmap_align mma;
172 int ret;
173
174 float_lock();
175 switch (float_declaration->mantissa->len + 1) {
176 case FLT_MANT_DIG:
177 tmpdef = static_float_declaration->p.definition_new(
178 &static_float_declaration->p,
179 NULL, 0, 0, "__tmpfloat");
180 break;
181 case DBL_MANT_DIG:
182 tmpdef = static_double_declaration->p.definition_new(
183 &static_double_declaration->p,
184 NULL, 0, 0, "__tmpfloat");
185 break;
186 default:
187 ret = -EINVAL;
188 goto end;
189 }
190 tmpfloat = container_of(tmpdef, struct definition_float, p);
191 memset(&destp, 0, sizeof(destp));
192 ctf_init_pos(&destp, -1, O_RDWR);
193 mmap_align_set_addr(&mma, (char *) u.bits);
194 destp.base_mma = &mma;
195 destp.packet_size = sizeof(u) * CHAR_BIT;
196 ctf_align_pos(pos, float_declaration->p.alignment);
197 ret = _ctf_float_copy(&destp.parent, tmpfloat, ppos, float_definition);
198 switch (float_declaration->mantissa->len + 1) {
199 case FLT_MANT_DIG:
200 float_definition->value = u.vf;
201 break;
202 case DBL_MANT_DIG:
203 float_definition->value = u.vd;
204 break;
205 default:
206 ret = -EINVAL;
207 goto end_unref;
208 }
209
210 end_unref:
211 definition_unref(tmpdef);
212 end:
213 float_unlock();
214 return ret;
215 }
216
217 int ctf_float_write(struct stream_pos *ppos, struct definition *definition)
218 {
219 struct definition_float *float_definition =
220 container_of(definition, struct definition_float, p);
221 const struct declaration_float *float_declaration =
222 float_definition->declaration;
223 struct ctf_stream_pos *pos = ctf_pos(ppos);
224 union doubleIEEE754 u;
225 struct definition *tmpdef;
226 struct definition_float *tmpfloat;
227 struct ctf_stream_pos srcp;
228 struct mmap_align mma;
229 int ret;
230
231 float_lock();
232 switch (float_declaration->mantissa->len + 1) {
233 case FLT_MANT_DIG:
234 tmpdef = static_float_declaration->p.definition_new(
235 &static_float_declaration->p,
236 NULL, 0, 0, "__tmpfloat");
237 break;
238 case DBL_MANT_DIG:
239 tmpdef = static_double_declaration->p.definition_new(
240 &static_double_declaration->p,
241 NULL, 0, 0, "__tmpfloat");
242 break;
243 default:
244 ret = -EINVAL;
245 goto end;
246 }
247 tmpfloat = container_of(tmpdef, struct definition_float, p);
248 ctf_init_pos(&srcp, -1, O_RDONLY);
249 mmap_align_set_addr(&mma, (char *) u.bits);
250 srcp.base_mma = &mma;
251 srcp.packet_size = sizeof(u) * CHAR_BIT;
252 switch (float_declaration->mantissa->len + 1) {
253 case FLT_MANT_DIG:
254 u.vf = float_definition->value;
255 break;
256 case DBL_MANT_DIG:
257 u.vd = float_definition->value;
258 break;
259 default:
260 ret = -EINVAL;
261 goto end_unref;
262 }
263 ctf_align_pos(pos, float_declaration->p.alignment);
264 ret = _ctf_float_copy(ppos, float_definition, &srcp.parent, tmpfloat);
265
266 end_unref:
267 definition_unref(tmpdef);
268 end:
269 float_unlock();
270 return ret;
271 }
272
273 void __attribute__((constructor)) ctf_float_init(void)
274 {
275 static_float_declaration =
276 float_declaration_new(FLT_MANT_DIG,
277 sizeof(float) * CHAR_BIT - FLT_MANT_DIG,
278 BYTE_ORDER,
279 __alignof__(float));
280 static_double_declaration =
281 float_declaration_new(DBL_MANT_DIG,
282 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
283 BYTE_ORDER,
284 __alignof__(double));
285 }
286
287 void __attribute__((destructor)) ctf_float_fini(void)
288 {
289 declaration_unref(&static_float_declaration->p);
290 declaration_unref(&static_double_declaration->p);
291 }
This page took 0.055447 seconds and 3 git commands to generate.