[BACK]Return to linux_threads.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gc

Diff for /OpenXM_contrib/gc/Attic/linux_threads.c between version 1.1 and 1.1.1.3

version 1.1, 1999/11/27 10:58:32 version 1.1.1.3, 2000/12/01 14:48:25
Line 36 
Line 36 
 # if defined(LINUX_THREADS)  # if defined(LINUX_THREADS)
   
 # include <pthread.h>  # include <pthread.h>
   # include <sched.h>
 # include <time.h>  # include <time.h>
 # include <errno.h>  # include <errno.h>
 # include <unistd.h>  # include <unistd.h>
 # include <sys/mman.h>  # include <sys/mman.h>
 # include <sys/time.h>  # include <sys/time.h>
 # include <semaphore.h>  # include <semaphore.h>
   # include <signal.h>
   
 #undef pthread_create  #ifdef USE_LD_WRAP
 #undef pthread_sigmask  #   define WRAP_FUNC(f) __wrap_##f
 #undef pthread_join  #   define REAL_FUNC(f) __real_##f
   #else
   #   define WRAP_FUNC(f) GC_##f
   #   define REAL_FUNC(f) f
   #   undef pthread_create
   #   undef pthread_sigmask
   #   undef pthread_join
   #endif
   
   
 void GC_thr_init();  void GC_thr_init();
   
 #if 0  #if 0
Line 86  typedef struct GC_Thread_Rep {
Line 96  typedef struct GC_Thread_Rep {
 #       define DETACHED 2       /* Thread is intended to be detached.   */  #       define DETACHED 2       /* Thread is intended to be detached.   */
 #       define MAIN_THREAD 4    /* True for the original thread only.   */  #       define MAIN_THREAD 4    /* True for the original thread only.   */
   
     ptr_t stack_end;      ptr_t stack_end;            /* Cold end of the stack.               */
     ptr_t stack_ptr;            /* Valid only when stopped. */      ptr_t stack_ptr;            /* Valid only when stopped.             */
   #   ifdef IA64
           ptr_t backing_store_end;
           ptr_t backing_store_ptr;
   #   endif
     int signal;      int signal;
     void * status;              /* The value returned from the thread.  */      void * status;              /* The value returned from the thread.  */
                                 /* Used only to avoid premature         */                                  /* Used only to avoid premature         */
Line 118  GC_linux_thread_top_of_stack() relies on implementatio
Line 132  GC_linux_thread_top_of_stack() relies on implementatio
 LinuxThreads, namely that thread stacks are allocated on 2M boundaries  LinuxThreads, namely that thread stacks are allocated on 2M boundaries
 and grow to no more than 2M.  and grow to no more than 2M.
 To make sure that we're using LinuxThreads and not some other thread  To make sure that we're using LinuxThreads and not some other thread
 package, we generate a dummy reference to `__pthread_initial_thread_bos',  package, we generate a dummy reference to `pthread_kill_other_threads_np'
   (was `__pthread_initial_thread_bos' but that disappeared),
 which is a symbol defined in LinuxThreads, but (hopefully) not in other  which is a symbol defined in LinuxThreads, but (hopefully) not in other
 thread packages.  thread packages.
 */  */
 extern char * __pthread_initial_thread_bos;  void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
 char **dummy_var_to_force_linux_threads = &__pthread_initial_thread_bos;  
   
 #define LINUX_THREADS_STACK_SIZE  (2 * 1024 * 1024)  #define LINUX_THREADS_STACK_SIZE  (2 * 1024 * 1024)
   
Line 138  static inline ptr_t GC_linux_thread_top_of_stack(void)
Line 152  static inline ptr_t GC_linux_thread_top_of_stack(void)
   return tos;    return tos;
 }  }
   
   #ifdef IA64
     extern word GC_save_regs_in_stack();
   #endif
   
 void GC_suspend_handler(int sig)  void GC_suspend_handler(int sig)
 {  {
     int dummy;      int dummy;
Line 160  void GC_suspend_handler(int sig)
Line 178  void GC_suspend_handler(int sig)
     /* to stop the world.  Thus concurrent modification of the  */      /* to stop the world.  Thus concurrent modification of the  */
     /* data structure is impossible.                            */      /* data structure is impossible.                            */
     me -> stack_ptr = (ptr_t)(&dummy);      me -> stack_ptr = (ptr_t)(&dummy);
     me -> stack_end = GC_linux_thread_top_of_stack();  #   ifdef IA64
           me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
   #   endif
   
     /* Tell the thread that wants to stop the world that this   */      /* Tell the thread that wants to stop the world that this   */
     /* thread has been stopped.  Note that sem_post() is        */      /* thread has been stopped.  Note that sem_post() is        */
Line 173  void GC_suspend_handler(int sig)
Line 193  void GC_suspend_handler(int sig)
     /* is no race.                                              */      /* is no race.                                              */
     if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");      if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");
     if (sigdelset(&mask, SIG_RESTART) != 0) ABORT("sigdelset() failed");      if (sigdelset(&mask, SIG_RESTART) != 0) ABORT("sigdelset() failed");
   #   ifdef NO_SIGNALS
         if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed");
         if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed");
         if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed");
   #   endif
     do {      do {
             me->signal = 0;              me->signal = 0;
             sigsuspend(&mask);             /* Wait for signal */              sigsuspend(&mask);             /* Wait for signal */
Line 375  void GC_start_world()
Line 400  void GC_start_world()
     #endif      #endif
 }  }
   
 /* We hold allocation lock.  We assume the world is stopped.    */  # ifdef IA64
   #   define IF_IA64(x) x
   # else
   #   define IF_IA64(x)
   # endif
   /* We hold allocation lock.  Should do exactly the right thing if the   */
   /* world is stopped.  Should not fail if it isn't.                      */
 void GC_push_all_stacks()  void GC_push_all_stacks()
 {  {
     register int i;      int i;
     register GC_thread p;      GC_thread p;
     register ptr_t sp = GC_approx_sp();      ptr_t sp = GC_approx_sp();
     register ptr_t lo, hi;      ptr_t lo, hi;
       /* On IA64, we also need to scan the register backing store. */
       IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
     pthread_t me = pthread_self();      pthread_t me = pthread_self();
   
     if (!GC_thr_initialized) GC_thr_init();      if (!GC_thr_initialized) GC_thr_init();
Line 393  void GC_push_all_stacks()
Line 426  void GC_push_all_stacks()
         if (p -> flags & FINISHED) continue;          if (p -> flags & FINISHED) continue;
         if (pthread_equal(p -> id, me)) {          if (pthread_equal(p -> id, me)) {
             lo = GC_approx_sp();              lo = GC_approx_sp();
               IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
         } else {          } else {
             lo = p -> stack_ptr;              lo = p -> stack_ptr;
               IF_IA64(bs_hi = p -> backing_store_ptr;)
         }          }
         if ((p -> flags & MAIN_THREAD) == 0) {          if ((p -> flags & MAIN_THREAD) == 0) {
             if (pthread_equal(p -> id, me)) {              hi = p -> stack_end;
                 hi = GC_linux_thread_top_of_stack();              IF_IA64(bs_lo = p -> backing_store_end);
             } else {  
                 hi = p -> stack_end;  
             }  
         } else {          } else {
             /* The original stack. */              /* The original stack. */
             hi = GC_stackbottom;              hi = GC_stackbottom;
               IF_IA64(bs_lo = BACKING_STORE_BASE;)
         }          }
         #if DEBUG_THREADS          #if DEBUG_THREADS
             GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",              GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
                 (unsigned long) p -> id,                  (unsigned long) p -> id,
                 (unsigned long) lo, (unsigned long) hi);                  (unsigned long) lo, (unsigned long) hi);
         #endif          #endif
           if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
         GC_push_all_stack(lo, hi);          GC_push_all_stack(lo, hi);
   #       ifdef IA64
             if (pthread_equal(p -> id, me)) {
               GC_push_all_eager(bs_lo, bs_hi);
             } else {
               GC_push_all_stack(bs_lo, bs_hi);
             }
   #       endif
       }        }
     }      }
 }  }
Line 420  void GC_push_all_stacks()
Line 461  void GC_push_all_stacks()
 /* We hold the allocation lock. */  /* We hold the allocation lock. */
 void GC_thr_init()  void GC_thr_init()
 {  {
       int dummy;
     GC_thread t;      GC_thread t;
     struct sigaction act;      struct sigaction act;
   
Line 433  void GC_thr_init()
Line 475  void GC_thr_init()
     if (sigfillset(&act.sa_mask) != 0) {      if (sigfillset(&act.sa_mask) != 0) {
         ABORT("sigfillset() failed");          ABORT("sigfillset() failed");
     }      }
   #   ifdef NO_SIGNALS
         if (sigdelset(&act.sa_mask, SIGINT) != 0
             || sigdelset(&act.sa_mask, SIGQUIT != 0)
             || sigdelset(&act.sa_mask, SIGTERM != 0)) {
           ABORT("sigdelset() failed");
         }
   #   endif
   
     /* SIG_RESTART is unmasked by the handler when necessary.   */      /* SIG_RESTART is unmasked by the handler when necessary.   */
     act.sa_handler = GC_suspend_handler;      act.sa_handler = GC_suspend_handler;
     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {      if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
Line 446  void GC_thr_init()
Line 496  void GC_thr_init()
   
     /* Add the initial thread, so we can stop it.       */      /* Add the initial thread, so we can stop it.       */
       t = GC_new_thread(pthread_self());        t = GC_new_thread(pthread_self());
       t -> stack_ptr = 0;        t -> stack_ptr = (ptr_t)(&dummy);
       t -> flags = DETACHED | MAIN_THREAD;        t -> flags = DETACHED | MAIN_THREAD;
 }  }
   
 int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)  int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
 {  {
     sigset_t fudged_set;      sigset_t fudged_set;
   
Line 459  int GC_pthread_sigmask(int how, const sigset_t *set, s
Line 509  int GC_pthread_sigmask(int how, const sigset_t *set, s
         sigdelset(&fudged_set, SIG_SUSPEND);          sigdelset(&fudged_set, SIG_SUSPEND);
         set = &fudged_set;          set = &fudged_set;
     }      }
     return(pthread_sigmask(how, set, oset));      return(REAL_FUNC(pthread_sigmask)(how, set, oset));
 }  }
   
 struct start_info {  struct start_info {
Line 483  void GC_thread_exit_proc(void *arg)
Line 533  void GC_thread_exit_proc(void *arg)
     } else {      } else {
         me -> flags |= FINISHED;          me -> flags |= FINISHED;
     }      }
       if (GC_incremental && GC_collection_in_progress()) {
           int old_gc_no = GC_gc_no;
   
           /* Make sure that no part of our stack is still on the mark stack, */
           /* since it's about to be unmapped.                                */
           while (GC_incremental && GC_collection_in_progress()
                  && old_gc_no == GC_gc_no) {
               ENTER_GC();
               GC_collect_a_little_inner(1);
               EXIT_GC();
               UNLOCK();
               sched_yield();
               LOCK();
           }
       }
     UNLOCK();      UNLOCK();
 }  }
   
 int GC_pthread_join(pthread_t thread, void **retval)  int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
 {  {
     int result;      int result;
     GC_thread thread_gc_id;      GC_thread thread_gc_id;
Line 496  int GC_pthread_join(pthread_t thread, void **retval)
Line 561  int GC_pthread_join(pthread_t thread, void **retval)
     /* This is guaranteed to be the intended one, since the thread id   */      /* This is guaranteed to be the intended one, since the thread id   */
     /* cant have been recycled by pthreads.                             */      /* cant have been recycled by pthreads.                             */
     UNLOCK();      UNLOCK();
     result = pthread_join(thread, retval);      result = REAL_FUNC(pthread_join)(thread, retval);
     LOCK();      LOCK();
     /* Here the pthread thread id may have been recycled. */      /* Here the pthread thread id may have been recycled. */
     GC_delete_gc_thread(thread, thread_gc_id);      GC_delete_gc_thread(thread, thread_gc_id);
Line 506  int GC_pthread_join(pthread_t thread, void **retval)
Line 571  int GC_pthread_join(pthread_t thread, void **retval)
   
 void * GC_start_routine(void * arg)  void * GC_start_routine(void * arg)
 {  {
       int dummy;
     struct start_info * si = arg;      struct start_info * si = arg;
     void * result;      void * result;
     GC_thread me;      GC_thread me;
Line 514  void * GC_start_routine(void * arg)
Line 580  void * GC_start_routine(void * arg)
     void *start_arg;      void *start_arg;
   
     my_pthread = pthread_self();      my_pthread = pthread_self();
   #   ifdef DEBUG_THREADS
           GC_printf1("Starting thread 0x%lx\n", my_pthread);
           GC_printf1("pid = %ld\n", (long) getpid());
           GC_printf1("sp = 0x%lx\n", (long) &arg);
   #   endif
     LOCK();      LOCK();
     me = GC_new_thread(my_pthread);      me = GC_new_thread(my_pthread);
     me -> flags = si -> flags;      me -> flags = si -> flags;
     me -> stack_ptr = 0;      me -> stack_ptr = 0;
     me -> stack_end = 0;      /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99)    */
       /* doesn't work because the stack base in /proc/self/stat is the    */
       /* one for the main thread.  There is a strong argument that that's */
       /* a kernel bug, but a pervasive one.                               */
   #   ifdef STACK_GROWS_DOWN
         me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
                                   & ~(GC_page_size - 1));
         me -> stack_ptr = me -> stack_end - 0x10;
           /* Needs to be plausible, since an asynchronous stack mark      */
           /* should not crash.                                            */
   #   else
         me -> stack_end = (ptr_t)(((word)(&dummy) & ~(GC_page_size - 1));
         me -> stack_ptr = me -> stack_end + 0x10;
   #   endif
       /* This is dubious, since we may be more than a page into the stack, */
       /* and hence skip some of it, though it's not clear that matters.    */
   #   ifdef IA64
         me -> backing_store_end = (ptr_t)
                           (GC_save_regs_in_stack() & ~(GC_page_size - 1));
         /* This is also < 100% convincing.  We should also read this      */
         /* from /proc, but the hook to do so isn't there yet.             */
   #   endif /* IA64 */
     UNLOCK();      UNLOCK();
     start = si -> start_routine;      start = si -> start_routine;
     start_arg = si -> arg;  
     sem_post(&(si -> registered));  
     pthread_cleanup_push(GC_thread_exit_proc, si);  
 #   ifdef DEBUG_THREADS  #   ifdef DEBUG_THREADS
         GC_printf1("Starting thread 0x%lx\n", pthread_self());  
         GC_printf1("pid = %ld\n", (long) getpid());  
         GC_printf1("sp = 0x%lx\n", (long) &arg);  
         GC_printf1("start_routine = 0x%lx\n", start);          GC_printf1("start_routine = 0x%lx\n", start);
 #   endif  #   endif
       start_arg = si -> arg;
       sem_post(&(si -> registered));
       pthread_cleanup_push(GC_thread_exit_proc, si);
     result = (*start)(start_arg);      result = (*start)(start_arg);
 #if DEBUG_THREADS  #if DEBUG_THREADS
         GC_printf1("Finishing thread 0x%x\n", pthread_self());          GC_printf1("Finishing thread 0x%x\n", pthread_self());
Line 544  void * GC_start_routine(void * arg)
Line 633  void * GC_start_routine(void * arg)
 }  }
   
 int  int
 GC_pthread_create(pthread_t *new_thread,  WRAP_FUNC(pthread_create)(pthread_t *new_thread,
                   const pthread_attr_t *attr,                    const pthread_attr_t *attr,
                   void *(*start_routine)(void *), void *arg)                    void *(*start_routine)(void *), void *arg)
 {  {
Line 576  GC_pthread_create(pthread_t *new_thread,
Line 665  GC_pthread_create(pthread_t *new_thread,
     if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;      if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
     si -> flags = my_flags;      si -> flags = my_flags;
     UNLOCK();      UNLOCK();
     result = pthread_create(new_thread, &new_attr, GC_start_routine, si);  #   ifdef DEBUG_THREADS
           GC_printf1("About to start new thread from thread 0x%X\n",
                      pthread_self());
   #   endif
       result = REAL_FUNC(pthread_create)(new_thread, &new_attr, GC_start_routine, si);
   #   ifdef DEBUG_THREADS
           GC_printf1("Started thread 0x%X\n", *new_thread);
   #   endif
     /* Wait until child has been added to the thread table.             */      /* Wait until child has been added to the thread table.             */
     /* This also ensures that we hold onto si until the child is done   */      /* This also ensures that we hold onto si until the child is done   */
     /* with it.  Thus it doesn't matter whether it is otherwise         */      /* with it.  Thus it doesn't matter whether it is otherwise         */
Line 588  GC_pthread_create(pthread_t *new_thread,
Line 684  GC_pthread_create(pthread_t *new_thread,
     return(result);      return(result);
 }  }
   
 GC_bool GC_collecting = 0;  #if defined(USE_SPIN_LOCK)
   
   VOLATILE GC_bool GC_collecting = 0;
                         /* A hint that we're in the collector and       */                          /* A hint that we're in the collector and       */
                         /* holding the allocation lock for an           */                          /* holding the allocation lock for an           */
                         /* extended period.                             */                          /* extended period.                             */
Line 660  yield:
Line 758  yield:
         }          }
     }      }
 }  }
   
   #endif /* known architecture */
   
 # endif /* LINUX_THREADS */  # endif /* LINUX_THREADS */
   

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.1.3

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>