Browse Source

async: Fix some async bugs. Unfinished test for async

Serj Kalichev 3 years ago
parent
commit
bf13b2c000

+ 4 - 0
faux/async/Makefile.am

@@ -1,3 +1,7 @@
 libfaux_la_SOURCES += \
 	faux/async/async.c \
 	faux/async/private.h
+
+if TESTC
+libfaux_la_SOURCES += faux/async/testc_async.c
+endif

+ 36 - 8
faux/async/async.c

@@ -241,7 +241,7 @@ ssize_t faux_async_write(faux_async_t *async, void *data, size_t len)
 
 		// Copy data
 		chunk_ptr = faux_list_data(faux_list_tail(async->o_list));
-		copy_len = (len < (size_t)bytes_free) ? len : (size_t)bytes_free;
+		copy_len = (data_left < (size_t)bytes_free) ? data_left : (size_t)bytes_free;
 		memcpy(chunk_ptr + async->o_wpos, data + len - data_left,
 			copy_len);
 		async->o_wpos += copy_len;
@@ -278,6 +278,8 @@ static ssize_t data_avail(faux_list_t *list, size_t rpos, size_t wpos)
 
 ssize_t faux_async_out(faux_async_t *async)
 {
+	ssize_t total_written = 0;
+
 	assert(async);
 	if (!async)
 		return -1;
@@ -287,29 +289,55 @@ ssize_t faux_async_out(faux_async_t *async)
 		char *chunk_ptr = NULL;
 		ssize_t data_to_write = 0;
 		ssize_t bytes_written = 0;
+		bool_t postpone = BOOL_FALSE;
 
 		node = faux_list_head(async->o_list);
+		if (!node) // List is empty while o_size > 0
+			return -1;
 		chunk_ptr = faux_list_data(faux_list_head(async->o_list));
 		data_to_write = data_avail(async->o_list,
 			async->o_rpos, async->o_wpos);
-		if (data_to_write < 0)
+		if (data_to_write <= 0) // Strange case
 			return -1;
+
 		bytes_written = write(async->fd, chunk_ptr + async->o_rpos,
 			data_to_write);
-		if (bytes_written <= 0)
-			return bytes_written;
-		async->o_size -= bytes_written;
-		if (bytes_written != data_to_write) {
+		if (bytes_written > 0) {
+			async->o_size -= bytes_written;
+			total_written += bytes_written;
+		}
+
+		if (bytes_written < 0) {
+			if ( // Something went wrong
+				(errno != EINTR) &&
+				(errno != EAGAIN) &&
+				(errno != EWOULDBLOCK)
+			)
+				return -1;
+			// Postpone next read
+			postpone = BOOL_TRUE;
+
+		// Not whole data block was written
+		} else if (bytes_written != data_to_write) {
 			async->o_rpos += bytes_written;
+			// Postpone next read
+			postpone = BOOL_TRUE;
+		}
+
+		// Postponed
+		if (postpone) {
 			// Execute callback
 			if (async->stall_cb)
 				async->stall_cb(async, async->o_size,
 					async->stall_udata);
-			return async->o_size;
+			break;
 		}
+
+		// Not postponed. Current chunk was fully written. So
+		// remove it from list.
 		async->o_rpos = 0;
 		faux_list_del(async->o_list, node);
 	}
 
-	return 0;
+	return total_written;
 }

+ 75 - 0
faux/async/testc_async.c

@@ -0,0 +1,75 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "faux/str.h"
+#include "faux/async.h"
+#include "faux/testc_helpers.h"
+
+static bool_t stall_cb(faux_async_t *async, size_t len, void *user_data)
+{
+	bool_t *o_flag = (bool_t *)user_data;
+
+	if (!o_flag)
+		return BOOL_FALSE;
+	*o_flag = BOOL_TRUE;
+	printf("Stall callback %lu\n", len);
+
+	async = async;
+
+	return BOOL_TRUE;
+}
+
+int testc_faux_async(void)
+{
+	const size_t len = 9000000l;
+	char *src_file = NULL;
+	int ret = -1; // Pessimistic return value
+	char *src_fn = NULL;
+	char *dst_fn = NULL;
+	unsigned int i = 0;
+	unsigned char counter = 0;
+	int fd = -1;
+	faux_async_t *out = NULL;
+	bool_t o_flag = BOOL_FALSE;
+
+	// Prepare files
+	src_file = faux_zmalloc(len);
+	for (i = 0; i < len; i++) {
+		src_file[i] = counter;
+		counter++;
+	}
+	src_fn = faux_testc_tmpfile_deploy(src_file, len);
+
+	dst_fn = faux_str_sprintf("%s/dst", getenv(FAUX_TESTC_TMPDIR_ENV));
+	fd = open(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+	out = faux_async_new(fd);
+	faux_async_set_stall_cb(out, stall_cb, &o_flag);
+	faux_async_set_overflow(out, len + 1);
+	if (faux_async_write(out, src_file, len) < 0) {
+		fprintf(stderr, "faux_async_write() error\n");
+		goto parse_error;
+	}
+
+	while (o_flag) {
+		o_flag = BOOL_FALSE;
+		faux_async_out(out);
+	}
+
+	if (faux_testc_file_cmp(dst_fn, src_fn) != 0) {
+		fprintf(stderr, "Destination file %s is not equal to source %s\n",
+			dst_fn, src_fn);
+		goto parse_error;
+	}
+
+	ret = 0; // success
+
+parse_error:
+	faux_async_free(out);
+	faux_str_free(dst_fn);
+	faux_str_free(src_fn);
+
+	return ret;
+}

+ 3 - 3
faux/base/testc_base.c

@@ -32,13 +32,13 @@ int testc_faux_filesize(void)
 
 	// Create files and dirs
 	mkdir(dn1, 0777);
-	if ((r = faux_testc_file_deploy(fn1, fd1)) < 0)
+	if ((r = faux_testc_file_deploy_str(fn1, fd1)) < 0)
 		goto err;
 	etalon_filesize += r;
-	if ((r = faux_testc_file_deploy(fn2, fd2)) < 0)
+	if ((r = faux_testc_file_deploy_str(fn2, fd2)) < 0)
 		goto err;
 	etalon_filesize += r;
-	if ((r = faux_testc_file_deploy(fn3, fd3)) < 0)
+	if ((r = faux_testc_file_deploy_str(fn3, fd3)) < 0)
 		goto err;
 	etalon_filesize += r;
 

+ 0 - 1
faux/file/file.c

@@ -109,7 +109,6 @@ bool_t faux_file_close(faux_file_t *f)
 {
 	int fd = -1;
 
-	assert(f);
 	if (!f)
 		return BOOL_FALSE;
 

+ 2 - 2
faux/ini/testc_ini.c

@@ -53,8 +53,8 @@ int testc_faux_ini_parse_file(void)
 	char *etalon_fn = NULL;
 
 	// Prepare files
-	src_fn = faux_testc_tmpfile_deploy(src_file);
-	etalon_fn = faux_testc_tmpfile_deploy(etalon_file);
+	src_fn = faux_testc_tmpfile_deploy_str(src_file);
+	etalon_fn = faux_testc_tmpfile_deploy_str(etalon_file);
 	dst_fn = faux_str_sprintf("%s/dst", getenv(FAUX_TESTC_TMPDIR_ENV));
 
 	ini = faux_ini_new();

+ 2 - 0
faux/testc_module/testc_module.c

@@ -41,6 +41,8 @@ const char *testc_module[][2] = {
 	// vec
 	{"testc_faux_vec", "Complex test of variable length vector"},
 
+	// async
+	{"testc_faux_async", "Async read/write operations"},
 
 	// End of list
 	{NULL, NULL}