1
/* @(#)fifo.c 1.28 01/04/11 Copyright 1989,1997 J. Schilling */
4
"@(#)fifo.c 1.28 01/04/11 Copyright 1989,1997 J. Schilling";
7
* A "fifo" that uses shared memory between two processes
9
* The actual code is a mixture of borrowed code from star's fifo.c
10
* and a proposal from Finn Arne Gangstad <finnag@guardian.no>
11
* who had the idea to use a ring buffer to handle average size chunks.
13
* Copyright (c) 1989,1997 J. Schilling
16
* This program is free software; you can redistribute it and/or modify
17
* it under the terms of the GNU General Public License as published by
18
* the Free Software Foundation; either version 2, or (at your option)
21
* This program is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
* GNU General Public License for more details.
26
* You should have received a copy of the GNU General Public License
27
* along with this program; see the file COPYING. If not, write to
28
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
34
#if !defined(HAVE_SMMAP) && !defined(HAVE_USGSHM) && !defined(HAVE_DOSALLOCSHAREDMEM)
35
#undef FIFO /* We cannot have a FIFO on this platform */
38
#if !defined(USE_MMAP) && !defined(USE_USGSHM)
43
# define USE_USGSHM /* now SYSV shared memory is the default*/
45
#ifdef USE_MMAP /* Only want to have one implementation */
46
# undef USE_USGSHM /* mmap() is preferred */
49
#ifdef HAVE_DOSALLOCSHAREDMEM /* This is for OS/2 */
56
#include <sys/types.h>
57
#if defined(HAVE_SMMAP) && defined(USE_MMAP)
76
#define USDEBUG1 if (debug) {if(s == owner_reader)fprintf(ef, "r");else fprintf(ef, "w");fflush(ef);}
77
#define USDEBUG2 if (debug) {if(s == owner_reader)fprintf(ef, "R");else fprintf(ef, "W");fflush(ef);}
82
#define EDEBUG(a) if (debug) error a
89
#define palign(x, a) (((char *)(x)) + ((a) - 1 - (((unsigned)((x)-1))%(a))))
91
typedef enum faio_owner {
92
owner_none, /* Unused in real life */
93
owner_writer, /* owned by process that writes into FIFO */
94
owner_faio, /* Intermediate state when buf still in use */
95
owner_reader /* owned by process that reads from FIFO */
105
typedef struct faio {
107
volatile fowner_t owner;
124
#define MIN_BUFFERS 3
127
#define SECS (1000*MSECS)
130
* Note: WRITER_MAXWAIT & READER_MAXWAIT need to be greater than the SCSI
131
* timeout for commands that write to the media. This is currently 200s
132
* if we are in SAO mode.
134
/* microsecond delay between each buffer-ready probe by writing process */
135
#define WRITER_DELAY (20*MSECS)
136
#define WRITER_MAXWAIT (240*SECS) /* 240 seconds max wait for data */
138
/* microsecond delay between each buffer-ready probe by reading process */
139
#define READER_DELAY (80*MSECS)
140
#define READER_MAXWAIT (240*SECS) /* 240 seconds max wait for reader */
150
EXPORT void init_fifo __PR((long));
152
LOCAL char* mkshare __PR((int size));
155
LOCAL char* mkshm __PR((int size));
158
LOCAL char* mkos2shm __PR((int size));
161
EXPORT BOOL init_faio __PR((int tracks, track_t *track, int));
162
EXPORT BOOL await_faio __PR((void));
163
EXPORT void kill_faio __PR((void));
164
EXPORT int wait_faio __PR((void));
165
LOCAL void faio_reader __PR((int tracks, track_t *track));
166
LOCAL void faio_read_track __PR((track_t *trackp));
167
LOCAL void faio_wait_on_buffer __PR((faio_t *f, fowner_t s,
169
unsigned long max_wait));
170
LOCAL int faio_read_segment __PR((int fd, faio_t *f, int len));
171
LOCAL faio_t *faio_ref __PR((int n));
172
EXPORT int faio_read_buf __PR((int f, char *bp, int size));
173
EXPORT int faio_get_buf __PR((int f, char **bpp, int size));
174
EXPORT void fifo_stats __PR((void));
175
EXPORT int fifo_percent __PR((BOOL addone));
188
pagesize = sysconf(_SC_PAGESIZE);
190
pagesize = getpagesize();
192
buflen = roundup(fs, pagesize) + pagesize;
193
EDEBUG(("fs: %ld buflen: %ld\n", fs, buflen));
195
#if defined(USE_MMAP)
196
buf = mkshare(buflen);
198
#if defined(USE_USGSHM)
201
#if defined(USE_OS2SHM)
202
buf = mkos2shm(buflen);
206
bufend = buf + buflen;
207
EDEBUG(("buf: %p bufend: %p, buflen: %ld\n", buf, bufend, buflen));
208
buf = palign(buf, pagesize);
209
buflen -= buf - bufbase;
210
EDEBUG(("buf: %p bufend: %p, buflen: %ld (align %ld)\n", buf, bufend, buflen, (long)(buf - bufbase)));
213
* Dirty the whole buffer. This can die with various signals if
214
* we're trying to lock too much memory
216
fillbytes(buf, buflen, '\0');
220
ef = fopen("/tmp/ef", "w");
232
#ifdef MAP_ANONYMOUS /* HP/UX */
234
addr = mmap(0, mmap_sizeparm(size),
235
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, f, 0);
237
if ((f = open("/dev/zero", O_RDWR)) < 0)
238
comerr("Cannot open '/dev/zero'.\n");
239
addr = mmap(0, mmap_sizeparm(size),
240
PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
242
if (addr == (char *)-1)
243
comerr("Cannot get mmap for %d Bytes on /dev/zero.\n", size);
246
if (debug) errmsgno(EX_BAD, "shared memory segment attached: %p\n", (void *)addr);
262
* Unfortunately, a declaration of shmat() is missing in old
263
* implementations such as AT&T SVr0 and SunOS.
264
* We cannot add this definition here because the return-type
265
* changed on newer systems.
267
* We will get a warning like this:
269
* warning: assignment of pointer from integer lacks a cast
271
* warning: illegal combination of pointer and integer, op =
273
/* extern char *shmat();*/
275
if ((id = shmget(IPC_PRIVATE, size, IPC_CREAT|0600)) == -1)
276
comerr("shmget failed\n");
278
if (debug) errmsgno(EX_BAD, "shared memory segment allocated: %d\n", id);
280
if ((addr = shmat(id, (char *)0, 0600)) == (char *)-1)
281
comerr("shmat failed\n");
283
if (debug) errmsgno(EX_BAD, "shared memory segment attached: %p\n", addr);
285
if (shmctl(id, IPC_RMID, 0) < 0)
286
comerr("shmctl failed to detach shared memory segment\n");
290
* Although SHM_LOCK is standard, it seems that all versions of AIX
291
* ommit this definition.
293
if (shmctl(id, SHM_LOCK, 0) < 0)
294
comerr("shmctl failed to lock shared memory segment\n");
309
* The OS/2 implementation of shm (using shm.dll) limits the size of one shared
310
* memory segment to 0x3fa000 (aprox. 4MBytes). Using OS/2 native API we have
311
* no such restriction so I decided to use it allowing fifos of arbitrary size.
313
if(DosAllocSharedMem(&addr,NULL,size,0X100L | 0x1L | 0x2L | 0x10L))
314
comerr("DosAllocSharedMem() failed\n");
317
errmsgno(EX_BAD, "shared memory allocated at address: %x\n", addr);
323
LOCAL int faio_buffers;
324
LOCAL int faio_buf_size;
326
LOCAL pid_t faio_pid;
327
LOCAL BOOL faio_didwait;
329
/*#define faio_ref(n) (&((faio_t *)buf)[n])*/
333
init_faio(tracks, track, bufsize)
347
pagesize = sysconf(_SC_PAGESIZE);
349
pagesize = getpagesize();
352
faio_buf_size = bufsize;
356
* Compute space for buffer headers.
357
* Round bufsize up to pagesize to make each FIFO segment
358
* properly page aligned.
360
bufsize = roundup(bufsize, pagesize);
361
faio_buffers = (buflen - sizeof(*sp)) / bufsize;
362
EDEBUG(("bufsize: %d buffers: %d hdrsize %ld\n", bufsize, faio_buffers, (long)faio_buffers * sizeof(struct faio)));
365
* Reduce buffer space by header space.
367
n = sizeof(*sp) + faio_buffers * sizeof(struct faio);
368
n = roundup(n, pagesize);
369
faio_buffers = (buflen-n) / bufsize;
370
EDEBUG(("bufsize: %d buffers: %d hdrsize %ld\n", bufsize, faio_buffers, (long)faio_buffers * sizeof(struct faio)));
372
if (faio_buffers < MIN_BUFFERS) {
374
"write-buffer too small, minimum is %dk. Disabling.\n",
375
MIN_BUFFERS*bufsize/1024);
380
printf("Using %d buffers of %d bytes.\n", faio_buffers, faio_buf_size);
383
base = buf + roundup(sizeof(*sp) + faio_buffers * sizeof(struct faio),
386
for (n = 0; n < faio_buffers; n++, f++, base += bufsize) {
387
/* Give all the buffers to the file reader process */
388
f->owner = owner_writer;
393
sp = (struct faio_stats *)f; /* point past headers */
394
sp->gets = sp->puts = sp->done = 0L;
399
comerr("fork(2) failed");
403
* child (background) process that fills the FIFO.
405
raisepri(1); /* almost max priority */
408
DosGetSharedMem(buf,3); /* PAG_READ|PAG_WRITE */
410
/* Ignoring SIGALRM cures the SCO usleep() bug */
411
/* signal(SIGALRM, SIG_IGN);*/
412
faio_reader(tracks, track);
415
faio_didwait = FALSE;
417
/* close all file-descriptors that only the child will use */
418
for (n = 1; n <= tracks; n++)
433
* Wait until the reader is active and has filled the buffer.
435
if (lverbose || debug) {
436
printf("Waiting for reader process to fill input buffer ... ");
440
faio_wait_on_buffer(faio_ref(faio_buffers - 1), owner_reader,
443
if (lverbose || debug)
444
printf("input buffer ready.\n");
446
sp->empty = sp->full = 0L; /* set correct stat state */
447
sp->cont_low = faio_buffers; /* set cont to max value */
450
for (n = 0; n < faio_buffers; n++, f++) {
451
if (f->fd != lastfd &&
452
f->fd == STDIN_FILENO && f->len == 0) {
453
errmsgno(EX_BAD, "Premature EOF on stdin.\n");
454
kill(faio_pid, SIGKILL);
466
kill(faio_pid, SIGKILL);
472
if (faio_pid > 0 && !faio_didwait)
479
faio_reader(tracks, track)
483
/* This function should not return, but _exit. */
487
printf("\nfaio_reader starting\n");
489
for (trackno = 1; trackno <= tracks; trackno++) {
491
printf("\nfaio_reader reading track %d\n", trackno);
492
faio_read_track(&track[trackno]);
496
printf("\nfaio_reader all tracks read, exiting\n");
498
/* Prevent hang if buffer is larger than all the tracks combined */
500
faio_ref(faio_buffers - 1)->owner = owner_reader;
504
sleep(30000); /* XXX If calling _exit() here the parent process seems to be blocked */
505
/* XXX This should be fixed soon */
508
error("\nfaio_reader _exit(0)\n");
517
return (&((faio_t *)buf)[n]);
523
faio_read_track(trackp)
527
int bytespt = trackp->secsize * trackp->secspt;
529
off_t tracksize = trackp->tracksize;
530
off_t bytes_read = (off_t)0;
533
if (bytespt > faio_buf_size) {
535
"faio_read_track fatal: secsize %d secspt %d, bytespt(%d) > %d !!\n",
536
trackp->secsize, trackp->secspt, bytespt,
541
bytes_to_read = bytespt;
543
if ((tracksize - bytes_read) > bytespt)
544
bytes_to_read = bytespt;
546
bytes_to_read = tracksize - bytes_read;
548
l = faio_read_segment(fd, faio_ref(buf_idx), bytes_to_read);
549
if (++buf_idx >= faio_buffers)
554
} while (tracksize < 0 || bytes_read < tracksize);
556
close(fd); /* Don't keep files open longer than neccesary */
560
faio_wait_on_buffer(f, s, delay, max_wait)
564
unsigned long max_wait;
566
unsigned long max_loops;
569
return; /* return immediately if the buffer is ours */
571
if (s == owner_reader)
576
max_loops = max_wait / delay + 1;
578
while (max_wait == 0 || max_loops--) {
588
"%lu microseconds passed waiting for %d current: %d idx: %ld\n",
589
max_wait, s, f->owner, (long)(f - faio_ref(0))/sizeof(*f));
591
comerrno(EX_BAD, "faio_wait_on_buffer for %s timed out.\n",
592
(s > owner_reader || s < owner_none) ? "bad_owner" : onames[s-owner_none]);
596
faio_read_segment(fd, f, len)
603
faio_wait_on_buffer(f, owner_writer, WRITER_DELAY, WRITER_MAXWAIT);
606
l = read_buf(fd, f->bufp, len);
608
f->saved_errno = errno;
609
f->owner = owner_reader;
610
f->users = sp->users;
618
faio_read_buf(fd, bp, size)
625
int len = faio_get_buf(fd, &bufp, size);
627
movebytes(bufp, bp, len);
633
faio_get_buf(fd, bpp, size)
642
f = faio_ref(buf_idx);
643
if (f->owner == owner_faio) {
644
f->owner = owner_writer;
645
if (++buf_idx >= faio_buffers)
647
f = faio_ref(buf_idx);
650
if ((sp->puts - sp->gets) < sp->cont_low && sp->done == 0) {
651
EDEBUG(("gets: %ld puts: %ld cont: %ld low: %ld\n", sp->gets, sp->puts, sp->puts - sp->gets, sp->cont_low));
652
sp->cont_low = sp->puts - sp->gets;
654
faio_wait_on_buffer(f, owner_reader, READER_DELAY, READER_MAXWAIT);
660
* If the tracksize for this track was known, and
661
* the tracksize is 0 mod bytespt, this happens.
666
"faio_get_buf fatal: fd=%d, f->fd=%d, f->len=%d f->errno=%d\n",
667
fd, f->fd, f->len, f->saved_errno);
671
"unexpected short read-attempt in faio_get_buf. size = %d, len = %d\n",
676
errno = f->saved_errno;
682
f->owner = owner_faio;
689
if (sp == NULL) /* We might not use a FIFO */
692
errmsgno(EX_BAD, "fifo had %ld puts and %ld gets.\n",
694
errmsgno(EX_BAD, "fifo was %ld times empty and %ld times full, min fill was %ld%%.\n",
695
sp->empty, sp->full, (100L*sp->cont_low)/faio_buffers);
708
percent = (100*(sp->puts + 1 - sp->gets)/faio_buffers);
715
#include <standard.h>
716
#include <sys/types.h>
719
#include "cdrecord.h"
721
EXPORT void init_fifo __PR((long));
722
EXPORT BOOL init_faio __PR((int tracks, track_t *track, int));
723
EXPORT BOOL await_faio __PR((void));
724
EXPORT void kill_faio __PR((void));
725
EXPORT int wait_faio __PR((void));
726
EXPORT int faio_read_buf __PR((int f, char *bp, int size));
727
EXPORT int faio_get_buf __PR((int f, char **bpp, int size));
728
EXPORT void fifo_stats __PR((void));
729
EXPORT int fifo_percent __PR((BOOL addone));
736
errmsgno(EX_BAD, "Fifo not supported.\n");
740
init_faio(tracks, track, bufsize)
766
faio_read_buf(fd, bp, size)
775
faio_get_buf(fd, bpp, size)