From: Tom Tromey <tromey@redhat.com>
To: Emacs discussions <emacs-devel@gnu.org>
Subject: [PATCH 02/10] make GC thread-ready
Date: Thu, 09 Aug 2012 13:37:43 -0600 [thread overview]
Message-ID: <87r4rfeu0o.fsf@fleche.redhat.com> (raw)
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 <http://www.gnu.org/licenses/>. */
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
reply other threads:[~2012-08-09 19:37 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87r4rfeu0o.fsf@fleche.redhat.com \
--to=tromey@redhat.com \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.