ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Algorithm-FEC/FEC.xs
Revision: 1.4
Committed: Sat Sep 13 20:35:49 2003 UTC (20 years, 8 months ago) by root
Branch: MAIN
Changes since 1.3: +3 -3 lines
Log Message:
*** empty log message ***

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.3 } *Algorithm__FEC;
32 root 1.1
33     static void
34     chk_array (SV *sv, int size, const char *func, const char *var)
35     {
36     if (!SvROK (sv)
37     || SvTYPE (SvRV (sv)) != SVt_PVAV
38     || av_len ((AV *)SvRV (sv)) != size - 1)
39     croak ("%s: %s must be a reference to an array of size %d", size);
40     }
41    
42     static void
43     free_files (struct state *self)
44     {
45     int i;
46    
47     if (self->b_addr && self->b_sv)
48     for (i = 0; i < self->dp; i++)
49     if (self->b_sv[i])
50     SvREFCNT_dec (self->b_sv[i]);
51     else if (self->b_mmap[i])
52     munmap (self->b_mmap[i], self->b_sz[i]);
53    
54     Safefree (self->b_addr); self->b_addr = 0;
55     Safefree (self->b_mmap); self->b_mmap = 0;
56     Safefree (self->b_sz ); self->b_sz = 0;
57     Safefree (self->b_sv ); self->b_sv = 0;
58     }
59    
60     static void
61     realloc_files (struct state *self)
62     {
63     free_files (self);
64    
65     Newz (0, self->b_addr, self->dp, void *);
66     Newz (0, self->b_mmap, self->dp, void *);
67     Newz (0, self->b_sz , self->dp, int);
68     Newz (0, self->b_sv , self->dp, SV *);
69     }
70    
71     static void
72 root 1.2 force_addrs (struct state *self, int dp)
73 root 1.1 {
74     int i;
75    
76 root 1.2 for (i = 0; i < dp; i++)
77 root 1.1 if (self->b_sv[i])
78     {
79     STRLEN size;
80     self->b_addr[i] = SvPV (self->b_sv[i], size);
81    
82     if (size != self->sz)
83     croak ("block #%d (a string) has size %d, not %d", i, (int)size, self->sz);
84     } else if (!self->b_mmap[i]) {
85 root 1.2 croak ("block #%d neither string nor file, did set_blocks fail and you ignored it?", i);
86 root 1.1 }
87     }
88    
89     static void
90     open_file (struct state *self, int idx, SV *sv, int rw)
91     {
92     IO *io = 0;
93     off_t offset;
94    
95     if (SvROK (sv) && SvTYPE (SvRV (sv)) == SVt_PVAV)
96     {
97     io = sv_2io (*av_fetch ((AV *)SvRV (sv), 0, 1));
98     offset = SvIV (*av_fetch ((AV *)SvRV (sv), 1, 1));
99     sv = 0;
100     }
101     else if (!SvPOK (sv))
102     {
103     io = sv_2io (sv);
104     offset = 0;
105     sv = 0;
106     }
107    
108     if (io)
109     {
110     int fd = PerlIO_fileno (IoIFP (io));
111     off_t ofs2 = offset & ~((off_t)getpagesize () - 1);
112     void *mm;
113    
114     if (fd <= 0)
115     croak ("invalid file descriptor for block #%d", idx);
116    
117     mm = mmap (0, self->sz + (offset - ofs2),
118     rw ? PROT_READ | PROT_WRITE : PROT_READ,
119     MAP_SHARED, fd, ofs2);
120    
121     if (mm == MAP_FAILED)
122     croak ("unable to mmap block #%d (wrong offset or size?): %s", idx, strerror (errno));
123    
124     self->b_mmap[idx] = mm;
125     self->b_addr[idx] = (void *)((char *)mm + (offset - ofs2));
126     self->b_sz [idx] = self->sz + (offset - ofs2);
127     }
128     else if (sv)
129     self->b_sv[idx] = SvREFCNT_inc (sv);
130     else
131     croak ("unable to open block #%d, must be either string, filehandle, or [filehandle, offset]", idx);
132     }
133    
134     static void
135     open_files (struct state *self, AV *av, int rw)
136     {
137     int i;
138    
139     realloc_files (self);
140    
141     for (i = 0; i < self->dp; i++)
142     open_file (self, i, *av_fetch (av, i, 1), rw);
143     }
144    
145 root 1.3 MODULE = Algorithm::FEC PACKAGE = Algorithm::FEC
146 root 1.1
147     PROTOTYPES: ENABLE
148    
149 root 1.3 Algorithm::FEC
150 root 1.1 new(class, data_packets, encoded_packets, blocksize)
151     SV * class
152     int data_packets
153     int encoded_packets
154     int blocksize
155     CODE:
156     void *code;
157     struct fec_imp *imp;
158    
159     if (data_packets < 2)
160     croak ("the number of data packets must be >= 2"); /* for copy_blocks :) */
161    
162     if (encoded_packets < data_packets)
163     croak ("the number of encoded packets must be >= the number of data packets");
164    
165     if (GF_SIZE16 < encoded_packets)
166     croak ("the number of encoded packets must be <= %d", GF_SIZE16);
167    
168     imp = GF_SIZE8 < encoded_packets ? &fec16_imp : &fec8_imp;
169    
170     code = imp->fec_new (data_packets, encoded_packets);
171     if (!code)
172     croak ("FATAL: unable to create fec state");
173    
174     Newz(0, RETVAL, 1, struct state);
175     RETVAL->imp = imp;
176     RETVAL->code = code;
177     RETVAL->sz = blocksize;
178     RETVAL->dp = data_packets;
179     RETVAL->ep = encoded_packets;
180     OUTPUT:
181     RETVAL
182    
183     void
184 root 1.2 set_blocks (self, blocks)
185 root 1.3 Algorithm::FEC self
186 root 1.1 SV * blocks
187     CODE:
188    
189     free_files (self);
190    
191     if (SvOK (blocks))
192     {
193     chk_array (blocks, self->dp, "encode", "blocks");
194     open_files (self, (AV *)SvRV (blocks), 0);
195     }
196    
197     SV *
198     encode (self, block_index)
199 root 1.3 Algorithm::FEC self
200 root 1.1 int block_index
201     CODE:
202    
203     if (block_index < 0 || self->ep <= block_index)
204     croak ("encode: block_index %d out of range, must be 0 <= block_index < %d",
205     block_index, self->ep);
206    
207     if (!self->b_addr)
208 root 1.2 croak ("no blocks specified by a preceding call to set_blocks");
209 root 1.1
210 root 1.2 force_addrs (self, self->dp);
211 root 1.1
212     RETVAL = newSV (self->sz);
213     if (!RETVAL)
214     croak ("unable to allocate result block (out of memory)");
215     SvPOK_only (RETVAL);
216     SvCUR_set (RETVAL, self->sz);
217    
218     self->imp->fec_encode (self->code, self->b_addr,
219     SvPVX (RETVAL), block_index, self->sz);
220    
221     OUTPUT:
222     RETVAL
223    
224     void
225     decode (self, blocks, indices)
226 root 1.3 Algorithm::FEC self
227 root 1.1 SV * blocks
228     SV * indices
229     CODE:
230     {
231     int i;
232     int *idx;
233    
234     chk_array (blocks, self->dp, "decode", "blocks");
235     chk_array (indices, self->dp, "decode", "indices");
236     open_files (self, (AV *)SvRV (blocks), 1);
237    
238 root 1.2 force_addrs (self, self->dp);
239 root 1.1
240     Newz (0, idx, self->dp, int);
241    
242     /* copy and check */
243     for (i = 0; i < self->dp; i++)
244     {
245     SV *a = *av_fetch ((AV *)SvRV (indices), i, 1);
246     idx[i] = SvIV (a);
247     sv_setiv (a, i);
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 root 1.4 while (idx[i] < self->dp && idx[i] != i)
263 root 1.1 {
264     SV **a, **b;
265     int d;
266     void *p;
267     SV *s;
268 root 1.4 int c = idx[i];
269 root 1.1
270     if (idx[c] == c)
271     {
272     Safefree (idx);
273 root 1.4 croak ("error while shuffling, duplicate indices? (idx[i]%d i%d idx[c]%d c%d", idx[i],i,idx[c],c);
274 root 1.1 }
275    
276     a = av_fetch ((AV *)SvRV (indices), i, 1);
277     b = av_fetch ((AV *)SvRV (indices), c, 1);
278    
279     d = idx[i]; idx[i] = idx[c]; idx[c] = d;
280     p = self->b_addr[i]; self->b_addr[i] = self->b_addr[c]; self->b_addr[c] = p;
281     s = *a; *a = *b; *b = s;
282     }
283    
284     self->imp->fec_decode (self->code, self->b_addr, idx, self->sz);
285    
286     Safefree (idx);
287    
288     free_files (self);
289     }
290    
291     void
292 root 1.2 copy (self, srcblock, dstblock)
293 root 1.3 Algorithm::FEC self
294 root 1.1 SV * srcblock
295     SV * dstblock
296     CODE:
297 root 1.2 realloc_files (self);
298     open_file (self, 0, srcblock, 0);
299     open_file (self, 1, dstblock, 1);
300     force_addrs (self, 2);
301     Copy (self->b_addr[0], self->b_addr[1], self->sz, char);
302     free_files (self);
303 root 1.1
304     void
305     DESTROY(self)
306 root 1.3 Algorithm::FEC self
307 root 1.1 CODE:
308     self->imp->fec_free (self->code);
309     free_files (self);
310     Safefree(self);
311