ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Algorithm-FEC/FEC.xs
Revision: 1.10
Committed: Thu Nov 22 01:41:39 2012 UTC (11 years, 5 months ago) by root
Branch: MAIN
CVS Tags: rel-1_1, HEAD
Changes since 1.9: +1 -1 lines
Log Message:
1.1

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include <string.h>
6 #include <unistd.h>
7 #include <sys/mman.h>
8
9 #include "fec.h"
10
11 struct fec_imp {
12 void (*fec_free)(void *p) ;
13 void *(*fec_new)(int k, int n) ;
14 void (*fec_encode)(void *code, void *src[], void *dst, int index, int sz) ;
15 int (*fec_decode)(void *code, void *pkt[], int index[], int sz) ;
16 };
17
18 static struct fec_imp fec8_imp = { fec8_free , fec8_new , fec8_encode , fec8_decode };
19 static struct fec_imp fec16_imp = { fec16_free, fec16_new, fec16_encode, fec16_decode };
20
21 typedef struct state {
22 struct fec_imp *imp;
23 void *code;
24 int sz;
25 int dp, ep;
26
27 void **b_addr;
28 void **b_mmap;
29 int *b_sz;
30 SV **b_sv;
31 int *idx; /* the decoding indices */
32 } *Algorithm__FEC;
33
34 static void
35 chk_array (SV *sv, int size, const char *func, const char *var)
36 {
37 if (!SvROK (sv)
38 || SvTYPE (SvRV (sv)) != SVt_PVAV
39 || av_len ((AV *)SvRV (sv)) != size - 1)
40 croak ("%s: %s (%s) must be a reference to an array of size %d", func, SvPV_nolen (sv), var, size);
41 }
42
43 static void
44 free_files (struct state *self)
45 {
46 int i;
47
48 if (self->b_addr && self->b_sv)
49 for (i = 0; i < self->dp; i++)
50 if (self->b_sv[i])
51 SvREFCNT_dec (self->b_sv[i]);
52 else if (self->b_mmap[i])
53 munmap (self->b_mmap[i], self->b_sz[i]);
54
55 Safefree (self->b_addr); self->b_addr = 0;
56 Safefree (self->b_mmap); self->b_mmap = 0;
57 Safefree (self->b_sz ); self->b_sz = 0;
58 Safefree (self->b_sv ); self->b_sv = 0;
59 Safefree (self->idx ); self->idx = 0;
60 }
61
62 static void
63 realloc_files (struct state *self)
64 {
65 free_files (self);
66
67 Newz (0, self->b_addr, self->dp, void *);
68 Newz (0, self->b_mmap, self->dp, void *);
69 Newz (0, self->b_sz , self->dp, int);
70 Newz (0, self->b_sv , self->dp, SV *);
71 }
72
73 static void
74 force_addrs (struct state *self, int dp)
75 {
76 int i;
77
78 for (i = 0; i < dp; i++)
79 if (self->b_sv[i])
80 {
81 STRLEN size;
82 self->b_addr[i] = SvPV_force (self->b_sv[i], size);
83
84 if (size != self->sz)
85 croak ("block #%d (a string) has size %d, not %d", i, (int)size, self->sz);
86 } else if (!self->b_mmap[i]) {
87 croak ("block #%d neither string nor file, did set_blocks fail and you ignored it?", i);
88 }
89 }
90
91 static void
92 open_file (struct state *self, int idx, SV *sv, int rw)
93 {
94 IO *io = 0;
95 off_t offset;
96
97 if (SvROK (sv) && SvTYPE (SvRV (sv)) == SVt_PVAV)
98 {
99 io = sv_2io (*av_fetch ((AV *)SvRV (sv), 0, 1));
100 offset = SvIV (*av_fetch ((AV *)SvRV (sv), 1, 1));
101 sv = 0;
102 }
103 else if (!SvPOK (sv))
104 {
105 io = sv_2io (sv);
106 offset = 0;
107 sv = 0;
108 }
109
110 if (io)
111 {
112 int fd = PerlIO_fileno (IoIFP (io));
113 off_t ofs2 = offset & ~((off_t)getpagesize () - 1);
114 void *mm;
115
116 if (fd <= 0)
117 croak ("invalid file descriptor for block #%d", idx);
118
119 mm = mmap (0, self->sz + (offset - ofs2),
120 rw ? PROT_READ | PROT_WRITE : PROT_READ,
121 MAP_SHARED, fd, ofs2);
122
123 if (mm == MAP_FAILED)
124 croak ("unable to mmap block #%d (wrong offset or size?): %s", idx, strerror (errno));
125
126 self->b_mmap[idx] = mm;
127 self->b_addr[idx] = (void *)((char *)mm + (offset - ofs2));
128 self->b_sz [idx] = self->sz + (offset - ofs2);
129 }
130 else if (sv)
131 self->b_sv[idx] = SvREFCNT_inc (sv);
132 else
133 croak ("unable to open block #%d, must be either string, filehandle, or [filehandle, offset]", idx);
134 }
135
136 static void
137 open_files (struct state *self, AV *av, int rw)
138 {
139 int i;
140
141 realloc_files (self);
142
143 for (i = 0; i < self->dp; i++)
144 open_file (self, i, *av_fetch (av, i, 1), rw);
145 }
146
147 MODULE = Algorithm::FEC PACKAGE = Algorithm::FEC
148
149 PROTOTYPES: ENABLE
150
151 Algorithm::FEC
152 new(class, data_packets, encoded_packets, blocksize)
153 SV * class
154 int data_packets
155 int encoded_packets
156 int blocksize
157 CODE:
158 void *code;
159 struct fec_imp *imp;
160
161 if (data_packets < 2)
162 croak ("the number of data packets must be >= 2"); /* for copy_blocks :) */
163
164 if (encoded_packets < data_packets)
165 croak ("the number of encoded packets must be >= the number of data packets");
166
167 if (GF_SIZE16 < encoded_packets)
168 croak ("the number of encoded packets must be <= %d", GF_SIZE16);
169
170 imp = GF_SIZE8 < encoded_packets ? &fec16_imp : &fec8_imp;
171
172 code = imp->fec_new (data_packets, encoded_packets);
173 if (!code)
174 croak ("FATAL: unable to create fec state");
175
176 Newz(0, RETVAL, 1, struct state);
177 RETVAL->imp = imp;
178 RETVAL->code = code;
179 RETVAL->sz = blocksize;
180 RETVAL->dp = data_packets;
181 RETVAL->ep = encoded_packets;
182 OUTPUT:
183 RETVAL
184
185 void
186 set_encode_blocks (self, blocks)
187 Algorithm::FEC self
188 SV * blocks
189 CODE:
190
191 free_files (self);
192
193 if (SvOK (blocks))
194 {
195 chk_array (blocks, self->dp, "set_encode_blocks", "blocks");
196 open_files (self, (AV *)SvRV (blocks), 0);
197 }
198
199 SV *
200 encode (self, block_index)
201 Algorithm::FEC self
202 int block_index
203 CODE:
204
205 if (block_index < 0 || self->ep <= block_index)
206 croak ("encode: block_index %d out of range, must be 0 <= block_index < %d",
207 block_index, self->ep);
208
209 if (!self->b_addr)
210 croak ("no blocks specified by a preceding call to set_encode_blocks");
211
212 force_addrs (self, self->dp);
213
214 RETVAL = newSV (self->sz);
215 if (!RETVAL)
216 croak ("unable to allocate result block (out of memory)");
217
218 SvPOK_only (RETVAL);
219 SvCUR_set (RETVAL, self->sz);
220
221 self->imp->fec_encode (self->code, self->b_addr,
222 SvPVX (RETVAL), block_index, self->sz);
223
224 OUTPUT:
225 RETVAL
226
227 void
228 set_decode_blocks (self, blocks, indices)
229 Algorithm::FEC self
230 SV * blocks
231 SV * indices
232 ALIAS:
233 shuffle = 1
234 CODE:
235 {
236 int i;
237 int *idx;
238
239 chk_array (blocks, self->dp, "set_decode_blocks", "blocks");
240 chk_array (indices, self->dp, "set_decode_blocks", "indices");
241
242 Newz (0, idx, self->dp, int);
243
244 /* copy and check */
245 for (i = 0; i < self->dp; i++)
246 {
247 idx[i] = SvIV (*av_fetch ((AV *)SvRV (indices), i, 1));
248
249 if (idx[i] < 0 || idx[i] >= self->ep)
250 {
251 Safefree (idx);
252 croak ("index %d in array out of bounds (0 <= %d < %d != true)",
253 i, idx[i], self->ep);
254 }
255 }
256
257 /*
258 * do the same shuffling as fec_decode does here,
259 * so we know the order.
260 */
261 for (i = 0; i < self->dp; i++)
262 while (idx[i] < self->dp && idx[i] != i)
263 {
264 SV **a, **b, **e, **f;
265 int d;
266 void *p;
267 SV *s;
268 int j = idx[i];
269
270 if (idx[j] == j)
271 {
272 Safefree (idx);
273 croak ("error while shuffling, duplicate indices?");
274 }
275
276 a = av_fetch ((AV *)SvRV (indices), i, 1);
277 b = av_fetch ((AV *)SvRV (indices), j, 1);
278 e = av_fetch ((AV *)SvRV (blocks ), i, 1);
279 f = av_fetch ((AV *)SvRV (blocks ), j, 1);
280
281 d = idx[i]; idx[i] = idx[j]; idx[j] = d;
282 s = *a; *a = *b; *b = s;
283 s = *e; *e = *f; *f = s;
284 }
285
286 if (ix)
287 Safefree (idx);
288 else
289 {
290 open_files (self, (AV *)SvRV (blocks), 1);
291 self->idx = idx;
292 }
293 }
294
295 void
296 decode (self)
297 Algorithm::FEC self
298 CODE:
299
300 if (!self->idx)
301 croak ("index array must be set by a prior call to set_decode_blocks");
302
303 force_addrs (self, self->dp);
304 self->imp->fec_decode (self->code, self->b_addr, self->idx, self->sz);
305 free_files (self);
306
307 void
308 copy (self, srcblock, dstblock)
309 Algorithm::FEC self
310 SV * srcblock
311 SV * dstblock
312 CODE:
313 realloc_files (self);
314 open_file (self, 0, srcblock, 0);
315 open_file (self, 1, dstblock, 1);
316 force_addrs (self, 2);
317 Copy (self->b_addr[0], self->b_addr[1], self->sz, char);
318 free_files (self);
319
320 void
321 DESTROY(self)
322 Algorithm::FEC self
323 CODE:
324 self->imp->fec_free (self->code);
325 free_files (self);
326 Safefree(self);
327