linux 下 tango.core.sync.Condition 和 gc 的相关问题, 源码检查

redsea 2007-09-10
今天用到 condition, 查看 Condition.d 源代码的时候, 想到一个问题:

  如果线程安装了某个信号处理器, 这个信号处理器没有设置 SA_RESTART, 那么信号发生的时候, pthread_cond_wait 会被打断, 同时返回0 (当作正常返回).

  因此, 不能认为 condition 返回的话, 要等的条件是一定发生了.

  想到 gc 也是通过 signal 暂停其他线程的, 进行了一些检查, 检查结果发现tango 设计是正确的, gc 不会打断 pthread_cond_wait.

检查的过程中大致了解了 gc 的启动情况.

gcx.d 中, 当进行内存分配, 而目前可用的 page 不足的时候, 会fullcollectshell, 然后调用到 fullcollect, fullcollect 调用 thread_suspendAll 暂停所有线程, 然后进行垃圾收集, 完事之后再 thread_resumeAll 让其他线程恢复执行.

thread_suspendAll, thread_resumeAll 都在 thread.d 中.

thread_suspendAll 通过发送 SIGUSR1 让线程进入 signal handler 等待 gc 完毕.
gc 处理完毕发送 SIGUSR2 通知其他线程, 可以从 signal handler 中返回. 整个逻辑还是比较简单的, 但是用到一些汇编代码都是 x86 的, 不可以移植.

我本来以为会有一个单独运行的 gc 线程 ---- 以前看 java 文章老是提到这个东西, 结果并没有这个线程.

相关的 signal handler 代码如下:

        extern (C) void thread_suspendHandler( int sig )
        in
        {
            assert( sig == SIGUSR1 );
        }
        body
        {
            version( D_InlineAsm_X86 )
            {
                asm
                {
                    pushad;
                }
            }
            else version( GNU )
            {
                __builtin_unwind_init();
            }
            else
            {
                static assert( false, "Architecture not supported." );
            }

            // NOTE: Since registers are being pushed and popped from the stack,
            //       any other stack data used by this function should be gone
            //       before the stack cleanup code is called below.
            {
                Thread  obj = Thread.getThis();

                // NOTE: The thread reference returned by getThis is set within
                //       the thread startup code, so it is possible that this
                //       handler may be called before the reference is set.  In
                //       this case it is safe to simply suspend and not worry
                //       about the stack pointers as the thread will not have
                //       any references to GC-managed data.
                if( obj && !obj.m_lock )
                {
                    obj.m_curr.tstack = getStackTop();
                }

                sigset_t    sigres = void;
                int         status;

                status = sigfillset( &sigres );
                assert( status == 0 );

                status = sigdelset( &sigres, SIGUSR2 );
                assert( status == 0 );

                status = sem_post( &suspendCount );
                assert( status == 0 );

                sigsuspend( &sigres );

                if( obj && !obj.m_lock )
                {
                    obj.m_curr.tstack = obj.m_curr.bstack;
                }
            }

            version( D_InlineAsm_X86 )
            {
                asm
                {
                    popad;
                }
            }
            else version( GNU )
            {
                // registers will be popped automatically
            }
            else
            {
                static assert( false, "Architecture not supported." );
            }
        }


        extern (C) void thread_resumeHandler( int sig )
        in
        {
            assert( sig == SIGUSR2 );
        }
        body
        {

        }

oldrev 2007-09-10
看来是跟 phobos 一样的策略,不知道什么时候能把runtime的这些接口规范一下,把基本的runtime代码统一起来
redsea 2007-09-10
oldrev 写道
看来是跟 phobos 一样的策略,不知道什么时候能把runtime的这些接口规范一下,把基本的runtime代码统一起来


我相信这些和操作系统底层密切相关的地方, 最优的方案应该都很接近.

稍高级别些, 例如 gc 的垃圾收集方法, 不同的应用程序可能不同的做法会更好, 这里可能会出现更多的设计选择, 如果有多种 gc, 编译时刻可选, 就更好了.
Global site tag (gtag.js) - Google Analytics