Browse Source

faux.buf: faux_buf_dwrite_block(). Untested

Serj Kalichev 3 years ago
parent
commit
7dcd16b3ff
1 changed files with 168 additions and 31 deletions
  1. 168 31
      faux/buf/buf.c

+ 168 - 31
faux/buf/buf.c

@@ -212,37 +212,6 @@ static faux_list_node_t *faux_buf_alloc_chunk(faux_buf_t *buf)
 }
 
 
-/*
-static bool_t faux_buf_rm_trailing_empty_chunks(faux_buf_t *buf)
-{
-	faux_list_node_t *node = NULL;
-
-	assert(buf);
-	if (!buf)
-		return BOOL_FALSE;
-	assert(buf->list);
-	if (!buf->list)
-		return BOOL_FALSE;
-
-	if (faux_buf_chunk_num(buf) == 0)
-		return BOOL_TRUE; // Empty list
-
-
-	while ((node = faux_list_tail(buf->list)) != buf->wchunk)
-		faux_list_del(buf->list, node);
-	if (buf->wchunk &&
-		((buf->wpos == 0) || // Empty chunk
-		((faux_buf_chunk_num(buf) == 1) && (buf->rpos == buf->wpos)))
-		) {
-		faux_list_del(buf->list, buf->wchunk);
-		buf->wchunk = NULL;
-		buf->wpos = buf->chunk_size;
-	}
-
-	return BOOL_TRUE;
-}
-*/
-
 static bool_t faux_buf_will_be_overflow(const faux_buf_t *buf, size_t add_len)
 {
 	assert(buf);
@@ -488,3 +457,171 @@ ssize_t faux_buf_dread_unblock(faux_buf_t *buf, size_t really_readed,
 
 	return really_readed;
 }
+
+
+ssize_t faux_buf_dwrite_block(faux_buf_t *buf, size_t len,
+	struct iovec **iov_out, size_t *iov_num_out)
+{
+	size_t vec_entries_num = 0;
+	struct iovec *iov = NULL;
+	unsigned int i = 0;
+	faux_list_node_t *iter = NULL;
+	faux_list_node_t *first_node = NULL;
+	size_t avail = 0;
+	size_t must_be_write = len;
+
+	assert(buf);
+	if (!buf)
+		return -1;
+	assert(iov_out);
+	if (!iov_out)
+		return -1;
+	assert(iov_num_out);
+	if (!iov_num_out)
+		return -1;
+
+	// Don't use already blocked buffer
+	if (faux_buf_is_wblocked(buf))
+		return -1;
+
+	// It will be overflow after writing
+	if (faux_buf_will_be_overflow(buf, len))
+		return -1;
+
+	// Nothing to block
+	if (0 == len) {
+		*iov_out = NULL;
+		*iov_num_out = 0;
+		return 0;
+	}
+
+	// Save wchunk
+	buf->wchunk = faux_list_tail(buf->list); // Can be NULL
+	buf->wblocked = len;
+
+	// Calculate number of struct iovec entries
+	avail = faux_buf_wavail(buf);
+	if (avail > 0)
+		vec_entries_num += 1;
+	else
+		buf->wpos = 0; // New chunk will be created when avail == 0
+	if (avail < len) {
+		size_t i = 0;
+		size_t new_chunk_num = 0;
+		size_t l = len - avail; // length wo first chunk
+		new_chunk_num += l / buf->chunk_size;
+		if ((l % buf->chunk_size) > 0)
+			new_chunk_num++;
+		vec_entries_num += new_chunk_num;
+		for (i = 0; i < new_chunk_num; i++)
+			faux_buf_alloc_chunk(buf);
+	}
+	iov = faux_zmalloc(vec_entries_num * sizeof(*iov));
+
+	// Iterate chunks
+	if ((iter = buf->wchunk) == NULL)
+		iter = faux_list_head(buf->list);
+	first_node = iter;
+	while ((must_be_write > 0) && (iter)) {
+		char *p = (char *)faux_list_data(iter);
+		size_t l = buf->chunk_size;
+		size_t p_len = 0;
+
+		if (iter == first_node) {
+			p += buf->wpos;
+			l = faux_buf_wavail(buf);
+		}
+		p_len = (must_be_write < l) ? must_be_write : l;
+
+		iov[i].iov_base = p;
+		iov[i].iov_len = p_len;
+		i++;
+		must_be_write -= p_len;
+		iter = faux_list_next_node(iter);
+	}
+
+	*iov_out = iov;
+	*iov_num_out = vec_entries_num;
+
+	return len;
+}
+
+
+/*
+static bool_t faux_buf_rm_trailing_empty_chunks(faux_buf_t *buf)
+{
+	faux_list_node_t *node = NULL;
+
+	assert(buf);
+	if (!buf)
+		return BOOL_FALSE;
+	assert(buf->list);
+	if (!buf->list)
+		return BOOL_FALSE;
+
+	if (faux_buf_chunk_num(buf) == 0)
+		return BOOL_TRUE; // Empty list
+
+
+	while ((node = faux_list_tail(buf->list)) != buf->wchunk)
+		faux_list_del(buf->list, node);
+	if (buf->wchunk &&
+		((buf->wpos == 0) || // Empty chunk
+		((faux_buf_chunk_num(buf) == 1) && (buf->rpos == buf->wpos)))
+		) {
+		faux_list_del(buf->list, buf->wchunk);
+		buf->wchunk = NULL;
+		buf->wpos = buf->chunk_size;
+	}
+
+	return BOOL_TRUE;
+}
+*/
+
+
+ssize_t faux_buf_dwrite_unblock(faux_buf_t *buf, size_t really_readed,
+	struct iovec *iov)
+{
+	size_t must_be_read = 0;
+
+	assert(buf);
+	if (!buf)
+		return -1;
+	if (0 == really_readed)
+		return -1;
+
+	// Can't unblock non-blocked buffer
+	if (!faux_buf_is_rblocked(buf))
+		return -1;
+
+	if (buf->rblocked < really_readed)
+		return -1; // Something went wrong
+	if (buf->len < really_readed)
+		return -1; // Something went wrong
+
+	must_be_read = really_readed;
+	while (must_be_read > 0) {
+		size_t avail = faux_buf_ravail(buf);
+		ssize_t data_to_rm = (must_be_read < avail) ? must_be_read : avail;
+
+		buf->len -= data_to_rm;
+		buf->rpos += data_to_rm;
+		must_be_read -= data_to_rm;
+
+		// Current chunk was fully readed. So remove it from list.
+		if ((buf->rpos == buf->chunk_size) ||
+			((faux_buf_chunk_num(buf) == 1) && (buf->rpos == buf->wpos))
+			) {
+			buf->rpos = 0; // 0 position within next chunk
+			faux_list_del(buf->list, faux_list_head(buf->list));
+		}
+		if (faux_buf_chunk_num(buf) == 0)
+			buf->wpos = buf->chunk_size;
+	}
+
+	// Unblock whole buffer. Not 'really readed' bytes only
+	buf->rblocked = 0;
+	faux_free(iov);
+
+	return really_readed;
+}