From: Heesob Park Date: 2008-05-12T10:51:09+09:00 Subject: Re: writing pipe on Windows problem. Hi, Heesob Park wrote: > Hi, all > > I tested pipe with this code: > > readPipe, writePipe = IO.pipe > t = Thread.new { puts "got #{readPipe.readline.length} bytes" } > sleep 1 > puts "hello from main" > writePipe.puts "a"*2048 > t.join > > > It works on Linux, but it blocks and fails to respond Ctrl-C on Windows. > How to avoid freezing on Windows? > It seems nobody cares about pipe blocking on windows.:( I made my own patch applied for win32.c of ruby1.8.6p114. It is not complete yet, but it will solve blocking problem of pipe and cosole input on windows. I hope this give some inpiration to the win32 ruby maintainer. Regards, Park Heesob --- win32.c.org 2008-04-29 14:44:41.000000000 +0900 +++ win32.c 2008-05-02 14:08:10.000000000 +0900 @@ -2046,6 +2050,114 @@ return fileset->fd_count; } +static HANDLE main_select_event=NULL; +static HANDLE *select_thread_list=NULL; + +static DWORD WINAPI +select_read_thread(PVOID argp) +{ + HANDLE fd_handle = (HANDLE)argp; + DWORD ret = 1; + DWORD mode = 0; + + GetConsoleMode(fd_handle,&mode); + if(mode) { + /* Console Input */ + DWORD num_events,num_events_read,pre_num=0; + INPUT_RECORD *input_record; + int i; + + while(1) { + if(WaitForSingleObject(main_select_event,0)!=WAIT_TIMEOUT) break; + GetNumberOfConsoleInputEvents(fd_handle, &num_events); + if(pre_num != num_events) { + input_record = (INPUT_RECORD*)malloc(sizeof(INPUT_RECORD)*num_events); + PeekConsoleInput(fd_handle, input_record, num_events,&num_events_read); + for(i=0;i0) { + return bytes_avail; + } + } + } + return ret; + } + return ret; +} + +typedef DWORD (WINAPI *PNtQueryInformationFile)(HANDLE, PVOID, PVOID,DWORD, DWORD ); +#define FilePipeLocalInformation 24 +typedef struct _FILE_PIPE_LOCAL_INFORMATION { + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; +static PNtQueryInformationFile NtQueryInformationFile=NULL; + +static DWORD WINAPI +select_write_thread(PVOID argp) +{ + HANDLE fd_handle = (HANDLE)argp; + DWORD ret = 1; + DWORD mode = 0; + + GetConsoleMode(fd_handle,&mode); + if(mode) { + /* Console Output */ + return ret; + } else { + DWORD state; + ret = GetNamedPipeHandleState(fd_handle,&state,NULL,NULL,NULL,NULL,0); + if(ret) { + /* Pipe output */ + int bytes_written=0; + int bytes_avail=0; + DWORD iob[2]; + FILE_PIPE_LOCAL_INFORMATION fpli = {0}; + if(NtQueryInformationFile) { + while(1) { + if(WaitForSingleObject(main_select_event,0)!=WAIT_TIMEOUT) break; + ret = NtQueryInformationFile(fd_handle,iob,&fpli,sizeof(fpli),FilePipeLocalInformation); + if(fpli.OutboundQuota==fpli.WriteQuotaAvailable) return ret; + } + } + } + } + return ret; +} + long rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout) @@ -2074,6 +2187,86 @@ file_nfds += extract_file_fd(wr, &file_wr); if (file_nfds) { + DWORD val,exit_code; + int i; + if(!NtQueryInformationFile) + NtQueryInformationFile = (PNtQueryInformationFile) +GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQueryInformationFile"); + main_select_event = CreateEvent(NULL,TRUE,FALSE,NULL); + if(main_select_event == NULL) + { + printf("CreateEvent failed (%d)\n", GetLastError()); + return -1; + } + select_thread_list = malloc(sizeof(HANDLE)*(file_nfds+1)); + for(i=0; itv_sec * 1000 + timeout->tv_usec / 1000); + else + r = WaitForMultipleObjects(file_nfds+1,select_thread_list,FALSE, + INFINITE); + + if (!SetEvent(main_select_event) ) + { + printf("SetEvent failed (%d)\n", GetLastError()); + return -1; + } + /* thread cleanup */ + for(i=0;i