summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-28 12:46:58 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-28 12:46:58 +0000
commit3c8dca55c43b78c0564ad0ff93d67587a7a64bf8 (patch)
tree93cd95d1ba96fc03cc3e38f66df3c4964ca8d6b6 /win32
parentcf6334e1cb91bfee0f95e5ae7ea9c4a72df1f6c2 (diff)
* 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
Diffstat (limited to 'win32')
-rw-r--r--win32/win32.c457
1 files changed, 448 insertions, 9 deletions
diff --git a/win32/win32.c b/win32/win32.c
index 29088d2f29..8827f3b593 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -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 */
@@ -3995,6 +3997,167 @@ rb_w32_getppid(void)
}
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 @@ rb_w32_fclose(FILE *fp)
}
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 @@ 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)
+ 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