ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Algorithm-FEC/FEC.xs
Revision: 1.3
Committed: Tue Sep 9 23:21:54 2003 UTC (20 years, 9 months ago) by root
Branch: MAIN
Changes since 1.2: +8 -8 lines
Log Message:
*** empty log message ***

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 } *Algorithm__FEC;
32
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 force_addrs (struct state *self, int dp)
73 {
74 int i;
75
76 for (i = 0; i < dp; i++)
77 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 croak ("block #%d neither string nor file, did set_blocks fail and you ignored it?", i);
86 }
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 MODULE = Algorithm::FEC PACKAGE = Algorithm::FEC
146
147 PROTOTYPES: ENABLE
148
149 Algorithm::FEC
150 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 set_blocks (self, blocks)
185 Algorithm::FEC self
186 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 Algorithm::FEC self
200 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 croak ("no blocks specified by a preceding call to set_blocks");
209
210 force_addrs (self, self->dp);
211
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 Algorithm::FEC self
227 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 force_addrs (self, self->dp);
239
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 if (idx[i] < self->dp && idx[i] != i)
263 {
264 int c = idx[i];
265 SV **a, **b;
266 int d;
267 void *p;
268 SV *s;
269
270 if (idx[c] == c)
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), 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 copy (self, srcblock, dstblock)
293 Algorithm::FEC self
294 SV * srcblock
295 SV * dstblock
296 CODE:
297 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
304 void
305 DESTROY(self)
306 Algorithm::FEC self
307 CODE:
308 self->imp->fec_free (self->code);
309 free_files (self);
310 Safefree(self);
311