|
|
1 | #define PERL_NO_GET_CONTEXT |
|
|
2 | |
1 | #include "EXTERN.h" |
3 | #include "EXTERN.h" |
2 | #include "perl.h" |
4 | #include "perl.h" |
3 | #include "XSUB.h" |
5 | #include "XSUB.h" |
4 | |
6 | |
5 | #include <sys/types.h> |
7 | #include <sys/types.h> |
… | |
… | |
11 | |
13 | |
12 | typedef void *InputStream; /* hack, but 5.6.1 is simply toooo old ;) */ |
14 | typedef void *InputStream; /* hack, but 5.6.1 is simply toooo old ;) */ |
13 | typedef void *OutputStream; /* hack, but 5.6.1 is simply toooo old ;) */ |
15 | typedef void *OutputStream; /* hack, but 5.6.1 is simply toooo old ;) */ |
14 | typedef void *InOutStream; /* hack, but 5.6.1 is simply toooo old ;) */ |
16 | typedef void *InOutStream; /* hack, but 5.6.1 is simply toooo old ;) */ |
15 | |
17 | |
|
|
18 | #ifndef __NR_pread64 |
|
|
19 | # define __NR_pread64 __NR_pread |
|
|
20 | #endif |
|
|
21 | #ifndef __NR_pwrite64 |
|
|
22 | # define __NR_pwrite64 __NR_pwrite |
|
|
23 | #endif |
|
|
24 | |
16 | #define STACKSIZE 1024 /* yeah */ |
25 | #define STACKSIZE 1024 /* yeah */ |
17 | |
26 | |
18 | enum { REQ_QUIT, REQ_OPEN, REQ_CLOSE, REQ_READ, REQ_WRITE, REQ_STAT, REQ_LSTAT, REQ_FSTAT}; |
27 | enum { REQ_QUIT, REQ_OPEN, REQ_CLOSE, REQ_READ, REQ_WRITE, REQ_STAT, REQ_LSTAT, REQ_FSTAT}; |
19 | |
28 | |
20 | typedef struct { |
29 | typedef struct { |
… | |
… | |
22 | } aio_thread; |
31 | } aio_thread; |
23 | |
32 | |
24 | typedef struct { |
33 | typedef struct { |
25 | int type; |
34 | int type; |
26 | aio_thread *thread; |
35 | aio_thread *thread; |
27 | |
|
|
28 | SV *savesv; |
|
|
29 | |
36 | |
30 | int fd; |
37 | int fd; |
31 | off_t offset; |
38 | off_t offset; |
32 | size_t length; |
39 | size_t length; |
33 | ssize_t result; |
40 | ssize_t result; |
… | |
… | |
79 | nreqs++; |
86 | nreqs++; |
80 | write (reqpipe[1], &req, sizeof (aio_req)); |
87 | write (reqpipe[1], &req, sizeof (aio_req)); |
81 | } |
88 | } |
82 | |
89 | |
83 | static void |
90 | static void |
|
|
91 | read_write (pTHX_ |
84 | read_write (pTHX_ int dowrite, int fd, off_t offset, size_t length, |
92 | int dowrite, int fd, off_t offset, size_t length, |
85 | SV *data, STRLEN dataoffset, SV*callback) |
93 | SV *data, STRLEN dataoffset, SV*callback) |
86 | { |
94 | { |
87 | aio_req req; |
95 | aio_req req; |
88 | STRLEN svlen; |
96 | STRLEN svlen; |
89 | char *svptr = SvPV (data, svlen); |
97 | char *svptr = SvPV (data, svlen); |
… | |
… | |
110 | } |
118 | } |
111 | |
119 | |
112 | if (length < 0) |
120 | if (length < 0) |
113 | croak ("length must not be negative"); |
121 | croak ("length must not be negative"); |
114 | |
122 | |
115 | New (0, req, 1, aio_cb); |
123 | Newz (0, req, 1, aio_cb); |
116 | |
124 | |
117 | if (!req) |
125 | if (!req) |
118 | croak ("out of memory during aio_req allocation"); |
126 | croak ("out of memory during aio_req allocation"); |
119 | |
127 | |
120 | req->type = dowrite ? REQ_WRITE : REQ_READ; |
128 | req->type = dowrite ? REQ_WRITE : REQ_READ; |
… | |
… | |
145 | else |
153 | else |
146 | { |
154 | { |
147 | int errorno = errno; |
155 | int errorno = errno; |
148 | errno = req->errorno; |
156 | errno = req->errorno; |
149 | |
157 | |
150 | if (req->savesv) |
|
|
151 | SvREFCNT_dec (req->savesv); |
|
|
152 | |
|
|
153 | if (req->type == REQ_READ) |
158 | if (req->type == REQ_READ) |
154 | SvCUR_set (req->data, req->dataoffset |
159 | SvCUR_set (req->data, req->dataoffset |
155 | + req->result > 0 ? req->result : 0); |
160 | + req->result > 0 ? req->result : 0); |
|
|
161 | |
|
|
162 | if (req->data) |
|
|
163 | SvREFCNT_dec (req->data); |
156 | |
164 | |
157 | if (req->type == REQ_STAT || req->type == REQ_LSTAT || req->type == REQ_FSTAT) |
165 | if (req->type == REQ_STAT || req->type == REQ_LSTAT || req->type == REQ_FSTAT) |
158 | { |
166 | { |
159 | PL_laststype = req->type == REQ_LSTAT ? OP_LSTAT : OP_STAT; |
167 | PL_laststype = req->type == REQ_LSTAT ? OP_LSTAT : OP_STAT; |
160 | PL_laststatval = req->result; |
168 | PL_laststatval = req->result; |
… | |
… | |
179 | XPUSHs (sv_2mortal (newSViv (req->result))); |
187 | XPUSHs (sv_2mortal (newSViv (req->result))); |
180 | PUTBACK; |
188 | PUTBACK; |
181 | call_sv (req->callback, G_VOID); |
189 | call_sv (req->callback, G_VOID); |
182 | SPAGAIN; |
190 | SPAGAIN; |
183 | |
191 | |
184 | SvREFCNT_dec (req->data); |
192 | if (req->callback) |
185 | SvREFCNT_dec (req->callback); |
193 | SvREFCNT_dec (req->callback); |
186 | |
194 | |
187 | errno = errorno; |
195 | errno = errorno; |
188 | nreqs--; |
196 | nreqs--; |
189 | count++; |
197 | count++; |
190 | } |
198 | } |
… | |
… | |
205 | { |
213 | { |
206 | aio_thread *thr = thr_arg; |
214 | aio_thread *thr = thr_arg; |
207 | aio_req req; |
215 | aio_req req; |
208 | int errno; |
216 | int errno; |
209 | |
217 | |
|
|
218 | /* this is very much x86 and kernel-specific :(:(:( */ |
210 | /* we rely on gcc's ability to create closures. */ |
219 | /* we rely on gcc's ability to create closures. */ |
211 | _syscall3(int,read,int,fd,char *,buf,size_t,count) |
220 | _syscall3(int,read,int,fd,char *,buf,size_t,count) |
212 | _syscall3(int,write,int,fd,char *,buf,size_t,count) |
221 | _syscall3(int,write,int,fd,char *,buf,size_t,count) |
213 | |
222 | |
214 | _syscall3(int,open,char *,pathname,int,flags,mode_t,mode) |
223 | _syscall3(int,open,char *,pathname,int,flags,mode_t,mode) |
215 | _syscall1(int,close,int,fd) |
224 | _syscall1(int,close,int,fd) |
216 | |
225 | |
217 | _syscall4(int,pread,int,fd,char *,buf,size_t,count,off_t,offset) |
226 | _syscall5(int,pread64,int,fd,char *,buf,size_t,count,unsigned int,offset_lo,unsigned int,offset_hi) |
218 | _syscall4(int,pwrite,int,fd,char *,buf,size_t,count,off_t,offset) |
227 | _syscall5(int,pwrite64,int,fd,char *,buf,size_t,count,unsigned int,offset_lo,unsigned int,offset_hi) |
219 | |
228 | |
220 | _syscall2(int,stat64, const char *, filename, struct stat64 *, buf) |
229 | _syscall2(int,stat64, const char *, filename, struct stat64 *, buf) |
221 | _syscall2(int,lstat64, const char *, filename, struct stat64 *, buf) |
230 | _syscall2(int,lstat64, const char *, filename, struct stat64 *, buf) |
222 | _syscall2(int,fstat64, int, fd, struct stat64 *, buf) |
231 | _syscall2(int,fstat64, int, fd, struct stat64 *, buf) |
223 | |
232 | |
… | |
… | |
225 | |
234 | |
226 | /* then loop */ |
235 | /* then loop */ |
227 | while (read (reqpipe[0], (void *)&req, sizeof (req)) == sizeof (req)) |
236 | while (read (reqpipe[0], (void *)&req, sizeof (req)) == sizeof (req)) |
228 | { |
237 | { |
229 | req->thread = thr; |
238 | req->thread = thr; |
230 | errno = 0; |
239 | errno = 0; /* strictly unnecessary */ |
231 | |
240 | |
232 | if (req->type == REQ_READ) |
241 | if (req->type == REQ_READ) |
233 | req->result = pread (req->fd, req->dataptr, req->length, req->offset); |
242 | req->result = pread64 (req->fd, req->dataptr, req->length, req->offset & 0xffffffff, req->offset >> 32); |
234 | else if (req->type == REQ_WRITE) |
243 | else if (req->type == REQ_WRITE) |
235 | req->result = pwrite (req->fd, req->dataptr, req->length, req->offset); |
244 | req->result = pwrite64(req->fd, req->dataptr, req->length, req->offset & 0xffffffff, req->offset >> 32); |
236 | else if (req->type == REQ_OPEN) |
245 | else if (req->type == REQ_OPEN) |
237 | req->result = open (req->dataptr, req->fd, req->mode); |
246 | req->result = open (req->dataptr, req->fd, req->mode); |
238 | else if (req->type == REQ_CLOSE) |
247 | else if (req->type == REQ_CLOSE) |
239 | req->result = close (req->fd); |
248 | req->result = close (req->fd); |
240 | else if (req->type == REQ_STAT) |
249 | else if (req->type == REQ_STAT) |
241 | req->result = stat64 (req->dataptr, req->statdata); |
250 | req->result = stat64 (req->dataptr, req->statdata); |
242 | else if (req->type == REQ_LSTAT) |
251 | else if (req->type == REQ_LSTAT) |
243 | req->result = lstat64 (req->dataptr, req->statdata); |
252 | req->result = lstat64 (req->dataptr, req->statdata); |
244 | else if (req->type == REQ_FSTAT) |
253 | else if (req->type == REQ_FSTAT) |
245 | req->result = fstat64 (req->fd, req->statdata); |
254 | req->result = fstat64 (req->fd, req->statdata); |
246 | else |
255 | else |
247 | { |
256 | { |
248 | write (respipe[1], (void *)&req, sizeof (req)); |
257 | write (respipe[1], (void *)&req, sizeof (req)); |
249 | break; |
258 | break; |
250 | } |
259 | } |
… | |
… | |
291 | { |
300 | { |
292 | end_thread (); |
301 | end_thread (); |
293 | cur--; |
302 | cur--; |
294 | } |
303 | } |
295 | |
304 | |
296 | poll_cb (); |
|
|
297 | while (started > nthreads) |
305 | while (started > nthreads) |
298 | { |
306 | { |
299 | sched_yield (); |
307 | fd_set rfd; |
300 | fcntl (respipe[0], F_SETFL, 0); |
308 | FD_ZERO(&rfd); |
|
|
309 | FD_SET(respipe[0], &rfd); |
|
|
310 | |
|
|
311 | select (respipe[0] + 1, &rfd, 0, 0, 0); |
301 | poll_cb (); |
312 | poll_cb (aTHX); |
302 | fcntl (respipe[0], F_SETFL, O_NONBLOCK); |
|
|
303 | } |
313 | } |
304 | |
314 | |
305 | void |
315 | void |
306 | aio_open(pathname,flags,mode,callback) |
316 | aio_open(pathname,flags,mode,callback) |
307 | SV * pathname |
317 | SV * pathname |
… | |
… | |
310 | SV * callback |
320 | SV * callback |
311 | PROTOTYPE: $$$$ |
321 | PROTOTYPE: $$$$ |
312 | CODE: |
322 | CODE: |
313 | aio_req req; |
323 | aio_req req; |
314 | |
324 | |
315 | New (0, req, 1, aio_cb); |
325 | Newz (0, req, 1, aio_cb); |
316 | |
326 | |
317 | if (!req) |
327 | if (!req) |
318 | croak ("out of memory during aio_req allocation"); |
328 | croak ("out of memory during aio_req allocation"); |
319 | |
329 | |
320 | req->type = REQ_OPEN; |
330 | req->type = REQ_OPEN; |
321 | req->savesv = newSVsv (pathname); |
331 | req->data = newSVsv (pathname); |
322 | req->dataptr = SvPV_nolen (req->savesv); |
332 | req->dataptr = SvPV_nolen (req->data); |
323 | req->fd = flags; |
333 | req->fd = flags; |
324 | req->mode = mode; |
334 | req->mode = mode; |
325 | req->callback = SvREFCNT_inc (callback); |
335 | req->callback = SvREFCNT_inc (callback); |
326 | |
336 | |
327 | send_req (req); |
337 | send_req (req); |
328 | |
338 | |
329 | void |
339 | void |
330 | aio_close(fh,callback) |
340 | aio_close(fh,callback) |
331 | InputStream fh |
341 | InputStream fh |
332 | SV * callback |
342 | SV * callback |
333 | PROTOTYPE: $ |
343 | PROTOTYPE: $$ |
334 | CODE: |
344 | CODE: |
335 | aio_req req; |
345 | aio_req req; |
336 | |
346 | |
337 | New (0, req, 1, aio_cb); |
347 | Newz (0, req, 1, aio_cb); |
338 | |
348 | |
339 | if (!req) |
349 | if (!req) |
340 | croak ("out of memory during aio_req allocation"); |
350 | croak ("out of memory during aio_req allocation"); |
341 | |
351 | |
342 | req->type = REQ_CLOSE; |
352 | req->type = REQ_CLOSE; |
… | |
… | |
377 | ALIAS: |
387 | ALIAS: |
378 | aio_lstat = 1 |
388 | aio_lstat = 1 |
379 | CODE: |
389 | CODE: |
380 | aio_req req; |
390 | aio_req req; |
381 | |
391 | |
382 | New (0, req, 1, aio_cb); |
392 | Newz (0, req, 1, aio_cb); |
383 | |
393 | |
384 | if (!req) |
394 | if (!req) |
385 | croak ("out of memory during aio_req allocation"); |
395 | croak ("out of memory during aio_req allocation"); |
386 | |
396 | |
387 | New (0, req->statdata, 1, struct stat64); |
397 | New (0, req->statdata, 1, struct stat64); |
… | |
… | |
390 | croak ("out of memory during aio_req->statdata allocation"); |
400 | croak ("out of memory during aio_req->statdata allocation"); |
391 | |
401 | |
392 | if (SvPOK (fh_or_path)) |
402 | if (SvPOK (fh_or_path)) |
393 | { |
403 | { |
394 | req->type = ix ? REQ_LSTAT : REQ_STAT; |
404 | req->type = ix ? REQ_LSTAT : REQ_STAT; |
395 | req->savesv = newSVsv (fh_or_path); |
405 | req->data = newSVsv (fh_or_path); |
396 | req->dataptr = SvPV_nolen (req->savesv); |
406 | req->dataptr = SvPV_nolen (req->data); |
397 | } |
407 | } |
398 | else |
408 | else |
399 | { |
409 | { |
400 | req->type = REQ_FSTAT; |
410 | req->type = REQ_FSTAT; |
401 | req->fd = PerlIO_fileno (IoIFP (sv_2io (fh_or_path))); |
411 | req->fd = PerlIO_fileno (IoIFP (sv_2io (fh_or_path))); |