/* * expand the size of pipe while there is data to be read, * and then free the old buffer once the current buffered * data has been transferred to new storage. * Required: PIPE_LOCK and io lock to be held by caller. * returns 0 on success or no expansion possible */ static int expand_pipespace(struct pipe *p, int target_size) { struct pipe tmp, oldpipe; int error; tmp.pipe_buffer.buffer = 0; if (p->pipe_buffer.size >= (unsigned) target_size) { return 0; /* the existing buffer is max size possible */ } /* create enough space in the target */ error = pipespace(&tmp, target_size); if (error != 0) return (error); oldpipe.pipe_buffer.buffer = p->pipe_buffer.buffer; oldpipe.pipe_buffer.size = p->pipe_buffer.size; memcpy(tmp.pipe_buffer.buffer, p->pipe_buffer.buffer, p->pipe_buffer.size); if (p->pipe_buffer.cnt > 0 && p->pipe_buffer.in <= p->pipe_buffer.out ){ /* we are in State 3 and need extra copying for read to be consistent */ memcpy(&tmp.pipe_buffer.buffer[p->pipe_buffer.size], p->pipe_buffer.buffer, p->pipe_buffer.size); p->pipe_buffer.in += p->pipe_buffer.size; } p->pipe_buffer.buffer = tmp.pipe_buffer.buffer; p->pipe_buffer.size = tmp.pipe_buffer.size; pipe_free_kmem(&oldpipe); return 0; }
/* * Allocate kva for pipe circular buffer, the space is pageable. * This routine will 'realloc' the size of a pipe safely, if it fails * it will retain the old buffer. * If it fails it will return ENOMEM. */ int pipespace(struct pipe *cpipe, u_int size) { caddr_t buffer; buffer = (caddr_t)uvm_km_valloc(kernel_map, size); if (buffer == NULL) { return (ENOMEM); } /* free old resources if we are resizing */ pipe_free_kmem(cpipe); cpipe->pipe_buffer.buffer = buffer; cpipe->pipe_buffer.size = size; cpipe->pipe_buffer.in = 0; cpipe->pipe_buffer.out = 0; cpipe->pipe_buffer.cnt = 0; amountpipekva += cpipe->pipe_buffer.size; return (0); }
/* * Allocate kva for pipe circular buffer, the space is pageable. * This routine will 'realloc' the size of a pipe safely, if it fails * it will retain the old buffer. * If it fails it will return ENOMEM. */ int pipespace(struct pipe *cpipe, u_int size) { caddr_t buffer; buffer = km_alloc(size, &kv_any, &kp_pageable, &kd_waitok); if (buffer == NULL) { return (ENOMEM); } /* free old resources if we are resizing */ pipe_free_kmem(cpipe); cpipe->pipe_buffer.buffer = buffer; cpipe->pipe_buffer.size = size; cpipe->pipe_buffer.in = 0; cpipe->pipe_buffer.out = 0; cpipe->pipe_buffer.cnt = 0; amountpipekva += cpipe->pipe_buffer.size; return (0); }
/* * shutdown the pipe */ void pipeclose(struct pipe *cpipe) { struct pipe *ppipe; if (cpipe) { pipeselwakeup(cpipe); /* * If the other side is blocked, wake it up saying that * we want to close it down. */ cpipe->pipe_state |= PIPE_EOF; while (cpipe->pipe_busy) { wakeup(cpipe); cpipe->pipe_state |= PIPE_WANT; tsleep(cpipe, PRIBIO, "pipecl", 0); } /* * Disconnect from peer */ if ((ppipe = cpipe->pipe_peer) != NULL) { pipeselwakeup(ppipe); ppipe->pipe_state |= PIPE_EOF; wakeup(ppipe); ppipe->pipe_peer = NULL; } /* * free resources */ pipe_free_kmem(cpipe); pool_put(&pipe_pool, cpipe); } }
/* * Allocate kva for pipe circular buffer, the space is pageable * This routine will 'realloc' the size of a pipe safely, if it fails * it will retain the old buffer. * If it fails it will return ENOMEM. */ static int pipespace(struct pipe *cpipe, int size) { vm_offset_t buffer; if (size <= 0) return(EINVAL); if ((buffer = (vm_offset_t)kalloc(size)) == 0 ) return(ENOMEM); /* free old resources if we're resizing */ pipe_free_kmem(cpipe); cpipe->pipe_buffer.buffer = (caddr_t)buffer; cpipe->pipe_buffer.size = size; cpipe->pipe_buffer.in = 0; cpipe->pipe_buffer.out = 0; cpipe->pipe_buffer.cnt = 0; OSAddAtomic(1, &amountpipes); OSAddAtomic(cpipe->pipe_buffer.size, &amountpipekva); return (0); }