Visa Hankala <v...@hankala.org> writes:

> The EPIPE error relates to the situation where a kevent(2) EVFILT_WRITE
> call on a pipe races with the closing of the pipe's other end.
> If the close(2) happens before the kevent registration, kevent(2)
> returns EPIPE. If the close(2) happens after the kevent(2) call,
> the registered event will trigger.
>
> The EPIPE error is a legacy feature of the kqueue implementation.
> I think the system should work correctly without it. When the pipe's
> write side has already been closed, the EVFILT_WRITE event can still
> be registered. It just triggers immediately.
>
> As for the ENOENT error from kevent(2), I think the unit test behaves
> incorrectly by trying to delete a non-existent event. The registration
> failed, after all.
>
> Below is a patch that removes the EPIPE special case. Could you try
> it?

Thanks for the prompt reply with the detailed explanation. The patch
makes my test pass. OK gnezdo

>
> Index: kern/sys_generic.c
> ===================================================================
> RCS file: src/sys/kern/sys_generic.c,v
> retrieving revision 1.155
> diff -u -p -r1.155 sys_generic.c
> --- kern/sys_generic.c        25 Feb 2023 09:55:46 -0000      1.155
> +++ kern/sys_generic.c        6 May 2023 17:10:27 -0000
> @@ -769,12 +769,6 @@ pselregister(struct proc *p, fd_set *pib
>                                                * __EV_SELECT */
>                                       error = 0;
>                                       break;
> -                             case EPIPE:     /* Specific to pipes */
> -                                     KASSERT(kev.filter == EVFILT_WRITE);
> -                                     FD_SET(kev.ident, pobits[1]);
> -                                     (*ncollected)++;
> -                                     error = 0;
> -                                     break;
>                               case ENXIO:     /* Device has been detached */
>                               default:
>                                       goto bad;
> @@ -1073,10 +1067,6 @@ again:
>                               goto again;
>                       }
>                       break;
> -             case EPIPE:     /* Specific to pipes */
> -                     KASSERT(kevp->filter == EVFILT_WRITE);
> -                     pl->revents |= POLLHUP;
> -                     break;
>               default:
>                       DPRINTFN(0, "poll err %lu fd %d revents %02x serial"
>                           " %lu filt %d ERROR=%d\n",
> Index: kern/sys_pipe.c
> ===================================================================
> RCS file: src/sys/kern/sys_pipe.c,v
> retrieving revision 1.145
> diff -u -p -r1.145 sys_pipe.c
> --- kern/sys_pipe.c   12 Feb 2023 10:41:00 -0000      1.145
> +++ kern/sys_pipe.c   6 May 2023 17:10:27 -0000
> @@ -857,9 +857,13 @@ pipe_kqfilter(struct file *fp, struct kn
>               break;
>       case EVFILT_WRITE:
>               if (wpipe == NULL) {
> -                     /* other end of pipe has been closed */
> -                     error = EPIPE;
> -                     break;
> +                     /*
> +                      * The other end of the pipe has been closed.
> +                      * Since the filter now always indicates a pending
> +                      * event, attach the knote to the read side to proceed
> +                      * with the registration.
> +                      */
> +                     wpipe = rpipe;
>               }
>               kn->kn_fop = &pipe_wfiltops;
>               kn->kn_hook = wpipe;

Reply via email to