コード例 #1
0
ファイル: UnixFileStream.cs プロジェクト: ikopylov/corefx
        /// <summary>
        /// Helper for making system calls that involve the stream's file descriptor.
        /// System calls are expected to return greather than or equal to zero on success,
        /// and less than zero on failure.  In the case of failure, errno is expected to
        /// be set to the relevant error code.
        /// </summary>
        /// <typeparam name="TArg1">Specifies the type of an argument to the system call.</typeparam>
        /// <typeparam name="TArg2">Specifies the type of another argument to the system call.</typeparam>
        /// <param name="sysCall">A delegate that invokes the system call.</param>
        /// <param name="arg1">The first argument to be passed to the system call, after the file descriptor.</param>
        /// <param name="arg2">The second argument to be passed to the system call.</param>
        /// <param name="throwOnError">true to throw an exception if a non-interuption error occurs; otherwise, false.</param>
        /// <returns>The return value of the system call.</returns>
        /// <remarks>
        /// Arguments are expected to be passed via <paramref name="arg1"/> and <paramref name="arg2"/>
        /// so as to avoid delegate and closure allocations at the call sites.
        /// </remarks>
        private long SysCall <TArg1, TArg2>(
            Func <int, TArg1, TArg2, long> sysCall,
            TArg1 arg1        = default(TArg1), TArg2 arg2 = default(TArg2),
            bool throwOnError = true)
        {
            SafeFileHandle handle = _fileHandle;

            Debug.Assert(sysCall != null);
            Debug.Assert(handle != null);

            bool gotRefOnHandle = false;

            try
            {
                // Get the file descriptor from the handle.  We increment the ref count to help
                // ensure it's not closed out from under us.
                handle.DangerousAddRef(ref gotRefOnHandle);
                Debug.Assert(gotRefOnHandle);
                int fd = (int)handle.DangerousGetHandle();
                Debug.Assert(fd >= 0);

                // System calls may fail due to EINTR (signal interruption).  We need to retry in those cases.
                while (true)
                {
                    long result = sysCall(fd, arg1, arg2);
                    if (result < 0)
                    {
                        Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
                        if (errorInfo.Error == Interop.Error.EINTR)
                        {
                            continue;
                        }
                        else if (throwOnError)
                        {
                            throw Interop.GetExceptionForIoErrno(errorInfo, _path, isDirectory: false);
                        }
                    }
                    return(result);
                }
            }
            finally
            {
                if (gotRefOnHandle)
                {
                    handle.DangerousRelease();
                }
                else
                {
                    throw new ObjectDisposedException(SR.ObjectDisposed_FileClosed);
                }
            }
        }