Example #1
0
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="value">The value to write to the channel.</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public async Task WriteAsync(T value, TimeSpan timeout, ITwoPhaseOffer offer)
        {
            var tcs = new TaskCompletionSource <bool>();
            await NetworkConfig.TransmitRequestAsync(new PendingNetworkRequest(this, typeof(T), timeout == Timeout.Infinite ? new DateTime(0) : DateTime.Now + timeout, offer, tcs, value));

            await tcs.Task;
        }
Example #2
0
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A two-phase offer, use null to unconditionally accept</param>
        /// <param name="value">The value to write to the channel.</param>
        /// <returns>The async.</returns>
        public async Task WriteAsync(T value, ITwoPhaseOffer offer)
        {
            var tcs = new TaskCompletionSource <bool>();
            await NetworkConfig.TransmitRequestAsync(new PendingNetworkRequest(this, typeof(T), Timeout.InfiniteDateTime, offer, tcs, value)).ConfigureAwait(false);

            await tcs.Task.ConfigureAwait(false);
        }
Example #3
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        public async Task <T> ReadAsync(ITwoPhaseOffer offer)
        {
            var tcs = new TaskCompletionSource <T>();
            await NetworkConfig.TransmitRequestAsync(new PendingNetworkRequest(this, typeof(T), Timeout.InfiniteDateTime, offer, tcs)).ConfigureAwait(false);

            return(await tcs.Task.ConfigureAwait(false));
        }
Example #4
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public async Task <T> ReadAsync(TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            var tcs = new TaskCompletionSource <T>();
            await NetworkConfig.TransmitRequestAsync(new PendingNetworkRequest(this, typeof(T), timeout == Timeout.Infinite ? new DateTime(0) : DateTime.Now + timeout, offer, tcs));

            return(await tcs.Task);
        }
Example #5
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        public async Task <T> ReadAsync(ITwoPhaseOffer offer)
        {
            if (m_maxreads > 0)
            {
                using (await m_readlock.LockAsync())
                {
                    m_reads++;

                    if (m_last_read_update > TimeSpan.TicksPerSecond)
                    {
                        m_reads            = 0;
                        m_last_read_update = DateTime.Now.Ticks;
                    }

                    // Check if there are too many in this period
                    if (m_reads > m_maxreads)
                    {
                        // Prevent others from entering
                        await Task.Delay(new TimeSpan(Math.Max(0, TimeSpan.TicksPerSecond - (DateTime.Now.Ticks - m_last_read_update)))).ConfigureAwait(false);

                        // Clear our attempt
                        m_reads            = 1;
                        m_last_read_update = DateTime.Now.Ticks;
                    }
                }
            }

            return(await m_channel.ReadAsync(offer));
        }
Example #6
0
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="value">The value to write</param>
        public async Task WriteAsync(T value, ITwoPhaseOffer offer)
        {
            if (m_maxwrites > 0)
            {
                using (await m_writelock.LockAsync())
                {
                    m_writes++;

                    if (m_last_write_update > TimeSpan.TicksPerSecond)
                    {
                        m_writes            = 0;
                        m_last_write_update = DateTime.Now.Ticks;
                    }

                    // Check if there are too many in this period
                    if (m_writes > m_maxwrites)
                    {
                        // Prevent others from entering
                        await Task.Delay(new TimeSpan(Math.Max(0, TimeSpan.TicksPerSecond - (DateTime.Now.Ticks - m_last_write_update)))).ConfigureAwait(false);

                        // Clear our attempt
                        m_writes            = 1;
                        m_last_write_update = DateTime.Now.Ticks;
                    }
                }
            }

            await m_channel.WriteAsync(value, offer);
        }
Example #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CoCoL.Channel&lt;T&gt;.WriterEntry"/> struct.
 /// </summary>
 /// <param name="offer">The offer handler</param>
 /// <param name="callback">The callback method for reporting progress.</param>
 /// <param name="expires">The timeout value.</param>
 /// <param name="value">The value being written.</param>
 public WriterEntry(ITwoPhaseOffer offer, TaskCompletionSource <bool> callback, DateTime expires, T value)
 {
     Offer   = offer;
     Source  = callback;
     Expires = expires;
     Value   = value;
 }
Example #8
0
 /// <summary>
 /// Registers a desire to write to the channel
 /// </summary>
 /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
 /// <param name="value">The value to write to the channel.</param>
 /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
 /// negative span to wait forever.</param>
 /// <returns>The async.</returns>
 public async Task WriteAsync(T value, TimeSpan timeout, ITwoPhaseOffer offer = null)
 {
     m_writeQueue.Enqueue(m_parent.WriteAsync(value, timeout, offer));
     while (m_writeQueue.Count > m_buffersize)
     {
         await m_writeQueue.Dequeue();
     }
 }
Example #9
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public Task <T> ReadAsync(TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            var tg = m_target;

            if (tg == null)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            return(((IReadChannel <T>)tg).ReadAsync(timeout, offer));
        }
Example #10
0
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="value">The value to write to the channel.</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public Task WriteAsync(T value, TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            var tg = m_target;

            if (tg == null)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            return(((IWriteChannel <T>)tg).WriteAsync(value, timeout, offer));
        }
Example #11
0
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="value">The value to write to the channel.</param>
        public async Task WriteAsync(T value, ITwoPhaseOffer offer)
        {
            var start = DateTime.Now.Ticks;
            await m_channel.WriteAsync(value, offer);

            var waitticks = DateTime.Now.Ticks - start;

            m_minwritedelayticks = Math.Min(m_minwritedelayticks, waitticks);
            m_maxwritedelayticks = Math.Max(m_maxwritedelayticks, waitticks);
            m_writedelayticks   += waitticks;
            m_writes++;
        }
Example #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CoCoL.Network.PendingNetworkRequest"/> class for representing a read request.
 /// </summary>
 /// <param name="channel">The channel to communicate over.</param>
 /// <param name="channeldatatype">The datatype on the channel.</param>
 /// <param name="timeout">The timeout associated with the request.</param>
 /// <param name="offer">The two-phase offer, if any.</param>
 /// <param name="task">The <see cref="System.Threading.Tasks.TaskCompletionSource&lt;T&gt;"/> instance for signaling.</param>
 public PendingNetworkRequest(INamedItem channel, Type channeldatatype, DateTime timeout, ITwoPhaseOffer offer, object task)
 {
     ChannelID         = channel.Name;
     AssociatedChannel = channel;
     ChannelDataType   = channeldatatype;
     RequestID         = Guid.NewGuid().ToString("N");
     SourceID          = NetworkConfig.SelfID;
     Timeout           = timeout;
     Offer             = offer;
     Task        = task;
     RequestType = NetworkMessageType.ReadRequest;
     NoOffer     = offer == null;
 }
Example #13
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        public async Task <T> ReadAsync(ITwoPhaseOffer offer)
        {
            var start = DateTime.Now.Ticks;
            var res   = await m_channel.ReadAsync(offer);

            var waitticks = DateTime.Now.Ticks - start;

            m_minreaddelayticks = Math.Min(m_minreaddelayticks, waitticks);
            m_maxreaddelayticks = Math.Max(m_maxreaddelayticks, waitticks);
            m_readdelayticks   += waitticks;
            m_reads++;

            return(res);
        }
Example #14
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public Task <T> ReadAsync(TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            if (offer != null)
            {
                throw new InvalidOperationException("LatencyHidingReader does not support offers");
            }

            while (m_readQueue.Count < m_buffersize)
            {
                m_readQueue.Enqueue(m_parent.ReadAsync(timeout, offer));
            }

            return(m_readQueue.Dequeue());
        }
Example #15
0
        /// <summary>
        /// Writes the channel synchronously
        /// </summary>
        /// <param name="self">The channel to write.</param>
        /// <param name="value">The value to write.</param>
        /// <param name="offer">The two-phase offer.</param>
        public static void Write(this IUntypedChannel self, object value, ITwoPhaseOffer offer)
        {
            var res = WriteAsync(self, value, offer).WaitForTask();

            if (res.Exception != null)
            {
                if (res.Exception.Flatten().InnerExceptions.Count == 1)
                {
                    throw res.Exception.InnerException;
                }

                throw res.Exception;
            }
            else if (res.IsCanceled)
            {
                throw new OperationCanceledException();
            }
        }
Example #16
0
 /// <summary>
 /// Registers a desire to write to the channel
 /// </summary>
 /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
 /// <param name="value">The value to write to the channel.</param>
 /// <returns>The async.</returns>
 public Task WriteAsync(T value, ITwoPhaseOffer offer = null)
 {
     return(WriteAsync(value, Timeout.Infinite, offer));
 }
Example #17
0
 /// <summary>
 /// Registers a desire to read from the channel
 /// </summary>
 /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
 /// <returns>The async.</returns>
 public Task <T> ReadAsync(ITwoPhaseOffer offer = null)
 {
     return(ReadAsync(Timeout.Infinite, offer));
 }
Example #18
0
 /// <summary>
 /// Writes the channel and returns the task
 /// </summary>
 /// <returns>The async task.</returns>
 /// <param name="channel">The channel to write to.</param>
 /// <param name="value">The value to write.</param>
 /// <param name="offer">The two-phase offer.</param>
 public Task WriteAsync(IUntypedChannel channel, object value, ITwoPhaseOffer offer)
 {
     return((channel as IWriteChannel <T>).WriteAsync((T)value, offer));
 }
Example #19
0
 /// <summary>
 /// Reads from the channel and returns the task
 /// </summary>
 /// <returns>The async task.</returns>
 /// <param name="channel">The channel to read from.</param>
 /// <param name="offer">The two-phase offer.</param>
 /// <param name="timeout">The timeout value.</param>
 public async Task <object> ReadAsync(IUntypedChannel channel, TimeSpan timeout, ITwoPhaseOffer offer = null)
 {
     return(await(channel as IReadChannel <T>).ReadAsync(timeout, offer));
 }
Example #20
0
 /// <summary>
 /// Reads from the channel and returns the task
 /// </summary>
 /// <returns>The async task.</returns>
 /// <param name="channel">The channel to read from.</param>
 /// <param name="offer">The two-phase offer.</param>
 public async Task <object> ReadAsync(IUntypedChannel channel, ITwoPhaseOffer offer)
 {
     return(await(channel as IReadChannel <T>).ReadAsync(offer));
 }
Example #21
0
 /// <summary>
 /// Writes the channel and returns the task
 /// </summary>
 /// <returns>The async task.</returns>
 /// <param name="channel">The channel to write to.</param>
 /// <param name="value">The value to write.</param>
 /// <param name="offer">The two-phase offer.</param>
 /// <param name="timeout">The timeout value.</param>
 public Task WriteAsync(IUntypedChannel channel, object value, TimeSpan timeout, ITwoPhaseOffer offer = null)
 {
     return((channel as IWriteChannel <T>).WriteAsync((T)value, timeout, offer));
 }
Example #22
0
 /// <summary>
 /// Reads the channel synchronously.
 /// </summary>
 /// <returns>The value read.</returns>
 /// <param name="self">The channel to read.</param>
 /// <param name="offer">The two-phase offer token.</param>
 public static object Read(this IUntypedChannel self, ITwoPhaseOffer offer)
 {
     return(WaitForTask <object>(ReadAsync(self, offer)).Result);
 }
Example #23
0
 /// <summary>
 /// Reads the channel asynchronously.
 /// </summary>
 /// <returns>The task for awaiting completion.</returns>
 /// <param name="self">The channel to read.</param>
 /// <param name="offer">The two-phase offer.</param>
 public static Task <object> ReadAsync(this IUntypedChannel self, ITwoPhaseOffer offer)
 {
     return(UntypedAccessMethods.CreateReadAccessor(self).ReadAsync(self, offer));
 }
Example #24
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CoCoL.Channel&lt;T&gt;.ReaderEntry"/> struct.
 /// </summary>
 /// <param name="offer">The offer handler</param>
 /// <param name="callback">The callback method for reporting progress.</param>
 /// <param name="expires">The timeout value.</param>
 public ReaderEntry(ITwoPhaseOffer offer, TaskCompletionSource <T> callback, DateTime expires)
 {
     Offer   = offer;
     Source  = callback;
     Expires = expires;
 }
Example #25
0
 /// <summary>
 /// Writes the channel asynchronously
 /// </summary>
 /// <returns>The task for awaiting completion.</returns>
 /// <param name="self">The channel to write.</param>
 /// <param name="offer">The two-phase offer.</param>
 /// <param name="value">The value to write.</param>
 public static Task WriteAsync(this IUntypedChannel self, object value, ITwoPhaseOffer offer)
 {
     return(UntypedAccessMethods.CreateWriteAccessor(self).WriteAsync(self, value, offer));
 }
Example #26
0
        // Since this is just a marker, we do not implement any methods

        #region IReadChannel implementation
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public Task <T> ReadAsync(TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            throw new NotImplementedException();
        }
Example #27
0
        /// <summary>
        /// Registers a desire to read from the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a negative span to wait forever.</param>
        public async Task <T> ReadAsync(TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            var rd = new ReaderEntry(offer, new TaskCompletionSource <T>(), timeout.Ticks <= 0 ? Timeout.InfiniteDateTime : DateTime.Now + timeout);

            using (await m_asynclock.LockAsync())
            {
                if (m_isRetired)
                {
                    ThreadPool.QueueItem(() => rd.Source.SetException(new RetiredException()));
                    return(await rd.Source.Task);
                }

                m_readerQueue.Add(rd);
                if (!await MatchReadersAndWriters(true, rd.Source.Task))
                {
                    System.Diagnostics.Debug.Assert(m_readerQueue[m_readerQueue.Count - 1].Source == rd.Source);

                    // If this was a probe call, return a timeout now
                    if (timeout.Ticks >= 0 && rd.Expires < DateTime.Now)
                    {
                        m_readerQueue.RemoveAt(m_readerQueue.Count - 1);
                        ThreadPool.QueueItem(() => rd.Source.TrySetException(new TimeoutException()));
                    }
                    else
                    {
                        // Make room if we have too many
                        if (m_maxPendingReaders > 0 && (m_readerQueue.Count - 1) >= m_maxPendingReaders)
                        {
                            switch (m_pendingReadersOverflowStrategy)
                            {
                            case QueueOverflowStrategy.FIFO:
                            {
                                var exp = m_readerQueue[0].Source;
                                m_readerQueue.RemoveAt(0);
                                ThreadPool.QueueItem(() => exp.TrySetException(new ChannelOverflowException()));
                            }

                            break;

                            case QueueOverflowStrategy.LIFO:
                            {
                                var exp = m_readerQueue[m_readerQueue.Count - 2].Source;
                                m_readerQueue.RemoveAt(m_readerQueue.Count - 2);
                                ThreadPool.QueueItem(() => exp.TrySetException(new ChannelOverflowException()));
                            }

                            break;

                            case QueueOverflowStrategy.Reject:
                            default:
                            {
                                var exp = m_readerQueue[m_readerQueue.Count - 1].Source;
                                m_readerQueue.RemoveAt(m_readerQueue.Count - 1);
                                ThreadPool.QueueItem(() => exp.TrySetException(new ChannelOverflowException()));

                                await rd.Source.Task;
                            }

                                return(await rd.Source.Task);
                            }
                        }

                        // If we have expanded the queue with a new batch, see if we can purge old entries
                        m_readerQueueCleanup = await PerformQueueCleanupAsync(m_readerQueue, true, m_readerQueueCleanup);

                        if (rd.Expires != Timeout.InfiniteDateTime)
                        {
                            ExpirationManager.AddExpirationCallback(rd.Expires, () => ExpireItemsAsync().FireAndForget());
                        }
                    }
                }
            }

            return(await rd.Source.Task);
        }
Example #28
0
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="value">The value to write to the channel.</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a negative span to wait forever.</param>
        public async Task WriteAsync(T value, TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            var wr = new WriterEntry(offer, new TaskCompletionSource <bool>(), timeout.Ticks <= 0 ? Timeout.InfiniteDateTime : DateTime.Now + timeout, value);

            using (await m_asynclock.LockAsync())
            {
                if (m_isRetired)
                {
                    ThreadPool.QueueItem(() => wr.Source.SetException(new RetiredException()));
                    await wr.Source.Task;
                    return;
                }

                m_writerQueue.Add(wr);
                if (!await MatchReadersAndWriters(false, wr.Source.Task))
                {
                    System.Diagnostics.Debug.Assert(m_writerQueue[m_writerQueue.Count - 1].Source == wr.Source);

                    // If we have a buffer slot to use
                    if (m_writerQueue.Count <= m_bufferSize && m_retireCount < 0)
                    {
                        if (offer == null || await offer.OfferAsync(this))
                        {
                            if (offer != null)
                            {
                                await offer.CommitAsync(this);
                            }

                            m_writerQueue[m_writerQueue.Count - 1] = new WriterEntry(null, null, Timeout.InfiniteDateTime, value);
                            wr.Source.TrySetResult(true);
                        }
                        else
                        {
                            wr.Source.TrySetCanceled();
                        }
                    }
                    else
                    {
                        // If this was a probe call, return a timeout now
                        if (timeout.Ticks >= 0 && wr.Expires < DateTime.Now)
                        {
                            m_writerQueue.RemoveAt(m_writerQueue.Count - 1);
                            ThreadPool.QueueItem(() => wr.Source.SetException(new TimeoutException()));
                        }
                        else
                        {
                            // Make room if we have too many
                            if (m_maxPendingWriters > 0 && (m_writerQueue.Count - m_bufferSize - 1) >= m_maxPendingWriters)
                            {
                                switch (m_pendingWritersOverflowStrategy)
                                {
                                case QueueOverflowStrategy.FIFO:
                                {
                                    var exp = m_writerQueue[m_bufferSize].Source;
                                    m_writerQueue.RemoveAt(m_bufferSize);
                                    if (exp != null)
                                    {
                                        ThreadPool.QueueItem(() => exp.TrySetException(new ChannelOverflowException()));
                                    }
                                }

                                break;

                                case QueueOverflowStrategy.LIFO:
                                {
                                    var exp = m_writerQueue[m_writerQueue.Count - 2].Source;
                                    m_writerQueue.RemoveAt(m_writerQueue.Count - 2);
                                    if (exp != null)
                                    {
                                        ThreadPool.QueueItem(() => exp.TrySetException(new ChannelOverflowException()));
                                    }
                                }

                                break;

                                case QueueOverflowStrategy.Reject:
                                default:
                                {
                                    var exp = m_writerQueue[m_writerQueue.Count - 1].Source;
                                    m_writerQueue.RemoveAt(m_writerQueue.Count - 1);
                                    if (exp != null)
                                    {
                                        ThreadPool.QueueItem(() => exp.TrySetException(new ChannelOverflowException()));
                                    }
                                    await wr.Source.Task;
                                }

                                    return;
                                }
                            }

                            // If we have expanded the queue with a new batch, see if we can purge old entries
                            m_writerQueueCleanup = await PerformQueueCleanupAsync(m_writerQueue, true, m_writerQueueCleanup);

                            if (wr.Expires != Timeout.InfiniteDateTime)
                            {
                                ExpirationManager.AddExpirationCallback(wr.Expires, () => ExpireItemsAsync().FireAndForget());
                            }
                        }
                    }
                }
            }

            await wr.Source.Task;

            return;
        }
Example #29
0
        // Since this is just a marker, we do not implement any methods

        #region IWriteChannel implementation
        /// <summary>
        /// Registers a desire to write to the channel
        /// </summary>
        /// <param name="offer">A callback method for offering an item, use null to unconditionally accept</param>
        /// <param name="value">The value to write to the channel.</param>
        /// <param name="timeout">The time to wait for the operation, use zero to return a timeout immediately if no items can be read. Use a
        /// negative span to wait forever.</param>
        /// <returns>The async.</returns>
        public Task WriteAsync(T value, TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            throw new NotImplementedException();
        }
Example #30
0
        /// <summary>
        /// Writes the channel synchronously
        /// </summary>
        /// <param name="self">The channel to write.</param>
        /// <param name="value">The value to write.</param>
        /// <param name="timeout">The write timeout.</param>
        /// <param name="offer">The two-phase offer instance or null.</param>
        public static void Write(this IUntypedChannel self, object value, TimeSpan timeout, ITwoPhaseOffer offer = null)
        {
            var res = WriteAsync(self, value, timeout, offer).WaitForTask();

            if (res.Exception != null)
            {
                if (res.Exception is AggregateException && ((AggregateException)res.Exception).Flatten().InnerExceptions.Count == 1)
                {
                    throw ((AggregateException)res.Exception).InnerException;
                }

                throw res.Exception;
            }
            else if (res.IsCanceled)
            {
                throw new OperationCanceledException();
            }
        }