return pdl->let.where;
}
-static Lisp_Object
-specpdl_saved_value (union specbinding *pdl)
-{
- eassert (pdl->kind >= SPECPDL_LET);
- return pdl->let.saved_value;
-}
-
static Lisp_Object
specpdl_arg (union specbinding *pdl)
{
specpdl_ptr->let.kind = SPECPDL_LET;
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = SYMBOL_VAL (sym);
- specpdl_ptr->let.saved_value = Qnil;
- grow_specpdl ();
- do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
break;
case SYMBOL_LOCALIZED:
case SYMBOL_FORWARDED:
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = ovalue;
specpdl_ptr->let.where = Fcurrent_buffer ();
- specpdl_ptr->let.saved_value = Qnil;
eassert (sym->u.s.redirect != SYMBOL_LOCALIZED
|| (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
having their own value. This is consistent with what
happens with other buffer-local variables. */
if (NILP (Flocal_variable_p (symbol, Qnil)))
- {
- specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
- grow_specpdl ();
- do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
- return;
- }
+ specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
}
else
specpdl_ptr->let.kind = SPECPDL_LET;
- grow_specpdl ();
- do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
break;
}
default: emacs_abort ();
}
+ grow_specpdl ();
+ do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
}
/* Push unwind-protect entries of various types. */
grow_specpdl ();
}
-void
-rebind_for_thread_switch (void)
-{
- union specbinding *bind;
-
- for (bind = specpdl; bind != specpdl_ptr; ++bind)
- {
- if (bind->kind >= SPECPDL_LET)
- {
- Lisp_Object value = specpdl_saved_value (bind);
- Lisp_Object sym = specpdl_symbol (bind);
- bind->let.saved_value = Qnil;
- do_specbind (XSYMBOL (sym), bind, value,
- SET_INTERNAL_THREAD_SWITCH);
- }
- }
-}
-
static void
do_one_unbind (union specbinding *this_binding, bool unwinding,
enum Set_Internal_Bind bindflag)
return value;
}
-void
-unbind_for_thread_switch (struct thread_state *thr)
-{
- union specbinding *bind;
-
- for (bind = thr->m_specpdl_ptr; bind > thr->m_specpdl;)
- {
- if ((--bind)->kind >= SPECPDL_LET)
- {
- Lisp_Object sym = specpdl_symbol (bind);
- bind->let.saved_value = find_symbol_value (sym);
- do_one_unbind (bind, false, SET_INTERNAL_THREAD_SWITCH);
- }
- }
-}
-
DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0,
doc: /* Return non-nil if SYMBOL's global binding has been declared special.
A special variable is one that will be bound dynamically, even in a
value and the old value stored in the specpdl), kind of like the inplace
pointer-reversal trick. As it turns out, the rewind does the same as the
unwind, except it starts from the other end of the specpdl stack, so we use
- the same function for both unwind and rewind. */
-static void
-backtrace_eval_unrewind (int distance)
+ the same function for both unwind and rewind.
+ This same code is used when switching threads, except in that case
+ we unwind/rewind the whole specpdl of the threads. */
+void
+specpdl_unrewind (union specbinding *pdl, int distance, bool vars_only)
{
- union specbinding *tmp = specpdl_ptr;
+ union specbinding *tmp = pdl;
int step = -1;
if (distance < 0)
{ /* It's a rewind rather than unwind. */
unwind_protect, but the problem is that we don't know how to
rewind them afterwards. */
case SPECPDL_UNWIND:
+ if (vars_only)
+ break;
if (tmp->unwind.func == set_buffer_if_live)
{
Lisp_Object oldarg = tmp->unwind.arg;
}
break;
case SPECPDL_UNWIND_EXCURSION:
+ if (vars_only)
+ break;
{
Lisp_Object marker = tmp->unwind_excursion.marker;
Lisp_Object window = tmp->unwind_excursion.window;
Lisp_Object sym = specpdl_symbol (tmp);
Lisp_Object old_value = specpdl_old_value (tmp);
set_specpdl_old_value (tmp, default_value (sym));
- Fset_default (sym, old_value);
+ set_default_internal (sym, old_value, SET_INTERNAL_THREAD_SWITCH);
}
break;
case SPECPDL_LET_LOCAL:
{
set_specpdl_old_value
(tmp, buffer_local_value (symbol, where));
- set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND);
+ set_internal (symbol, old_value, where,
+ SET_INTERNAL_THREAD_SWITCH);
}
+ else
+ /* FIXME: If the var is not local any more, we failed
+ to swap the old and new values. As long as the var remains
+ non-local, this is fine, but if it ever reverts to being
+ local we may end up using this entry "in the wrong
+ direction". */
+ ;
}
break;
}
}
}
+static void
+backtrace_eval_unrewind (int distance)
+{
+ specpdl_unrewind (specpdl_ptr, distance, false);
+}
+
DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL,
doc: /* Evaluate EXP in the context of some activation frame.
NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */)
case SPECPDL_LET:
mark_object (specpdl_symbol (pdl));
mark_object (specpdl_old_value (pdl));
- mark_object (specpdl_saved_value (pdl));
break;
case SPECPDL_UNWIND_PTR:
(let ((th (make-thread 'ignore)))
(should-not (equal th main-thread))))
+(defvar threads-test--var 'global)
+
+(ert-deftest threads-test-bug48990 ()
+ (skip-unless (fboundp 'make-thread))
+ (let ((buf1 (generate-new-buffer " thread-test"))
+ (buf2 (generate-new-buffer " thread-test")))
+ (with-current-buffer buf1
+ (setq-local threads-test--var 'local1))
+ (with-current-buffer buf2
+ (setq-local threads-test--var 'local2))
+ (let ((seen nil))
+ (with-current-buffer buf1
+ (should (eq threads-test--var 'local1))
+ (make-thread (lambda () (setq seen threads-test--var))))
+ (with-current-buffer buf2
+ (should (eq threads-test--var 'local2))
+ (let ((threads-test--var 'let2))
+ (should (eq threads-test--var 'let2))
+ (while (not seen)
+ (thread-yield))
+ (should (eq threads-test--var 'let2))
+ (should (eq seen 'local1)))
+ (should (eq threads-test--var 'local2)))
+ (should (eq threads-test--var 'global)))))
+
;;; thread-tests.el ends here