// // Writes the specified number of data items to the // stream blocking queue, activating the specified cancellers. // public int Write(T[] buffer, int offset, int count, StCancelArgs cargs) { // // If this is a zero length write, return immediately. // if (count == 0) { return(0); } // // Initialize the local variables. // int remaining = count; WaitNodeQueue <T> wl = new WaitNodeQueue <T>(); int toCopy; // // Acquire the queue's lock. // slock.Enter(); // // If the queue's buffer is full, check if the current // thread must wait. // if (available == length) { goto CheckForWait; } // // If there are waiting readers (i.e., the buffer is empty), // transfer data items transferring directly to the waiting // readers' buffers. // if (!waitQueue.IsEmpty) { do { WaitNode <T> rdw = waitQueue.head; // // Compute the number of data items to transfer to the // waiting reader's buffer and perform the transfer. // if ((toCopy = rdw.remaining) > remaining) { toCopy = remaining; } Array.Copy(buffer, offset, rdw.buffer, rdw.offset, toCopy); rdw.remaining -= toCopy; rdw.offset += toCopy; remaining -= toCopy; offset += toCopy; // // If the waiting reader completes its read operation, // remove its wait node from the wait list and try to // lock the associated parker. // if (rdw.remaining == 0) { waitQueue.Dequeue(); if (rdw.TryLock() && !rdw.UnparkInProgress(StParkStatus.Success)) { wl.Add(rdw); } } else { // // The data items are not enough to satisfy the waiting // reader that is at front of wait queue, so break the loop. // break; } } while (remaining != 0 && !waitQueue.IsEmpty); } // // If we have still data items to write and there is free space // in the queue's buffer, transfer the appropriate number of data // items the queue's buffer. // if (remaining != 0 && available < length) { // // Compute the number of data items that can be copied // to the queue's buffer and perform the transfer. // if ((toCopy = remaining) > (length - available)) { toCopy = length - available; } int t = tail; int tillEnd; if ((tillEnd = length - t) >= toCopy) { Array.Copy(buffer, offset, items, t, toCopy); if ((t += toCopy) >= length) { t = 0; } } else { int fromBegin = toCopy - tillEnd; Array.Copy(buffer, offset, items, t, tillEnd); Array.Copy(buffer, offset + tillEnd, items, 0, fromBegin); t = fromBegin; } // // Update counters and indexes. // tail = t; available += toCopy; remaining -= toCopy; offset += toCopy; } CheckForWait: // // If there are still data items to write, the current thread must // wait if a null timeout wasn't specified. // WaitNode <T> wn = null; bool mustWait; if (mustWait = (remaining != 0 && cargs.Timeout != 0)) { waitQueue.Enqueue(wn = new WaitNode <T>(buffer, offset, remaining)); } // // Release the queue's lock and unpark the readers threads // release above. // slock.Exit(); wl.UnparkAll(); // // If the current thread doesn't need to wait, return the // number of written data items. // if (!mustWait) { return(count - remaining); } // // Park the current thread, activating the specified cancellers. // int ws = wn.Park(cargs); // // If the write was completed, return the number of written // data items. // if (ws == StParkStatus.Success) { return(count); } // // The write was cancelled due to timeout, alert or interrupt. // If the wait node is still inserted in the wait queue, acquire // the queue's lock and unlink it. // if (wn.next != wn) { slock.Enter(); waitQueue.Remove(wn); slock.Exit(); } // // If at least a data item was written, ignore the cancellation // and return the number of transferred data items. // int c; if ((c = count - wn.remaining) != 0) { StCancelArgs.PostponeCancellation(ws); return(c); } // // No data items were written; so, report the failure appropriately. // StCancelArgs.ThrowIfException(ws); return(0); }
// // Waits until read the specified number of data items from // the stream queue, activating the specified cancellers. // public int Read(T[] buffer, int offset, int count, StCancelArgs cargs) { // // If this is a zero length read, return immediately. // if (count == 0) { return(0); } // // Initialize the local variables and acquire the queue's lock. // int remaining = count; WaitNodeQueue <T> wl = new WaitNodeQueue <T>(); int toCopy; slock.Enter(); // // If the queue's buffer is empty, check if the current thread // must wait. // if (available == 0) { goto CheckForWait; } // // Compute the number of data items that we can read // from the queue's buffer and perform the transfer. // if ((toCopy = remaining) > available) { toCopy = available; } int h = head; int tillEnd; if ((tillEnd = length - h) >= toCopy) { Array.Copy(items, h, buffer, offset, toCopy); if ((h += toCopy) >= length) { h = 0; } } else { int fromBegin = toCopy - tillEnd; Array.Copy(items, h, buffer, offset, tillEnd); Array.Copy(items, 0, buffer, offset + tillEnd, fromBegin); h = fromBegin; } // // Adjust counters and indexes. // head = h; available -= toCopy; remaining -= toCopy; offset += toCopy; // // If we have still data items to read and there are waiting // writers, transfer the data directly from our buffer to the // waiting writers' buffers. // if (remaining != 0 && !waitQueue.IsEmpty) { do { WaitNode <T> wrw = waitQueue.head; // // Compute the number of data items to transfer to the // waiting writer's buffer and perform the transfer. // if ((toCopy = remaining) > wrw.remaining) { toCopy = wrw.remaining; } Array.Copy(wrw.buffer, wrw.offset, buffer, offset, toCopy); wrw.remaining -= toCopy; wrw.offset += toCopy; remaining -= toCopy; offset += toCopy; // // If the write operation was completed, try to release // the writer thread. // if (wrw.remaining == 0) { waitQueue.Dequeue(); if (wrw.TryLock() && !wrw.UnparkInProgress(StParkStatus.Success)) { wl.Add(wrw); } } else { // // The read is completed, so break the loop. // break; } } while (remaining != 0 && !waitQueue.IsEmpty); } // // If there is available space in the queue's buffer and // waiting writers, try to fill the queue's buffer with // the data of the waiting writers. // if (available < length && !waitQueue.IsEmpty) { do { WaitNode <T> wrw = waitQueue.head; // // Compute the number of data items to copy from the writer's // buffer to the queue's buffer and perform the transfer. // if ((toCopy = wrw.remaining) > (length - available)) { toCopy = length - available; } int t = tail; if ((tillEnd = length - t) >= toCopy) { Array.Copy(wrw.buffer, wrw.offset, items, t, toCopy); if ((t += toCopy) >= length) { t = 0; } } else { int fromBegin = toCopy - tillEnd; Array.Copy(wrw.buffer, wrw.offset, items, t, tillEnd); Array.Copy(wrw.buffer, wrw.offset + tillEnd, items, 0, fromBegin); t = fromBegin; } // // Update counters and indexes. // tail = t; available += toCopy; wrw.remaining -= toCopy; wrw.offset += toCopy; // // If the writer completed its write, release it. // if (wrw.remaining == 0) { waitQueue.Dequeue(); if (wrw.TryLock() && !wrw.UnparkInProgress(StParkStatus.Success)) { wl.Add(wrw); } } else { // // The queue's buffer is full, so break the loop. // break; } } while (available < length && !waitQueue.IsEmpty); } CheckForWait: // // If the read operation was not completed, the current thread // must wait if it didn't read all data items and a null timeout // wasn't specified. // WaitNode <T> wn = null; bool mustWait; if (mustWait = (remaining != 0 && cargs.Timeout != 0)) { waitQueue.Enqueue(wn = new WaitNode <T>(buffer, offset, remaining)); } // // Release the queue's lock and unpark the released waiters. // slock.Exit(); wl.UnparkAll(); // // If the read was completed or the thread specified a null // timeout, return the number of read data items. // if (!mustWait) { return(count - remaining); } // // Park the current thread, activating the specified cancellers. // int ws = wn.Park(cargs); // // If succeed, return the number of data items transferred. // if (ws == StParkStatus.Success) { return(count); } // // The read was cancelled due to timeout, alert or interrupt. // If the wait block is still inserted in the wait queue, acquire // the queue's lock and remove it from the queue. // if (wn.next != wn) { slock.Enter(); waitQueue.Remove(wn); slock.Exit(); } int c; if ((c = count - wn.remaining) != 0) { StCancelArgs.PostponeCancellation(ws); return(c); } // // No data items were transferred, so report the failure // appropriately. // StCancelArgs.ThrowIfException(ws); return(0); }
// // Signals the barrier and then waits until the current phase // completes, activating the specified cancellers. // public bool SignalAndWait(StCancelArgs cargs) { // // Get the current phase state. // PhaseState phs = phState; int s, partners, arrived; do { partners = (s = phs.state) >> PARTNERS_SHIFT; arrived = s & ARRIVED_MASK; if (arrived == partners) { throw new InvalidOperationException("Barrier partners exceeded"); } if (Interlocked.CompareExchange(ref phs.state, s + 1, s) == s) { if (arrived + 1 == partners) { // // This is the last partner thread. So, finish the current // phase and return success. // FinishPhase(); return(true); } break; } } while (true); // // WaitOne on the phase event, activating the specified cancelers. // int ws = phs.waitEvent.Wait(cargs); // // If the event was signalled (i.e., successful synchronization), // return appropiately. // if (ws == StParkStatus.Success) { if (pphActionEx != null) { throw new StBarrierPostPhaseException(pphActionEx); } return(true); } // // The wait was cancelled. So, try to decrement the counter of // arrived partners on our phase, if that is still possible. // do { // // If our partners of our phase already arrived, we must wait // unconditionally on the phase's event, postpone the cancellation // and return normally. // partners = (s = phs.state) >> PARTNERS_SHIFT; arrived = s & ARRIVED_MASK; if (arrived == partners) { phs.waitEvent.Wait(StCancelArgs.None); StCancelArgs.PostponeCancellation(ws); if (pphActionEx != null) { throw new StBarrierPostPhaseException(pphActionEx); } return(true); } // // Try to decrement the counter of arrived partners of our phase. // if (Interlocked.CompareExchange(ref phs.state, s - 1, s) == s) { // // We get out, so report the failure appropriately. // StCancelArgs.ThrowIfException(ws); return(false); } } while (true); }