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

# User Rev Content
1 root 1.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 root 1.6 int *idx; /* the decoding indices */
32 root 1.3 } *Algorithm__FEC;
33 root 1.1
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 root 1.9 croak ("%s: %s (%s) must be a reference to an array of size %d", func, SvPV_nolen (sv), var, size);
41 root 1.1 }
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 root 1.5 Safefree (self->idx ); self->idx = 0;
60 root 1.1 }
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 root 1.2 force_addrs (struct state *self, int dp)
75 root 1.1 {
76     int i;
77    
78 root 1.2 for (i = 0; i < dp; i++)
79 root 1.1 if (self->b_sv[i])
80     {
81     STRLEN size;
82 root 1.10 self->b_addr[i] = SvPV_force (self->b_sv[i], size);
83 root 1.1
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 root 1.2 croak ("block #%d neither string nor file, did set_blocks fail and you ignored it?", i);
88 root 1.1 }
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 root 1.3 MODULE = Algorithm::FEC PACKAGE = Algorithm::FEC
148 root 1.1
149     PROTOTYPES: ENABLE
150    
151 root 1.3 Algorithm::FEC
152 root 1.1 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 root 1.5 set_encode_blocks (self, blocks)
187 root 1.3 Algorithm::FEC self
188 root 1.1 SV * blocks
189     CODE:
190    
191     free_files (self);
192    
193     if (SvOK (blocks))
194     {
195 root 1.5 chk_array (blocks, self->dp, "set_encode_blocks", "blocks");
196 root 1.1 open_files (self, (AV *)SvRV (blocks), 0);
197     }
198    
199     SV *
200     encode (self, block_index)
201 root 1.3 Algorithm::FEC self
202 root 1.1 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 root 1.5 croak ("no blocks specified by a preceding call to set_encode_blocks");
211 root 1.1
212 root 1.2 force_addrs (self, self->dp);
213 root 1.1
214     RETVAL = newSV (self->sz);
215     if (!RETVAL)
216     croak ("unable to allocate result block (out of memory)");
217 root 1.5
218 root 1.1 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 root 1.5 set_decode_blocks (self, blocks, indices)
229 root 1.3 Algorithm::FEC self
230 root 1.1 SV * blocks
231     SV * indices
232 root 1.7 ALIAS:
233     shuffle = 1
234 root 1.1 CODE:
235     {
236     int i;
237 root 1.6 int *idx;
238 root 1.1
239 root 1.5 chk_array (blocks, self->dp, "set_decode_blocks", "blocks");
240     chk_array (indices, self->dp, "set_decode_blocks", "indices");
241 root 1.1
242 root 1.6 Newz (0, idx, self->dp, int);
243 root 1.1
244     /* copy and check */
245     for (i = 0; i < self->dp; i++)
246     {
247 root 1.6 idx[i] = SvIV (*av_fetch ((AV *)SvRV (indices), i, 1));
248 root 1.1
249 root 1.6 if (idx[i] < 0 || idx[i] >= self->ep)
250 root 1.1 {
251 root 1.6 Safefree (idx);
252 root 1.1 croak ("index %d in array out of bounds (0 <= %d < %d != true)",
253 root 1.6 i, idx[i], self->ep);
254 root 1.1 }
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 root 1.6 while (idx[i] < self->dp && idx[i] != i)
263 root 1.1 {
264 root 1.5 SV **a, **b, **e, **f;
265 root 1.1 int d;
266     void *p;
267     SV *s;
268 root 1.6 int j = idx[i];
269 root 1.1
270 root 1.6 if (idx[j] == j)
271 root 1.1 {
272 root 1.6 Safefree (idx);
273 root 1.5 croak ("error while shuffling, duplicate indices?");
274 root 1.1 }
275    
276     a = av_fetch ((AV *)SvRV (indices), i, 1);
277 root 1.5 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 root 1.6 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 root 1.5 }
285 root 1.1
286 root 1.7 if (ix)
287     Safefree (idx);
288     else
289     {
290     open_files (self, (AV *)SvRV (blocks), 1);
291     self->idx = idx;
292     }
293 root 1.5 }
294 root 1.1
295 root 1.5 void
296     decode (self)
297     Algorithm::FEC self
298     CODE:
299 root 1.1
300 root 1.5 if (!self->idx)
301 root 1.6 croak ("index array must be set by a prior call to set_decode_blocks");
302 root 1.1
303 root 1.5 force_addrs (self, self->dp);
304     self->imp->fec_decode (self->code, self->b_addr, self->idx, self->sz);
305 root 1.1 free_files (self);
306    
307     void
308 root 1.2 copy (self, srcblock, dstblock)
309 root 1.3 Algorithm::FEC self
310 root 1.1 SV * srcblock
311     SV * dstblock
312     CODE:
313 root 1.2 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 root 1.1
320     void
321     DESTROY(self)
322 root 1.3 Algorithm::FEC self
323 root 1.1 CODE:
324     self->imp->fec_free (self->code);
325     free_files (self);
326     Safefree(self);
327