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