public static FutureIsReady ( |
||
futureHandle | ||
return | bool |
internal FdbFutureArray(FutureHandle[] handles, Func <FutureHandle, T> selector, CancellationToken ct) { Contract.Requires(handles != null && selector != null); m_handles = handles; m_resultSelector = selector; bool abortAllHandles = false; try { if (ct.IsCancellationRequested) { // already cancelled, we must abort everything SetFlag(FdbFuture.Flags.COMPLETED); abortAllHandles = true; m_resultSelector = null; this.TrySetCanceled(); return; } // add this instance to the list of pending futures var prm = RegisterCallback(this); foreach (var handle in handles) { if (FdbNative.FutureIsReady(handle)) { // this handle is already done continue; } Interlocked.Increment(ref m_pending); // register the callback handler var err = FdbNative.FutureSetCallback(handle, CallbackHandler, prm); if (Fdb.Failed(err)) { // uhoh Debug.WriteLine("Failed to set callback for Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " !!!"); throw Fdb.MapToException(err) !; } } // allow the callbacks to handle completion TrySetFlag(FdbFuture.Flags.READY); if (Volatile.Read(ref m_pending) == 0) { // all callbacks have already fired (or all handles were already completed) UnregisterCallback(this); HandleCompletion(); m_resultSelector = null; abortAllHandles = true; SetFlag(FdbFuture.Flags.COMPLETED); } else if (ct.CanBeCanceled) { // register for cancellation (if needed) RegisterForCancellation(ct); } } catch { // this is bad news, since we are in the constructor, we need to clear everything SetFlag(FdbFuture.Flags.DISPOSED); UnregisterCancellationRegistration(); UnregisterCallback(this); abortAllHandles = true; // this is technically not needed, but just to be safe... this.TrySetCanceled(); throw; } finally { if (abortAllHandles) { CloseHandles(handles); } } GC.KeepAlive(this); }
internal FdbFutureSingle([NotNull] FutureHandle handle, [NotNull] Func <FutureHandle, T> selector, CancellationToken ct) { Contract.NotNull(handle, nameof(handle)); Contract.NotNull(selector, nameof(selector)); m_handle = handle; m_resultSelector = selector; try { if (handle.IsInvalid) { // it's dead, Jim ! SetFlag(FdbFuture.Flags.COMPLETED); m_resultSelector = null; return; } if (FdbNative.FutureIsReady(handle)) { // either got a value or an error #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " was already ready"); #endif HandleCompletion(fromCallback: false); #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " completed inline"); #endif return; } // register for cancellation (if needed) if (ct.CanBeCanceled) { if (ct.IsCancellationRequested) { // we have already been cancelled #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " will complete later"); #endif // Abort the future and simulate a Canceled task SetFlag(FdbFuture.Flags.COMPLETED); // note: we don't need to call fdb_future_cancel because fdb_future_destroy will take care of everything handle.Dispose(); // also, don't keep a reference on the callback because it won't be needed m_resultSelector = null; this.TrySetCanceled(); return; } // token still active RegisterForCancellation(ct); } #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " will complete later"); #endif TrySetFlag(FdbFuture.Flags.READY); // add this instance to the list of pending futures var prm = RegisterCallback(this); // register the callback handler var err = FdbNative.FutureSetCallback(handle, CallbackHandler, prm); if (Fdb.Failed(err)) { // uhoh #if DEBUG_FUTURES Debug.WriteLine("Failed to set callback for Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " !!!"); #endif throw Fdb.MapToException(err); } } catch { // this is bad news, since we are in the constructor, we need to clear everything SetFlag(FdbFuture.Flags.DISPOSED); UnregisterCancellationRegistration(); UnregisterCallback(this); // kill the future handle m_handle.Dispose(); // this is technically not needed, but just to be safe... this.TrySetCanceled(); throw; } GC.KeepAlive(this); }