Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/sys_pipe.c
Show First 20 Lines • Show All 718 Lines • ▼ Show 20 Lines | */ | ||||
rpipe->pipe_map.pos, size, uio); | rpipe->pipe_map.pos, size, uio); | ||||
PIPE_LOCK(rpipe); | PIPE_LOCK(rpipe); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
nread += size; | nread += size; | ||||
rpipe->pipe_map.pos += size; | rpipe->pipe_map.pos += size; | ||||
rpipe->pipe_map.cnt -= size; | rpipe->pipe_map.cnt -= size; | ||||
if (rpipe->pipe_map.cnt == 0) { | if (rpipe->pipe_map.cnt == 0) { | ||||
rpipe->pipe_state &= ~(PIPE_DIRECTW|PIPE_WANTW); | rpipe->pipe_state &= ~PIPE_WANTW; | ||||
wakeup(rpipe); | wakeup(rpipe); | ||||
} | } | ||||
#endif | #endif | ||||
} else { | } else { | ||||
/* | /* | ||||
* detect EOF condition | * detect EOF condition | ||||
* read returns 0 on EOF, no need to set error | * read returns 0 on EOF, no need to set error | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | */ | ||||
if (uio->uio_iov->iov_len == 0) | if (uio->uio_iov->iov_len == 0) | ||||
uio->uio_iov++; | uio->uio_iov++; | ||||
uio->uio_resid -= size; | uio->uio_resid -= size; | ||||
uio->uio_offset += size; | uio->uio_offset += size; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* unmap and unwire the process buffer | * Unwire the process buffer. | ||||
*/ | */ | ||||
static void | static void | ||||
pipe_destroy_write_buffer(struct pipe *wpipe) | pipe_destroy_write_buffer(struct pipe *wpipe) | ||||
{ | { | ||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | ||||
KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0, | |||||
("%s: PIPE_DIRECTW not set on %p", __func__, wpipe)); | |||||
wpipe->pipe_state &= ~PIPE_DIRECTW; | |||||
vm_page_unhold_pages(wpipe->pipe_map.ms, wpipe->pipe_map.npages); | vm_page_unhold_pages(wpipe->pipe_map.ms, wpipe->pipe_map.npages); | ||||
wpipe->pipe_map.npages = 0; | wpipe->pipe_map.npages = 0; | ||||
} | } | ||||
/* | /* | ||||
* In the case of a signal, the writing process might go away. This | * In the case of a signal, the writing process might go away. This | ||||
* code copies the data into the circular buffer so that the source | * code copies the data into the circular buffer so that the source | ||||
* pages can be freed without loss of data. | * pages can be freed without loss of data. | ||||
*/ | */ | ||||
static void | static void | ||||
pipe_clone_write_buffer(struct pipe *wpipe) | pipe_clone_write_buffer(struct pipe *wpipe) | ||||
{ | { | ||||
struct uio uio; | struct uio uio; | ||||
struct iovec iov; | struct iovec iov; | ||||
int size; | int size; | ||||
int pos; | int pos; | ||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | ||||
KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0, | |||||
("%s: PIPE_DIRECTW not set on %p", __func__, wpipe)); | |||||
size = wpipe->pipe_map.cnt; | size = wpipe->pipe_map.cnt; | ||||
pos = wpipe->pipe_map.pos; | pos = wpipe->pipe_map.pos; | ||||
wpipe->pipe_buffer.in = size; | wpipe->pipe_buffer.in = size; | ||||
wpipe->pipe_buffer.out = 0; | wpipe->pipe_buffer.out = 0; | ||||
wpipe->pipe_buffer.cnt = size; | wpipe->pipe_buffer.cnt = size; | ||||
wpipe->pipe_state &= ~PIPE_DIRECTW; | |||||
PIPE_UNLOCK(wpipe); | PIPE_UNLOCK(wpipe); | ||||
iov.iov_base = wpipe->pipe_buffer.buffer; | iov.iov_base = wpipe->pipe_buffer.buffer; | ||||
iov.iov_len = size; | iov.iov_len = size; | ||||
uio.uio_iov = &iov; | uio.uio_iov = &iov; | ||||
uio.uio_iovcnt = 1; | uio.uio_iovcnt = 1; | ||||
uio.uio_offset = 0; | uio.uio_offset = 0; | ||||
uio.uio_resid = size; | uio.uio_resid = size; | ||||
Show All 22 Lines | retry: | ||||
error = pipelock(wpipe, 1); | error = pipelock(wpipe, 1); | ||||
if (error != 0) | if (error != 0) | ||||
goto error1; | goto error1; | ||||
if ((wpipe->pipe_state & PIPE_EOF) != 0) { | if ((wpipe->pipe_state & PIPE_EOF) != 0) { | ||||
error = EPIPE; | error = EPIPE; | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
goto error1; | goto error1; | ||||
} | } | ||||
while (wpipe->pipe_state & PIPE_DIRECTW) { | if (wpipe->pipe_state & PIPE_DIRECTW) { | ||||
if (wpipe->pipe_state & PIPE_WANTR) { | if (wpipe->pipe_state & PIPE_WANTR) { | ||||
wpipe->pipe_state &= ~PIPE_WANTR; | wpipe->pipe_state &= ~PIPE_WANTR; | ||||
wakeup(wpipe); | wakeup(wpipe); | ||||
} | } | ||||
pipeselwakeup(wpipe); | pipeselwakeup(wpipe); | ||||
wpipe->pipe_state |= PIPE_WANTW; | wpipe->pipe_state |= PIPE_WANTW; | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = msleep(wpipe, PIPE_MTX(wpipe), | error = msleep(wpipe, PIPE_MTX(wpipe), | ||||
Show All 26 Lines | retry: | ||||
error = pipe_build_write_buffer(wpipe, uio); | error = pipe_build_write_buffer(wpipe, uio); | ||||
PIPE_LOCK(wpipe); | PIPE_LOCK(wpipe); | ||||
if (error) { | if (error) { | ||||
wpipe->pipe_state &= ~PIPE_DIRECTW; | wpipe->pipe_state &= ~PIPE_DIRECTW; | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
goto error1; | goto error1; | ||||
} | } | ||||
error = 0; | while (wpipe->pipe_map.cnt != 0) { | ||||
while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) { | |||||
if (wpipe->pipe_state & PIPE_EOF) { | if (wpipe->pipe_state & PIPE_EOF) { | ||||
pipe_destroy_write_buffer(wpipe); | pipe_destroy_write_buffer(wpipe); | ||||
pipeselwakeup(wpipe); | pipeselwakeup(wpipe); | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = EPIPE; | error = EPIPE; | ||||
goto error1; | goto error1; | ||||
} | } | ||||
if (wpipe->pipe_state & PIPE_WANTR) { | if (wpipe->pipe_state & PIPE_WANTR) { | ||||
wpipe->pipe_state &= ~PIPE_WANTR; | wpipe->pipe_state &= ~PIPE_WANTR; | ||||
wakeup(wpipe); | wakeup(wpipe); | ||||
} | } | ||||
pipeselwakeup(wpipe); | pipeselwakeup(wpipe); | ||||
wpipe->pipe_state |= PIPE_WANTW; | wpipe->pipe_state |= PIPE_WANTW; | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH, | error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH, | ||||
"pipdwt", 0); | "pipdwt", 0); | ||||
pipelock(wpipe, 0); | pipelock(wpipe, 0); | ||||
if (error != 0) | |||||
break; | |||||
} | } | ||||
if (wpipe->pipe_state & PIPE_EOF) | if (wpipe->pipe_state & PIPE_EOF) | ||||
error = EPIPE; | error = EPIPE; | ||||
if (wpipe->pipe_state & PIPE_DIRECTW) { | if (error == EINTR || error == ERESTART) | ||||
/* | |||||
* this bit of trickery substitutes a kernel buffer for | |||||
* the process that might be going away. | |||||
*/ | |||||
pipe_clone_write_buffer(wpipe); | pipe_clone_write_buffer(wpipe); | ||||
} else { | else | ||||
pipe_destroy_write_buffer(wpipe); | pipe_destroy_write_buffer(wpipe); | ||||
} | |||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
KASSERT((wpipe->pipe_state & PIPE_DIRECTW) == 0, | |||||
("pipe %p leaked PIPE_DIRECTW", wpipe)); | |||||
return (error); | return (error); | ||||
error1: | error1: | ||||
wakeup(wpipe); | wakeup(wpipe); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 765 Lines • Show Last 20 Lines |