AutoThread.h   [plain text]


/*
 * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

#pragma once
#ifndef __AUTO_THREAD__
#define __AUTO_THREAD__


#include "AutoDefs.h"


namespace Auto {

    //
    // Forward declarations
    //
    class MemoryScanner;
    class Zone;



    //----- NonVolatileRegisters -----//
    
    //
    // Used to capture the register state of the current thread.
    //

#if defined(__ppc__) || defined(__ppc64__)
    
    class NonVolatileRegisters {

      private:
      
        enum {
            first_nonvolatile_register = 13,                // used to capture registers
            number_of_nonvolatile_registers = 32 - first_nonvolatile_register,
                                                            // used to capture registers
        };
        
        usword_t _registers[number_of_nonvolatile_registers];// buffer for capturing registers
        
        //
        // capture_registers
        //
        // Capture the state of the non-volatile registers.
        //
        static inline void capture_registers(register usword_t *registers) {
#if defined(__ppc__)
            __asm__ volatile ("stmw r13,0(%[registers])" : : [registers] "b" (registers) : "memory");
#else
            __asm__ volatile ("std r13,0(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r14,8(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r15,16(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r16,24(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r17,32(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r18,40(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r19,48(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r20,56(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r21,64(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r22,72(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r23,80(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r24,88(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r25,96(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r26,104(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r27,112(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r28,120(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r29,128(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r30,136(%[registers])" : : [registers] "b" (registers) : "memory");
            __asm__ volatile ("std r31,144(%[registers])" : : [registers] "b" (registers) : "memory");
#endif
        }

      public:
      
        //
        // Constructor
        //
        NonVolatileRegisters() { capture_registers(_registers); }
        
        
        //
        // buffer_range
        //
        // Returns the range of captured registers buffer.
        //
        inline Range buffer_range() { return Range(_registers, sizeof(_registers)); }
        
    };

#elif defined(__i386__)
    
    class NonVolatileRegisters {
      private:
        // Non-volatile registers are: ebx, ebp, esp, esi, edi
        usword_t _registers[5];  // buffer for capturing registers
        
        //
        // capture_registers
        //
        // Capture the state of the non-volatile registers.
        //
        static inline void capture_registers(register usword_t *registers) {
            __asm__ volatile ("mov %%ebx,  0(%[registers]) \n" 
                              "mov %%ebp,  4(%[registers]) \n" 
                              "mov %%esp,  8(%[registers]) \n" 
                              "mov %%esi, 12(%[registers]) \n" 
                              "mov %%edi, 16(%[registers]) \n" 
                              : : [registers] "a" (registers) : "memory");
        }

      public:
      
        //
        // Constructor
        //
        NonVolatileRegisters() { capture_registers(_registers); }
        
        
        //
        // buffer_range
        //
        // Returns the range of captured registers buffer.
        //
        inline Range buffer_range() { return Range(_registers, sizeof(_registers)); }
        
    };

#elif defined(__x86_64__)
    
    class NonVolatileRegisters {
      private:
        // Non-volatile registers are: rbx rsp rbp r12-r15
        usword_t _registers[7];  // buffer for capturing registers
        
        //
        // capture_registers
        //
        // Capture the state of the non-volatile registers.
        //
        static inline void capture_registers(register usword_t *registers) {
            __asm__ volatile ("movq %%rbx,  0(%[registers]) \n" 
                              "movq %%rsp,  8(%[registers]) \n" 
                              "movq %%rbp, 16(%[registers]) \n" 
                              "movq %%r12, 24(%[registers]) \n" 
                              "movq %%r13, 32(%[registers]) \n" 
                              "movq %%r14, 40(%[registers]) \n" 
                              "movq %%r15, 48(%[registers]) \n" 
                              : : [registers] "a" (registers) : "memory");
        }

      public:
      
        //
        // Constructor
        //
        NonVolatileRegisters() { capture_registers(_registers); }
        
        
        //
        // buffer_range
        //
        // Returns the range of captured registers buffer.
        //
        inline Range buffer_range() { return Range(_registers, sizeof(_registers)); }
        
    };

#else
#error Unknown Architecture
#endif


    //----- Thread -----//
    
    //
    // Track threads that need will be scanned during gc.
    //
    
    class Thread : public AuxAllocated {
    
      private:
            
        Thread      *_next;                                 // next thread in linked list
        Zone        *_zone;                                 // managing zone
        pthread_t   _pthread;                               // posix thread
        mach_port_t _thread;                                // mach thread
        void        *_stack;                                // cached value of pthread_get_stackaddr_np(_pthread)
        bool        _exiting;                               // used to record that the thread is exiting
        bool        _deadPort;                              // set true if the mach port found dead (missing unregister_thread)
        uint32_t    _suspended;                             // records suspend count.
        uint32_t    _retains;                               // tracks number of calls to Zone::register_thread().
        
        
        
        //
        // scan_current_thread
        //
        // Scan the current thread stack and registers for block references.
        //
        void scan_current_thread(MemoryScanner &scanner);


        //
        // scan_other_thread
        //
        // Scan a thread other than the current thread stack and registers for block references.
        //
        void scan_other_thread(MemoryScanner &scanner);


      public:
      
      
        //
        // Constructor
        //
        Thread(Zone *zone, pthread_t pthread, mach_port_t thread)
            : _next(NULL), _zone(zone), _pthread(pthread), _thread(thread), _stack(pthread_get_stackaddr_np(pthread)),
              _exiting(false), _deadPort(false), _suspended(0), _retains(0)
        {
        }
        
        
        //
        // Accessors
        //
        inline Thread      *next()                { return _next; }
        inline Zone        *zone()                { return _zone; }
        inline pthread_t   pthread()              { return _pthread; }
        inline mach_port_t thread()               { return _thread; }
        inline bool        is_exiting()           { return _exiting; }
        inline void        set_next(Thread *next) { _next = next; }
        inline void        set_is_exiting()       { _exiting = true; }
        inline void        retain()               { ++_retains; }
        inline uint32_t    release()              { return --_retains; }
        inline bool        deadPort()             { return _deadPort; }
        
        
        //
        // is_current_thread
        //
        // Returns true if the this thread is the current thread.
        //
        inline bool is_current_thread() const {
            return pthread_self() == _pthread;
        }
        
        
        //
        // unlink
        //
        // Unlink the thread from the list of threads.
        //
        inline void unlink(Thread **link) {
            for (Thread *t = *link; t; link = &t->_next, t = *link) {
                // if found
                if (t == this) {
                    // mend the link
                    *link = t->_next;
                    break;
                }
            }
        }

        
        //
        // scan_thread_with_suspend_and_closure
        //
        // Scan the current thread stack and registers for block references.  This
        // performs a complete scan of a suspended thread looking for roots.  This method
        // is called as a last pass during scanning to catch all thread's block references.
        //
        void scan_thread_with_suspend_and_closure(MemoryScanner &scanner);


        //
        // scan_thread_without_suspend
        //
        // Scan the current thread stack and registers for block references.  This
        // performs a fast scan an unsuspended thread looking for roots. This method
        // is called as a first pass during scanning to catch most of the thread's 
        // block references.
        //
        void scan_thread_without_suspend(MemoryScanner &scanner);


        //
        // suspend
        //
        // Temporarily suspend the thread from further execution.  Returns true if the thread is
        // still alive.
        //
        bool suspend();


        //
        // resume
        //
        // Resume a suspended thread.
        //
        bool resume();


        //
        // destroy_registered_thread
        //
        // Since the pthreads library automatically clears the registered thread tsd before calling us,
        // we set it back, to keep the thread registration alive until somebody calls unregister_thread().
        //
        static void destroy_registered_thread(void *data);
        
        
    };

};

#endif // __AUTO_THREAD__