ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/IO-AIO/AIO.xs
Revision: 1.63
Committed: Mon Oct 23 23:48:31 2006 UTC (17 years, 6 months ago) by root
Branch: MAIN
Changes since 1.62: +13 -2 lines
Log Message:
*** empty log message ***

File Contents

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