diff options
| author | Tom Tromey | 2012-08-15 13:04:34 -0600 |
|---|---|---|
| committer | Tom Tromey | 2012-08-15 13:04:34 -0600 |
| commit | e160922c665ba65e1dba5b87a924927e61be43b9 (patch) | |
| tree | de8f62c4788a9d641280cabc94767114f462aef4 /src/eval.c | |
| parent | 14b3dc5e4f2cdefde1ba04ddd3525115e7ca7dce (diff) | |
| download | emacs-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/eval.c')
| -rw-r--r-- | src/eval.c | 165 |
1 files changed, 124 insertions, 41 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 | ||
| 3105 | static Lisp_Object | ||
| 3106 | binding_symbol (const struct specbinding *bind) | ||
| 3107 | { | ||
| 3108 | if (!CONSP (bind->symbol)) | ||
| 3109 | return bind->symbol; | ||
| 3110 | return XCAR (bind->symbol); | ||
| 3111 | } | ||
| 3112 | |||
| 3113 | void | ||
| 3114 | do_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 | ||
| 3275 | void | ||
| 3276 | rebind_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 | |||
| 3292 | static void | ||
| 3293 | do_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 | |||
| 3230 | Lisp_Object | 3332 | Lisp_Object |
| 3231 | unbind_to (ptrdiff_t count, Lisp_Object value) | 3333 | unbind_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 | ||
| 3362 | void | ||
| 3363 | unbind_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 | |||
| 3294 | DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0, | 3377 | DEFUN ("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. |
| 3296 | A special variable is one that will be bound dynamically, even in a | 3379 | A special variable is one that will be bound dynamically, even in a |