aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTom Tromey2012-08-15 13:04:34 -0600
committerTom Tromey2012-08-15 13:04:34 -0600
commite160922c665ba65e1dba5b87a924927e61be43b9 (patch)
treede8f62c4788a9d641280cabc94767114f462aef4 /src
parent14b3dc5e4f2cdefde1ba04ddd3525115e7ca7dce (diff)
downloademacs-e160922c665ba65e1dba5b87a924927e61be43b9.tar.gz
emacs-e160922c665ba65e1dba5b87a924927e61be43b9.zip
This introduces some new functions to handle the specpdl. The basic
idea is that when a thread loses the interpreter lock, it will unbind the bindings it has put in place. Then when a thread acquires the lock, it will restore its bindings. This code reuses an existing empty slot in struct specbinding to store the current value when the thread is "swapped out". This approach performs worse than my previously planned approach. However, it was one I could implement with minimal time and brainpower. I hope that perhaps someone else could improve the code once it is in.
Diffstat (limited to 'src')
-rw-r--r--src/eval.c165
-rw-r--r--src/lisp.h4
-rw-r--r--src/thread.c1
-rw-r--r--src/thread.h6
4 files changed, 134 insertions, 42 deletions
diff --git a/src/eval.c b/src/eval.c
index 49ead499044..f5f6fe7a808 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3102,6 +3102,52 @@ grow_specpdl (void)
3102 specpdl_ptr = specpdl + count; 3102 specpdl_ptr = specpdl + count;
3103} 3103}
3104 3104
3105static Lisp_Object
3106binding_symbol (const struct specbinding *bind)
3107{
3108 if (!CONSP (bind->symbol))
3109 return bind->symbol;
3110 return XCAR (bind->symbol);
3111}
3112
3113void
3114do_specbind (struct Lisp_Symbol *sym, struct specbinding *bind,
3115 Lisp_Object value)
3116{
3117 switch (sym->redirect)
3118 {
3119 case SYMBOL_PLAINVAL:
3120 if (!sym->constant)
3121 SET_SYMBOL_VAL (sym, value);
3122 else
3123 set_internal (bind->symbol, value, Qnil, 1);
3124 break;
3125
3126 case SYMBOL_LOCALIZED:
3127 case SYMBOL_FORWARDED:
3128 if ((sym->redirect == SYMBOL_LOCALIZED
3129 || BUFFER_OBJFWDP (SYMBOL_FWD (sym)))
3130 && CONSP (bind->symbol))
3131 {
3132 Lisp_Object where;
3133
3134 where = XCAR (XCDR (bind->symbol));
3135 if (NILP (where)
3136 && sym->redirect == SYMBOL_FORWARDED)
3137 {
3138 Fset_default (XCAR (bind->symbol), value);
3139 return;
3140 }
3141 }
3142
3143 set_internal (binding_symbol (bind), value, Qnil, 1);
3144 break;
3145
3146 default:
3147 abort ();
3148 }
3149}
3150
3105/* `specpdl_ptr->symbol' is a field which describes which variable is 3151/* `specpdl_ptr->symbol' is a field which describes which variable is
3106 let-bound, so it can be properly undone when we unbind_to. 3152 let-bound, so it can be properly undone when we unbind_to.
3107 It can have the following two shapes: 3153 It can have the following two shapes:
@@ -3140,11 +3186,9 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3140 specpdl_ptr->symbol = symbol; 3186 specpdl_ptr->symbol = symbol;
3141 specpdl_ptr->old_value = SYMBOL_VAL (sym); 3187 specpdl_ptr->old_value = SYMBOL_VAL (sym);
3142 specpdl_ptr->func = NULL; 3188 specpdl_ptr->func = NULL;
3189 specpdl_ptr->saved_value = Qnil;
3143 ++specpdl_ptr; 3190 ++specpdl_ptr;
3144 if (!sym->constant) 3191 do_specbind (sym, specpdl_ptr - 1, value);
3145 SET_SYMBOL_VAL (sym, value);
3146 else
3147 set_internal (symbol, value, Qnil, 1);
3148 break; 3192 break;
3149 case SYMBOL_LOCALIZED: 3193 case SYMBOL_LOCALIZED:
3150 if (SYMBOL_BLV (sym)->frame_local) 3194 if (SYMBOL_BLV (sym)->frame_local)
@@ -3199,7 +3243,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3199 { 3243 {
3200 eassert (BUFFER_OBJFWDP (SYMBOL_FWD (sym))); 3244 eassert (BUFFER_OBJFWDP (SYMBOL_FWD (sym)));
3201 ++specpdl_ptr; 3245 ++specpdl_ptr;
3202 Fset_default (symbol, value); 3246 do_specbind (sym, specpdl_ptr - 1, value);
3203 return; 3247 return;
3204 } 3248 }
3205 } 3249 }
@@ -3207,7 +3251,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3207 specpdl_ptr->symbol = symbol; 3251 specpdl_ptr->symbol = symbol;
3208 3252
3209 specpdl_ptr++; 3253 specpdl_ptr++;
3210 set_internal (symbol, value, Qnil, 1); 3254 do_specbind (sym, specpdl_ptr - 1, value);
3211 break; 3255 break;
3212 } 3256 }
3213 default: abort (); 3257 default: abort ();
@@ -3224,9 +3268,67 @@ record_unwind_protect (Lisp_Object (*function) (Lisp_Object), Lisp_Object arg)
3224 specpdl_ptr->func = function; 3268 specpdl_ptr->func = function;
3225 specpdl_ptr->symbol = Qnil; 3269 specpdl_ptr->symbol = Qnil;
3226 specpdl_ptr->old_value = arg; 3270 specpdl_ptr->old_value = arg;
3271 specpdl_ptr->saved_value = Qnil;
3227 specpdl_ptr++; 3272 specpdl_ptr++;
3228} 3273}
3229 3274
3275void
3276rebind_for_thread_switch (void)
3277{
3278 struct specbinding *bind;
3279
3280 for (bind = specpdl; bind != specpdl_ptr; ++bind)
3281 {
3282 if (bind->func == NULL)
3283 {
3284 Lisp_Object value = bind->saved_value;
3285
3286 bind->saved_value = Qnil;
3287 do_specbind (XSYMBOL (binding_symbol (bind)), bind, value);
3288 }
3289 }
3290}
3291
3292static void
3293do_one_unbind (const struct specbinding *this_binding, int unwinding)
3294{
3295 if (this_binding->func != 0)
3296 (*this_binding->func) (this_binding->old_value);
3297 /* If the symbol is a list, it is really (SYMBOL WHERE
3298 . CURRENT-BUFFER) where WHERE is either nil, a buffer, or a
3299 frame. If WHERE is a buffer or frame, this indicates we
3300 bound a variable that had a buffer-local or frame-local
3301 binding. WHERE nil means that the variable had the default
3302 value when it was bound. CURRENT-BUFFER is the buffer that
3303 was current when the variable was bound. */
3304 else if (CONSP (this_binding->symbol))
3305 {
3306 Lisp_Object symbol, where;
3307
3308 symbol = XCAR (this_binding->symbol);
3309 where = XCAR (XCDR (this_binding->symbol));
3310
3311 if (NILP (where))
3312 Fset_default (symbol, this_binding->old_value);
3313 /* If `where' is non-nil, reset the value in the appropriate
3314 local binding, but only if that binding still exists. */
3315 else if (BUFFERP (where)
3316 ? !NILP (Flocal_variable_p (symbol, where))
3317 : !NILP (Fassq (symbol, XFRAME (where)->param_alist)))
3318 set_internal (symbol, this_binding->old_value, where, 1);
3319 }
3320 /* If variable has a trivial value (no forwarding), we can
3321 just set it. No need to check for constant symbols here,
3322 since that was already done by specbind. */
3323 else if (XSYMBOL (this_binding->symbol)->redirect == SYMBOL_PLAINVAL)
3324 SET_SYMBOL_VAL (XSYMBOL (this_binding->symbol),
3325 this_binding->old_value);
3326 else
3327 /* NOTE: we only ever come here if make_local_foo was used for
3328 the first time on this var within this let. */
3329 Fset_default (this_binding->symbol, this_binding->old_value);
3330}
3331
3230Lisp_Object 3332Lisp_Object
3231unbind_to (ptrdiff_t count, Lisp_Object value) 3333unbind_to (ptrdiff_t count, Lisp_Object value)
3232{ 3334{
@@ -3247,41 +3349,7 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3247 struct specbinding this_binding; 3349 struct specbinding this_binding;
3248 this_binding = *--specpdl_ptr; 3350 this_binding = *--specpdl_ptr;
3249 3351
3250 if (this_binding.func != 0) 3352 do_one_unbind (&this_binding, 1);
3251 (*this_binding.func) (this_binding.old_value);
3252 /* If the symbol is a list, it is really (SYMBOL WHERE
3253 . CURRENT-BUFFER) where WHERE is either nil, a buffer, or a
3254 frame. If WHERE is a buffer or frame, this indicates we
3255 bound a variable that had a buffer-local or frame-local
3256 binding. WHERE nil means that the variable had the default
3257 value when it was bound. CURRENT-BUFFER is the buffer that
3258 was current when the variable was bound. */
3259 else if (CONSP (this_binding.symbol))
3260 {
3261 Lisp_Object symbol, where;
3262
3263 symbol = XCAR (this_binding.symbol);
3264 where = XCAR (XCDR (this_binding.symbol));
3265
3266 if (NILP (where))
3267 Fset_default (symbol, this_binding.old_value);
3268 /* If `where' is non-nil, reset the value in the appropriate
3269 local binding, but only if that binding still exists. */
3270 else if (BUFFERP (where)
3271 ? !NILP (Flocal_variable_p (symbol, where))
3272 : !NILP (Fassq (symbol, XFRAME (where)->param_alist)))
3273 set_internal (symbol, this_binding.old_value, where, 1);
3274 }
3275 /* If variable has a trivial value (no forwarding), we can
3276 just set it. No need to check for constant symbols here,
3277 since that was already done by specbind. */
3278 else if (XSYMBOL (this_binding.symbol)->redirect == SYMBOL_PLAINVAL)
3279 SET_SYMBOL_VAL (XSYMBOL (this_binding.symbol),
3280 this_binding.old_value);
3281 else
3282 /* NOTE: we only ever come here if make_local_foo was used for
3283 the first time on this var within this let. */
3284 Fset_default (this_binding.symbol, this_binding.old_value);
3285 } 3353 }
3286 3354
3287 if (NILP (Vquit_flag) && !NILP (quitf)) 3355 if (NILP (Vquit_flag) && !NILP (quitf))
@@ -3291,6 +3359,21 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3291 return value; 3359 return value;
3292} 3360}
3293 3361
3362void
3363unbind_for_thread_switch (void)
3364{
3365 struct specbinding *bind;
3366
3367 for (bind = specpdl_ptr; bind != specpdl; --bind)
3368 {
3369 if (bind->func == NULL)
3370 {
3371 bind->saved_value = find_symbol_value (binding_symbol (bind));
3372 do_one_unbind (bind, 0);
3373 }
3374 }
3375}
3376
3294DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0, 3377DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0,
3295 doc: /* Return non-nil if SYMBOL's global binding has been declared special. 3378 doc: /* Return non-nil if SYMBOL's global binding has been declared special.
3296A special variable is one that will be bound dynamically, even in a 3379A special variable is one that will be bound dynamically, even in a
diff --git a/src/lisp.h b/src/lisp.h
index b0ed9be9f07..cbb5b51c783 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2014,7 +2014,9 @@ struct specbinding
2014 { 2014 {
2015 Lisp_Object symbol, old_value; 2015 Lisp_Object symbol, old_value;
2016 specbinding_func func; 2016 specbinding_func func;
2017 Lisp_Object unused; /* Dividing by 16 is faster than by 12 */ 2017 /* Normally this is unused; but it is to the symbol's current
2018 value when a thread is swapped out. */
2019 Lisp_Object saved_value;
2018 }; 2020 };
2019 2021
2020#define SPECPDL_INDEX() (specpdl_ptr - specpdl) 2022#define SPECPDL_INDEX() (specpdl_ptr - specpdl)
diff --git a/src/thread.c b/src/thread.c
index 19faa1bafae..605a52cb2f9 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -40,6 +40,7 @@ mark_one_thread (struct thread_state *thread)
40 { 40 {
41 mark_object (bind->symbol); 41 mark_object (bind->symbol);
42 mark_object (bind->old_value); 42 mark_object (bind->old_value);
43 mark_object (bind->saved_value);
43 } 44 }
44 45
45#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \ 46#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
diff --git a/src/thread.h b/src/thread.h
index 020346b9af2..def05fdaec9 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -83,6 +83,12 @@ struct thread_state
83 struct specbinding *m_specpdl_ptr; 83 struct specbinding *m_specpdl_ptr;
84#define specpdl_ptr (current_thread->m_specpdl_ptr) 84#define specpdl_ptr (current_thread->m_specpdl_ptr)
85 85
86 /* Pointer to the first "saved" element in specpdl. When this
87 thread is swapped out, the current values of all specpdl bindings
88 are pushed onto the specpdl; then these are popped again when
89 switching back to this thread. */
90 struct specbinding *m_saved_specpdl_ptr;
91
86 /* Depth in Lisp evaluations and function calls. */ 92 /* Depth in Lisp evaluations and function calls. */
87 EMACS_INT m_lisp_eval_depth; 93 EMACS_INT m_lisp_eval_depth;
88#define lisp_eval_depth (current_thread->m_lisp_eval_depth) 94#define lisp_eval_depth (current_thread->m_lisp_eval_depth)