summaryrefslogtreecommitdiff
path: root/libpipe
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1995-09-07 16:24:25 +0000
committerMiles Bader <miles@gnu.org>1995-09-07 16:24:25 +0000
commit4bc21e54c2270eba7243ce06399da88e9d9b47de (patch)
tree185088f84635d199878fd0bce6e208cad2266757 /libpipe
parentf16d26174389278cb478129ead8e476a00f23046 (diff)
(packet_read): Don't leave PACKET in a fucked up state when it's vm_allocate'd
but doesn't a page-multiple amount of data and we're reading everything.
Diffstat (limited to 'libpipe')
-rw-r--r--libpipe/pq.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/libpipe/pq.c b/libpipe/pq.c
index bd611155..31937573 100644
--- a/libpipe/pq.c
+++ b/libpipe/pq.c
@@ -357,27 +357,44 @@ packet_read (struct packet *packet,
if (packet->buf_vm_alloced && amount > vm_page_size)
/* We can return memory from BUF directly without copying. */
{
+ char *buf = packet->buf;
+ char *end = packet->buf_end;
+
+ /* Return the buffer directly. */
*data = start;
- if (start + amount < packet->buf_end)
+
+ if (buf > start)
+ /* BUF_START has been advanced past the start of the buffer
+ (perhaps by a series of small reads); as we're going to assume
+ everything before START is gone, make sure we deallocate any
+ memory on pages before those we return to the user. */
+ {
+ char *first_page = (char *)trunc_page (start);
+ if (first_page > buf)
+ vm_deallocate (mach_task_self (),
+ (vm_address_t)buf, first_page - buf);
+ }
+
+ if (start + amount < end)
/* Since returning a partial page actually means returning the
whole page, we have to be careful not to grab past the page
boundary before the end of the data we want, unless the rest
of the page is unimportant. */
- {
- amount = (char *)trunc_page (start + amount) - start;
- packet->buf_start = (char *)round_page (start + amount);
- }
- else
- /* As we're at the end of the buffer, we don't care about
- BUF_START remaining page-aligned (the buffer size will be
- zero anyway), and this way we ensure that BUF_START doesn't
- go past BUF_END (which causes all sorts of fun). */
- packet->buf_start = start + amount;
+ amount = (char *)trunc_page (start + amount) - start;
+
+ /* Advance the read point. */
+ start = (char *)round_page (start + amount);
+
+ if (start > end)
+ /* Make sure BUF_START is never beyond BUF_END (page-aligning the
+ new BUF_START may have move it past). */
+ packet->buf_end = start;
/* We've actually consumed the memory at the start of BUF, so
adjust it and BUF_LEN to reflect this. */
- packet->buf_len -= (packet->buf_start - packet->buf);
- packet->buf = packet->buf_start;
+ packet->buf = start;
+ packet->buf_start = start;
+ packet->buf_len -= start - buf;
}
else
/* Just copy the data the old fashioned way.... */