summaryrefslogtreecommitdiff
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;