1 /* @(#)fifo.c 1.66 15/04/22 Copyright 1989,1997-2015 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)fifo.c 1.66 15/04/22 Copyright 1989,1997-2015 J. Schilling";
6 #endif
7 /*
8 * A "fifo" that uses shared memory between two processes
9 *
10 * The actual code is a mixture of borrowed code from star's fifo.c
11 * and a proposal from Finn Arne Gangstad <finnag@guardian.no>
12 * who had the idea to use a ring buffer to handle average size chunks.
13 *
14 * Copyright (c) 1989,1997-2015 J. Schilling
15 */
16 /*
17 * The contents of this file are subject to the terms of the
18 * Common Development and Distribution License, Version 1.0 only
19 * (the "License"). You may not use this file except in compliance
20 * with the License.
21 *
22 * See the file CDDL.Schily.txt in this distribution for details.
23 * A copy of the CDDL is also available via the Internet at
24 * http://www.opensource.org/licenses/cddl1.txt
25 *
26 * When distributing Covered Code, include this CDDL HEADER in each
27 * file and include the License file CDDL.Schily.txt from this distribution.
28 */
29
30 #ifndef DEBUG
31 #define DEBUG
32 #endif
33 /*#define XDEBUG*/
34 #include <schily/mconfig.h>
35 #if defined(HAVE_OS_H) && \
36 defined(HAVE_CLONE_AREA) && defined(HAVE_CREATE_AREA) && \
37 defined(HAVE_DELETE_AREA)
38 #include <OS.h>
39 # define HAVE_BEOS_AREAS /* BeOS/Zeta/Haiku */
40 #endif
41 #if !defined(HAVE_SMMAP) && !defined(HAVE_USGSHM) && \
42 !defined(HAVE_DOSALLOCSHAREDMEM) && !defined(HAVE_BEOS_AREAS)
43 #undef FIFO /* We cannot have a FIFO on this platform */
44 #endif
45 #if !defined(HAVE_FORK)
46 #undef FIFO /* We cannot have a FIFO on this platform */
47 #endif
48 #ifdef FIFO
49 #if !defined(USE_MMAP) && !defined(USE_USGSHM)
50 #define USE_MMAP
51 #endif
52 #ifndef HAVE_SMMAP
53 # undef USE_MMAP
54 # define USE_USGSHM /* now SYSV shared memory is the default*/
55 #endif
56 #ifdef USE_MMAP /* Only want to have one implementation */
57 # undef USE_USGSHM /* mmap() is preferred */
58 #endif
59
60 #ifdef HAVE_DOSALLOCSHAREDMEM /* This is for OS/2 */
61 # undef USE_MMAP
62 # undef USE_USGSHM
63 # define USE_OS2SHM
64 #endif
65
66 #ifdef HAVE_BEOS_AREAS /* This is for BeOS/Zeta */
67 # undef USE_MMAP
68 # undef USE_USGSHM
69 # undef USE_OS2SHM
70 # define USE_BEOS_AREAS
71 #endif
72
73 #include <schily/stdio.h>
74 #include <schily/stdlib.h>
75 #include <schily/unistd.h> /* includes <sys/types.h> */
76 #include <schily/utypes.h>
77 #include <schily/fcntl.h>
78 #if defined(HAVE_SMMAP) && defined(USE_MMAP)
79 #include <schily/mman.h>
80 #endif
81 #include <schily/wait.h>
82 #include <schily/standard.h>
83 #include <schily/errno.h>
84 #include <schily/signal.h>
85 #include <schily/libport.h>
86 #include <schily/schily.h>
87 #include <schily/nlsdefs.h>
88 #include <schily/vfork.h>
89
90 #include "cdrecord.h"
91 #include "xio.h"
92
93 #ifdef DEBUG
94 #ifdef XDEBUG
95 FILE *ef;
96 #define USDEBUG1 if (debug) {if (s == owner_reader) fprintf(ef, "r"); else fprintf(ef, "w"); fflush(ef); }
97 #define USDEBUG2 if (debug) {if (s == owner_reader) fprintf(ef, "R"); else fprintf(ef, "W"); fflush(ef); }
98 #else
99 #define USDEBUG1
100 #define USDEBUG2
101 #endif
102 #define EDEBUG(a) if (debug) error a
103 #else
104 #define EDEBUG(a)
105 #define USDEBUG1
106 #define USDEBUG2
107 #endif
108
109 #define palign(x, a) (((char *)(x)) + ((a) - 1 - (((UIntptr_t)((x)-1))%(a))))
110
111 typedef enum faio_owner {
112 owner_none, /* Unused in real life */
113 owner_writer, /* owned by process that writes into FIFO */
114 owner_faio, /* Intermediate state when buf still in use */
115 owner_reader /* owned by process that reads from FIFO */
116 } fowner_t;
117
118 char *onames[] = {
119 "none",
120 "writer",
121 "faio",
122 "reader",
123 };
124
125 typedef struct faio {
126 int len;
127 volatile fowner_t owner;
128 volatile int users;
129 short fd;
130 short saved_errno;
131 char *bufp;
132 } faio_t;
133
134 struct faio_stats {
135 long puts;
136 long gets;
137 long empty;
138 long full;
139 long done;
140 long cont_low;
141 int users;
142 } *sp;
143
144 #define MIN_BUFFERS 3
145
146 #define MSECS 1000
147 #define SECS (1000*MSECS)
148
149 /*
150 * Note: WRITER_MAXWAIT & READER_MAXWAIT need to be greater than the SCSI
151 * timeout for commands that write to the media. This is currently 200s
152 * if we are in SAO mode.
153 */
154 /* microsecond delay between each buffer-ready probe by writing process */
155 #define WRITER_DELAY (20*MSECS)
156 #define WRITER_MAXWAIT (240*SECS) /* 240 seconds max wait for data */
157
158 /* microsecond delay between each buffer-ready probe by reading process */
159 #define READER_DELAY (80*MSECS)
160 #define READER_MAXWAIT (240*SECS) /* 240 seconds max wait for reader */
161
162 LOCAL char *buf;
163 LOCAL char *bufbase;
164 LOCAL char *bufend;
165 LOCAL long buflen; /* The size of the FIFO buffer */
166
167 extern int debug;
168 extern int lverbose;
169
170 EXPORT long init_fifo __PR((long));
171 #ifdef USE_MMAP
172 LOCAL char *mkshare __PR((int size));
173 #endif
174 #ifdef USE_USGSHM
175 LOCAL char *mkshm __PR((int size));
176 #endif
177 #ifdef USE_OS2SHM
178 LOCAL char *mkos2shm __PR((int size));
179 #endif
180 #ifdef USE_BEOS_AREAS
181 LOCAL char *mkbeosshm __PR((int size));
182 LOCAL void beosshm_child __PR((void));
183 #endif
184
185 EXPORT BOOL init_faio __PR((track_t *trackp, int));
186 EXPORT BOOL await_faio __PR((void));
187 EXPORT void kill_faio __PR((void));
188 EXPORT int wait_faio __PR((void));
189 LOCAL void faio_reader __PR((track_t *trackp));
190 LOCAL void faio_read_track __PR((track_t *trackp));
191 LOCAL void faio_wait_on_buffer __PR((faio_t *f, fowner_t s,
192 unsigned long delay,
193 unsigned long max_wait));
194 LOCAL int faio_read_segment __PR((int fd, faio_t *f, track_t *track, long secno, int len));
195 LOCAL faio_t *faio_ref __PR((int n));
196 EXPORT int faio_read_buf __PR((int f, char *bp, int size));
197 EXPORT int faio_get_buf __PR((int f, char **bpp, int size));
198 EXPORT void fifo_stats __PR((void));
199 EXPORT int fifo_percent __PR((BOOL addone));
200
201
202 EXPORT long
init_fifo(fs)203 init_fifo(fs)
204 long fs;
205 {
206 int pagesize;
207
208 if (fs == 0L)
209 return (fs);
210
211 #ifdef _SC_PAGESIZE
212 pagesize = sysconf(_SC_PAGESIZE);
213 #else
214 pagesize = getpagesize();
215 #endif
216 buflen = roundup(fs, pagesize) + pagesize;
217 EDEBUG(("fs: %ld buflen: %ld\n", fs, buflen));
218
219 #if defined(USE_MMAP)
220 buf = mkshare(buflen);
221 #endif
222 #if defined(USE_USGSHM)
223 buf = mkshm(buflen);
224 #endif
225 #if defined(USE_OS2SHM)
226 buf = mkos2shm(buflen);
227 #endif
228 #if defined(USE_BEOS_AREAS)
229 buf = mkbeosshm(buflen);
230 #endif
231
232 bufbase = buf;
233 bufend = buf + buflen;
234 EDEBUG(("buf: %p bufend: %p, buflen: %ld\n", buf, bufend, buflen));
235 buf = palign(buf, pagesize);
236 buflen -= buf - bufbase;
237 EDEBUG(("buf: %p bufend: %p, buflen: %ld (align %ld)\n", buf, bufend, buflen, (long)(buf - bufbase)));
238
239 /*
240 * Dirty the whole buffer. This can die with various signals if
241 * we're trying to lock too much memory
242 */
243 fillbytes(buf, buflen, '\0');
244
245 #ifdef XDEBUG
246 if (debug)
247 ef = fopen("/tmp/ef", "w");
248 #endif
249 return (buflen-pagesize); /* We use one page for administrative data */
250 }
251
252 #ifdef USE_MMAP
253 LOCAL char *
mkshare(size)254 mkshare(size)
255 int size;
256 {
257 int f;
258 char *addr;
259
260 #ifdef MAP_ANONYMOUS /* HP/UX */
261 f = -1;
262 addr = mmap(0, mmap_sizeparm(size),
263 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, f, 0);
264 #else
265 if ((f = open("/dev/zero", O_RDWR)) < 0)
266 comerr(_("Cannot open '/dev/zero'.\n"));
267 addr = mmap(0, mmap_sizeparm(size),
268 PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
269 #endif
270 if (addr == (char *)-1)
271 comerr(_("Cannot get mmap for %d Bytes on /dev/zero.\n"), size);
272 if (f >= 0)
273 close(f);
274
275 if (debug) errmsgno(EX_BAD, _("shared memory segment attached at: %p size %d\n"),
276 (void *)addr, size);
277
278 return (addr);
279 }
280 #endif
281
282 #ifdef USE_USGSHM
283 #include <schily/ipc.h>
284 #include <schily/shm.h>
285 LOCAL char *
mkshm(size)286 mkshm(size)
287 int size;
288 {
289 int id;
290 char *addr;
291 /*
292 * Unfortunately, a declaration of shmat() is missing in old
293 * implementations such as AT&T SVr0 and SunOS.
294 * We cannot add this definition here because the return-type
295 * changed on newer systems.
296 *
297 * We will get a warning like this:
298 *
299 * warning: assignment of pointer from integer lacks a cast
300 * or
301 * warning: illegal combination of pointer and integer, op =
302 */
303 /* extern char *shmat();*/
304
305 if ((id = shmget(IPC_PRIVATE, size, IPC_CREAT|0600)) == -1)
306 comerr(_("shmget failed\n"));
307
308 if (debug) errmsgno(EX_BAD, _("shared memory segment allocated: %d\n"), id);
309
310 if ((addr = shmat(id, (char *)0, 0600)) == (char *)-1)
311 comerr(_("shmat failed\n"));
312
313 if (debug) errmsgno(EX_BAD, _("shared memory segment attached at: %p size %d\n"),
314 (void *)addr, size);
315
316 if (shmctl(id, IPC_RMID, 0) < 0)
317 comerr(_("shmctl failed to detach shared memory segment\n"));
318
319 #ifdef SHM_LOCK
320 /*
321 * Although SHM_LOCK is standard, it seems that all versions of AIX
322 * ommit this definition.
323 */
324 if (shmctl(id, SHM_LOCK, 0) < 0)
325 comerr(_("shmctl failed to lock shared memory segment\n"));
326 #endif
327
328 return (addr);
329 }
330 #endif
331
332 #ifdef USE_OS2SHM
333 LOCAL char *
mkos2shm(size)334 mkos2shm(size)
335 int size;
336 {
337 char *addr;
338
339 /*
340 * The OS/2 implementation of shm (using shm.dll) limits the size of one shared
341 * memory segment to 0x3fa000 (aprox. 4MBytes). Using OS/2 native API we have
342 * no such restriction so I decided to use it allowing fifos of arbitrary size.
343 */
344 if (DosAllocSharedMem(&addr, NULL, size, 0X100L | 0x1L | 0x2L | 0x10L))
345 comerr(_("DosAllocSharedMem() failed\n"));
346
347 if (debug) errmsgno(EX_BAD, _("shared memory allocated attached at: %p size %d\n"),
348 (void *)addr, size);
349
350 return (addr);
351 }
352 #endif
353
354 #ifdef USE_BEOS_AREAS
355 LOCAL area_id faio_aid;
356 LOCAL void *faio_addr;
357 LOCAL char faio_name[32];
358
359 LOCAL char *
mkbeosshm(size)360 mkbeosshm(size)
361 int size;
362 {
363 snprintf(faio_name, sizeof (faio_name), "cdrecord FIFO %lld",
364 (Llong)getpid());
365
366 faio_aid = create_area(faio_name, &faio_addr,
367 B_ANY_ADDRESS,
368 size,
369 B_NO_LOCK, B_READ_AREA|B_WRITE_AREA);
370 if (faio_addr == NULL) {
371 comerrno(faio_aid,
372 _("Cannot get create_area for %d Bytes FIFO.\n"), size);
373 }
374 if (debug) errmsgno(EX_BAD, _("shared memory allocated attached at: %p size %d\n"),
375 (void *)faio_addr, size);
376 return (faio_addr);
377 }
378
379 LOCAL void
beosshm_child()380 beosshm_child()
381 {
382 /*
383 * Delete the area created by fork that is copy-on-write.
384 */
385 delete_area(area_for(faio_addr));
386 /*
387 * Clone (share) the original one.
388 * The original implementaion used B_ANY_ADDRESS, but newer Haiku
389 * versions implement address randomization that prevents us from
390 * using the pointer in the child. So we noe use B_EXACT_ADDRESS.
391 */
392 faio_aid = clone_area(faio_name, &faio_addr,
393 B_EXACT_ADDRESS, B_READ_AREA|B_WRITE_AREA,
394 faio_aid);
395 if (bufbase != faio_addr) {
396 comerrno(EX_BAD, _("Panic FIFO addr.\n"));
397 /* NOTREACHED */
398 }
399 }
400 #endif
401
402 LOCAL int faio_buffers;
403 LOCAL int faio_buf_size;
404 LOCAL int buf_idx = 0; /* Initialize to fix an Amiga bug */
405 LOCAL int buf_idx_reader = 0; /* Separate var to allow vfork() */
406 /* buf_idx_reader is for the process */
407 /* that fills the FIFO */
408 LOCAL pid_t faio_pid;
409 LOCAL BOOL faio_didwait;
410
411 #ifdef AMIGA
412 /*
413 * On Amiga fork will be replaced by the speciall vfork() like call ix_vfork,
414 * which lets the parent asleep. The child process later wakes up the parent
415 * process by calling ix_fork_resume().
416 */
417 #define fork() ix_vfork()
418 #define __vfork_resume() ix_vfork_resume()
419
420 #else /* !AMIGA */
421 #define __vfork_resume()
422 #endif
423
424
425 /*#define faio_ref(n) (&((faio_t *)buf)[n])*/
426
427
428 EXPORT BOOL
init_faio(trackp,bufsize)429 init_faio(trackp, bufsize)
430 track_t *trackp;
431 int bufsize; /* The size of a single transfer buffer */
432 {
433 int n;
434 faio_t *f;
435 int pagesize;
436 char *base;
437
438 if (buflen == 0L)
439 return (FALSE);
440
441 #ifdef _SC_PAGESIZE
442 pagesize = sysconf(_SC_PAGESIZE);
443 #else
444 pagesize = getpagesize();
445 #endif
446
447 faio_buf_size = bufsize;
448 f = (faio_t *)buf;
449
450 /*
451 * Compute space for buffer headers.
452 * Round bufsize up to pagesize to make each FIFO segment
453 * properly page aligned.
454 */
455 bufsize = roundup(bufsize, pagesize);
456 faio_buffers = (buflen - sizeof (*sp)) / bufsize;
457 EDEBUG(("bufsize: %d buffers: %d hdrsize %ld\n", bufsize, faio_buffers, (long)faio_buffers * sizeof (struct faio)));
458
459 /*
460 * Reduce buffer space by header space.
461 */
462 n = sizeof (*sp) + faio_buffers * sizeof (struct faio);
463 n = roundup(n, pagesize);
464 faio_buffers = (buflen-n) / bufsize;
465 EDEBUG(("bufsize: %d buffers: %d hdrsize %ld\n", bufsize, faio_buffers, (long)faio_buffers * sizeof (struct faio)));
466
467 if (faio_buffers < MIN_BUFFERS) {
468 errmsgno(EX_BAD,
469 _("write-buffer too small, minimum is %dk. Disabling.\n"),
470 MIN_BUFFERS*bufsize/1024);
471 return (FALSE);
472 }
473
474 if (debug)
475 printf(_("Using %d buffers of %d bytes.\n"), faio_buffers, faio_buf_size);
476
477 f = (faio_t *)buf;
478 base = buf + roundup(sizeof (*sp) + faio_buffers * sizeof (struct faio),
479 pagesize);
480
481 for (n = 0; n < faio_buffers; n++, f++, base += bufsize) {
482 /* Give all the buffers to the file reader process */
483 f->owner = owner_writer;
484 f->users = 0;
485 f->bufp = base;
486 f->fd = -1;
487 }
488 sp = (struct faio_stats *)f; /* point past headers */
489 sp->gets = sp->puts = sp->done = 0L;
490 sp->users = 1;
491
492 faio_pid = fork();
493 if (faio_pid < 0)
494 comerr(_("fork(2) failed"));
495
496 if (faio_pid == 0) {
497 /*
498 * child (background) process that fills the FIFO.
499 */
500 raisepri(1); /* almost max priority */
501
502 #ifdef USE_OS2SHM
503 DosGetSharedMem(buf, 3); /* PAG_READ|PAG_WRITE */
504 #endif
505 #ifdef USE_BEOS_AREAS
506 beosshm_child();
507 #endif
508 /* Ignoring SIGALRM cures the SCO usleep() bug */
509 /* signal(SIGALRM, SIG_IGN);*/
510 __vfork_resume(); /* Needed on some platforms */
511 faio_reader(trackp);
512 /* NOTREACHED */
513 } else {
514 #ifdef __needed__
515 Uint t;
516 #endif
517
518 faio_didwait = FALSE;
519
520 /*
521 * XXX We used to close all track files in the foreground
522 * XXX process. This was not correct before we used "xio"
523 * XXX and with "xio" it will start to fail because we need
524 * XXX the fd handles for the faio_get_buf() function.
525 */
526 #ifdef __needed__
527 /* close all file-descriptors that only the child will use */
528 for (t = 1; t <= trackp->tracks; t++) {
529 if (trackp[t].xfp != NULL)
530 xclose(trackp[t].xfp);
531 }
532 #endif
533 }
534
535 return (TRUE);
536 }
537
538 EXPORT BOOL
await_faio()539 await_faio()
540 {
541 int n;
542 int lastfd = -1;
543 faio_t *f;
544
545 /*
546 * Wait until the reader is active and has filled the buffer.
547 */
548 if (lverbose || debug) {
549 printf(_("Waiting for reader process to fill input buffer ... "));
550 flush();
551 }
552
553 faio_wait_on_buffer(faio_ref(faio_buffers - 1), owner_reader,
554 500*MSECS, 0);
555
556 if (lverbose || debug)
557 printf(_("input buffer ready.\n"));
558
559 sp->empty = sp->full = 0L; /* set correct stat state */
560 sp->cont_low = faio_buffers; /* set cont to max value */
561
562 f = faio_ref(0);
563 for (n = 0; n < faio_buffers; n++, f++) {
564 if (f->fd != lastfd &&
565 f->fd == STDIN_FILENO && f->len == 0) {
566 errmsgno(EX_BAD, _("Premature EOF on stdin.\n"));
567 kill_faio();
568 return (FALSE);
569 }
570 lastfd = f->fd;
571 }
572 return (TRUE);
573 }
574
575 EXPORT void
kill_faio()576 kill_faio()
577 {
578 if (faio_pid > 0)
579 kill(faio_pid, SIGKILL);
580 }
581
582 EXPORT int
wait_faio()583 wait_faio()
584 {
585 if (faio_pid > 0 && !faio_didwait)
586 return (wait(0));
587 faio_didwait = TRUE;
588 return (0);
589 }
590
591 LOCAL void
faio_reader(trackp)592 faio_reader(trackp)
593 track_t *trackp;
594 {
595 /* This function should not return, but _exit. */
596 Uint trackno;
597
598 if (debug)
599 printf(_("\nfaio_reader starting\n"));
600
601 for (trackno = 0; trackno <= trackp->tracks; trackno++) {
602 if (trackno == 0 && trackp[0].xfp == NULL)
603 continue;
604 if (debug)
605 printf(_("\nfaio_reader reading track %u\n"), trackno);
606 faio_read_track(&trackp[trackno]);
607 }
608 sp->done++;
609 if (debug)
610 printf(_("\nfaio_reader all tracks read, exiting\n"));
611
612 /* Prevent hang if buffer is larger than all the tracks combined */
613 if (sp->gets == 0)
614 faio_ref(faio_buffers - 1)->owner = owner_reader;
615
616 #ifdef USE_OS2SHM
617 DosFreeMem(buf);
618 sleep(30000); /* XXX If calling _exit() here the parent process seems to be blocked */
619 /* XXX This should be fixed soon */
620 #endif
621 if (debug)
622 error(_("\nfaio_reader _exit(0)\n"));
623 _exit(0);
624 }
625
626 #ifndef faio_ref
627 LOCAL faio_t *
faio_ref(n)628 faio_ref(n)
629 int n;
630 {
631 return (&((faio_t *)buf)[n]);
632 }
633 #endif
634
635
636 LOCAL void
faio_read_track(trackp)637 faio_read_track(trackp)
638 track_t *trackp;
639 {
640 int fd = -1;
641 int bytespt = trackp->secsize * trackp->secspt;
642 int secspt = trackp->secspt;
643 int l;
644 long secno = trackp->trackstart;
645 tsize_t tracksize = trackp->tracksize;
646 tsize_t bytes_read = (tsize_t)0;
647 long bytes_to_read;
648
649 if (trackp->xfp != NULL)
650 fd = xfileno(trackp->xfp);
651
652 if (bytespt > faio_buf_size) {
653 comerrno(EX_BAD,
654 _("faio_read_track fatal: secsize %d secspt %d, bytespt(%d) > %d !!\n"),
655 trackp->secsize, trackp->secspt, bytespt,
656 faio_buf_size);
657 }
658
659 do {
660 bytes_to_read = bytespt;
661 if (tracksize > 0) {
662 if ((tracksize - bytes_read) > bytespt) {
663 bytes_to_read = bytespt;
664 } else {
665 bytes_to_read = tracksize - bytes_read;
666 }
667 }
668 l = faio_read_segment(fd, faio_ref(buf_idx_reader), trackp, secno, bytes_to_read);
669 if (++buf_idx_reader >= faio_buffers)
670 buf_idx_reader = 0;
671 if (l <= 0)
672 break;
673 bytes_read += l;
674 secno += secspt;
675 } while (tracksize < 0 || bytes_read < tracksize);
676
677 if (trackp->xfp != NULL) {
678 xclose(trackp->xfp); /* Don't keep files open longer than neccesary */
679 trackp->xfp = NULL;
680 }
681 }
682
683 LOCAL void
684 #ifdef PROTOTYPES
faio_wait_on_buffer(faio_t * f,fowner_t s,unsigned long delay,unsigned long max_wait)685 faio_wait_on_buffer(faio_t *f, fowner_t s,
686 unsigned long delay,
687 unsigned long max_wait)
688 #else
689 faio_wait_on_buffer(f, s, delay, max_wait)
690 faio_t *f;
691 fowner_t s;
692 unsigned long delay;
693 unsigned long max_wait;
694 #endif
695 {
696 unsigned long max_loops;
697
698 if (f->owner == s)
699 return; /* return immediately if the buffer is ours */
700
701 if (s == owner_reader)
702 sp->empty++;
703 else
704 sp->full++;
705
706 max_loops = max_wait / delay + 1;
707
708 while (max_wait == 0 || max_loops--) {
709 USDEBUG1;
710 usleep(delay);
711 USDEBUG2;
712
713 if (f->owner == s)
714 return;
715 }
716 if (debug) {
717 errmsgno(EX_BAD,
718 _("%lu microseconds passed waiting for %d current: %d idx: %ld\n"),
719 max_wait, s, f->owner, (long)(f - faio_ref(0))/sizeof (*f));
720 }
721 comerrno(EX_BAD, _("faio_wait_on_buffer for %s timed out.\n"),
722 (s > owner_reader || s < owner_none) ? "bad_owner" : onames[s-owner_none]);
723 }
724
725 LOCAL int
faio_read_segment(fd,f,trackp,secno,len)726 faio_read_segment(fd, f, trackp, secno, len)
727 int fd;
728 faio_t *f;
729 track_t *trackp;
730 long secno;
731 int len;
732 {
733 int l;
734
735 faio_wait_on_buffer(f, owner_writer, WRITER_DELAY, WRITER_MAXWAIT);
736
737 f->fd = fd;
738 l = fill_buf(fd, trackp, secno, f->bufp, len);
739 f->len = l;
740 f->saved_errno = geterrno();
741 f->owner = owner_reader;
742 f->users = sp->users;
743
744 sp->puts++;
745
746 return (l);
747 }
748
749 EXPORT int
faio_read_buf(fd,bp,size)750 faio_read_buf(fd, bp, size)
751 int fd;
752 char *bp;
753 int size;
754 {
755 char *bufp;
756
757 int len = faio_get_buf(fd, &bufp, size);
758 if (len > 0) {
759 movebytes(bufp, bp, len);
760 }
761 return (len);
762 }
763
764 EXPORT int
faio_get_buf(fd,bpp,size)765 faio_get_buf(fd, bpp, size)
766 int fd;
767 char **bpp;
768 int size;
769 {
770 faio_t *f;
771 int len;
772
773 again:
774 f = faio_ref(buf_idx);
775 if (f->owner == owner_faio) {
776 f->owner = owner_writer;
777 if (++buf_idx >= faio_buffers)
778 buf_idx = 0;
779 f = faio_ref(buf_idx);
780 }
781
782 if ((sp->puts - sp->gets) < sp->cont_low && sp->done == 0) {
783 EDEBUG(("gets: %ld puts: %ld cont: %ld low: %ld\n", sp->gets, sp->puts, sp->puts - sp->gets, sp->cont_low));
784 sp->cont_low = sp->puts - sp->gets;
785 }
786 faio_wait_on_buffer(f, owner_reader, READER_DELAY, READER_MAXWAIT);
787 len = f->len;
788
789 if (f->fd != fd) {
790 if (f->len == 0) {
791 /*
792 * If the tracksize for this track was known, and
793 * the tracksize is 0 mod bytespt, this happens.
794 */
795 goto again;
796 }
797 comerrno(EX_BAD,
798 _("faio_get_buf fatal: fd=%d, f->fd=%d, f->len=%d f->errno=%d\n"),
799 fd, f->fd, f->len, f->saved_errno);
800 }
801 if (size < len) {
802 comerrno(EX_BAD,
803 _("unexpected short read-attempt in faio_get_buf. size = %d, len = %d\n"),
804 size, len);
805 }
806
807 if (len < 0)
808 seterrno(f->saved_errno);
809
810 sp->gets++;
811
812 *bpp = f->bufp;
813 if (--f->users <= 0)
814 f->owner = owner_faio;
815 return (len);
816 }
817
818 EXPORT void
fifo_stats()819 fifo_stats()
820 {
821 if (sp == NULL) /* We might not use a FIFO */
822 return;
823
824 errmsgno(EX_BAD, _("fifo had %ld puts and %ld gets.\n"),
825 sp->puts, sp->gets);
826 errmsgno(EX_BAD, _("fifo was %ld times empty and %ld times full, min fill was %ld%%.\n"),
827 sp->empty, sp->full, (100L*sp->cont_low)/faio_buffers);
828 }
829
830 EXPORT int
fifo_percent(addone)831 fifo_percent(addone)
832 BOOL addone;
833 {
834 int percent;
835
836 if (sp == NULL) /* We might not use a FIFO */
837 return (-1);
838
839 if (sp->done)
840 return (100);
841 percent = (100*(sp->puts + 1 - sp->gets)/faio_buffers);
842 if (percent > 100)
843 return (100);
844 return (percent);
845 }
846 #else /* FIFO */
847
848 #include <schily/standard.h>
849 #include <schily/utypes.h> /* includes sys/types.h */
850 #include <schily/schily.h>
851 #include <schily/nlsdefs.h>
852
853 #include "cdrecord.h"
854
855 EXPORT long init_fifo __PR((long));
856 EXPORT BOOL init_faio __PR((track_t *track, int));
857 EXPORT BOOL await_faio __PR((void));
858 EXPORT void kill_faio __PR((void));
859 EXPORT int wait_faio __PR((void));
860 EXPORT int faio_read_buf __PR((int f, char *bp, int size));
861 EXPORT int faio_get_buf __PR((int f, char **bpp, int size));
862 EXPORT void fifo_stats __PR((void));
863 EXPORT int fifo_percent __PR((BOOL addone));
864
865
866 EXPORT long
init_fifo(fs)867 init_fifo(fs)
868 long fs;
869 {
870 errmsgno(EX_BAD, _("Fifo not supported.\n"));
871 return (0L);
872 }
873
874 EXPORT BOOL
init_faio(track,bufsize)875 init_faio(track, bufsize)
876 track_t *track;
877 int bufsize;
878 {
879 return (FALSE);
880 }
881
882 EXPORT BOOL
await_faio()883 await_faio()
884 {
885 return (TRUE);
886 }
887
888 EXPORT void
kill_faio()889 kill_faio()
890 {
891 }
892
893 EXPORT int
wait_faio()894 wait_faio()
895 {
896 return (0);
897 }
898
899 EXPORT int
faio_read_buf(fd,bp,size)900 faio_read_buf(fd, bp, size)
901 int fd;
902 char *bp;
903 int size;
904 {
905 return (0);
906 }
907
908 EXPORT int
faio_get_buf(fd,bpp,size)909 faio_get_buf(fd, bpp, size)
910 int fd;
911 char **bpp;
912 int size;
913 {
914 return (0);
915 }
916
917 EXPORT void
fifo_stats()918 fifo_stats()
919 {
920 }
921
922 EXPORT int
fifo_percent(addone)923 fifo_percent(addone)
924 BOOL addone;
925 {
926 return (-1);
927 }
928
929 #endif /* FIFO */
930