Example #1
0
        public static bool IsStopped(Thread self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            RubyThreadStatus status = GetStatus(self);

            return(status == RubyThreadStatus.Sleeping || status == RubyThreadStatus.Completed || status == RubyThreadStatus.Aborted);
        }
Example #2
0
        public static MutableString /*!*/ Inspect(RubyContext /*!*/ context, Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);

            MutableString result = MutableString.CreateMutable();

            result.Append("#<");
            result.Append(RubyUtils.GetClassName(context, self));
            result.Append(':');
            RubyUtils.AppendFormatHexObjectId(result, RubyUtils.GetObjectId(context, self));
            result.Append(' ');

            if ((self.ThreadState & ThreadState.WaitSleepJoin) != 0)
            {
                result.Append("sleep");
            }
            else if ((self.ThreadState & (ThreadState.Stopped | ThreadState.Aborted | ThreadState.AbortRequested)) != 0)
            {
                result.Append("dead");
            }
            else
            {
                result.Append("run");
            }

            result.Append('>');
            return(result);
        }
Example #3
0
        public static object AbortOnException(Thread /*!*/ self, bool value)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            info.AbortOnException = value;
            return(value);
        }
Example #4
0
        public static object Status(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            switch (GetStatus(self))
            {
            case RubyThreadStatus.Unstarted:
                return(MutableString.CreateAscii("unstarted"));

            case RubyThreadStatus.Running:
                return(MutableString.CreateAscii("run"));

            case RubyThreadStatus.Sleeping:
                return(MutableString.CreateAscii("sleep"));

            case RubyThreadStatus.Aborting:
                return(MutableString.CreateAscii("aborting"));

            case RubyThreadStatus.Completed:
                return(false);

            case RubyThreadStatus.Aborted:
                return(null);

            default:
                throw new ArgumentException("unknown thread status");
            }
        }
Example #5
0
        public static Thread Priority(Thread /*!*/ self, int priority)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            if (priority <= -2)
            {
                self.Priority = ThreadPriority.Lowest;
            }
            else if (priority == -1)
            {
                self.Priority = ThreadPriority.BelowNormal;
            }
            else if (priority == 0)
            {
                self.Priority = ThreadPriority.Normal;
            }
            else if (priority == 1)
            {
                self.Priority = ThreadPriority.AboveNormal;
            }
            else
            {
                self.Priority = ThreadPriority.Highest;
            }

            return(self);
        }
Example #6
0
        private static RubyThreadStatus GetStatus(Thread thread)
        {
            ThreadState    state = thread.ThreadState;
            RubyThreadInfo info  = RubyThreadInfo.FromThread(thread);

            if ((state & ThreadState.Unstarted) == ThreadState.Unstarted)
            {
                if (info.CreatedFromRuby)
                {
                    // Ruby threads do not have an unstarted status. We must be in the tiny window when ThreadOps.CreateThread
                    // created the thread, but has not called Thread.Start on it yet.
                    return(RubyThreadStatus.Running);
                }
                else
                {
                    // This is a thread created from outside Ruby. In such a case, we do not know when Thread.Start
                    // will be called on it. So we report it as unstarted.
                    return(RubyThreadStatus.Unstarted);
                }
            }

            if ((state & (ThreadState.Stopped | ThreadState.Aborted)) != 0)
            {
                if (RubyThreadInfo.FromThread(thread).Exception == null)
                {
                    return(RubyThreadStatus.Completed);
                }
                else
                {
                    return(RubyThreadStatus.Aborted);
                }
            }

            if ((state & ThreadState.WaitSleepJoin) == ThreadState.WaitSleepJoin)
            {
                // We will report a thread to be sleeping more often than in CRuby. This is because any "lock" statement
                // can potentially cause ThreadState.WaitSleepJoin. Also, "Thread.pass" does System.Threading.Thread.Sleep(0)
                // which also briefly changes the state to ThreadState.WaitSleepJoin
                return(RubyThreadStatus.Sleeping);
            }

            if ((state & ThreadState.AbortRequested) != 0)
            {
                return(RubyThreadStatus.Aborting);
            }

            if ((state & ThreadState.Running) == ThreadState.Running)
            {
                if (info.Blocked)
                {
                    return(RubyThreadStatus.Sleeping);
                }
                else
                {
                    return(RubyThreadStatus.Running);
                }
            }

            throw new ArgumentException("unknown thread status: " + state);
        }
Example #7
0
        public static object SetElement(Thread /*!*/ self, [NotNull] RubySymbol /*!*/ key, object value)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            info[key] = value;
            return(value);
        }
Example #8
0
        internal static void DoSleep()
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            // TODO: MRI throws an exception if you try to stop the main thread
            RubyThreadInfo info = RubyThreadInfo.FromThread(Thread.CurrentThread);

            info.Sleep();
        }
Example #9
0
        public static Thread Run(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            info.Run();
            return(self);
        }
Example #10
0
 internal static RubyThreadInfo FromThread(Thread t) {
     RubyThreadInfo result;
     lock (_mapping) {
         int key = t.ManagedThreadId;
         if (!_mapping.TryGetValue(key, out result)) {
             result = new RubyThreadInfo(t);
             _mapping[key] = result;
         }
     }
     return result;
 }
Example #11
0
            internal static RubyThreadInfo FromThread(Thread t)
            {
                RubyThreadInfo result;

                lock (_mapping) {
                    int key = t.ManagedThreadId;
                    if (!_mapping.TryGetValue(key, out result))
                    {
                        result        = new RubyThreadInfo(t);
                        _mapping[key] = result;
                    }
                }
                return(result);
            }
Example #12
0
        public static Thread /*!*/ Join(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);

            self.Join();

            Exception threadException = RubyThreadInfo.FromThread(self).Exception;

            if (threadException != null)
            {
                throw threadException;
            }

            return(self);
        }
Example #13
0
        public static Thread Kill(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            if (GetStatus(self) == RubyThreadStatus.Sleeping && info.ExitRequested)
            {
                // Thread must be sleeping in an ensure clause. Wake up the thread and allow ensure clause to complete
                info.Run();
                return(self);
            }

            info.ExitRequested = true;
            RubyUtils.ExitThread(self);
            return(self);
        }
Example #14
0
        public static RubyArray /*!*/ List(object self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);

            RubyThreadInfo[] threads = RubyThreadInfo.Threads;
            RubyArray        result  = new RubyArray(threads.Length);

            foreach (RubyThreadInfo threadInfo in threads)
            {
                Thread thread = threadInfo.Thread;
                if (thread != null)
                {
                    result.Add(thread);
                }
            }

            return(result);
        }
Example #15
0
        public static Thread /*!*/ Join(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);

            if (!(self.ThreadState == ThreadState.AbortRequested || self.ThreadState == ThreadState.Aborted))
            {
                self.Join();
            }

            Exception threadException = RubyThreadInfo.FromThread(self).Exception;

            if (threadException != null)
            {
                throw threadException;
            }

            return(self);
        }
Example #16
0
        public static MutableString /*!*/ Inspect(RubyContext /*!*/ context, Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);

            MutableString result = MutableString.CreateMutable(context.GetIdentifierEncoding());

            result.Append("#<");
            result.Append(context.GetClassDisplayName(self));
            result.Append(':');
            RubyUtils.AppendFormatHexObjectId(result, RubyUtils.GetObjectId(context, self));
            result.Append(' ');

            RubyThreadStatus status = GetStatus(self);

            switch (status)
            {
            case RubyThreadStatus.Unstarted:
                result.Append("unstarted");
                break;

            case RubyThreadStatus.Running:
                result.Append("run");
                break;

            case RubyThreadStatus.Sleeping:
                result.Append("sleep");
                break;

            case RubyThreadStatus.Aborting:
                result.Append("aborting");
                break;

            case RubyThreadStatus.Completed:
            case RubyThreadStatus.Aborted:
                result.Append("dead");
                break;
            }

            result.Append('>');
            return(result);
        }
Example #17
0
        public static Thread /*!*/ CreateThread(RubyContext /*!*/ context, BlockParam startRoutine, object self, [NotNull] params object[] /*!*/ args)
        {
            if (startRoutine == null)
            {
                throw new ThreadError("must be called with a block");
            }
            ThreadGroup group  = Group(Thread.CurrentThread);
            Thread      result = new Thread(new ThreadStart(delegate() {
                RubyThreadInfo info = RubyThreadInfo.FromThread(Thread.CurrentThread);
                info.Group          = group;

                try {
                    object threadResult;
                    // TODO: break?
                    startRoutine.Yield(args, out threadResult);
                    info.Result = threadResult;
#if !SILVERLIGHT
                } catch (ThreadInterruptedException) {
                    // Do nothing with this for now
#endif
                } catch (Exception e) {
                    info.Exception = e;

                    Utils.Log(
                        e.Message + "\r\n\r\n" +
                        e.StackTrace + "\r\n\r\n" +
                        IListOps.Join(context, RubyExceptionData.GetInstance(e).Backtrace).ToString(),
                        "THREAD"
                        );

                    if (_globalAbortOnException || info.AbortOnException)
                    {
                        throw;
                    }
                }
            }));

            result.Start();
            return(result);
        }
Example #18
0
        public static object Status(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            switch (self.ThreadState)
            {
            case ThreadState.WaitSleepJoin:
                return(MutableString.Create("sleep"));

            case ThreadState.Running:
                return(MutableString.Create("run"));

            case ThreadState.Aborted:
            case ThreadState.AbortRequested:
                return(null);

            case ThreadState.Stopped:
            case ThreadState.StopRequested:
                return(false);

            default:
                throw new ArgumentException("unknown thread status: " + self.ThreadState.ToString());
            }
        }
Example #19
0
        public static Thread /*!*/ Join(Thread /*!*/ self, double seconds)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);

            if (!(self.ThreadState == ThreadState.AbortRequested || self.ThreadState == ThreadState.Aborted))
            {
                double ms      = seconds * 1000;
                int    timeout = (ms <Int32.MinValue || ms> Int32.MaxValue) ? Timeout.Infinite : (int)ms;
                if (!self.Join(timeout))
                {
                    return(null);
                }
            }

            Exception threadException = RubyThreadInfo.FromThread(self).Exception;

            if (threadException != null)
            {
                throw threadException;
            }

            return(self);
        }
Example #20
0
        public static object Priority(Thread /*!*/ self)
        {
            RubyThreadInfo.RegisterThread(Thread.CurrentThread);
            switch (self.Priority)
            {
            case ThreadPriority.Lowest:
                return(-2);

            case ThreadPriority.BelowNormal:
                return(-1);

            case ThreadPriority.Normal:
                return(0);

            case ThreadPriority.AboveNormal:
                return(1);

            case ThreadPriority.Highest:
                return(2);

            default:
                return(0);
            }
        }
Example #21
0
        public static object AbortOnException(Thread /*!*/ self)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            return(info.AbortOnException);
        }
Example #22
0
        public static object Keys(RubyContext /*!*/ context, Thread /*!*/ self)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            return(info.GetKeys());
        }
Example #23
0
 public static bool IsAlive(Thread /*!*/ self)
 {
     RubyThreadInfo.RegisterThread(Thread.CurrentThread);
     return(self.IsAlive);
 }
Example #24
0
 public static void Yield(object self)
 {
     RubyThreadInfo.RegisterThread(Thread.CurrentThread);
     Thread.Sleep(0);
 }
Example #25
0
        public static ThreadGroup Group(Thread /*!*/ self)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            return(info.Group);
        }
Example #26
0
        private static void RubyThreadStart(RubyContext /*!*/ context, BlockParam /*!*/ startRoutine, object[] /*!*/ args, ThreadGroup group)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(Thread.CurrentThread);

            info.CreatedFromRuby = true;

            info.Group = group;

            try {
                object threadResult;
                // TODO: break/returns might throw LocalJumpError if the RFC that was created for startRoutine is not active anymore:
                if (startRoutine.Yield(args, out threadResult) && startRoutine.Returning(threadResult, out threadResult))
                {
                    info.Exception = new ThreadError("return can't jump across threads");
                }
                info.Result = threadResult;
            } catch (MethodUnwinder) {
                info.Exception = new ThreadError("return can't jump across threads");
            } catch (Exception e) {
                if (info.ExitRequested)
                {
                    // Note that "e" may not be ThreadAbortException at this point If an exception was raised from a finally block,
                    // we will get that here instead
                    Utils.Log(String.Format("Thread {0} exited.", info.Thread.ManagedThreadId), "THREAD");
                    info.Result = false;
#if !SILVERLIGHT
                    Thread.ResetAbort();
#endif
                }
                else
                {
                    e = RubyUtils.GetVisibleException(e);
                    RubyExceptionData.ActiveExceptionHandled(e);
                    info.Exception = e;

                    StringBuilder trace = new StringBuilder();
                    trace.Append(e.Message);
                    trace.AppendLine();
                    trace.AppendLine();
                    trace.Append(e.StackTrace);
                    trace.AppendLine();
                    trace.AppendLine();
                    RubyExceptionData data = RubyExceptionData.GetInstance(e);
                    if (data.Backtrace != null)
                    {
                        foreach (var frame in data.Backtrace)
                        {
                            trace.Append(frame.ToString());
                        }
                    }

                    Utils.Log(trace.ToString(), "THREAD");

                    if (_globalAbortOnException || info.AbortOnException)
                    {
                        throw;
                    }
                }
            } finally {
                // Its not a good idea to terminate a thread which has set Thread.critical=true, but its hard to predict
                // which thread will be scheduled next, even with green threads. However, ConditionVariable.create_timer
                // in monitor.rb explicitly does "Thread.critical=true; other_thread.raise" before exiting, and expects
                // other_thread to be scheduled immediately.
                // To deal with such code, we release the critical monitor here if the current thread is holding it
                if (context.RubyOptions.Compatibility < RubyCompatibility.Ruby19 && context.CriticalThread == Thread.CurrentThread)
                {
                    SetCritical(context, false);
                }
            }
        }
Example #27
0
 public static Thread /*!*/ Current(object self)
 {
     RubyThreadInfo.RegisterThread(Thread.CurrentThread);
     return(Thread.CurrentThread);
 }
Example #28
0
 public static void Critical(RubyContext /*!*/ context, object self, bool value)
 {
     RubyThreadInfo.RegisterThread(Thread.CurrentThread);
     SetCritical(context, value);
 }
Example #29
0
 [RubyMethod("critical", RubyMethodAttributes.PublicSingleton)] // Compatibility <= RubyCompatibility.Ruby18
 public static bool Critical(RubyContext /*!*/ context, object self)
 {
     RubyThreadInfo.RegisterThread(Thread.CurrentThread);
     return(context.CriticalThread != null);
 }
Example #30
0
 public static object Value(Thread /*!*/ self)
 {
     Join(self);
     return(RubyThreadInfo.FromThread(self).Result);
 }
Example #31
0
        public static object HasKey(Thread /*!*/ self, [NotNull] RubySymbol /*!*/ key)
        {
            RubyThreadInfo info = RubyThreadInfo.FromThread(self);

            return(info.HasKey(key));
        }