[前][次][番号順一覧][スレッド一覧]

ruby-changes:7378

From: usa <ko1@a...>
Date: Thu, 28 Aug 2008 21:49:59 +0900 (JST)
Subject: [ruby-changes:7378] Ruby:r18897 (trunk): * win32/win32.c, include/ruby/win32.h (rb_w32_open): overlapped file

usa	2008-08-28 21:46:58 +0900 (Thu, 28 Aug 2008)

  New Revision: 18897

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=18897

  Log:
    * win32/win32.c, include/ruby/win32.h (rb_w32_open): overlapped file
      I/O support.
    
    * win32/win32.c, include/ruby/win32.h (rb_w32_pipe): overlapped pipe
      I/O support.
    
    * wn32/win32.c (rb_w32_read, rb_w32_write): overlapped I/O support to
      enable canceling I/O.
    
    * thread_win32.c (ubf_handle): remove workaround.

  Modified files:
    trunk/ChangeLog
    trunk/include/ruby/win32.h
    trunk/thread_win32.c
    trunk/win32/win32.c

Index: thread_win32.c
===================================================================
--- thread_win32.c	(revision 18896)
+++ thread_win32.c	(revision 18897)
@@ -524,18 +524,9 @@
 ubf_handle(void *ptr)
 {
     typedef BOOL (WINAPI *cancel_io_func_t)(HANDLE);
-    static cancel_io_func_t cancel_func = NULL;
     rb_thread_t *th = (rb_thread_t *)ptr;
     thread_debug("ubf_handle: %p\n", th);
 
-    if (!cancel_func) {
-	cancel_func = (cancel_io_func_t)GetProcAddress(GetModuleHandle("kernel32"), "CancelSynchronousIo");
-	if (!cancel_func)
-	    cancel_func = (cancel_io_func_t)-1;
-    }
-    if (cancel_func != (cancel_io_func_t)-1)
-	cancel_func((HANDLE)th->thread_id);
-
     w32_set_event(th->native_thread_data.interrupt_event);
 }
 
Index: include/ruby/win32.h
===================================================================
--- include/ruby/win32.h	(revision 18896)
+++ include/ruby/win32.h	(revision 18897)
@@ -134,7 +134,8 @@
 #define utime(_p, _t)		rb_w32_utime(_p, _t)
 #define lseek(_f, _o, _w)	_lseeki64(_f, _o, _w)
 
-#define pipe(p)			_pipe(p, 65536L, _O_NOINHERIT)
+#define pipe(p)			rb_w32_pipe(p)
+#define open			rb_w32_open
 #define close(h)		rb_w32_close(h)
 #define fclose(f)		rb_w32_fclose(f)
 #define read(f, b, s)		rb_w32_read(f, b, s)
@@ -543,8 +544,10 @@
 int  rb_w32_sleep(unsigned long msec);
 int  rb_w32_putc(int, FILE*);
 int  rb_w32_getc(FILE*);
+int  rb_w32_open(const char *, int, ...);
 int  rb_w32_close(int);
 int  rb_w32_fclose(FILE*);
+int  rb_w32_pipe(int[2]);
 size_t rb_w32_read(int, void *, size_t);
 size_t rb_w32_write(int, const void *, size_t);
 int  rb_w32_utime(const char *, const struct utimbuf *);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 18896)
+++ ChangeLog	(revision 18897)
@@ -1,3 +1,16 @@
+Thu Aug 28 21:43:05 2008  NAKAMURA Usaku  <usa@r...>
+
+	* win32/win32.c, include/ruby/win32.h (rb_w32_open): overlapped file
+	  I/O support.
+
+	* win32/win32.c, include/ruby/win32.h (rb_w32_pipe): overlapped pipe
+	  I/O support.
+
+	* wn32/win32.c (rb_w32_read, rb_w32_write): overlapped I/O support to
+	  enable canceling I/O.
+
+	* thread_win32.c (ubf_handle): remove workaround.
+
 Thu Aug 28 20:22:49 2008  Yukihiro Matsumoto  <matz@r...>
 
 	* vm_insnhelper.c (vm_yield_setup_args): object with to_ary should
Index: win32/win32.c
===================================================================
--- win32/win32.c	(revision 18896)
+++ win32/win32.c	(revision 18897)
@@ -1736,6 +1736,8 @@
 #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
 
 #define FOPEN			0x01	/* file handle open */
+#define FEOFLAG			0x02	/* end of file has been encountered */
+#define FPIPE			0x08	/* file handle refers to a pipe */
 #define FNOINHERIT		0x10	/* file handle opened O_NOINHERIT */
 #define FAPPEND			0x20	/* file handle opened O_APPEND */
 #define FDEV			0x40	/* file handle refers to device */
@@ -3995,6 +3997,167 @@
 }
 
 int
+rb_w32_open(const char *file, int oflag, ...)
+{
+    char flags = 0;
+    int fd;
+    DWORD access;
+    DWORD create;
+    DWORD attr = FILE_ATTRIBUTE_NORMAL;
+    SECURITY_ATTRIBUTES sec;
+    HANDLE h;
+
+    sec.nLength = sizeof(sec);
+    sec.lpSecurityDescriptor = NULL;
+    if (oflag & O_NOINHERIT) {
+	sec.bInheritHandle = FALSE;
+	flags |= FNOINHERIT;
+    }
+    else {
+	sec.bInheritHandle = TRUE;
+    }
+    oflag &= ~O_NOINHERIT;
+
+    /* always open with binary mode */
+    oflag &= ~(O_BINARY | O_TEXT);
+
+    switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
+      case O_RDWR:
+	access = GENERIC_READ | GENERIC_WRITE;
+	break;
+      case O_RDONLY:
+	access = GENERIC_READ;
+	break;
+      case O_WRONLY:
+	access = GENERIC_WRITE;
+	break;
+      default:
+	errno = EINVAL;
+	return -1;
+    }
+    oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
+
+    switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
+      case O_CREAT:
+	create = OPEN_ALWAYS;
+	break;
+      case 0:
+      case O_EXCL:
+	create = OPEN_EXISTING;
+	break;
+      case O_CREAT | O_EXCL:
+      case O_CREAT | O_EXCL | O_TRUNC:
+	create = CREATE_NEW;
+	break;
+      case O_TRUNC:
+      case O_TRUNC | O_EXCL:
+	create = TRUNCATE_EXISTING;
+	break;
+      case O_CREAT | O_TRUNC:
+	create = CREATE_ALWAYS;
+	break;
+      default:
+	errno = EINVAL;
+	return -1;
+    }
+    if (oflag & O_CREAT) {
+	va_list arg;
+	int pmode;
+	va_start(arg, oflag);
+	pmode = va_arg(arg, int);
+	va_end(arg);
+	/* TODO: we need to check umask here, but it's not exported... */
+	if (!(pmode & S_IWRITE))
+	    attr = FILE_ATTRIBUTE_READONLY;
+    }
+    oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
+
+    if (oflag & O_TEMPORARY) {
+	attr |= FILE_FLAG_DELETE_ON_CLOSE;
+	access |= DELETE;
+    }
+    oflag &= ~O_TEMPORARY;
+
+    if (oflag & _O_SHORT_LIVED)
+	attr |= FILE_ATTRIBUTE_TEMPORARY;
+    oflag &= ~_O_SHORT_LIVED;
+
+    switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
+      case 0:
+	break;
+      case O_SEQUENTIAL:
+	attr |= FILE_FLAG_SEQUENTIAL_SCAN;
+	break;
+      case O_RANDOM:
+	attr |= FILE_FLAG_RANDOM_ACCESS;
+	break;
+      default:
+	errno = EINVAL;
+	return -1;
+    }
+    oflag &= ~(O_SEQUENTIAL | O_RANDOM);
+
+    if (oflag & ~O_APPEND) {
+	errno = EINVAL;
+	return -1;
+    }
+
+    /* allocate a C Runtime file handle */
+    RUBY_CRITICAL({
+	h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
+	fd = _open_osfhandle((long)h, 0);
+	CloseHandle(h);
+    });
+    if (fd == -1) {
+	errno = EMFILE;
+	return -1;
+    }
+    RUBY_CRITICAL({
+	MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
+	_set_osfhnd(fd, (long)INVALID_HANDLE_VALUE);
+	_set_osflags(fd, 0);
+
+	/* open with FILE_FLAG_OVERLAPPED if have CancelIo */
+	if (cancel_io)
+	    attr |= FILE_FLAG_OVERLAPPED;
+	h = CreateFile(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
+		       create, attr, NULL);
+	if (h == INVALID_HANDLE_VALUE) {
+	    errno = map_errno(GetLastError());
+	    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	    fd = -1;
+	    goto quit;
+	}
+
+	switch (GetFileType(h)) {
+	  case FILE_TYPE_CHAR:
+	    flags |= FDEV;
+	    break;
+	  case FILE_TYPE_PIPE:
+	    flags |= FPIPE;
+	    break;
+	  case FILE_TYPE_UNKNOWN:
+	    errno = map_errno(GetLastError());
+	    CloseHandle(h);
+	    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	    fd = -1;
+	    goto quit;
+	}
+	if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
+	    flags |= FAPPEND;
+
+	_set_osfhnd(fd, (long)h);
+	_osfile(fd) = flags | FOPEN;
+
+	MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+      quit:
+	;
+    });
+
+    return fd;
+}
+
+int
 rb_w32_fclose(FILE *fp)
 {
     int fd = fileno(fp);
@@ -4017,6 +4180,98 @@
 }
 
 int
+rb_w32_pipe(int fds[2])
+{
+    static DWORD serial = 0;
+    char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
+    char *p;
+    SECURITY_ATTRIBUTES sec;
+    HANDLE hRead, hWrite, h;
+    int fdRead, fdWrite;
+    int ret;
+
+    /* if doesn't have CancelIo, use default pipe function */
+    if (!cancel_io)
+	return _pipe(fds, 65536L, _O_NOINHERIT);
+
+    p = strchr(name, '0');
+    snprintf(p, strlen(p) + 1, "%x-%x", rb_w32_getpid(), serial++);
+
+    sec.nLength = sizeof(sec);
+    sec.lpSecurityDescriptor = NULL;
+    sec.bInheritHandle = FALSE;
+
+    RUBY_CRITICAL({
+	hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+				0, 2, 65536, 65536, 0, &sec);
+    });
+    if (hRead == INVALID_HANDLE_VALUE) {
+	DWORD err = GetLastError();
+	if (err == ERROR_PIPE_BUSY)
+	    errno = EMFILE;
+	else
+	    errno = map_errno(GetLastError());
+	return -1;
+    }
+
+    RUBY_CRITICAL({
+	hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
+			    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+    });
+    if (hWrite == INVALID_HANDLE_VALUE) {
+	errno = map_errno(GetLastError());
+	CloseHandle(hRead);
+	return -1;
+    }
+
+    RUBY_CRITICAL(do {
+	ret = 0;
+	h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
+	fdRead = _open_osfhandle((long)h, 0);
+	CloseHandle(h);
+	if (fdRead == -1) {
+	    errno = EMFILE;
+	    CloseHandle(hWrite);
+	    CloseHandle(hRead);
+	    ret = -1;
+	    break;
+	}
+
+	MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
+	_set_osfhnd(fdRead, (long)hRead);
+	_set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
+	MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
+    } while (0));
+    if (ret)
+	return ret;
+
+    RUBY_CRITICAL(do {
+	h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
+	fdWrite = _open_osfhandle((long)h, 0);
+	CloseHandle(h);
+	if (fdWrite == -1) {
+	    errno = EMFILE;
+	    CloseHandle(hWrite);
+	    ret = -1;
+	    break;
+	}
+	MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
+	_set_osfhnd(fdWrite, (long)hWrite);
+	_set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
+	MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
+    } while (0));
+    if (ret) {
+	rb_w32_close(fdRead);
+	return ret;
+    }
+
+    fds[0] = fdRead;
+    fds[1] = fdWrite;
+
+    return 0;
+}
+
+int
 rb_w32_close(int fd)
 {
     SOCKET sock = TO_SOCKET(fd);
@@ -4045,11 +4300,107 @@
 rb_w32_read(int fd, void *buf, size_t size)
 {
     SOCKET sock = TO_SOCKET(fd);
+    DWORD read;
+    DWORD wait;
+    DWORD err;
+    OVERLAPPED ol, *pol = NULL;
 
-    if (!is_socket(sock))
-	return read(fd, buf, size);
-    else
+    if (is_socket(sock))
 	return rb_w32_recv(fd, buf, size, 0);
+
+    if (!(_osfile(fd) & FOPEN)) {
+	errno = EBADF;
+	return -1;
+    }
+
+    MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
+
+    if (!size || _osfile(fd) & FEOFLAG) {
+	MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	return 0;
+    }
+
+    /* if have cancel_io, use Overlapped I/O */
+    if (cancel_io) {
+	memset(&ol, 0, sizeof(ol));
+	if (!(_osfile(fd) & (FDEV | FPIPE))) {
+	    LONG high = 0;
+	    DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high,
+				       FILE_CURRENT);
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+	    if (low == INVALID_SET_FILE_POINTER) {
+		errno = map_errno(GetLastError());
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return -1;
+	    }
+	    ol.Offset = low;
+	    ol.OffsetHigh = high;
+	}
+	ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+	if (!ol.hEvent) {
+	    errno = map_errno(GetLastError());
+	    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	    return -1;
+	}
+
+	pol = &ol;
+    }
+
+    if (!ReadFile((HANDLE)_osfhnd(fd), buf, size, &read, pol)) {
+	err = GetLastError();
+	if (err != ERROR_IO_PENDING) {
+	    if (err == ERROR_ACCESS_DENIED)
+		errno = EBADF;
+	    else if (err == ERROR_BROKEN_PIPE) {
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return 0;
+	    }
+	    else
+		errno = map_errno(err);
+
+	    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	    return -1;
+	}
+
+	if (pol) {
+	    wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
+	    if (wait != WAIT_OBJECT_0) {
+		if (errno != EINTR)
+		    errno = map_errno(GetLastError());
+		CloseHandle(ol.hEvent);
+		cancel_io((HANDLE)_osfhnd(fd));
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return -1;
+	    }
+
+	    if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
+		(err = GetLastError()) != ERROR_HANDLE_EOF) {
+		errno = map_errno(err);
+		CloseHandle(ol.hEvent);
+		cancel_io((HANDLE)_osfhnd(fd));
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return -1;
+	    }
+	}
+    }
+
+    if (pol) {
+	CloseHandle(ol.hEvent);
+
+	if (!(_osfile(fd) & (FDEV | FPIPE))) {
+	    LONG high = ol.OffsetHigh;
+	    LONG low = ol.Offset + read;
+	    if (low < ol.Offset)
+		++high;
+	    SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
+	}
+    }
+
+    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+
+    return read;
 }
 
 #undef write
@@ -4057,15 +4408,103 @@
 rb_w32_write(int fd, const void *buf, size_t size)
 {
     SOCKET sock = TO_SOCKET(fd);
+    DWORD written;
+    DWORD wait;
+    DWORD err;
+    OVERLAPPED ol, *pol = NULL;
 
-    if (!is_socket(sock)) {
-	size_t ret = write(fd, buf, size);
-	if ((int)ret < 0 && errno == EINVAL)
+    if (is_socket(sock))
+	return rb_w32_send(fd, buf, size, 0);
+
+    if (!(_osfile(fd) & FOPEN)) {
+	errno = EBADF;
+	return -1;
+    }
+
+    MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
+
+    if (!size || _osfile(fd) & FEOFLAG) {
+	MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	return 0;
+    }
+
+    /* if have cancel_io, use Overlapped I/O */
+    if (cancel_io) {
+	memset(&ol, 0, sizeof(ol));
+	if (!(_osfile(fd) & (FDEV | FPIPE))) {
+	    LONG high = 0;
+	    DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high,
+				       FILE_CURRENT);
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+	    if (low == INVALID_SET_FILE_POINTER) {
+		errno = map_errno(GetLastError());
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return -1;
+	    }
+	    ol.Offset = low;
+	    ol.OffsetHigh = high;
+	}
+	ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+	if (!ol.hEvent) {
 	    errno = map_errno(GetLastError());
-	return ret;
+	    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	    return -1;
+	}
+
+	pol = &ol;
     }
-    else
-	return rb_w32_send(fd, buf, size, 0);
+
+    if (!WriteFile((HANDLE)_osfhnd(fd), buf, size, &written, pol)) {
+	err = GetLastError();
+	if (err != ERROR_IO_PENDING) {
+	    if (err == ERROR_ACCESS_DENIED)
+		errno = EBADF;
+	    else
+		errno = map_errno(err);
+
+	    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+	    return -1;
+	}
+
+	if (pol) {
+	    wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
+	    if (wait != WAIT_OBJECT_0) {
+		if (errno != EINTR)
+		    errno = map_errno(GetLastError());
+		CloseHandle(ol.hEvent);
+		cancel_io((HANDLE)_osfhnd(fd));
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return -1;
+	    }
+
+	    if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
+				     TRUE)) {
+		errno = map_errno(err);
+		CloseHandle(ol.hEvent);
+		cancel_io((HANDLE)_osfhnd(fd));
+		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+		return -1;
+	    }
+	}
+    }
+
+    if (pol) {
+	CloseHandle(ol.hEvent);
+
+	if (!(_osfile(fd) & (FDEV | FPIPE))) {
+	    LONG high = ol.OffsetHigh;
+	    LONG low = ol.Offset + written;
+	    if (low < ol.Offset)
+		++high;
+	    SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
+	}
+    }
+
+    MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+
+    return written;
 }
 
 static int

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]