Exemplo n.º 1
0
        /// <summary>
        /// Invoke an action in place.
        /// </summary>
        /// <param name="handler">Action to invoke.</param>
        /// <returns><see langword="null"/> if the handler was executed sucessfully, the captured exception otherwise.</returns>
        public Exception InvokeNow(Action handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            if (_referenceCount < 1)
            {
                throw new InvalidOperationException("Cannot call invoke an unaquired TaskEnv");
            }

            // store current task environment
            TaskEnv previousEnv = _currentEnv;

            try {
                // set task environment
                _currentEnv = this;

                // execute handler
                handler();
            } catch (Exception e) {
                return(e);
            } finally {
                // restore current task environment
                _currentEnv = previousEnv;
            }
            return(null);
        }
Exemplo n.º 2
0
        /// <summary>
        /// De-schedule the current execution environment to sleep for some period.
        /// </summary>
        /// <param name="duration">Time to sleep.</param>
        /// <returns>Synchronization handle to continue execution after the sleep period.</returns>
        public static Result Sleep(TimeSpan duration)
        {
            Result result = new Result(TimeSpan.MaxValue);

            TaskTimerFactory.Current.New(duration, _ => result.Return(), null, TaskEnv.New());
            return(result);
        }
Exemplo n.º 3
0
        public static Action WithEnv <T>(this Func <T> handler, TaskEnv env, Result <T> result)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            System.Diagnostics.StackTrace stacktrace = DebugUtil.GetStackTrace();
            env.Acquire();
            return(() => {
                try {
                    T response = default(T);
                    Exception exception = env.InvokeNow(() => {
                        response = handler();
                    });
                    env.Release();

                    // check if a result object was provided
                    if (result != null)
                    {
                        if (exception != null)
                        {
                            result.Throw(exception);
                        }
                        else
                        {
                            result.Return(response);
                        }
                    }
                } catch (Exception e) {
                    _log.ErrorExceptionMethodCall(e, "Execution failed for state wrapped handler", stacktrace, handler.Method.Name);
                }
            });
        }
Exemplo n.º 4
0
        private static Yield ExecuteProcess_Helper(string application, string cmdline, Stream input, Stream output, Stream error, Result <int> result)
        {
            // start process
            var proc = new Process();

            proc.StartInfo.FileName               = application;
            proc.StartInfo.Arguments              = cmdline;
            proc.StartInfo.UseShellExecute        = false;
            proc.StartInfo.CreateNoWindow         = true;
            proc.StartInfo.RedirectStandardInput  = (input != null);
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.RedirectStandardError  = true;
            proc.Start();

            // inject input
            if (input != null)
            {
                input.CopyTo(proc.StandardInput.BaseStream, long.MaxValue, new Result <long>(TimeSpan.MaxValue)).WhenDone(_ => {
                    // trying closing the original input stream
                    try {
                        input.Close();
                    } catch { }

                    // try closing the process input pipe
                    try {
                        proc.StandardInput.Close();
                    } catch { }
                });
            }

            // extract output stream
            Result <long> outputDone = proc.StandardOutput.BaseStream.CopyTo(output, long.MaxValue, new Result <long>(TimeSpan.MaxValue));

            // extract error stream
            Result <long> errorDone = proc.StandardError.BaseStream.CopyTo(error, long.MaxValue, new Result <long>(TimeSpan.MaxValue));
            TaskTimer     timer     = TaskTimerFactory.Current.New(result.Timeout, delegate(TaskTimer t) {
                try {
                    // NOTE (steveb): we had to add the try..catch handler because mono throws an exception when killing a terminated process (why? who knows!)

                    proc.Kill();
                } catch { }
            }, null, TaskEnv.New());

            // wait for output and error streams to be done
            yield return(new AResult[] { outputDone, errorDone }.Join());

            int?exitCode = WaitForExit(proc, result.Timeout);

            timer.Cancel();
            proc.Close();
            if (exitCode.HasValue)
            {
                result.Return(exitCode.Value);
            }
            else
            {
                result.Throw(new InvalidOperationException("Unable to access process exit code"));
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Invoke a one argument action.
        /// </summary>
        /// <typeparam name="T1">Type of first argument.</typeparam>
        /// <param name="handler">Action to invoke.</param>
        /// <param name="arg1">First argument.</param>
        public void Invoke <T1>(Action <T1> handler, T1 arg1)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            if (_referenceCount < 1)
            {
                throw new InvalidOperationException("Cannot call invoke an unaquired TaskEnv");
            }
#pragma warning disable 219
            System.Diagnostics.StackTrace stacktrace = DebugUtil.GetStackTrace();
#pragma warning restore 219

            // check if handler can be invoked in-place or needs to queued up
            if (_dispatchQueue != null)
            {
                _dispatchQueue.QueueWorkItem(() => {
                    // store current thread-specific settings
                    TaskEnv previousEnv = _currentEnv;
                    try {
                        // set thread-specific settings
                        _currentEnv = this;

                        // execute handler
                        handler(arg1);
                    } catch (Exception e) {
                        _log.WarnExceptionMethodCall(e, "Invoke: unhandled exception in handler");
                    } finally {
                        Release();

                        // restore thread-specific settings
                        _currentEnv = previousEnv;
                    }
                });
            }
            else
            {
                // store current thread-specific settings
                TaskEnv previousEnv = _currentEnv;
                try {
                    // set thread-specific settings
                    _currentEnv = this;

                    // execute handler
                    handler(arg1);
                } catch (Exception e) {
                    _log.WarnExceptionMethodCall(e, "Invoke: unhandled exception in handler");
                } finally {
                    Release();

                    // restore thread-specific settings
                    _currentEnv = previousEnv;
                }
            }
        }
Exemplo n.º 6
0
 private TaskEnv(TaskEnv env, IDispatchQueue dispatchQueue, TaskTimerFactory taskTimerFactory)
 {
     if (env != null)
     {
         foreach (var entry in env)
         {
             var cloneable = entry.Value as ITaskLifespan;
             Add(entry.Key, cloneable == null ? entry.Value : cloneable.Clone());
         }
     }
     _taskTimerFactory = taskTimerFactory;
     _dispatchQueue    = (dispatchQueue is ImmediateDispatchQueue) ? null : dispatchQueue;
 }
Exemplo n.º 7
0
        /// <summary>
        /// Shut down all timers related to this factory.
        /// </summary>
        /// <remarks>
        /// Warning: this call is thread-blocking. It will try to execute all pending timers immediately, but
        /// will wait for each timer to complete.
        /// </remarks>
        public void Shutdown()
        {
            lock (_factories) {
                _factories.Remove(this);
            }
            List <KeyValuePair <TaskTimer, TaskEnv> > timers = null;

            // stop the thread timer
            _shutdown = true;
            GlobalClock.RemoveCallback(Tick);
            _owner.Target = null;

            // schedule all queued items for immediate execution
            // Note (arnec): should run the below in a helper so we can respect the timeout on this part as well
            //               (or maybe this should just be part of the thread clean-up)
            lock (_queue) {
                while (_queue.Count > 0)
                {
                    TaskTimer timer = _queue.Dequeue();
                    if (timer.TryLockPending())
                    {
                        // retrieve the associated behavior and reset the timer
                        TaskEnv env = timer.Env;
                        timer.Env = null;
                        timer.SetStatus(TaskTimerStatus.Done);

                        // add timer
                        timers = timers ?? new List <KeyValuePair <TaskTimer, TaskEnv> >();
                        timers.Add(new KeyValuePair <TaskTimer, TaskEnv>(timer, env));
                    }
                }
            }

            // BUGBUGBUG (arnec): we don't actually do anything with timeout, but let every timer take
            // an indefinite time.
            // check if any timers were gathered for immediate execution
            if (timers != null)
            {
                foreach (KeyValuePair <TaskTimer, TaskEnv> entry in timers)
                {
                    entry.Key.Execute(entry.Value);
                }
            }

            _running = false;
        }
Exemplo n.º 8
0
 void ITaskTimerOwner.AddToQueue(TaskTimer timer, TaskEnv env, TaskTimerStatus next)
 {
     env.Acquire();
     if (timer.Env != null)
     {
         timer.Env.Release();
     }
     if (_running)
     {
         lock (_queue) {
             timer.Env = env;
             timer.SetStatus(next);
             _queue.Enqueue(timer);
         }
     }
     else
     {
         env.Release();
         timer.Env = null;
         timer.SetStatus(TaskTimerStatus.Done);
     }
 }
Exemplo n.º 9
0
 void ITaskTimerOwner.AddToPending(TaskTimer timer, TaskEnv env, TaskTimerStatus next)
 {
     env.Acquire();
     if (timer.Env != null)
     {
         timer.Env.Release();
     }
     if (_running)
     {
         lock (_pending) {
             timer.Env = env;
             timer.SetStatus(next);
             _pending[timer] = null;
         }
     }
     else
     {
         env.Release();
         timer.Env = null;
         timer.SetStatus(TaskTimerStatus.Done);
     }
 }
Exemplo n.º 10
0
        private void Tick(DateTime now, TimeSpan elapsed)
        {
            // check if some timers are ready
            List <KeyValuePair <TaskTimer, TaskEnv> > timers = null;

            System.Threading.Interlocked.Increment(ref _counter);
            _last = now;
            lock (_queue) {
                // dequeue all timers that are ready to go
                while ((_queue.Count > 0) && (_queue.Peek().When <= now))
                {
                    TaskTimer timer = _queue.Dequeue();

                    // check if timer can be transitioned
                    if (timer.TryLockQueued())
                    {
                        // retrieve the associated behavior and reset the timer
                        TaskEnv env = timer.Env;
                        timer.Env = null;
                        timer.SetStatus(TaskTimerStatus.Done);

                        // add timer
                        timers = timers ?? new List <KeyValuePair <TaskTimer, TaskEnv> >();
                        timers.Add(new KeyValuePair <TaskTimer, TaskEnv>(timer, env));
                    }
                }

                // check if a maintance run is due
                if (_maintenance <= now)
                {
                    _maintenance = now.AddSeconds(TaskTimer.QUEUE_RESCAN);
                    DateTime horizon = now.AddSeconds(TaskTimer.QUEUE_CUTOFF);
                    lock (_pending) {
                        List <TaskTimer> activate = new List <TaskTimer>();
                        foreach (TaskTimer timer in _pending.Keys)
                        {
                            if (timer.When <= horizon)
                            {
                                activate.Add(timer);
                            }
                        }
                        foreach (TaskTimer timer in activate)
                        {
                            _pending.Remove(timer);
                            if (timer.TryQueuePending())
                            {
                                _queue.Enqueue(timer);
                            }
                        }
                    }
                }
            }

            // run schedule on its own thread to avoid re-entrancy issues
            if (timers != null)
            {
                foreach (KeyValuePair <TaskTimer, TaskEnv> entry in timers)
                {
                    entry.Key.Execute(entry.Value);
                }
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Create a new timer and set its fire time.
        /// </summary>
        /// <param name="when">Relateive time from now until when the timer should fire.</param>
        /// <param name="handler">The action to invoke when the timer fires.</param>
        /// <param name="state">A state object to associate with the timer.</param>
        /// <param name="env">The environment in which the timer should fire.</param>
        /// <returns>New timer instance.</returns>
        public TaskTimer New(TimeSpan when, Action <TaskTimer> handler, object state, TaskEnv env)
        {
            var result = new TaskTimer(this, handler, state);

            result.Change(when, env);
            return(result);
        }
Exemplo n.º 12
0
 public static Action WithEnv <T>(this Func <T> handler, TaskEnv env)
 {
     return(handler.WithEnv(env, null));
 }
Exemplo n.º 13
0
 public static Action WithEnv(this Action handler, TaskEnv env)
 {
     return(handler.WithEnv(env, null));
 }
Exemplo n.º 14
0
 /// <summary>
 /// Dispatch an action to be executed with a new, dedicated backgrouns thread.
 /// </summary>
 /// <typeparam name="T">Type of result value produced by action.</typeparam>
 /// <param name="handler">Action to enqueue for execution.</param>
 /// <param name="result">The <see cref="Result{T}"/>instance to be returned by this method.</param>
 /// <returns>Synchronization handle for the action's execution.</returns>
 public static Result <T> ForkThread <T>(Func <T> handler, Result <T> result)
 {
     ForkThread(TaskEnv.Clone().MakeAction(handler, result));
     return(result);
 }
Exemplo n.º 15
0
 /// <summary>
 /// Dispatch an action to be executed with a new, dedicated backgrouns thread.
 /// </summary>
 /// <param name="handler">Action to enqueue for execution.</param>
 /// <param name="result">The <see cref="Result"/>instance to be returned by this method.</param>
 /// <returns>Synchronization handle for the action's execution.</returns>
 public static Result ForkThread(Action handler, Result result)
 {
     ForkThread(TaskEnv.Clone().MakeAction(handler, result));
     return(result);
 }
Exemplo n.º 16
0
 /// <summary>
 /// Dispatch an action to be executed via the <see cref="GlobalDispatchQueue"/>.
 /// </summary>
 /// <param name="handler">Action to enqueue for execution.</param>
 /// <param name="env">Environment in which to execute the action.</param>
 /// <param name="result">The <see cref="Result"/>instance to be returned by this method.</param>
 /// <returns>Synchronization handle for the action's execution.</returns>
 public static Result Fork(Action handler, TaskEnv env, Result result)
 {
     return(GlobalDispatchQueue.QueueWorkItemWithEnv(handler, env, result));
 }