[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.1.2 and 1.1.1.3

version 1.1.1.2, 2000/04/14 11:07:59 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 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.1.2  
changed lines
  Added in v.1.1.1.3

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