You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by st...@locus.apache.org on 2000/07/03 05:21:16 UTC

cvs commit: apache-2.0/src/lib/apr/threadproc/win32 proc.c

stoddard    00/07/02 20:21:16

  Modified:    src/lib/apr/file_io/win32 fileio.h open.c pipe.c readwrite.c
               src/lib/apr/threadproc/win32 proc.c
  Log:
  Win32: First cut at implementing non-blocking pipes with timeout on Windows NT.
  
  Revision  Changes    Path
  1.27      +14 -7     apache-2.0/src/lib/apr/file_io/win32/fileio.h
  
  Index: fileio.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/fileio.h,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- fileio.h	2000/06/22 16:05:29	1.26
  +++ fileio.h	2000/07/03 03:21:09	1.27
  @@ -103,18 +103,19 @@
   struct ap_file_t {
       ap_pool_t *cntxt;
       HANDLE filehand;
  -    char *fname;
  -    DWORD dwFileAttributes;
  -    int eof_hit;
  -    int pipe;
  +    BOOLEAN pipe;              // Is this a pipe of a file?
  +    OVERLAPPED *pOverlapped;
       ap_interval_time_t timeout;
  -    int buffered;
  -    int ungetchar;    /* Last char provided by an unget op. (-1 = no char)*/
   
  +    /* File specific info */
  +    char *fname;
       char *demonfname; 
       char *lowerdemonfname; 
  +    DWORD dwFileAttributes;
  +    int eof_hit;
  +    BOOLEAN buffered;          // Use buffered I/O?
  +    int ungetchar;             // Last char provided by an unget op. (-1 = no char)
       int append; 
  -
       off_t size;
       ap_time_t atime;
       ap_time_t mtime;
  @@ -127,6 +128,9 @@
       int direction;            // buffer being used for 0 = read, 1 = write
       ap_ssize_t filePtr;       // position in file of handle
       ap_lock_t *mutex;         // mutex semaphore, must be owned to access the above fields
  +
  +    /* Pipe specific info */
  +    
   };
   
   struct ap_dir_t {
  @@ -143,5 +147,8 @@
                                                const char *szFile);
   char * canonical_filename(struct ap_pool_t *pCont, const char *szFile);
   
  +ap_status_t ap_create_nt_pipe(ap_file_t **in, ap_file_t **out, 
  +                              BOOLEAN bAsyncRead, BOOLEAN bAsyncWrite, 
  +                              ap_pool_t *p);
   #endif  /* ! FILE_IO_H */
   
  
  
  
  1.43      +4 -3      apache-2.0/src/lib/apr/file_io/win32/open.c
  
  Index: open.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/open.c,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- open.c	2000/06/22 04:42:51	1.42
  +++ open.c	2000/07/03 03:21:10	1.43
  @@ -67,10 +67,11 @@
   ap_status_t file_cleanup(void *thefile)
   {
       ap_file_t *file = thefile;
  -    if (!CloseHandle(file->filehand)) {
  -        return GetLastError();
  -    }
  +    CloseHandle(file->filehand);
       file->filehand = INVALID_HANDLE_VALUE;
  +    if (file->pOverlapped) {
  +        CloseHandle(file->pOverlapped->hEvent);
  +    }
       return APR_SUCCESS;
   }
   
  
  
  
  1.24      +116 -55   apache-2.0/src/lib/apr/file_io/win32/pipe.c
  
  Index: pipe.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/pipe.c,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- pipe.c	2000/06/30 18:14:48	1.23
  +++ pipe.c	2000/07/03 03:21:11	1.24
  @@ -63,72 +63,89 @@
   #include <sys/stat.h>
   #include "misc.h"
   
  -static ap_status_t setpipeblockmode(ap_file_t *pipe, DWORD dwMode) {
  -    if (!SetNamedPipeHandleState(pipe->filehand, &dwMode, NULL, NULL)) {
  -        return GetLastError();
  -    }
  +ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_interval_time_t timeout)
  +{
  +    thepipe->timeout = timeout;
       return APR_SUCCESS;
   }
   
  -ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_interval_time_t timeout)
  +ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *p)
   {
  -    ap_status_t rc = APR_SUCCESS;
  -    ap_oslevel_e oslevel;
  +    SECURITY_ATTRIBUTES sa;
   
  -    /* This code relies on the fact that anonymous pipes (which
  -     * do not support nonblocking I/O) are really named pipes
  -     * (which support nonblocking I/O) on Windows NT.
  -     */
  -    if (thepipe->pipe == 1) {
  -        if (ap_get_oslevel(thepipe->cntxt, &oslevel) == APR_SUCCESS &&
  -            oslevel >= APR_WIN_NT) {
  -            /* Temporary hack to make CGIs work in alpha5 
  -             * NT doesn't support timing out non-blocking pipes. Specifically,
  -             * NT has no event notification to tell you when data has arrived
  -             * on a pipe. select, WaitForSingleObject or WSASelect, et. al.
  -             * do not tell you when data is available. You have to poll the read
  -             * which just sucks. I will implement this using async i/o later.
  -             * For now, if ap_set_pipe_timeout is set with a timeout, just make
  -             * the pipe full blocking...*/
  -            if (timeout > 0) {
  -                setpipeblockmode(thepipe, PIPE_WAIT);
  -                return APR_SUCCESS;
  -            }
  -            if (timeout >= 0) {
  -                /* Set the pipe non-blocking if it was previously blocking */  
  -                if (thepipe->timeout < 0) {
  -                    rc = setpipeblockmode(thepipe, PIPE_NOWAIT);
  -                }
  -            }
  -            else if (thepipe->timeout >= 0) {
  -                rc = setpipeblockmode(thepipe, PIPE_WAIT);
  -            }
  -        } 
  -        else {
  -            /* can't make anonymous pipes non-blocking on Win9x */
  -            rc = APR_ENOTIMPL;
  -        }
  -        thepipe->timeout = timeout;
  -    }
  -    else {
  -        /* Timeout not valid for file i/o (yet...) */
  -        rc = APR_EINVAL;
  +    sa.nLength = sizeof(sa);
  +    sa.bInheritHandle = TRUE;
  +    sa.lpSecurityDescriptor = NULL;
  +
  +    (*in) = (ap_file_t *)ap_pcalloc(p, sizeof(ap_file_t));
  +    (*in)->cntxt = p;
  +    (*in)->fname = ap_pstrdup(p, "PIPE");
  +    (*in)->pipe = 1;
  +    (*in)->timeout = -1;
  +    (*in)->ungetchar = -1;
  +    (*in)->eof_hit = 0;
  +    (*in)->filePtr = 0;
  +    (*in)->bufpos = 0;
  +    (*in)->dataRead = 0;
  +    (*in)->direction = 0;
  +
  +    (*out) = (ap_file_t *)ap_pcalloc(p, sizeof(ap_file_t));
  +    (*out)->cntxt = p;
  +    (*out)->fname = ap_pstrdup(p, "PIPE");
  +    (*out)->pipe = 1;
  +    (*out)->timeout = -1;
  +    (*out)->ungetchar = -1;
  +    (*out)->eof_hit = 0;
  +    (*out)->filePtr = 0;
  +    (*out)->bufpos = 0;
  +    (*out)->dataRead = 0;
  +    (*out)->direction = 0;
  +
  +    if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 0)) {
  +        return GetLastError();
       }
   
  -    return rc;
  +    return APR_SUCCESS;
   }
   
  -ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont)
  +/* ap_create_nt_pipe()
  + * An internal (for now) APR function created for use by ap_create_process() 
  + * when setting up pipes to communicate with the child process. 
  + * ap_create_nt_pipe() allows setting the blocking mode of each end of 
  + * the pipe when the pipe is created (rather than after the pipe is created). 
  + * A pipe handle must be opened in full async i/o mode in order to 
  + * emulate Unix non-blocking pipes with timeouts. 
  + *
  + * In general, we don't want to enable child side pipe handles for async i/o.
  + * This prevents us from enabling both ends of the pipe for async i/o in 
  + * ap_create_pipe.
  + *
  + * Why not use NamedPipes on NT which support setting pipe state to
  + * non-blocking? On NT, even though you can set a pipe non-blocking, 
  + * there is no clean way to set event driven non-zero timeouts (e.g select(),
  + * WaitForSinglelObject, et. al. will not detect pipe i/o). On NT, you 
  + * have to poll the pipe to detech i/o on a non-blocking pipe.
  + *
  + * wgs
  + */
  +ap_status_t ap_create_nt_pipe(ap_file_t **in, ap_file_t **out, 
  +                              BOOLEAN bAsyncRead, BOOLEAN bAsyncWrite, 
  +                              ap_pool_t *p)
   {
  +    ap_oslevel_e level;
       SECURITY_ATTRIBUTES sa;
  +    static unsigned long id = 0;
  +    DWORD dwPipeMode;
  +    DWORD dwOpenMode;
  +    char name[50];
   
       sa.nLength = sizeof(sa);
       sa.bInheritHandle = TRUE;
       sa.lpSecurityDescriptor = NULL;
   
  -    (*in) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t));
  -    (*in)->cntxt = cont;
  -    (*in)->fname = ap_pstrdup(cont, "PIPE");
  +    (*in) = (ap_file_t *)ap_pcalloc(p, sizeof(ap_file_t));
  +    (*in)->cntxt = p;
  +    (*in)->fname = ap_pstrdup(p, "PIPE");
       (*in)->pipe = 1;
       (*in)->timeout = -1;
       (*in)->ungetchar = -1;
  @@ -137,10 +154,11 @@
       (*in)->bufpos = 0;
       (*in)->dataRead = 0;
       (*in)->direction = 0;
  +    (*in)->pOverlapped = NULL;
   
  -    (*out) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t));
  -    (*out)->cntxt = cont;
  -    (*out)->fname = ap_pstrdup(cont, "PIPE");
  +    (*out) = (ap_file_t *)ap_pcalloc(p, sizeof(ap_file_t));
  +    (*out)->cntxt = p;
  +    (*out)->fname = ap_pstrdup(p, "PIPE");
       (*out)->pipe = 1;
       (*out)->timeout = -1;
       (*out)->ungetchar = -1;
  @@ -149,9 +167,52 @@
       (*out)->bufpos = 0;
       (*out)->dataRead = 0;
       (*out)->direction = 0;
  +    (*out)->pOverlapped = NULL;
   
  -    if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 0)) {
  -        return GetLastError();
  +    if (ap_get_oslevel(p, &level) == APR_SUCCESS && level >= APR_WIN_NT) {
  +        /* Create the read end of the pipe */
  +        dwOpenMode = PIPE_ACCESS_INBOUND;
  +        if (bAsyncRead) {
  +            dwOpenMode |= FILE_FLAG_OVERLAPPED;
  +            (*in)->pOverlapped = (OVERLAPPED*) ap_pcalloc(p, sizeof(OVERLAPPED));
  +            (*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  +            /* register a cleanup for the event handle... */
  +        }
  +
  +        dwPipeMode = 0;
  +
  +        sprintf(name, "\\\\.\\pipe\\%d.%d", getpid(), id++);
  +
  +        (*in)->filehand = CreateNamedPipe(name,
  +                                          dwOpenMode,
  +                                          dwPipeMode,
  +                                          1,            //nMaxInstances,
  +                                          8182,         //nOutBufferSize, 
  +                                          8192,         //nInBufferSize,                   
  +                                          1,            //nDefaultTimeOut,                
  +                                          &sa);
  +
  +        /* Create the write end of the pipe */
  +        dwOpenMode = FILE_ATTRIBUTE_NORMAL;
  +        if (bAsyncWrite) {
  +            dwOpenMode |= FILE_FLAG_OVERLAPPED;
  +            (*out)->pOverlapped = (OVERLAPPED*) ap_pcalloc(p, sizeof(OVERLAPPED));
  +            (*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  +        }
  +        
  +        (*out)->filehand = CreateFile(name,
  +                                      GENERIC_WRITE,   // access mode
  +                                      0,               // share mode
  +                                      &sa,             // Security attributes
  +                                      OPEN_EXISTING,   // dwCreationDisposition
  +                                      dwOpenMode,      // Pipe attributes
  +                                      NULL);           // handle to template file
  +    }
  +    else {
  +        /* Pipes on Win9* are blocking. Live with it. */
  +        if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 0)) {
  +            return GetLastError();
  +        }
       }
   
       return APR_SUCCESS;
  
  
  
  1.43      +98 -31    apache-2.0/src/lib/apr/file_io/win32/readwrite.c
  
  Index: readwrite.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/readwrite.c,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- readwrite.c	2000/06/22 04:42:51	1.42
  +++ readwrite.c	2000/07/03 03:21:11	1.43
  @@ -60,13 +60,96 @@
   #include <malloc.h>
   #include "atime.h"
   
  -ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes)
  +/*
  + * read_with_timeout() 
  + * Uses async i/o to emulate unix non-blocking i/o with timeouts.
  + */
  +static ap_status_t read_with_timeout(ap_file_t *file, void *buf, ap_ssize_t len, ap_ssize_t *nbytes)
   {
  +    ap_status_t rv;
  +    *nbytes = 0;
  +
  +    /* Handle the zero timeout non-blocking case */
  +    if (file->timeout == 0) {
  +        /* Peek at the pipe. If there is no data available, return APR_EAGAIN.
  +         * If data is available, go ahead and read it.
  +         */
  +        if (file->pipe) {
  +            char tmpbuf[5];
  +            DWORD dwBytesRead;
  +            DWORD dwBytesAvail;
  +            DWORD dwBytesLeftThisMsg;
  +            if (!PeekNamedPipe(file->filehand,         // handle to pipe to copy from
  +                               &tmpbuf,                   // pointer to data buffer
  +                               sizeof(tmpbuf),            // size, in bytes, of data buffer
  +                               &dwBytesRead,           // pointer to number of bytes read
  +                               &dwBytesAvail,          // pointer to total number of bytes available
  +                               &dwBytesLeftThisMsg)) { // pointer to unread bytes in this message
  +                rv = GetLastError();
  +                if (rv = ERROR_BROKEN_PIPE)
  +                    return APR_SUCCESS;
  +            }
  +            else {
  +                if (dwBytesRead == 0) {
  +                    return APR_EAGAIN;
  +                }
  +            }
  +        }
  +        else {
  +            /* ToDo: Handle zero timeout non-blocking file i/o 
  +             * This is not needed until an APR application needs to
  +             * timeout file i/o (which means setting file i/o non-blocking)
  +             */
  +        }
  +    }
  +
  +    rv = ReadFile(file->filehand, buf, len, nbytes, file->pOverlapped);
  +
  +    if (!rv) {
  +        rv = GetLastError();
  +        if (rv == ERROR_IO_PENDING) {
  +            /* Wait for the pending i/o */
  +            if (file->timeout > 0) {
  +                rv = WaitForSingleObject(file->pOverlapped->hEvent, file->timeout/1000); // timeout in milliseconds...
  +            }
  +            else if (file->timeout == -1) {
  +                rv = WaitForSingleObject(file->pOverlapped->hEvent, INFINITE);
  +            }
  +            switch (rv) {
  +            case WAIT_OBJECT_0:
  +                GetOverlappedResult(file->filehand, file->pOverlapped, nbytes, TRUE);
  +                rv = APR_SUCCESS;
  +                break;
  +            case WAIT_TIMEOUT:
  +                rv = APR_TIMEUP;
  +                break;
  +            case WAIT_FAILED:
  +                rv = GetLastError();
  +                break;
  +            default:
  +                break;
  +            }
  +            if (rv != APR_SUCCESS) {
  +                CancelIo(file->filehand);
  +            }
  +        }
  +        else if (rv == ERROR_BROKEN_PIPE) {
  +            /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
  +            rv = APR_SUCCESS; /* APR_EOF? */
  +        }
  +    } else {
  +        rv = APR_SUCCESS;
  +    }
  +    return rv;
  +}
  +
  +ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *len)
  +{
       ap_ssize_t rv;
       DWORD bytes_read = 0;
   
  -    if (*nbytes <= 0) {
  -        *nbytes = 0;
  +    if (*len <= 0) {
  +        *len = 0;
           return APR_SUCCESS;
       }
   
  @@ -75,17 +158,17 @@
           bytes_read = 1;
           *(char *)buf = (char)thefile->ungetchar;
           buf = (char *)buf + 1;
  -        (*nbytes)--;
  +        (*len)--;
           thefile->ungetchar = -1;
  -        if (*nbytes == 0) {
  -            *nbytes = bytes_read;
  +        if (*len == 0) {
  +            *len = bytes_read;
               return APR_SUCCESS;
           }
       }
       if (thefile->buffered) {
           char *pos = (char *)buf;
           ap_ssize_t blocksize;
  -        ap_ssize_t size = *nbytes;
  +        ap_ssize_t size = *len;
   
           ap_lock(thefile->mutex);
   
  @@ -99,9 +182,10 @@
           rv = 0;
           while (rv == 0 && size > 0) {
               if (thefile->bufpos >= thefile->dataRead) {
  -                rv = ReadFile(thefile->filehand, thefile->buffer, APR_FILE_BUFSIZE, &thefile->dataRead, NULL ) ? 0 : GetLastError();
  +                rv = read_with_timeout(thefile, thefile->buffer, 
  +                                       APR_FILE_BUFSIZE, &thefile->dataRead);
                   if (thefile->dataRead == 0) {
  -                    if (rv == 0) {
  +                    if (rv == APR_SUCCESS) {
                           thefile->eof_hit = TRUE;
                           rv = APR_EOF;
                       }
  @@ -119,33 +203,16 @@
               size -= blocksize;
           }
   
  -        *nbytes = pos - (char *)buf;
  -        if (*nbytes) {
  +        *len = pos - (char *)buf;
  +        if (*len) {
               rv = 0;
           }
           ap_unlock(thefile->mutex);
       } else {  
           /* Unbuffered i/o */
  -        DWORD dwBytesRead;
  -        if (ReadFile(thefile->filehand, buf, *nbytes, &dwBytesRead, NULL)) {
  -            *nbytes = bytes_read + dwBytesRead;
  -            if (*nbytes) {
  -                return APR_SUCCESS;
  -            }
  -            else {
  -                return APR_EOF;
  -            }
  -        }
  -
  -        *nbytes = 0;
  -        rv = GetLastError();
  -        if (rv == ERROR_BROKEN_PIPE) {
  -            /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
  -            return APR_SUCCESS;
  -        } else if (rv == ERROR_NO_DATA) {
  -            /* Receive this error on a read to a pipe in nonblocking mode */
  -            return APR_EAGAIN;
  -        }
  +        ap_ssize_t nbytes;
  +        rv = read_with_timeout(thefile, buf, *len, &nbytes);
  +        *len = nbytes;
       }
   
       return rv;
  
  
  
  1.33      +40 -27    apache-2.0/src/lib/apr/threadproc/win32/proc.c
  
  Index: proc.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/threadproc/win32/proc.c,v
  retrieving revision 1.32
  retrieving revision 1.33
  diff -u -r1.32 -r1.33
  --- proc.c	2000/06/20 19:36:48	1.32
  +++ proc.c	2000/07/03 03:21:13	1.33
  @@ -92,61 +92,74 @@
                                 ap_int32_t out, ap_int32_t err)
   {
       ap_status_t stat;
  +    BOOLEAN bAsyncRead, bAsyncWrite;
       if (in) {
  -        if ((stat = ap_create_pipe(&attr->child_in, &attr->parent_in, 
  -                                   attr->cntxt)) != APR_SUCCESS) {
  -            return stat;
  -        }
           switch (in) {
           case APR_FULL_BLOCK:
  +            bAsyncRead = bAsyncWrite = FALSE;
               break;
           case APR_PARENT_BLOCK:
  -            ap_set_pipe_timeout(attr->child_in, 0);
  +            bAsyncRead = FALSE;
  +            bAsyncWrite = TRUE;
               break;
           case APR_CHILD_BLOCK:
  -            ap_set_pipe_timeout(attr->parent_in, 0);
  +            bAsyncRead = TRUE;
  +            bAsyncWrite = FALSE;
               break;
           default:
  -            ap_set_pipe_timeout(attr->child_in, 0);
  -            ap_set_pipe_timeout(attr->parent_in, 0);
  +            bAsyncRead = TRUE;
  +            bAsyncWrite = TRUE;
  +        }        
  +        if ((stat = ap_create_nt_pipe(&attr->child_in, &attr->parent_in, 
  +                                      bAsyncRead, bAsyncWrite,
  +                                      attr->cntxt)) != APR_SUCCESS) {
  +            return stat;
           }
       }
       if (out) {
  -        if ((stat = ap_create_pipe(&attr->parent_out, &attr->child_out, 
  -                                   attr->cntxt)) != APR_SUCCESS) {
  -            return stat;
  -        }
           switch (out) {
           case APR_FULL_BLOCK:
  +            bAsyncRead = bAsyncWrite = FALSE;
               break;
           case APR_PARENT_BLOCK:
  -            ap_set_pipe_timeout(attr->child_out, 0);
  +            bAsyncRead = FALSE;
  +            bAsyncWrite = TRUE;
               break;
           case APR_CHILD_BLOCK:
  -            ap_set_pipe_timeout(attr->parent_out, 0);
  +            bAsyncRead = TRUE;
  +            bAsyncWrite = FALSE;
               break;
           default:
  -            ap_set_pipe_timeout(attr->child_out, 0);
  -            ap_set_pipe_timeout(attr->parent_out, 0);
  +            bAsyncRead = TRUE;
  +            bAsyncWrite = TRUE;
  +        }        
  +        if ((stat = ap_create_nt_pipe(&attr->parent_out, &attr->child_out,
  +                                      bAsyncRead, bAsyncWrite,
  +                                      attr->cntxt)) != APR_SUCCESS) {
  +            return stat;
           }
       }
       if (err) {
  -        if ((stat = ap_create_pipe(&attr->parent_err, &attr->child_err, 
  -                                   attr->cntxt)) != APR_SUCCESS) {
  -            return stat;
  -        }
           switch (err) {
           case APR_FULL_BLOCK:
  +            bAsyncRead = bAsyncWrite = FALSE;
               break;
           case APR_PARENT_BLOCK:
  -            ap_set_pipe_timeout(attr->child_err, 0);
  +            bAsyncRead = FALSE;
  +            bAsyncWrite = TRUE;
               break;
           case APR_CHILD_BLOCK:
  -            ap_set_pipe_timeout(attr->parent_err, 0);
  +            bAsyncRead = TRUE;
  +            bAsyncWrite = FALSE;
               break;
           default:
  -            ap_set_pipe_timeout(attr->child_err, 0);
  -            ap_set_pipe_timeout(attr->parent_err, 0);
  +            bAsyncRead = TRUE;
  +            bAsyncWrite = TRUE;
  +        }        
  +        if ((stat = ap_create_nt_pipe(&attr->parent_err, &attr->child_err,
  +                                      bAsyncRead, bAsyncWrite,
  +                                      attr->cntxt)) != APR_SUCCESS) {
  +            return stat;
           }
       } 
       return APR_SUCCESS;
  @@ -337,15 +350,15 @@
       }
       else {
           if (attr->child_in) {
  -            ap_close(attr->parent_in);
  +            CloseHandle(attr->parent_in->filehand);
               attr->parent_in->filehand = hParentindup;
           }
           if (attr->child_out) {
  -            ap_close(attr->parent_out);
  +            CloseHandle(attr->parent_out->filehand);
               attr->parent_out->filehand = hParentoutdup;
           }
           if (attr->child_err) {
  -            ap_close(attr->parent_err);
  +            CloseHandle(attr->parent_err->filehand);
               attr->parent_err->filehand = hParenterrdup;
           }
       }