// FIXME: Only render dirty rects public void Render(BoundingRect rect) { var ctx = Surface.GetDrawingContext (); ApplyTransform (ctx); // If we were alredy rendering, stop it if (renderFiber != null && renderFiber.Status == FutureStatus.Pending) renderFiber.Cancel (); renderFiber = Render (rect, ctx); // Render children last //foreach (var child in Children) { // child.Render (rect.GetIntersection (child.Bounds)); //} }
public FutureCancelledException(Future f) : base("This Future has been cancelled.") { CancelledFuture = f; }
protected bool Chain(Future f) { chained = f; // UBER IMPORTANTE! Must acquire reader lock on chained future's status to prevent race condition chained.status_lock.EnterReadLock (); try { if (chained.Status == FutureStatus.Pending) { Unschedule (); chained.OnComplete += Reschedule; return true; } } finally { chained.status_lock.ExitReadLock (); } return false; }
protected void Reschedule(Future completed) { completed.OnComplete -= Reschedule; Schedule (thread); }
// This method is thread-safe, however if this method is called from a different thread than // this Future is scheduled on, it is not guaranteed that this Future will not be scheduled for execution // until this method returns. // Additionally, unscheduling a Future from one Thread and then scheduling it to a DIFFERENT thread // is currently not supported due to a race condition. protected internal void Unschedule () { Future actual; var prev = Interlocked.Exchange<Future> (ref previous, null); if (prev == null) { // already unscheduled return; } unlink_next: // set next = null if next == this actual = Interlocked.CompareExchange<Future> (ref next, null, this); if (actual == this || actual == null) { // we were the only ones scheduled.. Thread.current_fiber will get set to null naturally. return; } // Set next.previous = previous actual = Interlocked.CompareExchange<Future> (ref actual.previous, prev, this); if (actual != this) { // someone just scheduled themselves b/w us and next (I think.. is there a possibility this would loop forever?) this.next = actual; goto unlink_next; } // Set previous.next = next Interlocked.CompareExchange<Future> (ref prev.next, next, this); }
// This is thread-safe. protected internal void Schedule (Thread thread) { Future current, target, actual, potential; top: actual = Interlocked.CompareExchange<Future> (ref this.previous, this, null); if (actual != null) return; // already scheduled // Scheduling algorithm: // This must be done carefully, since other Futures may be concurrently (un)scheduling themselves // from different threads. // 1. Assume there are no currently scheduled fibers. // Maintain circularity of the scheduler this.next = this; set_current_to_this: // 2. Slip ourselves in to the thread.current_fiber if there isn't any. // Either way, also grabs current = thread.current_fiber current = Interlocked.CompareExchange<Future> (ref thread.current_fiber, this, null); // 2a. If there actually wasn't any previously scheduled fiber, // we have to wake the thread up... if (current == null) { thread.Enabled.Set (); return; } //acquire_new_target: // 3. We really want the fiber scheduled *previously* to the current one // (less likely to be unscheduled, for one) target = current.previous; find_new_current: // 3a. If we're unlucky, the current fiber was unscheduled during this time. // Negotiate for a new current fiber (possibly this one) while (target == null) { potential = current.next; actual = Interlocked.CompareExchange<Future> (ref thread.current_fiber, potential, current); current = (actual == current? potential : actual); if (current == null) goto set_current_to_this; target = current.previous; } begin_update: // 4. We can still update our fields without worry here because nobody points to us yet. this.next = current; this.previous = target; // 4a. Set current.previous = this actual = Interlocked.CompareExchange<Future> (ref current.previous, this, target); if (actual == null) { // current was unscheduled target = null; goto find_new_current; } if (actual != target) { // some other fiber beat us to the chase; or target unscheduled itself target = actual; goto begin_update; } // 4b. Set target.next = this actual = Interlocked.CompareExchange<Future> (ref target.next, this, current); if (actual == null) { // was only fiber and unscheduled itself goto top; } if ((actual != current) && (actual != this) && (actual != this.previous)) { // some other fiber beat us to the chase, // OR, more likely, a fiber is in the process of unscheduling itself b/w current & target. // this is ok if our previous has been updated too; otherwise ??? throw new Exception ("should not be reached"); } }