ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/IO-AIO/AIO.xs
Revision: 1.56
Committed: Mon Oct 23 14:49:51 2006 UTC (17 years, 6 months ago) by root
Branch: MAIN
Changes since 1.55: +8 -12 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.20 #define _REENTRANT 1
2 root 1.19 #include <errno.h>
3    
4 root 1.15 #include "EXTERN.h"
5 root 1.1 #include "perl.h"
6     #include "XSUB.h"
7    
8 root 1.16 #include "autoconf/config.h"
9    
10 root 1.32 #include <pthread.h>
11    
12 root 1.37 #include <stddef.h>
13 root 1.41 #include <errno.h>
14 root 1.45 #include <sys/time.h>
15     #include <sys/select.h>
16 root 1.1 #include <sys/types.h>
17     #include <sys/stat.h>
18 root 1.37 #include <limits.h>
19 root 1.1 #include <unistd.h>
20     #include <fcntl.h>
21     #include <signal.h>
22     #include <sched.h>
23    
24 root 1.32 #if HAVE_SENDFILE
25     # if __linux
26     # include <sys/sendfile.h>
27     # elif __freebsd
28     # include <sys/socket.h>
29     # include <sys/uio.h>
30     # elif __hpux
31     # include <sys/socket.h>
32 root 1.35 # elif __solaris /* not yet */
33     # include <sys/sendfile.h>
34 root 1.34 # else
35     # error sendfile support requested but not available
36 root 1.32 # endif
37     #endif
38 root 1.1
39 root 1.39 /* used for struct dirent, AIX doesn't provide it */
40     #ifndef NAME_MAX
41     # define NAME_MAX 4096
42     #endif
43    
44 root 1.4 #if __ia64
45     # define STACKSIZE 65536
46 root 1.1 #else
47 root 1.37 # define STACKSIZE 8192
48 root 1.1 #endif
49    
50     enum {
51     REQ_QUIT,
52     REQ_OPEN, REQ_CLOSE,
53     REQ_READ, REQ_WRITE, REQ_READAHEAD,
54 root 1.32 REQ_SENDFILE,
55 root 1.22 REQ_STAT, REQ_LSTAT, REQ_FSTAT,
56 root 1.1 REQ_FSYNC, REQ_FDATASYNC,
57 root 1.40 REQ_UNLINK, REQ_RMDIR, REQ_RENAME,
58 root 1.37 REQ_READDIR,
59 root 1.40 REQ_LINK, REQ_SYMLINK,
60 root 1.54 REQ_GROUP, REQ_NOP,
61 root 1.45 REQ_SLEEP,
62 root 1.1 };
63    
64 root 1.44 #define AIO_REQ_KLASS "IO::AIO::REQ"
65     #define AIO_GRP_KLASS "IO::AIO::GRP"
66 root 1.43
67     typedef struct aio_cb
68     {
69 root 1.49 struct aio_cb *volatile next;
70 root 1.43
71 root 1.49 struct aio_cb *grp, *grp_prev, *grp_next, *grp_first;
72 root 1.1
73 root 1.43 SV *self; /* the perl counterpart of this request, if any */
74 root 1.1
75 root 1.43 SV *data, *callback;
76     SV *fh, *fh2;
77     void *dataptr, *data2ptr;
78     Stat_t *statdata;
79 root 1.1 off_t offset;
80     size_t length;
81     ssize_t result;
82 root 1.43
83     int type;
84     int fd, fd2;
85 root 1.1 int errorno;
86     STRLEN dataoffset;
87 root 1.43 mode_t mode; /* open */
88     unsigned char cancelled;
89 root 1.1 } aio_cb;
90    
91     typedef aio_cb *aio_req;
92 root 1.43 typedef aio_cb *aio_req_ornot;
93 root 1.1
94 root 1.30 static int started, wanted;
95 root 1.11 static volatile int nreqs;
96 root 1.4 static int max_outstanding = 1<<30;
97 root 1.3 static int respipe [2];
98 root 1.1
99 root 1.3 static pthread_mutex_t reslock = PTHREAD_MUTEX_INITIALIZER;
100     static pthread_mutex_t reqlock = PTHREAD_MUTEX_INITIALIZER;
101     static pthread_cond_t reqwait = PTHREAD_COND_INITIALIZER;
102    
103     static volatile aio_req reqs, reqe; /* queue start, queue end */
104     static volatile aio_req ress, rese; /* queue start, queue end */
105 root 1.1
106 root 1.50 static void req_invoke (aio_req req);
107 root 1.45 static void req_free (aio_req req);
108    
109 root 1.43 /* must be called at most once */
110 root 1.44 static SV *req_sv (aio_req req, const char *klass)
111 root 1.43 {
112 root 1.49 if (!req->self)
113     {
114     req->self = (SV *)newHV ();
115     sv_magic (req->self, 0, PERL_MAGIC_ext, (char *)req, 0);
116     }
117 root 1.43
118 root 1.45 return sv_2mortal (sv_bless (newRV_inc (req->self), gv_stashpv (klass, 1)));
119 root 1.43 }
120    
121 root 1.45 static aio_req SvAIO_REQ (SV *sv)
122 root 1.26 {
123 root 1.53 MAGIC *mg;
124    
125 root 1.45 if (!sv_derived_from (sv, AIO_REQ_KLASS) || !SvROK (sv))
126     croak ("object of class " AIO_REQ_KLASS " expected");
127 root 1.43
128 root 1.53 mg = mg_find (SvRV (sv), PERL_MAGIC_ext);
129 root 1.43
130     return mg ? (aio_req)mg->mg_ptr : 0;
131     }
132    
133 root 1.49 static void aio_grp_feed (aio_req grp)
134     {
135     while (grp->length < grp->fd2)
136     {
137     int old_len = grp->length;
138    
139     if (grp->fh2 && SvOK (grp->fh2))
140     {
141     dSP;
142    
143     ENTER;
144     SAVETMPS;
145     PUSHMARK (SP);
146     XPUSHs (req_sv (grp, AIO_GRP_KLASS));
147     PUTBACK;
148     call_sv (grp->fh2, G_VOID | G_EVAL);
149     SPAGAIN;
150     FREETMPS;
151     LEAVE;
152     }
153    
154     /* stop if no progress has been made */
155     if (old_len == grp->length)
156     {
157     SvREFCNT_dec (grp->fh2);
158     grp->fh2 = 0;
159     break;
160     }
161     }
162     }
163    
164 root 1.50 static void aio_grp_dec (aio_req grp)
165     {
166     --grp->length;
167    
168     /* call feeder, if applicable */
169     aio_grp_feed (grp);
170    
171     /* finish, if done */
172     if (!grp->length && grp->fd)
173     {
174     req_invoke (grp);
175     req_free (grp);
176     }
177     }
178    
179 root 1.45 static void poll_wait ()
180     {
181     if (nreqs && !ress)
182     {
183     fd_set rfd;
184     FD_ZERO(&rfd);
185     FD_SET(respipe [0], &rfd);
186    
187     select (respipe [0] + 1, &rfd, 0, 0, 0);
188     }
189     }
190    
191     static void req_invoke (aio_req req)
192     {
193     dSP;
194     int errorno = errno;
195    
196     if (req->cancelled || !SvOK (req->callback))
197     return;
198    
199     errno = req->errorno;
200    
201     ENTER;
202 root 1.49 SAVETMPS;
203 root 1.45 PUSHMARK (SP);
204 root 1.48 EXTEND (SP, 1);
205 root 1.45
206     switch (req->type)
207     {
208     case REQ_READDIR:
209     {
210     SV *rv = &PL_sv_undef;
211    
212     if (req->result >= 0)
213     {
214     char *buf = req->data2ptr;
215     AV *av = newAV ();
216    
217     while (req->result)
218     {
219     SV *sv = newSVpv (buf, 0);
220    
221     av_push (av, sv);
222     buf += SvCUR (sv) + 1;
223     req->result--;
224     }
225    
226     rv = sv_2mortal (newRV_noinc ((SV *)av));
227     }
228    
229 root 1.48 PUSHs (rv);
230 root 1.45 }
231     break;
232    
233     case REQ_OPEN:
234     {
235     /* convert fd to fh */
236     SV *fh;
237    
238 root 1.48 PUSHs (sv_2mortal (newSViv (req->result)));
239 root 1.45 PUTBACK;
240     call_pv ("IO::AIO::_fd2fh", G_SCALAR | G_EVAL);
241     SPAGAIN;
242    
243     fh = SvREFCNT_inc (POPs);
244    
245     PUSHMARK (SP);
246     XPUSHs (sv_2mortal (fh));
247     }
248     break;
249    
250 root 1.48 case REQ_GROUP:
251 root 1.49 req->fd = 2; /* mark group as finished */
252    
253 root 1.48 if (req->data)
254     {
255     int i;
256     AV *av = (AV *)req->data;
257    
258     EXTEND (SP, AvFILL (av) + 1);
259     for (i = 0; i <= AvFILL (av); ++i)
260     PUSHs (*av_fetch (av, i, 0));
261     }
262     break;
263    
264 root 1.54 case REQ_NOP:
265 root 1.45 case REQ_SLEEP:
266     break;
267    
268     default:
269 root 1.48 PUSHs (sv_2mortal (newSViv (req->result)));
270 root 1.45 break;
271     }
272    
273    
274     PUTBACK;
275     call_sv (req->callback, G_VOID | G_EVAL);
276     SPAGAIN;
277    
278 root 1.51 FREETMPS;
279     LEAVE;
280    
281     errno = errorno;
282    
283 root 1.45 if (SvTRUE (ERRSV))
284     {
285     req_free (req);
286     croak (0);
287     }
288     }
289    
290 root 1.43 static void req_free (aio_req req)
291     {
292 root 1.45 if (req->grp)
293     {
294     aio_req grp = req->grp;
295    
296     /* unlink request */
297 root 1.49 if (req->grp_next) req->grp_next->grp_prev = req->grp_prev;
298     if (req->grp_prev) req->grp_prev->grp_next = req->grp_next;
299    
300     if (grp->grp_first == req)
301     grp->grp_first = req->grp_next;
302    
303 root 1.50 aio_grp_dec (grp);
304 root 1.45 }
305    
306 root 1.43 if (req->self)
307     {
308     sv_unmagic (req->self, PERL_MAGIC_ext);
309     SvREFCNT_dec (req->self);
310     }
311    
312 root 1.49 SvREFCNT_dec (req->data);
313     SvREFCNT_dec (req->fh);
314     SvREFCNT_dec (req->fh2);
315     SvREFCNT_dec (req->callback);
316     Safefree (req->statdata);
317 root 1.26
318 root 1.37 if (req->type == REQ_READDIR && req->result >= 0)
319     free (req->data2ptr);
320    
321 root 1.26 Safefree (req);
322     }
323    
324 root 1.45 static void req_cancel (aio_req req)
325 root 1.1 {
326 root 1.45 req->cancelled = 1;
327    
328     if (req->type == REQ_GROUP)
329 root 1.11 {
330 root 1.45 aio_req sub;
331 root 1.3
332 root 1.49 for (sub = req->grp_first; sub; sub = sub->grp_next)
333 root 1.45 req_cancel (sub);
334 root 1.11 }
335 root 1.1 }
336    
337 root 1.45 static int poll_cb ()
338 root 1.1 {
339     dSP;
340     int count = 0;
341 root 1.24 int do_croak = 0;
342 root 1.27 aio_req req;
343    
344     for (;;)
345     {
346     pthread_mutex_lock (&reslock);
347     req = ress;
348    
349     if (req)
350     {
351     ress = req->next;
352 root 1.11
353 root 1.27 if (!ress)
354     {
355     /* read any signals sent by the worker threads */
356     char buf [32];
357     while (read (respipe [0], buf, 32) == 32)
358     ;
359 root 1.30
360     rese = 0;
361 root 1.27 }
362     }
363 root 1.1
364 root 1.27 pthread_mutex_unlock (&reslock);
365 root 1.3
366 root 1.27 if (!req)
367     break;
368 root 1.3
369 root 1.50 --nreqs;
370 root 1.1
371     if (req->type == REQ_QUIT)
372     started--;
373 root 1.49 else if (req->type == REQ_GROUP && req->length)
374 root 1.46 {
375     req->fd = 1; /* mark request as delayed */
376     continue;
377     }
378 root 1.1 else
379     {
380     if (req->type == REQ_READ)
381 root 1.27 SvCUR_set (req->data, req->dataoffset + (req->result > 0 ? req->result : 0));
382 root 1.1
383 root 1.28 if (req->data2ptr && (req->type == REQ_READ || req->type == REQ_WRITE))
384     SvREADONLY_off (req->data);
385    
386 root 1.27 if (req->statdata)
387 root 1.1 {
388     PL_laststype = req->type == REQ_LSTAT ? OP_LSTAT : OP_STAT;
389     PL_laststatval = req->result;
390     PL_statcache = *(req->statdata);
391     }
392    
393 root 1.45 req_invoke (req);
394 root 1.26
395 root 1.1 count++;
396     }
397    
398 root 1.43 req_free (req);
399 root 1.1 }
400    
401     return count;
402     }
403    
404 root 1.4 static void *aio_proc(void *arg);
405    
406 root 1.45 static void start_thread (void)
407 root 1.4 {
408     sigset_t fullsigset, oldsigset;
409     pthread_t tid;
410     pthread_attr_t attr;
411    
412     pthread_attr_init (&attr);
413     pthread_attr_setstacksize (&attr, STACKSIZE);
414 root 1.31 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
415 root 1.4
416     sigfillset (&fullsigset);
417     sigprocmask (SIG_SETMASK, &fullsigset, &oldsigset);
418    
419     if (pthread_create (&tid, &attr, aio_proc, 0) == 0)
420     started++;
421    
422     sigprocmask (SIG_SETMASK, &oldsigset, 0);
423     }
424    
425 root 1.45 static void req_send (aio_req req)
426 root 1.4 {
427 root 1.30 while (started < wanted && nreqs >= started)
428     start_thread ();
429    
430 root 1.50 ++nreqs;
431 root 1.4
432     pthread_mutex_lock (&reqlock);
433    
434     req->next = 0;
435    
436     if (reqe)
437     {
438     reqe->next = req;
439     reqe = req;
440     }
441     else
442     reqe = reqs = req;
443    
444     pthread_cond_signal (&reqwait);
445     pthread_mutex_unlock (&reqlock);
446    
447 root 1.27 if (nreqs > max_outstanding)
448     for (;;)
449     {
450     poll_cb ();
451    
452     if (nreqs <= max_outstanding)
453     break;
454    
455     poll_wait ();
456     }
457 root 1.4 }
458    
459 root 1.45 static void end_thread (void)
460 root 1.4 {
461     aio_req req;
462 root 1.26 Newz (0, req, 1, aio_cb);
463 root 1.4 req->type = REQ_QUIT;
464    
465 root 1.43 req_send (req);
466 root 1.4 }
467    
468 root 1.22 static void min_parallel (int nthreads)
469     {
470 root 1.30 if (wanted < nthreads)
471     wanted = nthreads;
472 root 1.22 }
473    
474     static void max_parallel (int nthreads)
475     {
476     int cur = started;
477 root 1.27
478 root 1.30 if (wanted > nthreads)
479     wanted = nthreads;
480    
481     while (cur > wanted)
482     {
483 root 1.22 end_thread ();
484     cur--;
485     }
486    
487 root 1.30 while (started > wanted)
488 root 1.22 {
489     poll_wait ();
490     poll_cb ();
491     }
492     }
493    
494 root 1.26 static void create_pipe ()
495 root 1.22 {
496 root 1.26 if (pipe (respipe))
497     croak ("unable to initialize result pipe");
498 root 1.22
499 root 1.26 if (fcntl (respipe [0], F_SETFL, O_NONBLOCK))
500     croak ("cannot set result pipe to nonblocking mode");
501 root 1.22
502 root 1.26 if (fcntl (respipe [1], F_SETFL, O_NONBLOCK))
503     croak ("cannot set result pipe to nonblocking mode");
504     }
505 root 1.22
506     /*****************************************************************************/
507 root 1.17 /* work around various missing functions */
508    
509     #if !HAVE_PREADWRITE
510     # define pread aio_pread
511     # define pwrite aio_pwrite
512    
513     /*
514     * make our pread/pwrite safe against themselves, but not against
515     * normal read/write by using a mutex. slows down execution a lot,
516     * but that's your problem, not mine.
517     */
518 root 1.37 static pthread_mutex_t preadwritelock = PTHREAD_MUTEX_INITIALIZER;
519 root 1.17
520 root 1.45 static ssize_t pread (int fd, void *buf, size_t count, off_t offset)
521 root 1.17 {
522     ssize_t res;
523     off_t ooffset;
524    
525 root 1.37 pthread_mutex_lock (&preadwritelock);
526 root 1.17 ooffset = lseek (fd, 0, SEEK_CUR);
527     lseek (fd, offset, SEEK_SET);
528     res = read (fd, buf, count);
529     lseek (fd, ooffset, SEEK_SET);
530 root 1.37 pthread_mutex_unlock (&preadwritelock);
531 root 1.17
532     return res;
533     }
534    
535 root 1.45 static ssize_t pwrite (int fd, void *buf, size_t count, off_t offset)
536 root 1.17 {
537     ssize_t res;
538     off_t ooffset;
539    
540 root 1.37 pthread_mutex_lock (&preadwritelock);
541 root 1.17 ooffset = lseek (fd, 0, SEEK_CUR);
542     lseek (fd, offset, SEEK_SET);
543     res = write (fd, buf, count);
544     lseek (fd, offset, SEEK_SET);
545 root 1.37 pthread_mutex_unlock (&preadwritelock);
546 root 1.17
547     return res;
548     }
549     #endif
550    
551     #if !HAVE_FDATASYNC
552     # define fdatasync fsync
553     #endif
554    
555     #if !HAVE_READAHEAD
556     # define readahead aio_readahead
557    
558 root 1.45 static ssize_t readahead (int fd, off_t offset, size_t count)
559 root 1.17 {
560 root 1.37 char readahead_buf[4096];
561    
562 root 1.17 while (count > 0)
563     {
564     size_t len = count < sizeof (readahead_buf) ? count : sizeof (readahead_buf);
565    
566     pread (fd, readahead_buf, len, offset);
567     offset += len;
568     count -= len;
569     }
570    
571     errno = 0;
572     }
573     #endif
574    
575 root 1.37 #if !HAVE_READDIR_R
576     # define readdir_r aio_readdir_r
577    
578     static pthread_mutex_t readdirlock = PTHREAD_MUTEX_INITIALIZER;
579    
580 root 1.45 static int readdir_r (DIR *dirp, struct dirent *ent, struct dirent **res)
581 root 1.37 {
582     struct dirent *e;
583     int errorno;
584    
585     pthread_mutex_lock (&readdirlock);
586    
587     e = readdir (dirp);
588     errorno = errno;
589    
590     if (e)
591     {
592     *res = ent;
593     strcpy (ent->d_name, e->d_name);
594     }
595     else
596     *res = 0;
597    
598     pthread_mutex_unlock (&readdirlock);
599    
600     errno = errorno;
601     return e ? 0 : -1;
602     }
603     #endif
604    
605 root 1.32 /* sendfile always needs emulation */
606 root 1.45 static ssize_t sendfile_ (int ofd, int ifd, off_t offset, size_t count)
607 root 1.32 {
608 root 1.37 ssize_t res;
609 root 1.32
610 root 1.37 if (!count)
611     return 0;
612 root 1.32
613 root 1.35 #if HAVE_SENDFILE
614     # if __linux
615 root 1.37 res = sendfile (ofd, ifd, &offset, count);
616 root 1.32
617 root 1.35 # elif __freebsd
618 root 1.37 /*
619     * Of course, the freebsd sendfile is a dire hack with no thoughts
620     * wasted on making it similar to other I/O functions.
621     */
622     {
623     off_t sbytes;
624     res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0);
625    
626     if (res < 0 && sbytes)
627     /* maybe only on EAGAIN only: as usual, the manpage leaves you guessing */
628     res = sbytes;
629     }
630 root 1.32
631 root 1.35 # elif __hpux
632 root 1.37 res = sendfile (ofd, ifd, offset, count, 0, 0);
633 root 1.32
634 root 1.35 # elif __solaris
635 root 1.37 {
636     struct sendfilevec vec;
637     size_t sbytes;
638    
639     vec.sfv_fd = ifd;
640     vec.sfv_flag = 0;
641     vec.sfv_off = offset;
642     vec.sfv_len = count;
643    
644     res = sendfilev (ofd, &vec, 1, &sbytes);
645    
646     if (res < 0 && sbytes)
647     res = sbytes;
648     }
649 root 1.35
650 root 1.38 # endif
651     #else
652 root 1.37 res = -1;
653     errno = ENOSYS;
654 root 1.32 #endif
655    
656 root 1.37 if (res < 0
657     && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK
658 root 1.35 #if __solaris
659 root 1.37 || errno == EAFNOSUPPORT || errno == EPROTOTYPE
660 root 1.35 #endif
661 root 1.37 )
662     )
663     {
664     /* emulate sendfile. this is a major pain in the ass */
665     char buf[4096];
666     res = 0;
667    
668 root 1.38 while (count)
669 root 1.37 {
670     ssize_t cnt;
671    
672 root 1.38 cnt = pread (ifd, buf, count > 4096 ? 4096 : count, offset);
673 root 1.32
674 root 1.37 if (cnt <= 0)
675     {
676     if (cnt && !res) res = -1;
677     break;
678     }
679    
680     cnt = write (ofd, buf, cnt);
681    
682     if (cnt <= 0)
683     {
684     if (cnt && !res) res = -1;
685     break;
686     }
687    
688     offset += cnt;
689     res += cnt;
690 root 1.38 count -= cnt;
691 root 1.37 }
692     }
693    
694     return res;
695     }
696    
697     /* read a full directory */
698 root 1.45 static int scandir_ (const char *path, void **namesp)
699 root 1.37 {
700     DIR *dirp = opendir (path);
701     union
702     {
703     struct dirent d;
704     char b [offsetof (struct dirent, d_name) + NAME_MAX + 1];
705     } u;
706     struct dirent *entp;
707     char *name, *names;
708     int memlen = 4096;
709     int memofs = 0;
710     int res = 0;
711     int errorno;
712    
713     if (!dirp)
714     return -1;
715    
716     names = malloc (memlen);
717    
718     for (;;)
719     {
720     errno = 0, readdir_r (dirp, &u.d, &entp);
721    
722     if (!entp)
723     break;
724    
725     name = entp->d_name;
726    
727     if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2])))
728     {
729     int len = strlen (name) + 1;
730    
731     res++;
732    
733     while (memofs + len > memlen)
734     {
735     memlen *= 2;
736     names = realloc (names, memlen);
737     if (!names)
738     break;
739     }
740    
741     memcpy (names + memofs, name, len);
742     memofs += len;
743     }
744     }
745    
746     errorno = errno;
747     closedir (dirp);
748    
749     if (errorno)
750     {
751     free (names);
752     errno = errorno;
753     res = -1;
754     }
755    
756     *namesp = (void *)names;
757     return res;
758 root 1.32 }
759    
760 root 1.22 /*****************************************************************************/
761    
762 root 1.45 static void *aio_proc (void *thr_arg)
763 root 1.1 {
764     aio_req req;
765 root 1.3 int type;
766 root 1.1
767 root 1.3 do
768 root 1.1 {
769 root 1.3 pthread_mutex_lock (&reqlock);
770    
771     for (;;)
772     {
773     req = reqs;
774    
775     if (reqs)
776     {
777     reqs = reqs->next;
778     if (!reqs) reqe = 0;
779     }
780    
781     if (req)
782     break;
783    
784     pthread_cond_wait (&reqwait, &reqlock);
785     }
786    
787     pthread_mutex_unlock (&reqlock);
788    
789 root 1.1 errno = 0; /* strictly unnecessary */
790    
791 root 1.43 if (!req->cancelled)
792 root 1.50 switch (type = req->type) /* remember type for QUIT check */
793 root 1.43 {
794     case REQ_READ: req->result = pread (req->fd, req->dataptr, req->length, req->offset); break;
795     case REQ_WRITE: req->result = pwrite (req->fd, req->dataptr, req->length, req->offset); break;
796 root 1.3
797 root 1.43 case REQ_READAHEAD: req->result = readahead (req->fd, req->offset, req->length); break;
798     case REQ_SENDFILE: req->result = sendfile_ (req->fd, req->fd2, req->offset, req->length); break;
799 root 1.16
800 root 1.43 case REQ_STAT: req->result = stat (req->dataptr, req->statdata); break;
801     case REQ_LSTAT: req->result = lstat (req->dataptr, req->statdata); break;
802     case REQ_FSTAT: req->result = fstat (req->fd , req->statdata); break;
803    
804     case REQ_OPEN: req->result = open (req->dataptr, req->fd, req->mode); break;
805     case REQ_CLOSE: req->result = close (req->fd); break;
806     case REQ_UNLINK: req->result = unlink (req->dataptr); break;
807     case REQ_RMDIR: req->result = rmdir (req->dataptr); break;
808     case REQ_RENAME: req->result = rename (req->data2ptr, req->dataptr); break;
809     case REQ_LINK: req->result = link (req->data2ptr, req->dataptr); break;
810     case REQ_SYMLINK: req->result = symlink (req->data2ptr, req->dataptr); break;
811    
812     case REQ_FDATASYNC: req->result = fdatasync (req->fd); break;
813     case REQ_FSYNC: req->result = fsync (req->fd); break;
814     case REQ_READDIR: req->result = scandir_ (req->dataptr, &req->data2ptr); break;
815 root 1.1
816 root 1.45 case REQ_SLEEP:
817     {
818     struct timeval tv;
819    
820     tv.tv_sec = req->fd;
821     tv.tv_usec = req->fd2;
822    
823     req->result = select (0, 0, 0, 0, &tv);
824     }
825    
826 root 1.55 case REQ_GROUP:
827     case REQ_NOP:
828 root 1.43 case REQ_QUIT:
829     break;
830 root 1.1
831 root 1.43 default:
832     req->result = ENOSYS;
833     break;
834     }
835 root 1.1
836     req->errorno = errno;
837 root 1.3
838     pthread_mutex_lock (&reslock);
839    
840     req->next = 0;
841    
842     if (rese)
843     {
844     rese->next = req;
845     rese = req;
846     }
847     else
848     {
849     rese = ress = req;
850    
851     /* write a dummy byte to the pipe so fh becomes ready */
852     write (respipe [1], &respipe, 1);
853     }
854    
855     pthread_mutex_unlock (&reslock);
856 root 1.1 }
857 root 1.3 while (type != REQ_QUIT);
858 root 1.1
859     return 0;
860     }
861    
862 root 1.37 /*****************************************************************************/
863    
864     static void atfork_prepare (void)
865     {
866     pthread_mutex_lock (&reqlock);
867     pthread_mutex_lock (&reslock);
868     #if !HAVE_PREADWRITE
869     pthread_mutex_lock (&preadwritelock);
870     #endif
871     #if !HAVE_READDIR_R
872     pthread_mutex_lock (&readdirlock);
873     #endif
874     }
875    
876     static void atfork_parent (void)
877     {
878     #if !HAVE_READDIR_R
879     pthread_mutex_unlock (&readdirlock);
880     #endif
881     #if !HAVE_PREADWRITE
882     pthread_mutex_unlock (&preadwritelock);
883     #endif
884     pthread_mutex_unlock (&reslock);
885     pthread_mutex_unlock (&reqlock);
886     }
887    
888     static void atfork_child (void)
889     {
890     aio_req prv;
891    
892     started = 0;
893    
894     while (reqs)
895     {
896     prv = reqs;
897     reqs = prv->next;
898 root 1.43 req_free (prv);
899 root 1.37 }
900    
901     reqs = reqe = 0;
902    
903     while (ress)
904     {
905     prv = ress;
906     ress = prv->next;
907 root 1.43 req_free (prv);
908 root 1.37 }
909    
910     ress = rese = 0;
911    
912     close (respipe [0]);
913     close (respipe [1]);
914     create_pipe ();
915    
916     atfork_parent ();
917     }
918    
919 root 1.22 #define dREQ \
920     aio_req req; \
921     \
922     if (SvOK (callback) && !SvROK (callback)) \
923 root 1.43 croak ("callback must be undef or of reference type"); \
924 root 1.22 \
925     Newz (0, req, 1, aio_cb); \
926     if (!req) \
927     croak ("out of memory during aio_req allocation"); \
928     \
929 root 1.43 req->callback = newSVsv (callback)
930    
931     #define REQ_SEND \
932     req_send (req); \
933     \
934     if (GIMME_V != G_VOID) \
935 root 1.44 XPUSHs (req_sv (req, AIO_REQ_KLASS));
936 root 1.22
937 root 1.1 MODULE = IO::AIO PACKAGE = IO::AIO
938    
939 root 1.8 PROTOTYPES: ENABLE
940    
941 root 1.1 BOOT:
942     {
943 root 1.41 HV *stash = gv_stashpv ("IO::AIO", 1);
944     newCONSTSUB (stash, "EXDEV", newSViv (EXDEV));
945     newCONSTSUB (stash, "O_RDONLY", newSViv (O_RDONLY));
946     newCONSTSUB (stash, "O_WRONLY", newSViv (O_WRONLY));
947    
948 root 1.26 create_pipe ();
949 root 1.22 pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
950 root 1.1 }
951    
952     void
953 root 1.40 min_parallel (nthreads)
954 root 1.1 int nthreads
955     PROTOTYPE: $
956    
957     void
958 root 1.40 max_parallel (nthreads)
959 root 1.1 int nthreads
960     PROTOTYPE: $
961    
962 root 1.4 int
963 root 1.40 max_outstanding (nreqs)
964 root 1.4 int nreqs
965     PROTOTYPE: $
966     CODE:
967     RETVAL = max_outstanding;
968     max_outstanding = nreqs;
969    
970 root 1.1 void
971 root 1.40 aio_open (pathname,flags,mode,callback=&PL_sv_undef)
972 root 1.1 SV * pathname
973     int flags
974     int mode
975     SV * callback
976 root 1.8 PROTOTYPE: $$$;$
977 root 1.43 PPCODE:
978 root 1.1 {
979 root 1.22 dREQ;
980 root 1.1
981     req->type = REQ_OPEN;
982     req->data = newSVsv (pathname);
983 root 1.22 req->dataptr = SvPVbyte_nolen (req->data);
984 root 1.1 req->fd = flags;
985     req->mode = mode;
986    
987 root 1.43 REQ_SEND;
988 root 1.1 }
989    
990     void
991 root 1.40 aio_close (fh,callback=&PL_sv_undef)
992 root 1.13 SV * fh
993     SV * callback
994 root 1.8 PROTOTYPE: $;$
995 root 1.1 ALIAS:
996     aio_close = REQ_CLOSE
997     aio_fsync = REQ_FSYNC
998     aio_fdatasync = REQ_FDATASYNC
999 root 1.43 PPCODE:
1000 root 1.1 {
1001 root 1.22 dREQ;
1002 root 1.1
1003     req->type = ix;
1004 root 1.13 req->fh = newSVsv (fh);
1005     req->fd = PerlIO_fileno (IoIFP (sv_2io (fh)));
1006 root 1.1
1007 root 1.43 REQ_SEND (req);
1008 root 1.1 }
1009    
1010     void
1011 root 1.40 aio_read (fh,offset,length,data,dataoffset,callback=&PL_sv_undef)
1012 root 1.13 SV * fh
1013     UV offset
1014 root 1.32 UV length
1015 root 1.13 SV * data
1016 root 1.32 UV dataoffset
1017 root 1.13 SV * callback
1018     ALIAS:
1019     aio_read = REQ_READ
1020     aio_write = REQ_WRITE
1021 root 1.8 PROTOTYPE: $$$$$;$
1022 root 1.43 PPCODE:
1023 root 1.13 {
1024     aio_req req;
1025     STRLEN svlen;
1026 root 1.21 char *svptr = SvPVbyte (data, svlen);
1027 root 1.13
1028     SvUPGRADE (data, SVt_PV);
1029     SvPOK_on (data);
1030 root 1.1
1031 root 1.13 if (dataoffset < 0)
1032     dataoffset += svlen;
1033    
1034     if (dataoffset < 0 || dataoffset > svlen)
1035     croak ("data offset outside of string");
1036    
1037     if (ix == REQ_WRITE)
1038     {
1039     /* write: check length and adjust. */
1040     if (length < 0 || length + dataoffset > svlen)
1041     length = svlen - dataoffset;
1042     }
1043     else
1044     {
1045     /* read: grow scalar as necessary */
1046     svptr = SvGROW (data, length + dataoffset);
1047     }
1048    
1049     if (length < 0)
1050     croak ("length must not be negative");
1051    
1052 root 1.22 {
1053     dREQ;
1054 root 1.13
1055 root 1.22 req->type = ix;
1056     req->fh = newSVsv (fh);
1057     req->fd = PerlIO_fileno (ix == REQ_READ ? IoIFP (sv_2io (fh))
1058     : IoOFP (sv_2io (fh)));
1059     req->offset = offset;
1060     req->length = length;
1061     req->data = SvREFCNT_inc (data);
1062     req->dataptr = (char *)svptr + dataoffset;
1063 root 1.13
1064 root 1.28 if (!SvREADONLY (data))
1065     {
1066     SvREADONLY_on (data);
1067     req->data2ptr = (void *)data;
1068     }
1069    
1070 root 1.43 REQ_SEND;
1071 root 1.22 }
1072 root 1.13 }
1073 root 1.1
1074     void
1075 root 1.40 aio_sendfile (out_fh,in_fh,in_offset,length,callback=&PL_sv_undef)
1076 root 1.32 SV * out_fh
1077     SV * in_fh
1078     UV in_offset
1079     UV length
1080     SV * callback
1081     PROTOTYPE: $$$$;$
1082 root 1.43 PPCODE:
1083 root 1.32 {
1084     dREQ;
1085    
1086     req->type = REQ_SENDFILE;
1087     req->fh = newSVsv (out_fh);
1088     req->fd = PerlIO_fileno (IoIFP (sv_2io (out_fh)));
1089     req->fh2 = newSVsv (in_fh);
1090     req->fd2 = PerlIO_fileno (IoIFP (sv_2io (in_fh)));
1091     req->offset = in_offset;
1092     req->length = length;
1093    
1094 root 1.43 REQ_SEND;
1095 root 1.32 }
1096    
1097     void
1098 root 1.40 aio_readahead (fh,offset,length,callback=&PL_sv_undef)
1099 root 1.13 SV * fh
1100     UV offset
1101     IV length
1102     SV * callback
1103 root 1.8 PROTOTYPE: $$$;$
1104 root 1.43 PPCODE:
1105 root 1.1 {
1106 root 1.22 dREQ;
1107 root 1.1
1108     req->type = REQ_READAHEAD;
1109 root 1.13 req->fh = newSVsv (fh);
1110     req->fd = PerlIO_fileno (IoIFP (sv_2io (fh)));
1111 root 1.1 req->offset = offset;
1112     req->length = length;
1113    
1114 root 1.43 REQ_SEND;
1115 root 1.1 }
1116    
1117     void
1118 root 1.40 aio_stat (fh_or_path,callback=&PL_sv_undef)
1119 root 1.1 SV * fh_or_path
1120     SV * callback
1121     ALIAS:
1122 root 1.8 aio_stat = REQ_STAT
1123     aio_lstat = REQ_LSTAT
1124 root 1.43 PPCODE:
1125 root 1.1 {
1126 root 1.22 dREQ;
1127 root 1.1
1128     New (0, req->statdata, 1, Stat_t);
1129     if (!req->statdata)
1130 root 1.27 {
1131 root 1.43 req_free (req);
1132 root 1.27 croak ("out of memory during aio_req->statdata allocation");
1133     }
1134 root 1.1
1135     if (SvPOK (fh_or_path))
1136     {
1137 root 1.8 req->type = ix;
1138 root 1.1 req->data = newSVsv (fh_or_path);
1139 root 1.22 req->dataptr = SvPVbyte_nolen (req->data);
1140 root 1.1 }
1141     else
1142     {
1143     req->type = REQ_FSTAT;
1144 root 1.13 req->fh = newSVsv (fh_or_path);
1145 root 1.1 req->fd = PerlIO_fileno (IoIFP (sv_2io (fh_or_path)));
1146     }
1147    
1148 root 1.43 REQ_SEND;
1149 root 1.1 }
1150    
1151     void
1152 root 1.40 aio_unlink (pathname,callback=&PL_sv_undef)
1153 root 1.1 SV * pathname
1154     SV * callback
1155 root 1.22 ALIAS:
1156 root 1.40 aio_unlink = REQ_UNLINK
1157     aio_rmdir = REQ_RMDIR
1158     aio_readdir = REQ_READDIR
1159 root 1.43 PPCODE:
1160 root 1.1 {
1161 root 1.22 dREQ;
1162 root 1.1
1163 root 1.22 req->type = ix;
1164     req->data = newSVsv (pathname);
1165     req->dataptr = SvPVbyte_nolen (req->data);
1166 root 1.1
1167 root 1.43 REQ_SEND;
1168 root 1.22 }
1169    
1170     void
1171 root 1.40 aio_link (oldpath,newpath,callback=&PL_sv_undef)
1172 root 1.22 SV * oldpath
1173     SV * newpath
1174     SV * callback
1175 root 1.40 ALIAS:
1176     aio_link = REQ_LINK
1177     aio_symlink = REQ_SYMLINK
1178     aio_rename = REQ_RENAME
1179 root 1.43 PPCODE:
1180 root 1.22 {
1181     dREQ;
1182 root 1.1
1183 root 1.40 req->type = ix;
1184 root 1.22 req->fh = newSVsv (oldpath);
1185     req->data2ptr = SvPVbyte_nolen (req->fh);
1186     req->data = newSVsv (newpath);
1187     req->dataptr = SvPVbyte_nolen (req->data);
1188 root 1.1
1189 root 1.43 REQ_SEND;
1190 root 1.1 }
1191    
1192 root 1.42 void
1193 root 1.45 aio_sleep (delay,callback=&PL_sv_undef)
1194     double delay
1195     SV * callback
1196     PPCODE:
1197     {
1198     dREQ;
1199    
1200     req->type = REQ_SLEEP;
1201     req->fd = delay < 0. ? 0 : delay;
1202     req->fd2 = delay < 0. ? 0 : 1000. * (delay - req->fd);
1203    
1204     REQ_SEND;
1205     }
1206    
1207     void
1208 root 1.44 aio_group (callback=&PL_sv_undef)
1209     SV * callback
1210 root 1.46 PROTOTYPE: ;$
1211 root 1.44 PPCODE:
1212 root 1.42 {
1213 root 1.44 dREQ;
1214     req->type = REQ_GROUP;
1215 root 1.45 req_send (req);
1216 root 1.44 XPUSHs (req_sv (req, AIO_GRP_KLASS));
1217 root 1.42 }
1218    
1219 root 1.6 void
1220 root 1.54 aio_nop (callback=&PL_sv_undef)
1221     SV * callback
1222     PPCODE:
1223     {
1224     dREQ;
1225    
1226     req->type = REQ_NOP;
1227    
1228     REQ_SEND;
1229     }
1230    
1231     void
1232 root 1.40 flush ()
1233 root 1.6 PROTOTYPE:
1234     CODE:
1235     while (nreqs)
1236     {
1237     poll_wait ();
1238     poll_cb ();
1239     }
1240    
1241 root 1.7 void
1242     poll()
1243     PROTOTYPE:
1244     CODE:
1245     if (nreqs)
1246     {
1247     poll_wait ();
1248     poll_cb ();
1249     }
1250    
1251 root 1.1 int
1252     poll_fileno()
1253     PROTOTYPE:
1254     CODE:
1255 root 1.3 RETVAL = respipe [0];
1256 root 1.1 OUTPUT:
1257     RETVAL
1258    
1259     int
1260     poll_cb(...)
1261     PROTOTYPE:
1262     CODE:
1263 root 1.5 RETVAL = poll_cb ();
1264 root 1.1 OUTPUT:
1265     RETVAL
1266    
1267     void
1268     poll_wait()
1269     PROTOTYPE:
1270     CODE:
1271 root 1.3 if (nreqs)
1272     poll_wait ();
1273 root 1.1
1274     int
1275     nreqs()
1276     PROTOTYPE:
1277     CODE:
1278     RETVAL = nreqs;
1279     OUTPUT:
1280     RETVAL
1281    
1282 root 1.48 PROTOTYPES: DISABLE
1283    
1284 root 1.44 MODULE = IO::AIO PACKAGE = IO::AIO::REQ
1285 root 1.43
1286     void
1287     cancel (aio_req_ornot req)
1288     PROTOTYPE:
1289     CODE:
1290 root 1.45 req_cancel (req);
1291    
1292 root 1.56 void
1293     cb (aio_req req, SV *callback=&PL_sv_undef)
1294     CODE:
1295     SvREFCNT_dec (req->callback);
1296     req->callback = newSVsv (callback);
1297    
1298 root 1.45 MODULE = IO::AIO PACKAGE = IO::AIO::GRP
1299    
1300     void
1301     add (aio_req grp, ...)
1302     PPCODE:
1303     {
1304     int i;
1305 root 1.53 aio_req req;
1306 root 1.45
1307 root 1.49 if (grp->fd == 2)
1308     croak ("cannot add requests to IO::AIO::GRP after the group finished");
1309    
1310 root 1.45 for (i = 1; i < items; ++i )
1311     {
1312 root 1.46 if (GIMME_V != G_VOID)
1313     XPUSHs (sv_2mortal (newSVsv (ST (i))));
1314    
1315 root 1.53 req = SvAIO_REQ (ST (i));
1316 root 1.45
1317 root 1.46 if (req)
1318     {
1319 root 1.49 ++grp->length;
1320     req->grp = grp;
1321    
1322     req->grp_prev = 0;
1323     req->grp_next = grp->grp_first;
1324 root 1.45
1325 root 1.49 if (grp->grp_first)
1326     grp->grp_first->grp_prev = req;
1327    
1328     grp->grp_first = req;
1329 root 1.46 }
1330 root 1.45 }
1331     }
1332 root 1.43
1333 root 1.48 void
1334 root 1.51 result (aio_req grp, ...)
1335     CODE:
1336     {
1337     int i;
1338     AV *av = newAV ();
1339    
1340     for (i = 1; i < items; ++i )
1341     av_push (av, newSVsv (ST (i)));
1342    
1343     SvREFCNT_dec (grp->data);
1344     grp->data = (SV *)av;
1345     }
1346    
1347     void
1348 root 1.56 feed_limit (aio_req grp, int limit)
1349 root 1.49 CODE:
1350     grp->fd2 = limit;
1351     aio_grp_feed (grp);
1352    
1353     void
1354 root 1.56 feed (aio_req grp, SV *callback=&PL_sv_undef)
1355 root 1.49 CODE:
1356     {
1357     SvREFCNT_dec (grp->fh2);
1358     grp->fh2 = newSVsv (callback);
1359    
1360     if (grp->fd2 <= 0)
1361     grp->fd2 = 2;
1362    
1363     aio_grp_feed (grp);
1364     }
1365