1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18897 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
usa 2008-08-28 12:46:58 +00:00
parent cf6334e1cb
commit 3c8dca55c4
4 changed files with 466 additions and 20 deletions

View file

@ -1,3 +1,16 @@
Thu Aug 28 21:43:05 2008 NAKAMURA Usaku <usa@ruby-lang.org>
* 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@ruby-lang.org>
* vm_insnhelper.c (vm_yield_setup_args): object with to_ary should

View file

@ -134,7 +134,8 @@ extern DWORD rb_w32_osid(void);
#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 @@ HANDLE GetCurrentThreadHandle(void);
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 *);

View file

@ -524,18 +524,9 @@ static void
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);
}

View file

@ -1736,6 +1736,8 @@ set_pioinfo_extra(void)
#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 */
@ -3994,6 +3996,167 @@ rb_w32_getppid(void)
return ppid;
}
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)
{
@ -4016,6 +4179,98 @@ rb_w32_fclose(FILE *fp)
return 0;
}
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)
{
@ -4045,11 +4300,107 @@ size_t
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 @@ size_t
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)
errno = map_errno(GetLastError());
return ret;
}
else
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());
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
return -1;
}
pol = &ol;
}
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