Example #1
0
        def write(self, buf, full=False, timeout=None):
            """Write data in 'buf' to file. If 'full' is True, the function
            waits till all data in buf is written; otherwise, it waits
            until one write completes. It returns length of data written.

            If no data has been written before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be written, it returns length of
            data written before timeout if any data has been written.

            Must be used with 'yield' as
            'n = yield fd.write(buf)' to write (some) data in buf.
            """

            def _write(view, written):
                try:
                    n = os.write(self._fileno, view)
                except (OSError, IOError) as exc:
                    if exc.errno in (errno.EAGAIN, errno.EINTR):
                        n = 0
                    else:
                        self._notifier.clear(self, _AsyncPoller._Write)
                        if full:
                            view.release()
                        self._write_task.throw(*sys.exc_info())
                        self._write_task = self._write_fn = None
                        return
                written += n
                if n == len(view) or not full:
                    self._notifier.clear(self, _AsyncPoller._Write)
                    if full:
                        view.release()
                    self._write_task._proceed_(written)
                    self._write_task = self._write_fn = None
                else:
                    view = view[n:]
                    self._write_fn = partial_func(_write, view, written)

            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                if hasattr(self._fd, '_fileno'):
                    self._notifier.unregister(self._fd)
            if full:
                view = memoryview(buf)
            else:
                view = buf
            self._timeout = timeout
            self._write_task = Pycos.cur_task(self._pycos)
            self._write_task._await_()
            self._write_fn = partial_func(_write, view, 0)
            self._notifier.add(self, _AsyncPoller._Write)
        def write(self, buf, full=False, timeout=None):
            """Write data in 'buf' to file. If 'full' is True, the function
            waits till all data in buf is written; otherwise, it waits
            until one write completes. It returns length of data written.

            If no data has been written before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be written, it returns length of
            data written before timeout if any data has been written.

            Must be used with 'yield' as
            'n = yield fd.write(buf)' to write (some) data in buf.
            """

            def _write(view, written):
                try:
                    n = os.write(self._fileno, view)
                except (OSError, IOError) as exc:
                    if exc.errno in (errno.EAGAIN, errno.EINTR):
                        n = 0
                    else:
                        self._notifier.clear(self, _AsyncPoller._Write)
                        self._write_task.throw(*sys.exc_info())
                        self._write_task = self._write_fn = None
                        return
                written += n
                if n == len(view) or not full:
                    self._notifier.clear(self, _AsyncPoller._Write)
                    self._write_task._proceed_(written)
                    self._write_task = self._write_fn = None
                else:
                    view = view[n:]
                    self._write_fn = partial_func(_write, view, written)

            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                if hasattr(self._fd, '_fileno'):
                    self._notifier.unregister(self._fd)
            if full:
                view = buffer(buf)
            else:
                view = buf
            self._timeout = timeout
            self._write_task = Pycos.cur_task(self._pycos)
            self._write_task._await_()
            self._write_fn = partial_func(_write, view, 0)
            self._notifier.add(self, _AsyncPoller._Write)
Example #3
0
 def __init__(self, fd):
     """'fd' is either a file object (e.g., obtained with 'open')
     or a file number (e.g., obtained with socket's fileno()).
     """
     if hasattr(fd, 'fileno'):
         self._fd = fd
         self._fileno = fd.fileno()
     elif isinstance(fd, int):
         self._fd, self._fileno = None, self._fd
     else:
         raise ValueError('invalid file descriptor')
     self._pycos = Pycos.scheduler()
     if self._pycos:
         self._notifier = self._pycos._notifier
         if hasattr(fd, '_fileno'):  # assume it is AsyncSocket
             self._notifier.unregister(fd)
     else:
         self._notifier = None
     self._timeout = None
     self._read_task = None
     self._read_fn = None
     self._write_task = None
     self._write_fn = None
     self._buflist = []
     self._event = None
     flags = fcntl.fcntl(self._fileno, fcntl.F_GETFL)
     fcntl.fcntl(self._fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
 def __init__(self, fd):
     """'fd' is either a file object (e.g., obtained with 'open')
     or a file number (e.g., obtained with socket's fileno()).
     """
     if hasattr(fd, 'fileno'):
         self._fd = fd
         self._fileno = fd.fileno()
     elif isinstance(fd, int):
         self._fd, self._fileno = None, self._fd
     else:
         raise ValueError('invalid file descriptor')
     self._pycos = Pycos.scheduler()
     if self._pycos:
         self._notifier = self._pycos._notifier
         if hasattr(fd, '_fileno'):  # assume it is AsyncSocket
             self._notifier.unregister(fd)
     else:
         self._notifier = None
     self._timeout = None
     self._read_task = None
     self._read_fn = None
     self._write_task = None
     self._write_fn = None
     self._buflist = []
     flags = fcntl.fcntl(self._fileno, fcntl.F_GETFL)
     fcntl.fcntl(self._fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
Example #5
0
        def read(self, size=0, full=False, timeout=None):
            """Read at most 'size' bytes from file; if 'size' <= 0,
            all data up to EOF is read and returned. If 'full' is
            True, exactly 'size' bytes are returned (unless EOF or
            timeout occur before). If EOF is encountered before any
            more data is available, empty buffer is returned.

            If no data has been read before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be read, it returns partial data
            read before timeout if any data has been read.

            Must be used in a task with 'yield' as
            'data = yield fd.read(1024)'
            """

            def _read(size, full):
                if size > 0:
                    count = size
                else:
                    count = 16384
                try:
                    buf = os.read(self._fileno, count)
                except (OSError, IOError) as exc:
                    if exc.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
                        return
                    else:
                        raise
                except Exception:
                    self._notifier.clear(self, _AsyncPoller._Read)
                    self._read_task.throw(*sys.exc_info())
                    self._read_task = self._read_fn = None
                    return

                if buf:
                    if size > 0:
                        size -= len(buf)
                        # assert size >= 0
                        if size == 0:
                            full = False
                    self._buflist.append(buf)
                    if full:
                        self._read_fn = partial_func(_read, size, full)
                        return

                if self._buflist:
                    buf, self._buflist = ''.join(self._buflist), []
                self._notifier.clear(self, _AsyncPoller._Read)
                self._read_task._proceed_(buf)
                self._read_task = self._read_fn = None

            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                if hasattr(self._fd, '_fileno'):
                    self._notifier.unregister(self._fd)
            if not size or size < 0:
                size = 0
                full = True
            elif self._buflist:
                buf, self._buflist = ''.join(self._buflist), []
                if len(buf) > size:
                    buf, self._buflist = buf[:size], [buf[size:]]
                if (not full) or (len(buf) == size):
                    return buf
                self._buflist = [buf]
                size -= len(buf)
            self._timeout = timeout
            self._read_task = Pycos.cur_task(self._pycos)
            self._read_task._await_()
            self._read_fn = partial_func(_read, size, full)
            self._notifier.add(self, _AsyncPoller._Read)
Example #6
0
        def write(self, buf, full=False, timeout=None):
            """Write data in 'buf' to file. If 'full' is True, the function
            waits till all data in buf is written; otherwise, it waits
            until one write completes. It returns length of data written.

            If no data has been written before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be written, it returns length of
            data written before timeout if any data has been written.

            Must be used with 'yield' as
            'n = yield fd.write(buf)' to write (some) data in buf.
            """

            def _write(written, rc, n):
                if rc or n == 0:
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    if rc != winerror.ERROR_OPERATION_ABORTED:
                        if written:
                            self._write_task._proceed_(written)
                        else:
                            self._write_task.throw(IOError(rc, 'WriteFile', str(rc)))
                    self._overlap.object = self._write_task = self._write_result = None
                    return

                written += n
                self._overlap.Offset += n
                self._write_result = self._write_result[n:]
                if not full or len(self._write_result) == 0:
                    self._overlap.object = self._write_result = None
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    self._write_task._proceed_(written)
                    self._write_task = None
                    return

                self._overlap.object = partial_func(_write, written)
                try:
                    rc, _ = win32file.WriteFile(self._handle, self._write_result, self._overlap)
                except pywintypes.error as exc:
                    rc = exc.winerror
                if rc and rc != winerror.ERROR_IO_PENDING:
                    self._overlap.object = self._write_result = None
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    if written:
                        self._write_task._proceed_(written)
                    else:
                        self._write_task.throw(IOError(rc, 'WriteFile', str(rc)))
                    self._write_task = None
                return

            self._write_result = buffer(buf)
            self._overlap.object = partial_func(_write, 0)
            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                self._notifier.register(self._handle)
            self._write_task = Pycos.cur_task(self._pycos)
            self._write_task._await_()
            try:
                rc, _ = win32file.WriteFile(self._handle, self._write_result, self._overlap)
            except pywintypes.error as exc:
                if exc.winerror == winerror.ERROR_BROKEN_PIPE:
                    self._write_task._proceed_(0)
                    self._write_result = self._write_task = self._overlap.object = None
                    return
                else:
                    rc = exc.winerror
            if rc and rc != winerror.ERROR_IO_PENDING:
                self._overlap.object = self._write_result = self._write_task = None
                self._write_task._proceed_(None)
                raise IOError(rc, 'WriteFile', str(rc))
            if timeout:
                self._timeout = timeout
                self._notifier._add_timeout(self)
Example #7
0
        def read(self, size=0, full=False, timeout=None):
            """Read at most 'size' bytes from file; if 'size' <= 0,
            all data up to EOF is read and returned. If 'full' is
            True, exactly 'size' bytes are returned (unless EOF or
            timeout occur before). If EOF is encountered before any
            more data is available, empty buffer is returned.

            If no data has been read before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be read, it returns partial data
            read before timeout if any data has been read.

            Must be used in a task with 'yield' as
            'data = yield fd.read(1024)'
            """

            def _read(size, full, rc, n):
                if rc or n == 0:
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    self._overlap.object = self._read_result = None
                    if rc != winerror.ERROR_OPERATION_ABORTED:
                        if (self._buflist or rc == winerror.ERROR_HANDLE_EOF or
                           rc == winerror.ERROR_BROKEN_PIPE):
                            buf, self._buflist = ''.join(self._buflist), []
                            self._read_task._proceed_(buf)
                            return
                        self._read_task.throw(IOError(rc, 'ReadFile', str(rc)))
                    self._overlap.object = self._read_task = self._read_result = None
                    return

                buf = self._read_result[:n]
                if size > 0:
                    size -= len(buf)
                    assert size >= 0
                    if size == 0:
                        full = False
                self._buflist.append(buf)
                self._overlap.Offset += n
                if full:
                    self._overlap.object = partial_func(_read, size, full)
                    try:
                        rc, _ = win32file.ReadFile(self._handle, self._read_result, self._overlap)
                    except pywintypes.error as exc:
                        rc = exc.winerror
                    if rc and rc != winerror.ERROR_IO_PENDING:
                        buf, self._buflist = ''.join(self._buflist), []
                        self._overlap.object = self._read_result = None
                        if self._timeout:
                            self._notifier._del_timeout(self)
                        self._read_task._proceed_(buf)
                        self._read_task = None
                    return

                if self._buflist:
                    buf, self._buflist = ''.join(self._buflist), []
                if self._timeout:
                    self._notifier._del_timeout(self)
                self._overlap.object = self._read_result = None
                self._read_task._proceed_(buf)
                self._read_task = None

            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                self._notifier.register(self._handle)
            if not size or size < 0:
                count = 16384
                full = True
            else:
                if self._buflist:
                    buf, self._buflist = ''.join(self._buflist), []
                    if len(buf) > size:
                        buf, self._buflist = buf[:size], [buf[size:]]
                    if (not full) or (len(buf) == size):
                        return buf
                    self._buflist = [buf]
                    size -= len(buf)
                count = size
            self._read_result = win32file.AllocateReadBuffer(count)
            self._overlap.object = partial_func(_read, size, full)
            self._read_task = Pycos.cur_task(self._pycos)
            self._read_task._await_()
            try:
                rc, _ = win32file.ReadFile(self._handle, self._read_result, self._overlap)
            except pywintypes.error as exc:
                if exc.winerror == winerror.ERROR_BROKEN_PIPE:
                    buf, self._buflist = ''.join(self._buflist), []
                    self._read_task._proceed_(buf)
                    self._read_result = self._read_task = self._overlap.object = None
                    return
                else:
                    rc = exc.winerror
            if rc and rc != winerror.ERROR_IO_PENDING:
                self._overlap.object = self._read_result = self._read_task = None
                self._read_task.throw(IOError(rc, 'ReadFile', str(rc)))
            if timeout:
                self._timeout = timeout
                self._notifier._add_timeout(self)
Example #8
0
        def __init__(self, path_handle, mode='r', share=None):
            """If 'path_handle' is a string, opens that file for
            asynchronous I/O; if it is a handle (pipe client / server,
            for example), sets up for asynchronous I/O. 'mode' is as
            per 'open' Python function, although limited to
            basic/common modes.
            """
            self._overlap = pywintypes.OVERLAPPED()
            if isinstance(path_handle, str):
                self._path = path_handle
                if mode.startswith('r'):
                    access = win32file.GENERIC_READ
                    if share is None:
                        share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE
                    create = win32file.OPEN_EXISTING
                    if '+' in mode:
                        access |= win32file.GENERIC_WRITE
                elif mode.startswith('w'):
                    access = win32file.GENERIC_WRITE
                    if share is None:
                        share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE
                    create = win32file.CREATE_ALWAYS
                    if '+' in mode:
                        access |= win32file.GENERIC_READ
                elif mode.startswith('a'):
                    access = win32file.GENERIC_WRITE
                    if share is None:
                        share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE
                    create = win32file.OPEN_ALWAYS
                    if '+' in mode:
                        access |= win32file.GENERIC_READ
                        # TODO: if reading, offset should be 0?
                    sb = os.stat(path_handle)
                    self._overlap.Offset = sb.st_size
                else:
                    self._overlap = None
                    raise ValueError('invalid mode "%s"' % mode)

                flags = win32file.FILE_FLAG_OVERLAPPED

                try:
                    self._handle = win32file.CreateFile(path_handle, access, share, None, create,
                                                        flags, None)
                except Exception:
                    self._overlap = None
                    raise
                if mode.startswith('r'):
                    flags = os.O_RDONLY
                elif mode.startswith('a'):
                    flags = os.O_APPEND
                else:
                    flags = 0
                self._fileno = msvcrt.open_osfhandle(self._handle, flags)
            else:
                self._handle = path_handle
                # pipe mode should be either 'r' or 'w'
                flags = os.O_RDONLY if mode.startswith('r') else 0
                self._fileno = msvcrt.open_osfhandle(self._handle, flags)

            self._buflist = []
            self._read_result = None
            self._write_result = None
            self._timeout = None
            self._timeout_id = None
            self._pycos = Pycos.scheduler()
            if self._pycos:
                self._notifier = self._pycos._notifier
                self._notifier.register(self._handle)
            else:
                self._notifier = None
            self._event = None
        def read(self, size=0, full=False, timeout=None):
            """Read at most 'size' bytes from file; if 'size' <= 0,
            all data up to EOF is read and returned. If 'full' is
            True, exactly 'size' bytes are returned (unless EOF or
            timeout occur before). If EOF is encountered before any
            more data is available, empty buffer is returned.

            If no data has been read before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be read, it returns partial data
            read before timeout if any data has been read.

            Must be used in a task with 'yield' as
            'data = yield fd.read(1024)'
            """

            def _read(size, full):
                if size > 0:
                    count = size
                else:
                    count = 16384
                try:
                    buf = os.read(self._fileno, count)
                except (OSError, IOError) as exc:
                    if exc.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
                        return
                    else:
                        raise
                except:
                    self._notifier.clear(self, _AsyncPoller._Read)
                    self._read_task.throw(*sys.exc_info())
                    self._read_task = self._read_fn = None
                    return

                if buf:
                    if size > 0:
                        size -= len(buf)
                        # assert size >= 0
                        if size == 0:
                            full = False
                    self._buflist.append(buf)
                    if full:
                        self._read_fn = partial_func(_read, size, full)
                        return

                if self._buflist:
                    buf, self._buflist = ''.join(self._buflist), []
                self._notifier.clear(self, _AsyncPoller._Read)
                self._read_task._proceed_(buf)
                self._read_task = self._read_fn = None

            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                if hasattr(self._fd, '_fileno'):
                    self._notifier.unregister(self._fd)
            if not size or size < 0:
                size = 0
                full = True
            elif self._buflist:
                buf, self._buflist = ''.join(self._buflist), []
                if len(buf) > size:
                    buf, self._buflist = buf[:size], [buf[size:]]
                if (not full) or (len(buf) == size):
                    return buf
                self._buflist = [buf]
                size -= len(buf)
            self._timeout = timeout
            self._read_task = Pycos.cur_task(self._pycos)
            self._read_task._await_()
            self._read_fn = partial_func(_read, size, full)
            self._notifier.add(self, _AsyncPoller._Read)
        def write(self, buf, full=False, timeout=None):
            """Write data in 'buf' to file. If 'full' is True, the function
            waits till all data in buf is written; otherwise, it waits
            until one write completes. It returns length of data written.

            If no data has been written before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be written, it returns length of
            data written before timeout if any data has been written.

            Must be used with 'yield' as
            'n = yield fd.write(buf)' to write (some) data in buf.
            """

            def _write(written, rc, n):
                if rc or n == 0:
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    if rc != winerror.ERROR_OPERATION_ABORTED:
                        if written:
                            self._write_task._proceed_(written)
                        else:
                            self._write_task.throw(IOError(rc, 'WriteFile', str(rc)))
                    self._overlap.object = self._write_task = self._write_result = None
                    return

                written += n
                self._overlap.Offset += n
                self._write_result = self._write_result[n:]
                if not full or len(self._write_result) == 0:
                    self._overlap.object = self._write_result = None
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    self._write_task._proceed_(written)
                    self._write_task = None
                    return

                self._overlap.object = partial_func(_write, written)
                try:
                    rc, _ = win32file.WriteFile(self._handle, self._write_result, self._overlap)
                except pywintypes.error as exc:
                    rc = exc.winerror
                if rc and rc != winerror.ERROR_IO_PENDING:
                    self._overlap.object = self._write_result = None
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    if written:
                        self._write_task._proceed_(written)
                    else:
                        self._write_task.throw(IOError(rc, 'WriteFile', str(rc)))
                    self._write_task = None
                return

            self._write_result = buffer(buf)
            self._overlap.object = partial_func(_write, 0)
            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                self._notifier.register(self._handle)
            self._write_task = Pycos.cur_task(self._pycos)
            self._write_task._await_()
            try:
                rc, _ = win32file.WriteFile(self._handle, self._write_result, self._overlap)
            except pywintypes.error as exc:
                if exc.winerror == winerror.ERROR_BROKEN_PIPE:
                    self._write_task._proceed_(0)
                    self._write_result = self._write_task = self._overlap.object = None
                    return
                else:
                    rc = exc.winerror
            if rc and rc != winerror.ERROR_IO_PENDING:
                self._overlap.object = self._write_result = self._write_task = None
                self._write_task._proceed_(None)
                raise IOError(rc, 'WriteFile', str(rc))
            if timeout:
                self._timeout = timeout
                self._notifier._add_timeout(self)
        def read(self, size=0, full=False, timeout=None):
            """Read at most 'size' bytes from file; if 'size' <= 0,
            all data up to EOF is read and returned. If 'full' is
            True, exactly 'size' bytes are returned (unless EOF or
            timeout occur before). If EOF is encountered before any
            more data is available, empty buffer is returned.

            If no data has been read before timeout, then
            IOError('timedout') will be thrown.

            If timeout is given and full is True and timeout expires
            before all the data could be read, it returns partial data
            read before timeout if any data has been read.

            Must be used in a task with 'yield' as
            'data = yield fd.read(1024)'
            """

            def _read(size, full, rc, n):
                if rc or n == 0:
                    if self._timeout:
                        self._notifier._del_timeout(self)
                    self._overlap.object = self._read_result = None
                    if rc != winerror.ERROR_OPERATION_ABORTED:
                        if (self._buflist or rc == winerror.ERROR_HANDLE_EOF or
                           rc == winerror.ERROR_BROKEN_PIPE):
                            buf, self._buflist = ''.join(self._buflist), []
                            self._read_task._proceed_(buf)
                            return
                        self._read_task.throw(IOError(rc, 'ReadFile', str(rc)))
                    self._overlap.object = self._read_task = self._read_result = None
                    return

                buf = self._read_result[:n]
                if size > 0:
                    size -= len(buf)
                    assert size >= 0
                    if size == 0:
                        full = False
                self._buflist.append(buf)
                self._overlap.Offset += n
                if full:
                    self._overlap.object = partial_func(_read, size, full)
                    try:
                        rc, _ = win32file.ReadFile(self._handle, self._read_result, self._overlap)
                    except pywintypes.error as exc:
                        rc = exc.winerror
                    if rc and rc != winerror.ERROR_IO_PENDING:
                        buf, self._buflist = ''.join(self._buflist), []
                        self._overlap.object = self._read_result = None
                        if self._timeout:
                            self._notifier._del_timeout(self)
                        self._read_task._proceed_(buf)
                        self._read_task = None
                    return

                if self._buflist:
                    buf, self._buflist = ''.join(self._buflist), []
                if self._timeout:
                    self._notifier._del_timeout(self)
                self._overlap.object = self._read_result = None
                self._read_task._proceed_(buf)
                self._read_task = None

            if not self._pycos:
                self._pycos = Pycos.scheduler()
                self._notifier = self._pycos._notifier
                self._notifier.register(self._handle)
            if not size or size < 0:
                count = 16384
                full = True
            else:
                if self._buflist:
                    buf, self._buflist = ''.join(self._buflist), []
                    if len(buf) > size:
                        buf, self._buflist = buf[:size], [buf[size:]]
                    if (not full) or (len(buf) == size):
                        return buf
                    self._buflist = [buf]
                    size -= len(buf)
                count = size
            self._read_result = win32file.AllocateReadBuffer(count)
            self._overlap.object = partial_func(_read, size, full)
            self._read_task = Pycos.cur_task(self._pycos)
            self._read_task._await_()
            try:
                rc, _ = win32file.ReadFile(self._handle, self._read_result, self._overlap)
            except pywintypes.error as exc:
                if exc.winerror == winerror.ERROR_BROKEN_PIPE:
                    buf, self._buflist = ''.join(self._buflist), []
                    self._read_task._proceed_(buf)
                    self._read_result = self._read_task = self._overlap.object = None
                    return
                else:
                    rc = exc.winerror
            if rc and rc != winerror.ERROR_IO_PENDING:
                self._overlap.object = self._read_result = self._read_task = None
                self._read_task.throw(IOError(rc, 'ReadFile', str(rc)))
            if timeout:
                self._timeout = timeout
                self._notifier._add_timeout(self)
        def __init__(self, path_handle, mode='r', share=None):
            """If 'path_handle' is a string, opens that file for
            asynchronous I/O; if it is a handle (pipe client / server,
            for example), sets up for asynchronous I/O. 'mode' is as
            per 'open' Python function, although limited to
            basic/common modes.
            """
            self._overlap = pywintypes.OVERLAPPED()
            if isinstance(path_handle, str):
                self._path = path_handle
                if mode.startswith('r'):
                    access = win32file.GENERIC_READ
                    if share is None:
                        share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE
                    create = win32file.OPEN_EXISTING
                    if '+' in mode:
                        access |= win32file.GENERIC_WRITE
                elif mode.startswith('w'):
                    access = win32file.GENERIC_WRITE
                    if share is None:
                        share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE
                    create = win32file.CREATE_ALWAYS
                    if '+' in mode:
                        access |= win32file.GENERIC_READ
                elif mode.startswith('a'):
                    access = win32file.GENERIC_WRITE
                    if share is None:
                        share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE
                    create = win32file.OPEN_ALWAYS
                    if '+' in mode:
                        access |= win32file.GENERIC_READ
                        # TODO: if reading, offset should be 0?
                    sb = os.stat(path_handle)
                    self._overlap.Offset = sb.st_size
                else:
                    self._overlap = None
                    raise ValueError('invalid mode "%s"' % mode)

                flags = win32file.FILE_FLAG_OVERLAPPED

                try:
                    self._handle = win32file.CreateFile(path_handle, access, share, None, create,
                                                        flags, None)
                except:
                    self._overlap = None
                    raise
                if mode.startswith('r'):
                    flags = os.O_RDONLY
                elif mode.startswith('a'):
                    flags = os.O_APPEND
                else:
                    flags = 0
                self._fileno = msvcrt.open_osfhandle(self._handle, flags)
            else:
                self._handle = path_handle
                # pipe mode should be either 'r' or 'w'
                flags = os.O_RDONLY if mode.startswith('r') else 0
                self._fileno = msvcrt.open_osfhandle(self._handle, flags)

            self._buflist = []
            self._read_result = None
            self._write_result = None
            self._timeout = None
            self._timeout_id = None
            self._pycos = Pycos.scheduler()
            if self._pycos:
                self._notifier = self._pycos._notifier
                self._notifier.register(self._handle)
            else:
                self._notifier = None