aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Monnier2022-02-12 15:25:53 -0500
committerStefan Monnier2022-02-12 15:25:53 -0500
commitb8460fcb8c320ea6d7449f37f07502d10eb74cd5 (patch)
tree49eed9555d20693eb01321881204dd9bc45176d1 /src
parent89bb5a5f357e911aeb0b9f14e8b2f7c5a5fbabf7 (diff)
downloademacs-b8460fcb8c320ea6d7449f37f07502d10eb74cd5.tar.gz
emacs-b8460fcb8c320ea6d7449f37f07502d10eb74cd5.zip
Rewrite thread context switch code (bug#48990)
Make the context switch code handle buffer-local variables more correctly by reusing the code originally written for `backtrace-eval`. This has the side benefit of making the `saved_value` field unused. * src/lisp.h (enum specbind_tag): Remove `saved_value` field. (rebind_for_thread_switch, unbind_for_thread_switch): Delete decls. (specpdl_unrewind): Declare function. * src/eval.c (specpdl_saved_value): Delete function. (specbind): Delete the code related to `saved_value`, and consolidate common code between the different branches. (rebind_for_thread_switch, -unbind_for_thread_switch): Move to `thread.c`. (specpdl_unrewind): New function, extracted from `backtrace_eval_unrewind`. Use `SET_INTERNAL_THREAD_SWITCH`. Skip the buffer & excursion unwinds depending on new arg `vars_only`. (backtrace_eval_unrewind): Use it. (mark_specpdl): Don't mark `saved_value`. * src/thread.c (rebind_for_thread_switch, unbind_for_thread_switch): Move from `eval.c` and rewrite using `specpdl_unrewind`. * test/src/thread-tests.el (threads-test-bug48990): New test. * test/Makefile.in (test_template): Add a + as suggested by make: "warning: jobserver unavailable: using -j1. Add '+' to parent make rule".
Diffstat (limited to 'src')
-rw-r--r--src/eval.c89
-rw-r--r--src/lisp.h6
-rw-r--r--src/thread.c16
3 files changed, 46 insertions, 65 deletions
diff --git a/src/eval.c b/src/eval.c
index d1c45fca56b..6bed7c4a899 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -104,13 +104,6 @@ specpdl_where (union specbinding *pdl)
104} 104}
105 105
106static Lisp_Object 106static Lisp_Object
107specpdl_saved_value (union specbinding *pdl)
108{
109 eassert (pdl->kind >= SPECPDL_LET);
110 return pdl->let.saved_value;
111}
112
113static Lisp_Object
114specpdl_arg (union specbinding *pdl) 107specpdl_arg (union specbinding *pdl)
115{ 108{
116 eassert (pdl->kind == SPECPDL_UNWIND); 109 eassert (pdl->kind == SPECPDL_UNWIND);
@@ -3589,9 +3582,6 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3589 specpdl_ptr->let.kind = SPECPDL_LET; 3582 specpdl_ptr->let.kind = SPECPDL_LET;
3590 specpdl_ptr->let.symbol = symbol; 3583 specpdl_ptr->let.symbol = symbol;
3591 specpdl_ptr->let.old_value = SYMBOL_VAL (sym); 3584 specpdl_ptr->let.old_value = SYMBOL_VAL (sym);
3592 specpdl_ptr->let.saved_value = Qnil;
3593 grow_specpdl ();
3594 do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
3595 break; 3585 break;
3596 case SYMBOL_LOCALIZED: 3586 case SYMBOL_LOCALIZED:
3597 case SYMBOL_FORWARDED: 3587 case SYMBOL_FORWARDED:
@@ -3601,7 +3591,6 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3601 specpdl_ptr->let.symbol = symbol; 3591 specpdl_ptr->let.symbol = symbol;
3602 specpdl_ptr->let.old_value = ovalue; 3592 specpdl_ptr->let.old_value = ovalue;
3603 specpdl_ptr->let.where = Fcurrent_buffer (); 3593 specpdl_ptr->let.where = Fcurrent_buffer ();
3604 specpdl_ptr->let.saved_value = Qnil;
3605 3594
3606 eassert (sym->u.s.redirect != SYMBOL_LOCALIZED 3595 eassert (sym->u.s.redirect != SYMBOL_LOCALIZED
3607 || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ()))); 3596 || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
@@ -3619,22 +3608,17 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3619 having their own value. This is consistent with what 3608 having their own value. This is consistent with what
3620 happens with other buffer-local variables. */ 3609 happens with other buffer-local variables. */
3621 if (NILP (Flocal_variable_p (symbol, Qnil))) 3610 if (NILP (Flocal_variable_p (symbol, Qnil)))
3622 { 3611 specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
3623 specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
3624 grow_specpdl ();
3625 do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
3626 return;
3627 }
3628 } 3612 }
3629 else 3613 else
3630 specpdl_ptr->let.kind = SPECPDL_LET; 3614 specpdl_ptr->let.kind = SPECPDL_LET;
3631 3615
3632 grow_specpdl ();
3633 do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
3634 break; 3616 break;
3635 } 3617 }
3636 default: emacs_abort (); 3618 default: emacs_abort ();
3637 } 3619 }
3620 grow_specpdl ();
3621 do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
3638} 3622}
3639 3623
3640/* Push unwind-protect entries of various types. */ 3624/* Push unwind-protect entries of various types. */
@@ -3710,24 +3694,6 @@ record_unwind_protect_module (enum specbind_tag kind, void *ptr)
3710 grow_specpdl (); 3694 grow_specpdl ();
3711} 3695}
3712 3696
3713void
3714rebind_for_thread_switch (void)
3715{
3716 union specbinding *bind;
3717
3718 for (bind = specpdl; bind != specpdl_ptr; ++bind)
3719 {
3720 if (bind->kind >= SPECPDL_LET)
3721 {
3722 Lisp_Object value = specpdl_saved_value (bind);
3723 Lisp_Object sym = specpdl_symbol (bind);
3724 bind->let.saved_value = Qnil;
3725 do_specbind (XSYMBOL (sym), bind, value,
3726 SET_INTERNAL_THREAD_SWITCH);
3727 }
3728 }
3729}
3730
3731static void 3697static void
3732do_one_unbind (union specbinding *this_binding, bool unwinding, 3698do_one_unbind (union specbinding *this_binding, bool unwinding,
3733 enum Set_Internal_Bind bindflag) 3699 enum Set_Internal_Bind bindflag)
@@ -3884,22 +3850,6 @@ unbind_to (specpdl_ref count, Lisp_Object value)
3884 return value; 3850 return value;
3885} 3851}
3886 3852
3887void
3888unbind_for_thread_switch (struct thread_state *thr)
3889{
3890 union specbinding *bind;
3891
3892 for (bind = thr->m_specpdl_ptr; bind > thr->m_specpdl;)
3893 {
3894 if ((--bind)->kind >= SPECPDL_LET)
3895 {
3896 Lisp_Object sym = specpdl_symbol (bind);
3897 bind->let.saved_value = find_symbol_value (sym);
3898 do_one_unbind (bind, false, SET_INTERNAL_THREAD_SWITCH);
3899 }
3900 }
3901}
3902
3903DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0, 3853DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0,
3904 doc: /* Return non-nil if SYMBOL's global binding has been declared special. 3854 doc: /* Return non-nil if SYMBOL's global binding has been declared special.
3905A special variable is one that will be bound dynamically, even in a 3855A special variable is one that will be bound dynamically, even in a
@@ -4055,11 +4005,13 @@ or a lambda expression for macro calls. */)
4055 value and the old value stored in the specpdl), kind of like the inplace 4005 value and the old value stored in the specpdl), kind of like the inplace
4056 pointer-reversal trick. As it turns out, the rewind does the same as the 4006 pointer-reversal trick. As it turns out, the rewind does the same as the
4057 unwind, except it starts from the other end of the specpdl stack, so we use 4007 unwind, except it starts from the other end of the specpdl stack, so we use
4058 the same function for both unwind and rewind. */ 4008 the same function for both unwind and rewind.
4059static void 4009 This same code is used when switching threads, except in that case
4060backtrace_eval_unrewind (int distance) 4010 we unwind/rewind the whole specpdl of the threads. */
4011void
4012specpdl_unrewind (union specbinding *pdl, int distance, bool vars_only)
4061{ 4013{
4062 union specbinding *tmp = specpdl_ptr; 4014 union specbinding *tmp = pdl;
4063 int step = -1; 4015 int step = -1;
4064 if (distance < 0) 4016 if (distance < 0)
4065 { /* It's a rewind rather than unwind. */ 4017 { /* It's a rewind rather than unwind. */
@@ -4077,6 +4029,8 @@ backtrace_eval_unrewind (int distance)
4077 unwind_protect, but the problem is that we don't know how to 4029 unwind_protect, but the problem is that we don't know how to
4078 rewind them afterwards. */ 4030 rewind them afterwards. */
4079 case SPECPDL_UNWIND: 4031 case SPECPDL_UNWIND:
4032 if (vars_only)
4033 break;
4080 if (tmp->unwind.func == set_buffer_if_live) 4034 if (tmp->unwind.func == set_buffer_if_live)
4081 { 4035 {
4082 Lisp_Object oldarg = tmp->unwind.arg; 4036 Lisp_Object oldarg = tmp->unwind.arg;
@@ -4085,6 +4039,8 @@ backtrace_eval_unrewind (int distance)
4085 } 4039 }
4086 break; 4040 break;
4087 case SPECPDL_UNWIND_EXCURSION: 4041 case SPECPDL_UNWIND_EXCURSION:
4042 if (vars_only)
4043 break;
4088 { 4044 {
4089 Lisp_Object marker = tmp->unwind_excursion.marker; 4045 Lisp_Object marker = tmp->unwind_excursion.marker;
4090 Lisp_Object window = tmp->unwind_excursion.window; 4046 Lisp_Object window = tmp->unwind_excursion.window;
@@ -4125,7 +4081,7 @@ backtrace_eval_unrewind (int distance)
4125 Lisp_Object sym = specpdl_symbol (tmp); 4081 Lisp_Object sym = specpdl_symbol (tmp);
4126 Lisp_Object old_value = specpdl_old_value (tmp); 4082 Lisp_Object old_value = specpdl_old_value (tmp);
4127 set_specpdl_old_value (tmp, default_value (sym)); 4083 set_specpdl_old_value (tmp, default_value (sym));
4128 Fset_default (sym, old_value); 4084 set_default_internal (sym, old_value, SET_INTERNAL_THREAD_SWITCH);
4129 } 4085 }
4130 break; 4086 break;
4131 case SPECPDL_LET_LOCAL: 4087 case SPECPDL_LET_LOCAL:
@@ -4141,14 +4097,28 @@ backtrace_eval_unrewind (int distance)
4141 { 4097 {
4142 set_specpdl_old_value 4098 set_specpdl_old_value
4143 (tmp, buffer_local_value (symbol, where)); 4099 (tmp, buffer_local_value (symbol, where));
4144 set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND); 4100 set_internal (symbol, old_value, where,
4101 SET_INTERNAL_THREAD_SWITCH);
4145 } 4102 }
4103 else
4104 /* FIXME: If the var is not local any more, we failed
4105 to swap the old and new values. As long as the var remains
4106 non-local, this is fine, but if it ever reverts to being
4107 local we may end up using this entry "in the wrong
4108 direction". */
4109 ;
4146 } 4110 }
4147 break; 4111 break;
4148 } 4112 }
4149 } 4113 }
4150} 4114}
4151 4115
4116static void
4117backtrace_eval_unrewind (int distance)
4118{
4119 specpdl_unrewind (specpdl_ptr, distance, false);
4120}
4121
4152DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL, 4122DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL,
4153 doc: /* Evaluate EXP in the context of some activation frame. 4123 doc: /* Evaluate EXP in the context of some activation frame.
4154NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */) 4124NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */)
@@ -4302,7 +4272,6 @@ mark_specpdl (union specbinding *first, union specbinding *ptr)
4302 case SPECPDL_LET: 4272 case SPECPDL_LET:
4303 mark_object (specpdl_symbol (pdl)); 4273 mark_object (specpdl_symbol (pdl));
4304 mark_object (specpdl_old_value (pdl)); 4274 mark_object (specpdl_old_value (pdl));
4305 mark_object (specpdl_saved_value (pdl));
4306 break; 4275 break;
4307 4276
4308 case SPECPDL_UNWIND_PTR: 4277 case SPECPDL_UNWIND_PTR:
diff --git a/src/lisp.h b/src/lisp.h
index f27c2ad2dd5..19788ef07cc 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3337,9 +3337,6 @@ union specbinding
3337 ENUM_BF (specbind_tag) kind : CHAR_BIT; 3337 ENUM_BF (specbind_tag) kind : CHAR_BIT;
3338 /* `where' is not used in the case of SPECPDL_LET. */ 3338 /* `where' is not used in the case of SPECPDL_LET. */
3339 Lisp_Object symbol, old_value, where; 3339 Lisp_Object symbol, old_value, where;
3340 /* Normally this is unused; but it is set to the symbol's
3341 current value when a thread is swapped out. */
3342 Lisp_Object saved_value;
3343 } let; 3340 } let;
3344 struct { 3341 struct {
3345 ENUM_BF (specbind_tag) kind : CHAR_BIT; 3342 ENUM_BF (specbind_tag) kind : CHAR_BIT;
@@ -4453,8 +4450,7 @@ extern void set_unwind_protect (specpdl_ref, void (*) (Lisp_Object),
4453 Lisp_Object); 4450 Lisp_Object);
4454extern void set_unwind_protect_ptr (specpdl_ref, void (*) (void *), void *); 4451extern void set_unwind_protect_ptr (specpdl_ref, void (*) (void *), void *);
4455extern Lisp_Object unbind_to (specpdl_ref, Lisp_Object); 4452extern Lisp_Object unbind_to (specpdl_ref, Lisp_Object);
4456extern void rebind_for_thread_switch (void); 4453void specpdl_unrewind (union specbinding *pdl, int distance, bool vars_only);
4457extern void unbind_for_thread_switch (struct thread_state *);
4458extern AVOID error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); 4454extern AVOID error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
4459extern AVOID verror (const char *, va_list) 4455extern AVOID verror (const char *, va_list)
4460 ATTRIBUTE_FORMAT_PRINTF (1, 0); 4456 ATTRIBUTE_FORMAT_PRINTF (1, 0);
diff --git a/src/thread.c b/src/thread.c
index 8a6a2de18be..4c98d590b7a 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -83,6 +83,22 @@ release_global_lock (void)
83 sys_mutex_unlock (&global_lock); 83 sys_mutex_unlock (&global_lock);
84} 84}
85 85
86static void
87rebind_for_thread_switch (void)
88{
89 ptrdiff_t distance
90 = current_thread->m_specpdl_ptr - current_thread->m_specpdl;
91 specpdl_unrewind (specpdl_ptr, -distance, true);
92}
93
94static void
95unbind_for_thread_switch (struct thread_state *thr)
96{
97 ptrdiff_t distance = thr->m_specpdl_ptr - thr->m_specpdl;
98 specpdl_unrewind (thr->m_specpdl_ptr, distance, true);
99}
100
101
86/* You must call this after acquiring the global lock. 102/* You must call this after acquiring the global lock.
87 acquire_global_lock does it for you. */ 103 acquire_global_lock does it for you. */
88static void 104static void