From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Tom Tromey Newsgroups: gmane.emacs.devel Subject: [PATCH 02/10] make GC thread-ready Date: Thu, 09 Aug 2012 13:37:43 -0600 Message-ID: <87r4rfeu0o.fsf@fleche.redhat.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: dough.gmane.org 1344541077 11147 80.91.229.3 (9 Aug 2012 19:37:57 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 9 Aug 2012 19:37:57 +0000 (UTC) To: Emacs discussions Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Aug 09 21:37:57 2012 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1SzYYL-0002yf-6n for ged-emacs-devel@m.gmane.org; Thu, 09 Aug 2012 21:37:53 +0200 Original-Received: from localhost ([::1]:46714 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SzYYK-0000wj-DA for ged-emacs-devel@m.gmane.org; Thu, 09 Aug 2012 15:37:52 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:46587) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SzYYH-0000wc-16 for emacs-devel@gnu.org; Thu, 09 Aug 2012 15:37:50 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SzYYF-0003UC-7L for emacs-devel@gnu.org; Thu, 09 Aug 2012 15:37:48 -0400 Original-Received: from mx1.redhat.com ([209.132.183.28]:31648) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SzYYE-0003U3-UR for emacs-devel@gnu.org; Thu, 09 Aug 2012 15:37:47 -0400 Original-Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q79JbksE008553 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 9 Aug 2012 15:37:46 -0400 Original-Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q79JbheT011499 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Thu, 9 Aug 2012 15:37:44 -0400 X-Attribution: Tom User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:152376 Archived-At: This parameterizes the GC a bit to make it thread-ready. The basic idea is that whenever a thread "exits lisp" -- that is, releases the global lock in favor of another thread -- it must save its stack boundaries in the thread object. This way the boundaries are always available for marking. This is the purpose of flush_stack_call_func. I haven't tested this under all the possible GC configurations. There is a new FIXME in a spot that i didn't convert. Arguably all_threads should go in the previous patch. --- src/alloc.c | 78 ++++++++++++++++++------------------------------------ src/bytecode.c | 11 +++----- src/eval.c | 13 +++++++++ src/lisp.h | 18 +++++++++--- src/thread.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/thread.h | 5 +++ 6 files changed, 140 insertions(+), 64 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 0fdf7da..b3dab59 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -379,7 +379,6 @@ static struct mem_node mem_z; static struct Lisp_Vector *allocate_vectorlike (ptrdiff_t); static void lisp_free (void *); -static void mark_stack (void); static int live_vector_p (struct mem_node *, void *); static int live_buffer_p (struct mem_node *, void *); static int live_string_p (struct mem_node *, void *); @@ -4857,8 +4856,27 @@ dump_zombies (void) would be necessary, each one starting with one byte more offset from the stack start. */ -static void -mark_stack (void) +void +mark_stack (char *bottom, char *end) +{ + /* This assumes that the stack is a contiguous region in memory. If + that's not the case, something has to be done here to iterate + over the stack segments. */ + mark_memory (bottom, end); + + /* Allow for marking a secondary stack, like the register stack on the + ia64. */ +#ifdef GC_MARK_SECONDARY_STACK + GC_MARK_SECONDARY_STACK (); +#endif + +#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS + check_gcpros (); +#endif +} + +void +flush_stack_call_func (void (*func) (void *arg), void *arg) { void *end; @@ -4914,20 +4932,8 @@ mark_stack (void) #endif /* not GC_SAVE_REGISTERS_ON_STACK */ #endif /* not HAVE___BUILTIN_UNWIND_INIT */ - /* This assumes that the stack is a contiguous region in memory. If - that's not the case, something has to be done here to iterate - over the stack segments. */ - mark_memory (stack_bottom, end); - - /* Allow for marking a secondary stack, like the register stack on the - ia64. */ -#ifdef GC_MARK_SECONDARY_STACK - GC_MARK_SECONDARY_STACK (); -#endif - -#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS - check_gcpros (); -#endif + current_thread->stack_top = end; + (*func) (arg); } #endif /* GC_MARK_STACK != 0 */ @@ -5449,11 +5455,7 @@ See Info node `(elisp)Garbage Collection'. */) for (i = 0; i < staticidx; i++) mark_object (*staticvec[i]); - for (bind = specpdl; bind != specpdl_ptr; bind++) - { - mark_object (bind->symbol); - mark_object (bind->old_value); - } + mark_threads (); mark_terminals (); mark_kboards (); mark_ttys (); @@ -5465,40 +5467,12 @@ See Info node `(elisp)Garbage Collection'. */) } #endif -#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \ - || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS) - mark_stack (); -#else - { - register struct gcpro *tail; - for (tail = gcprolist; tail; tail = tail->next) - for (i = 0; i < tail->nvars; i++) - mark_object (tail->var[i]); - } - mark_byte_stack (); - { - struct catchtag *catch; - struct handler *handler; - - for (catch = catchlist; catch; catch = catch->next) - { - mark_object (catch->tag); - mark_object (catch->val); - } - for (handler = handlerlist; handler; handler = handler->next) - { - mark_object (handler->handler); - mark_object (handler->var); - } - } - mark_backtrace (); -#endif - #ifdef HAVE_WINDOW_SYSTEM mark_fringe_data (); #endif #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES + FIXME; mark_stack (); #endif @@ -5548,7 +5522,7 @@ See Info node `(elisp)Garbage Collection'. */) /* Clear the mark bits that we set in certain root slots. */ - unmark_byte_stack (); + unmark_threads (); VECTOR_UNMARK (&buffer_defaults); VECTOR_UNMARK (&buffer_local_symbols); diff --git a/src/bytecode.c b/src/bytecode.c index 0194594..d61e37d 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -335,12 +335,11 @@ struct byte_stack #if BYTE_MARK_STACK void -mark_byte_stack (void) +mark_byte_stack (struct byte_stack *stack) { - struct byte_stack *stack; Lisp_Object *obj; - for (stack = byte_stack_list; stack; stack = stack->next) + for (; stack; stack = stack->next) { /* If STACK->top is null here, this means there's an opcode in Fbyte_code that wasn't expected to GC, but did. To find out @@ -364,11 +363,9 @@ mark_byte_stack (void) counters. Called when GC has completed. */ void -unmark_byte_stack (void) +unmark_byte_stack (struct byte_stack *stack) { - struct byte_stack *stack; - - for (stack = byte_stack_list; stack; stack = stack->next) + for (; stack; stack = stack->next) { if (stack->byte_string_start != SDATA (stack->byte_string)) { diff --git a/src/eval.c b/src/eval.c index 768cdc1..49ead49 100644 --- a/src/eval.c +++ b/src/eval.c @@ -165,6 +165,19 @@ init_eval (void) when_entered_debugger = -1; } +#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \ + || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS) +void +mark_catchlist (struct catchtag *catch) +{ + for (; catch; catch = catch->next) + { + mark_object (catch->tag); + mark_object (catch->val); + } +} +#endif + /* Unwind-protect function used by call_debugger. */ static Lisp_Object diff --git a/src/lisp.h b/src/lisp.h index 2cf8499..db8d9b4 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2714,6 +2714,10 @@ extern void mark_object (Lisp_Object); #if defined REL_ALLOC && !defined SYSTEM_MALLOC extern void refill_memory_reserve (void); #endif +#if GC_MARK_STACK +extern void mark_stack (char *, char *); +#endif +extern void flush_stack_call_func (void (*func) (void *arg), void *arg); extern const char *pending_malloc_warning; extern Lisp_Object zero_vector; extern EMACS_INT consing_since_gc; @@ -2901,6 +2905,10 @@ extern Lisp_Object Vautoload_queue; extern Lisp_Object Vsignaling_function; extern Lisp_Object inhibit_lisp_code; extern int handling_signal; +#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \ + || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS) +extern void mark_catchlist (struct catchtag *); +#endif /* To run a normal hook, use the appropriate function from the list below. The calling convention: @@ -2950,11 +2958,11 @@ extern Lisp_Object safe_call (ptrdiff_t, Lisp_Object, ...); extern Lisp_Object safe_call1 (Lisp_Object, Lisp_Object); extern Lisp_Object safe_call2 (Lisp_Object, Lisp_Object, Lisp_Object); extern void init_eval (void); -#if BYTE_MARK_STACK -extern void mark_backtrace (void); -#endif extern void syms_of_eval (void); +/* Defined in thread.c. */ +extern void mark_threads (void); + /* Defined in editfns.c. */ extern Lisp_Object Qfield; extern void insert1 (Lisp_Object); @@ -3210,9 +3218,9 @@ extern int read_bytecode_char (int); extern Lisp_Object Qbytecode; extern void syms_of_bytecode (void); #if BYTE_MARK_STACK -extern void mark_byte_stack (void); +extern void mark_byte_stack (struct byte_stack *); #endif -extern void unmark_byte_stack (void); +extern void unmark_byte_stack (struct byte_stack *); extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, ptrdiff_t, Lisp_Object *); diff --git a/src/thread.c b/src/thread.c index 0bd97b4..ba2d663 100644 --- a/src/thread.c +++ b/src/thread.c @@ -24,3 +24,82 @@ along with GNU Emacs. If not, see . */ struct thread_state the_only_thread; struct thread_state *current_thread = &the_only_thread; + +struct thread_state *all_threads = &the_only_thread; + +static void +mark_one_thread (struct thread_state *thread) +{ + register struct specbinding *bind; + struct handler *handler; + Lisp_Object tem; + + for (bind = thread->m_specpdl; bind != thread->m_specpdl_ptr; bind++) + { + mark_object (bind->symbol); + mark_object (bind->old_value); + } + +#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \ + || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS) + mark_stack (thread->m_stack_bottom, thread->stack_top); +#else + { + register struct gcpro *tail; + for (tail = thread->m_gcprolist; tail; tail = tail->next) + for (i = 0; i < tail->nvars; i++) + mark_object (tail->var[i]); + } + +#if BYTE_MARK_STACK + if (thread->m_byte_stack_list) + mark_byte_stack (thread->m_byte_stack_list); +#endif + + mark_catchlist (thread->m_catchlist); + + for (handler = thread->m_handlerlist; handler; handler = handler->next) + { + mark_object (handler->handler); + mark_object (handler->var); + } + + mark_backtrace (thread->m_backtrace_list); +#endif + + if (thread->m_current_buffer) + { + XSETBUFFER (tem, thread->m_current_buffer); + mark_object (tem); + } + + mark_object (thread->m_last_thing_searched); + + if (thread->m_saved_last_thing_searched) + mark_object (thread->m_saved_last_thing_searched); +} + +static void +mark_threads_callback (void *ignore) +{ + struct thread_state *iter; + + for (iter = all_threads; iter; iter = iter->next_thread) + mark_one_thread (iter); +} + +void +mark_threads (void) +{ + flush_stack_call_func (mark_threads_callback, NULL); +} + +void +unmark_threads (void) +{ + struct thread_state *iter; + + for (iter = all_threads; iter; iter = iter->next_thread) + if (iter->m_byte_stack_list) + unmark_byte_stack (iter->m_byte_stack_list); +} diff --git a/src/thread.h b/src/thread.h index b2eb04d..6d61d0e 100644 --- a/src/thread.h +++ b/src/thread.h @@ -133,8 +133,13 @@ struct thread_state /* Regexp to use to replace spaces, or NULL meaning don't. */ /*re_char*/ unsigned char *m_whitespace_regexp; #define whitespace_regexp (current_thread->m_whitespace_regexp) + + /* Threads are kept on a linked list. */ + struct thread_state *next_thread; }; extern struct thread_state *current_thread; +extern void unmark_threads (void); + #endif /* THREAD_H */ -- 1.7.7.6