Ejemplo n.º 1
0
        private unsafe int ReadCoreWithCancellation(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            DebugAssertReadWriteArgs(buffer, offset, count, _handle);
            Debug.Assert(cancellationToken.CanBeCanceled, "ReadCoreNoCancellation should be used if cancellation can't happen");

            // Register for a cancellation request.  This will throw if cancellation has already been requested,
            // and otherwise will write to the cancellation pipe if/when cancellation has been requested.
            using (DescriptorCancellationRegistration cancellation = RegisterForCancellation(cancellationToken))
            {
                bool gotRef = false;
                try
                {
                    cancellation.Poll.DangerousAddRef(ref gotRef);
                    fixed (byte* bufPtr = buffer)
                    {
                        const int CancellationSentinel = -42;
                        int rv = (int)SysCall(_handle, (fd, ptr, len, cancellationFd) =>
                        {
                            // Wait for data to be available on either the pipe we want to read from
                            // or on the cancellation pipe, which would signal a cancellation request.
                            Interop.libc.pollfd* fds = stackalloc Interop.libc.pollfd[2];
                            fds[0] = new Interop.libc.pollfd { fd = fd, events = Interop.libc.PollFlags.POLLIN, revents = 0 };
                            fds[1] = new Interop.libc.pollfd { fd = (int)cancellationFd, events = Interop.libc.PollFlags.POLLIN, revents = 0 };
                            while (Interop.CheckIo(Interop.libc.poll(fds, 2, -1))) ;

                            // If we woke up because of a cancellation request, bail.
                            if ((fds[1].revents & Interop.libc.PollFlags.POLLIN) != 0)
                            {
                                return CancellationSentinel;
                            }

                            // Otherwise, we woke up because data is available on the pipe. Read it.
                            Debug.Assert((fds[0].revents & Interop.libc.PollFlags.POLLIN) != 0);
                            long result = (long)Interop.libc.read(fd, (byte*)ptr, (IntPtr)len);
                            Debug.Assert(result <= len);
                            return result;
                        }, (IntPtr)(bufPtr + offset), count, cancellation.Poll.DangerousGetHandle());
                        Debug.Assert(rv >= 0 || rv == CancellationSentinel);

                        // If cancellation was requested, waking up the read, throw.
                        if (rv == CancellationSentinel)
                        {
                            Debug.Assert(cancellationToken.IsCancellationRequested);
                            throw new OperationCanceledException(cancellationToken);
                        }

                        // Otherwise return what we read.
                        return rv;
                    }
                }
                finally
                {
                    if (gotRef)
                        cancellation.Poll.DangerousRelease();
                }
            }
        }
Ejemplo n.º 2
0
        private unsafe int ReadCoreWithCancellation(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            DebugAssertReadWriteArgs(buffer, offset, count, _handle);
            Debug.Assert(cancellationToken.CanBeCanceled, "ReadCoreNoCancellation should be used if cancellation can't happen");

            // Register for a cancellation request.  This will throw if cancellation has already been requested,
            // and otherwise will write to the cancellation pipe if/when cancellation has been requested.
            using (DescriptorCancellationRegistration cancellation = RegisterForCancellation(cancellationToken))
            {
                bool gotRef = false;
                try
                {
                    cancellation.Poll.DangerousAddRef(ref gotRef);
                    fixed(byte *bufPtr = buffer)
                    {
                        const int CancellationSentinel = -42;
                        int       rv = (int)SysCall(_handle, (fd, ptr, len, cancellationFd) =>
                        {
                            // Wait for data to be available on either the pipe we want to read from
                            // or on the cancellation pipe, which would signal a cancellation request.
                            Interop.libc.pollfd *fds = stackalloc Interop.libc.pollfd[2];
                            fds[0] = new Interop.libc.pollfd {
                                fd = fd, events = Interop.libc.PollFlags.POLLIN, revents = 0
                            };
                            fds[1] = new Interop.libc.pollfd {
                                fd = (int)cancellationFd, events = Interop.libc.PollFlags.POLLIN, revents = 0
                            };
                            while (Interop.CheckIo(Interop.libc.poll(fds, 2, -1)))
                            {
                                ;
                            }

                            // If we woke up because of a cancellation request, bail.
                            if ((fds[1].revents & Interop.libc.PollFlags.POLLIN) != 0)
                            {
                                return(CancellationSentinel);
                            }

                            // Otherwise, we woke up because data is available on the pipe. Read it.
                            Debug.Assert((fds[0].revents & Interop.libc.PollFlags.POLLIN) != 0);
                            long result = (long)Interop.libc.read(fd, (byte *)ptr, (IntPtr)len);
                            Debug.Assert(result <= len);
                            return(result);
                        }, (IntPtr)(bufPtr + offset), count, cancellation.Poll.DangerousGetHandle());

                        Debug.Assert(rv >= 0 || rv == CancellationSentinel);

                        // If cancellation was requested, waking up the read, throw.
                        if (rv == CancellationSentinel)
                        {
                            Debug.Assert(cancellationToken.IsCancellationRequested);
                            throw new OperationCanceledException(cancellationToken);
                        }

                        // Otherwise return what we read.
                        return(rv);
                    }
                }
                finally
                {
                    if (gotRef)
                    {
                        cancellation.Poll.DangerousRelease();
                    }
                }
            }
        }