about summary refs log tree commit diff
path: root/src/stdio/__stdio_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdio/__stdio_write.c')
-rw-r--r--src/stdio/__stdio_write.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/src/stdio/__stdio_write.c b/src/stdio/__stdio_write.c
index 63d9c858..dd97cf68 100644
--- a/src/stdio/__stdio_write.c
+++ b/src/stdio/__stdio_write.c
@@ -1,4 +1,11 @@
 #include "stdio_impl.h"
+#include <pthread.h>
+
+static void cleanup(void *p)
+{
+	FILE *f = p;
+	if (!f->lockcount) __unlockfile(f);
+}
 
 size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
 {
@@ -10,10 +17,14 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
 	size_t rem = iov[0].iov_len + iov[1].iov_len;
 	int iovcnt = 2;
 	ssize_t cnt;
-	f->wpos = f->wbase;
 	for (;;) {
-		cnt = syscall(SYS_writev, f->fd, iov, iovcnt);
-		if (cnt == rem) return len;
+		pthread_cleanup_push(cleanup, f);
+		cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt);
+		pthread_cleanup_pop(0);
+		if (cnt == rem) {
+			f->wpos = f->wbase = f->buf;
+			return len;
+		}
 		if (cnt < 0) {
 			f->wpos = f->wbase = f->wend = 0;
 			f->flags |= F_ERR;
@@ -21,8 +32,11 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
 		}
 		rem -= cnt;
 		if (cnt > iov[0].iov_len) {
+			f->wpos = f->wbase = f->buf;
 			cnt -= iov[0].iov_len;
 			iov++; iovcnt--;
+		} else if (iovcnt == 2) {
+			f->wbase += cnt;
 		}
 		iov[0].iov_base = (char *)iov[0].iov_base + cnt;
 		iov[0].iov_len -= cnt;