📄 fifo_gnodeops.c
字号:
goto wrloop; /* fifonode unlocked */ } /* new buffer...tack it on the of the list */ bp->fb_next = (struct fifo_bufhdr *) NULL; if (fp->fn_buf == (struct fifo_bufhdr *) NULL) { fp->fn_buf = bp; } else { fp->fn_bufend->fb_next = bp; } fp->fn_bufend = bp; } /* * There is now enough space to write 'count' bytes. * Find append point and copy new data. */ bp = fp->fn_buf; for (off = fp->fn_wptr; off >= PIPE_BSZ; off -= PIPE_BSZ) bp = bp->fb_next; while (count) { i = PIPE_BSZ - off; i = MIN(count, i); if (rval = uiomove(&bp->fb_data[off], (int) i, UIO_WRITE, uiop)){ /* error during copy from user space */ /* NOTE:LEAVE ALLOCATED BUFS FOR NOW */ goto rdwrdone; } fp->fn_size += i; fp->fn_wptr += i; count -= i; off = 0; bp = bp->fb_next; } gp->g_flag |= GUPD|GCHG; (void) fifo_gupdat(gp, timepick, timepick, 0, cred); /* wake up any sleeping readers */ if (fp->fn_flag & IFIR) { fp->fn_flag &= ~IFIR; wakeup((caddr_t) &fp->fn_rcnt); } /* wake up any procs sleeping on select */ if (fp->fn_rselp) { selwakeup(fp->fn_rselp, fp->fn_flag & IF_RCOLL); fp->fn_flag &= ~IF_RCOLL; fp->fn_rselp = 0; }wrloop: /* bottom of write 'while' loop */ first_pass = 0; continue; } } else { /* UIO_READ */ /* * Handle zero-length reads specially here */ if ((count = uiop->uio_resid) == 0) { goto rdwrdone; } while ((i = fp->fn_size) == 0) { if (fp->fn_wcnt == 0) { /* no data in pipe and no writers...(EOF) */ goto rdwrdone; } /* no data in pipe, but writer is there */ if (ioflag & (FNDELAY|FNBLOCK)) { rval = EAGAIN; goto rdwrdone; } fp->fn_flag |= IFIR; (void) sleep_unlock((caddr_t) &fp->fn_rcnt, PPIPE, &gp->g_lk); gfs_lock(gp); /* loop to make sure there is still a writer */ }#ifdef SANITY if ((fp->fn_wptr - fp->fn_rptr) != fp->fn_size) printf("fifo_read: ptr mismatch...size:%d wptr:%d rptr:%d\n", fp->fn_size, fp->fn_wptr, fp->fn_rptr); if (fp->fn_rptr > PIPE_BSZ) printf("fifo_read: rptr too big...rptr:%d\n", fp->fn_rptr); if (fp->fn_wptr > (fp->fn_nbuf * PIPE_BSZ)) printf("fifo_read: wptr too big...wptr:%d nbuf:%d\n", fp->fn_wptr, fp->fn_nbuf);#endif SANITY /* * Get offset into first buffer at which to start getting data. * Truncate read, if necessary, to amount of data available. */ off = fp->fn_rptr; bp = fp->fn_buf; count = MIN(count, i); /* smaller of pipe size and read size */ while (count) { i = PIPE_BSZ - off; i = MIN(count, i); if (rval = uiomove(&bp->fb_data[off], (int)i, UIO_READ, uiop)){ goto rdwrdone; } fp->fn_size -= i; fp->fn_rptr += i; count -= i; off = 0;#ifdef SANITY if (fp->fn_rptr > PIPE_BSZ) printf("fifo_read: rptr after uiomove too big...rptr:%d\n", fp->fn_rptr);#endif SANITY if (fp->fn_rptr == PIPE_BSZ) { fp->fn_rptr = 0; bp = fifo_buffree(bp, fp); fp->fn_buf = bp; fp->fn_wptr -= PIPE_BSZ; } /* * At this point, if fp->fn_size is zero, there may be * an allocated, but unused, buffer. [In this case, * fp->fn_rptr == fp->fn_wptr != 0.] * NOTE: FOR NOW, LEAVE THIS EXTRA BUFFER ALLOCATED. * NOTE: fifo_buffree() CAN'T HANDLE A BUFFER NOT 1ST. */ } gp->g_flag |= GACC; (void) fifo_gupdat(gp, timepick, timepick, 0, cred); /* wake up any sleeping writers */ if (fp->fn_flag & IFIW) { fp->fn_flag &= ~IFIW; wakeup((caddr_t) &fp->fn_wcnt); } /* wake up any procs sleeping on select */ if (fp->fn_wselp) { selwakeup(fp->fn_wselp, fp->fn_flag & IF_WCOLL); fp->fn_flag &= ~IF_WCOLL; fp->fn_wselp = 0; } } /* end of UIO_READ code */rdwrdone: gfs_unlock(gp); uiop->uio_offset = 0; /* guarantee that f_offset stays 0 */ return (rval);}/* * test for fifo selections *//*ARGSUSED*/intfifo_select(gp, flag, cred) struct gnode *gp; int flag; struct ucred *cred;{ register struct fifonode *fp; int ret_val=0; fp = GTOF(gp); gfs_lock(gp); switch (flag) { case FREAD: if ((fp->fn_size != 0) || (fp->fn_wcnt == 0)) ret_val = 1; else { if (fp->fn_rselp) fp->fn_flag |= IF_RCOLL; else fp->fn_rselp = u.u_procp; } break; case FWRITE: if ((fp->fn_size < PIPE_BUF) || (fp->fn_rcnt == 0)) ret_val=1; else { if (fp->fn_wselp) fp->fn_flag |= IF_WCOLL; else fp->fn_wselp = u.u_procp; } break; } gfs_unlock(gp); return (ret_val);}intfifo_rele(gp) struct gnode *gp;{ extern struct lock_t lk_gnode; gfs_lock(gp); if ((gp->g_mode & GFMT) == GFPIPE) { /* * We have to take out a spin lock here to workaround an * smp lock primitive problem. When a sleep lock resides * in km_alloc space a race condition can exist between * km_freeing the memory, and checking the wakeup bit in the * lock. Its ugly, but it works... prs */ smp_lock(&lk_gnode, LK_RETRY); if (gp->g_count == 1) { gfs_unlock(gp); smp_unlock(&lk_gnode); kmem_free((caddr_t)gp, KM_TEMP); } else { gp->g_count--; gfs_unlock(gp); smp_unlock(&lk_gnode); } return (0); } gfs_unlock(gp);}intfifo_gupdat(gp, ta, tm, waitfor, cred) struct gnode *gp; struct timeval *ta, *tm; int waitfor; struct ucred *cred;{ if ((gp->g_mode & GFMT) == GFPIPE) { if (gp->g_flag & GACC) gp->g_atime = *ta; if (gp->g_flag & GUPD) gp->g_mtime = *tm; if (gp->g_flag & GCHG) gp->g_ctime = *timepick; gp->g_flag &= ~(GUPD|GACC|GCHG|GMOD); return (0); } return (gp->g_altops->go_gupdat(gp, ta, tm, waitfor, cred));} fifo_wakeup(fp) register struct fifonode *fp;{ register struct proc *p; /* * If ASYNC is set on fifo, send SIGIO signal to * procs in process group. */ if (fp->fn_flag & IF_RASYNC) { if (fp->fn_rpgrp < 0) gsignal(-fp->fn_rpgrp, SIGIO); else if ((fp->fn_rpgrp > 0) && (p = pfind(fp->fn_rpgrp)) != 0) psignal(p, SIGIO); } if (fp->fn_flag & IF_WASYNC) { if (fp->fn_wpgrp < 0) gsignal(-fp->fn_wpgrp, SIGIO); else if ((fp->fn_wpgrp > 0) && (p = pfind(fp->fn_wpgrp)) != 0) psignal(p, SIGIO); }}/* * allocate a buffer for a fifo * return NULL if had to sleep */static struct fifo_bufhdr *fifo_bufalloc(gp, fp) register struct gnode *gp; register struct fifonode *fp;{ register struct fifo_bufhdr *bp; if (fifo_alloc >= PIPE_MNB) { /* * Impose a system-wide maximum on buffered data in pipes. * NOTE: This could lead to deadlock! */ (void) sleep_unlock((caddr_t) &fifo_alloc, PPIPE, &gp->g_lk); gfs_lock(gp); return ((struct fifo_bufhdr *)NULL); } /* the call to kmem_alloc() might sleep, so leave fifonode locked */ fifo_alloc += FIFO_BUFFER_SIZE; kmem_alloc(bp, struct fifo_bufhdr *, (u_int)FIFO_BUFFER_SIZE, KM_TEMP); fp->fn_nbuf++; return ((struct fifo_bufhdr *) bp);}/* * deallocate a fifo buffer */static struct fifo_bufhdr *fifo_buffree(bp, fp) struct fifo_bufhdr *bp; struct fifonode *fp;{ register struct fifo_bufhdr *nbp; fp->fn_nbuf--; /* * NOTE: THE FOLLOWING ONLY WORKS IF THE FREED BUFFER WAS THE 1ST ONE. */ if (fp->fn_bufend == bp) fp->fn_bufend = (struct fifo_bufhdr *) NULL; nbp = bp->fb_next; kmem_free((caddr_t)bp, KM_TEMP); if (fifo_alloc >= PIPE_MNB) { wakeup((caddr_t) &fifo_alloc); } fifo_alloc -= FIFO_BUFFER_SIZE; return (nbp);}intfifo_lock(gp) struct gnode *gp;{ if ((gp->g_mode & GFMT) == GFPIPE) { while (glocked(gp)) { gp->g_flag |= GWANT; sleep((caddr_t)gp, PINOD); } gfs_lock(gp); return (0); } return (gp->g_altops->go_lock (gp));}intfifo_unlock(gp) struct gnode *gp;{ if ((gp->g_mode & GFMT) == GFPIPE) { gfs_unlock(gp); if (gp->g_flag&GWANT) { gp->g_flag &= ~GWANT; wakeup((caddr_t)gp); } return (0); } return (gp->g_altops->go_unlock (gp));}intfifo_stat(gp, sb) struct gnode *gp; struct stat *sb;{ register struct fifonode *fp; fp = GTOF(gp); if ((gp->g_mode & GFMT) == GFPORT) /* Named pipe */ gp->g_altops->go_stat (gp, sb); else { bzero((caddr_t)sb, sizeof(*sb)); sb->st_atime = gp->g_atime.tv_sec; sb->st_spare1 = gp->g_atime.tv_usec; sb->st_mtime = gp->g_mtime.tv_sec; sb->st_spare2 = gp->g_mtime.tv_usec; sb->st_ctime = gp->g_ctime.tv_sec; sb->st_spare3 = gp->g_ctime.tv_usec; } if (fp) sb->st_size = fp->fn_size; sb->st_blksize = PIPE_BUF; return (0);}/*ARGSUSED*/intfifo_ioctl(gp, com, data, flag, cred) struct gnode *gp; int com; caddr_t data; int flag; struct ucred *cred;{ register struct fifonode *fp; int error = 0; switch (com) { case FIONREAD: fp = GTOF(gp); *(off_t *)data = fp->fn_size; break; case FIOGETOWN: fp = GTOF(gp); if (flag & FREAD) *(int *)data = fp->fn_rpgrp; else *(int *)data = fp->fn_wpgrp; break; case FIOSETOWN: fp = GTOF(gp); if (flag & FREAD) fp->fn_rpgrp = *(int *)data; else fp->fn_wpgrp = *(int *)data; break; case FIOASYNC: fp = GTOF(gp); if (*(int *)data) { if (flag & FREAD) fp->fn_flag |= IF_RASYNC; else fp->fn_flag |= IF_WASYNC; } else { if (flag & FREAD) fp->fn_flag &= ~IF_RASYNC; else fp->fn_flag &= ~IF_WASYNC; } break; case FIONBIO: break; default: error = ENOTTY; break; } return (error);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -