# Writing pipe on Windows problem

**URL:** <https://www.ruby-forum.com/t/writing-pipe-on-windows-problem/136754>\
**Category:** Ruby\
**Created:** [May 6, 2008, 5:13am UTC](https://www.ruby-forum.com/t/writing-pipe-on-windows-problem/136754 "2008-05-06T05:13:44Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![phasis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/e56c9b/32.png) [@phasis](https://www.ruby-forum.com/u/phasis)\
**Post date:** [May 6, 2008, 5:13am UTC](https://www.ruby-forum.com/t/writing-pipe-on-windows-problem/136754/1 "2008-05-06T05:13:44Z")

</div>

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?

Regards,  
Park H.

---

<div class="post-metadata">

**Author:** ![phasis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/e56c9b/32.png) [@phasis](https://www.ruby-forum.com/u/phasis)\
**Post date:** [May 12, 2008, 3:51am UTC](https://www.ruby-forum.com/t/writing-pipe-on-windows-problem/136754/2 "2008-05-12T03:51:06Z")

</div>

Hi,

Heesob P. 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 H.

— [win32.c.org](http://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;i<num_events;i++) {

```

+if(input\_record[i].Event.KeyEvent.uChar.AsciiChar) return ret;

- 

```
               if ((input_record[i].EventType == KEY_EVENT) && 

```

input\_record[i].Event.KeyEvent.bKeyDown) {  
+if(input\_record[i].Event.KeyEvent.uChar.AsciiChar==13) { /\* carriage  
return \*/

- 

```
                       free(input_record);

```

- 

```
                       return ret;

```

- 

```
                   }

```

- 

```
                   else 

```

if(input\_record[i].Event.KeyEvent.uChar.AsciiChar==26) { /\* ^Z - end of  
file \*/

- 

```
                       free(input_record);

```

- 

```
                       return ret;

```

- 

```
                   }

```

- 

```
               }

```

- 

```
           }

```

- 

```
           free(input_record);

```

- 

```
           pre_num = num_events;

```

- 

```
      }

```

- 

```
   }

```

- 

```
   return ret;

```

- } else {
- 

```
   DWORD state;

```

- 

```
   ret = 

```

GetNamedPipeHandleState(fd\_handle,&state,NULL,NULL,NULL,NULL,0);

- 

```
   if(ret) {

```

- 

```
       /* Pipe Input */

```

- 

```
       int bytes_avail=0;

```

- 

```
       while(1) {

```

+if(WaitForSingleObject(main\_select\_event,0)!=WAIT\_TIMEOUT) break;

- 

```
           ret = 

```

PeekNamedPipe(fd\_handle,NULL,0,NULL,&bytes\_avail,NULL);

- 

```
           if(bytes_avail>0) {

```

- 

```
               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; i<file_nfds; i++)

```

- 

```
   {

```

- 

```
     if(i<file_rd.fd_count) {

```

- 

```
       select_thread_list[i] = 

```

CreateThread(NULL,0,select\_read\_thread,

- 

```
           (PVOID)file_rd.fd_array[i],0,&val);

```

- 

```
     }

```

- 

```
     else {

```

- 

```
       select_thread_list[i] = 

```

CreateThread(NULL,0,select\_write\_thread,

- 

```
           (PVOID)file_wr.fd_array[i-file_rd.fd_count],0,&val);

```

- 

```
     }

```

- 

```
     if (select_thread_list[i] == NULL)

```

- 

```
     {

```

- 

```
       printf("CreateThread failed (%d)\n", GetLastError());

```

- 

```
       return -1;

```

- 

```
     }

```

- 

```
   }

```

- 
- 

```
   select_thread_list[file_nfds] = interrupted_event;

```

- 

```
   if(timeout)

```

- 

```
       r = 

```

WaitForMultipleObjects(file\_nfds+1,select\_thread\_list,FALSE,

- 

```
           timeout->tv_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<file_nfds;i++) {

```

- 

```
       while(1) {

```

- 

```
             exit_code = 0;

```

- 

```
             GetExitCodeThread(select_thread_list[i],&exit_code);

```

- 

```
             if(exit_code!=STILL_ACTIVE) {

```

- 

```
                 CloseHandle(select_thread_list[i]);

```

- 

```
                 break;

```

- 

```
             }

```

- 

```
       }

```

- 

```
   }

```

- 

```
   free(select_thread_list);

```

- 

```
   CloseHandle(main_select_event);

```

- 
- 

```
   if(r==WAIT_TIMEOUT) { /* timeout */

```

- 

```
           FD_ZERO(&file_rd);

```

- 

```
           FD_ZERO(&file_wr);

```

- 

```
           if(rd) *rd = file_rd;

```

- 

```
           if(wr) *wr = file_wr;

```

- 

```
           return 0;

```

- 

```
   } else if((r -= WAIT_OBJECT_0) == file_nfds) { /* interrupt */

```

- 

```
           FD_ZERO(&file_rd);

```

- 

```
           FD_ZERO(&file_wr);

```

- 

```
           if(rd) *rd = file_rd;

```

- 

```
           if(wr) *wr = file_wr;

```

- 

```
           return -1;

```

- } else if(r\<file\_rd.fd\_count) { /\* read ready \*/
- 

```
           FD_ZERO(&file_wr);

```

- 

```
           if(rd) *rd = file_rd;

```

- 

```
           if(wr) *wr = file_wr;

```

- 

```
           return 1;

```

- 

```
   } else { /* write ready */

```

- 

```
           FD_ZERO(&file_rd);

```

- 

```
           if(rd) *rd = file_rd;

```

- 

```
           if(wr) *wr = file_wr;

```

- 

```
           return 1;

```

- 

```
   }

```

- // assume normal files are always readable/writable  
// fake read/write fd\_set and return value  
if (rd) \*rd = file\_rd;
