Explorar o código

make stdio open, read, and write operations cancellation points

it should be noted that only the actual underlying buffer flush and
fill operations are cancellable, not reads from or writes to the
buffer. this behavior is compatible with POSIX, which makes all
cancellation points in stdio optional, and it achieves the goal of
allowing cancellation of a thread that's "stuck" on IO (due to a
non-responsive socket/pipe peer, slow/stuck hardware, etc.) without
imposing any measurable performance cost.
Rich Felker %!s(int64=13) %!d(string=hai) anos
pai
achega
5816592389
Modificáronse 3 ficheiros con 28 adicións e 5 borrados
  1. 10 1
      src/stdio/__stdio_read.c
  2. 17 3
      src/stdio/__stdio_write.c
  3. 1 1
      src/stdio/fopen.c

+ 10 - 1
src/stdio/__stdio_read.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_read(FILE *f, unsigned char *buf, size_t len)
 {
@@ -8,7 +15,9 @@ size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
 	};
 	ssize_t cnt;
 
-	cnt = syscall(SYS_readv, f->fd, iov, 2);
+	pthread_cleanup_push(cleanup, f);
+	cnt = syscall_cp(SYS_readv, f->fd, iov, 2);
+	pthread_cleanup_pop(0);
 	if (cnt <= 0) {
 		f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt);
 		f->rpos = f->rend = 0;

+ 17 - 3
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;

+ 1 - 1
src/stdio/fopen.c

@@ -21,7 +21,7 @@ FILE *fopen(const char *filename, const char *mode)
 	if (*mode == 'w') flags |= O_TRUNC;
 	if (*mode == 'a') flags |= O_APPEND;
 
-	fd = syscall(SYS_open, filename, flags|O_LARGEFILE, 0666);
+	fd = syscall_cp(SYS_open, filename, flags|O_LARGEFILE, 0666);
 	if (fd < 0) return 0;
 
 	f = __fdopen(fd, mode);