It's intended to solve the problem which comes up every time someone
uses threads and special variables: that is that there is no way to
influence which special variables are bound in the thread if you are
not in control of the thread's main function. Also it allows
library/package developer to designate which specials inside their
package should be bound on thread entry.
Summary:
New parameter 'default-bindings' added to make-thread, defaults
to sb-ext:*default-special-bindings*
New macro sb-ext:define-thread-local-var with exactly same syntax as
defvar, except in addition to doing what defvar does, symbol and value
is also added to *default-special-bindings*. On uni-threaded build it
does same thing as defvar.
Changed the fixed to make printer thread-safe to use the new feature.
Note: I personally think that having a macro named
(make-variable-thread-local) is a better convention to changing
*default-special-bindings* then having a (def....) form, but I was
told on #lisp to change it to mimic defvar so thats why its done this
way. IMHO make-...local is simularly named to Emacs's
make-variable-...-local. Also it reflects better what code does ie it
adds variable to *default-special-bindings* thus "making" it thread
local for new threads.
Regards,
Max
SW5kZXg6IHBhY2thZ2UtZGF0YS1saXN0Lmxpc3AtZXhwcgo9PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ClJDUyBmaWxlOiAv
Y3Zzcm9vdC9zYmNsL3NiY2wvcGFja2FnZS1kYXRhLWxpc3QubGlzcC1leHByLHYKcmV0cmlldmlu
ZyByZXZpc2lvbiAxLjM1NwpkaWZmIC11IC1yMS4zNTcgcGFja2FnZS1kYXRhLWxpc3QubGlzcC1l
eHByCi0tLSBwYWNrYWdlLWRhdGEtbGlzdC5saXNwLWV4cHIJMjAgSnVuIDIwMDYgMDU6Mzg6NDIg
LTAwMDAJMS4zNTcKKysrIHBhY2thZ2UtZGF0YS1saXN0Lmxpc3AtZXhwcgkyNyBKdWwgMjAwNiAy
MzozNDo1OSAtMDAwMApAQCAtNzQ5LDcgKzc0OSwxMiBAQAogCiAgICAgICAgICAgICAgICA7OyB0
aW1lcgogICAgICAgICAgICAgICAgIlRJTUVSIiAiTUFLRS1USU1FUiIgIlRJTUVSLU5BTUUiICJU
SU1FUi1TQ0hFRFVMRUQtUCIKLSAgICAgICAgICAgICAgICJTQ0hFRFVMRS1USU1FUiIgIlVOU0NI
RURVTEUtVElNRVIiICJMSVNULUFMTC1USU1FUlMiKSkKKyAgICAgICAgICAgICAgICJTQ0hFRFVM
RS1USU1FUiIgIlVOU0NIRURVTEUtVElNRVIiICJMSVNULUFMTC1USU1FUlMiCisKKyAgICAgICAg
ICAgICAgIDs7IHRocmVhZC1sb2NhbAorICAgICAgICAgICAgICAgIkRFRklORS1USFJFQUQtTE9D
QUwtVkFSIgorICAgICAgICAgICAgICAgIipERUZBVUxULVNQRUNJQUwtQklORElOR1MqIgorICAg
ICAgICAgICAgICAgKSkKIAogICAgI3Moc2ItY29sZDpwYWNrYWdlLWRhdGEKICAgICAgIDpuYW1l
ICJTQiFGT1JNQVQiCkBAIC0xNjI1LDcgKzE2MzAsMTAgQEAKICAgICAgIDpuYW1lICJTQiFUSFJF
QUQiCiAgICAgICA6dXNlICgiQ0wiICJTQiFBTElFTiIgIlNCIUlOVCIgIlNCIVNZUyIpCiAgICAg
ICA6ZG9jICJwdWJsaWMgKGJ1dCBsb3ctbGV2ZWwpOiBuYXRpdmUgdGhyZWFkIHN1cHBvcnQiCi0g
ICAgICA6ZXhwb3J0ICgiKkNVUlJFTlQtVEhSRUFEKiIgIlRIUkVBRCIgIk1BS0UtVEhSRUFEIgor
ICAgICAgOmltcG9ydC1mcm9tICgoIlNCIUVYVCIgIipERUZBVUxULVNQRUNJQUwtQklORElOR1Mq
IikpCisgICAgICA6cmVleHBvcnQgKCIqREVGQVVMVC1TUEVDSUFMLUJJTkRJTkdTKiIpCisgICAg
ICA6ZXhwb3J0ICgiKkNVUlJFTlQtVEhSRUFEKiIKKyAgICAgICAgICAgICAgICJUSFJFQUQiICJN
QUtFLVRIUkVBRCIKICAgICAgICAgICAgICAgICJUSFJFQUQtTkFNRSIgIlRIUkVBRC1BTElWRS1Q
IgogICAgICAgICAgICAgICAgIkxJU1QtQUxMLVRIUkVBRFMiCiAgICAgICAgICAgICAgICAiSU5U
RVJSVVBULVRIUkVBRC1FUlJPUiIKSW5kZXg6IHNyYy9jb2RlL2RlZmJvb3QubGlzcAo9PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09ClJDUyBmaWxlOiAvY3Zzcm9vdC9zYmNsL3NiY2wvc3JjL2NvZGUvZGVmYm9vdC5saXNwLHYK
cmV0cmlldmluZyByZXZpc2lvbiAxLjUyCmRpZmYgLXUgLXIxLjUyIGRlZmJvb3QubGlzcAotLS0g
c3JjL2NvZGUvZGVmYm9vdC5saXNwCTE1IE1heSAyMDA2IDE2OjExOjM4IC0wMDAwCTEuNTIKKysr
IHNyYy9jb2RlL2RlZmJvb3QubGlzcAkyNyBKdWwgMjAwNiAyMzozNTowMCAtMDAwMApAQCAtMjQx
LDcgKzI0MSwyNCBAQAogICAgICAoZXZhbC13aGVuICg6bG9hZC10b3BsZXZlbCA6ZXhlY3V0ZSkK
ICAgICAgICAoJWRlZnZhciAnLHZhciAodW5sZXNzIChib3VuZHAgJyx2YXIpICx2YWwpCiAgICAg
ICAgICAgICAgICAgJyx2YWxwICxkb2MgJyxkb2NwCi0gICAgICAgICAgICAgICAgKHNiIWM6c291
cmNlLWxvY2F0aW9uKSkpKSkKKyAgICAgICAgICAgICAgICAoc2IhYzpzb3VyY2UtbG9jYXRpb24p
IG5pbCkpKSkKKworKGRlZm1hY3JvLW11bmRhbmVseSBkZWZpbmUtdGhyZWFkLWxvY2FsLXZhciAo
dmFyICZvcHRpb25hbCAodmFsIG5pbCB2YWxwKSAoZG9jIG5pbCBkb2NwKSkKKyAgIyErc2ItZG9j
CisgICJEZWZpbmUgYSBnbG9iYWwgdmFyaWFibGUgYXQgdG9wIGxldmVsLiBEZWNsYXJlIHRoZSB2
YXJpYWJsZQorICBTUEVDSUFMIGFuZCwgb3B0aW9uYWxseSwgaW5pdGlhbGl6ZSBpdC4gSW4gYWRk
aXRpb24gYWRkIHRoZSB2YXJpYWJsZQorICB0byAqZGVmYXVsdC1zcGVjaWFsLWJpbmRpbmdzKiBh
LWxpc3QuIElmIHRoZSB2YXJpYWJsZSBhbHJlYWR5IGhhcyBhCisgIHZhbHVlLCB0aGUgb2xkIHZh
bHVlIGlzIG5vdCBjbG9iYmVyZWQuIFRoZSB0aGlyZCBhcmd1bWVudCBpcyBhbiBvcHRpb25hbAor
ICBkb2N1bWVudGF0aW9uIHN0cmluZyBmb3IgdGhlIHZhcmlhYmxlLiAiCisgIGAocHJvZ24KKyAg
ICAgKGV2YWwtd2hlbiAoOmNvbXBpbGUtdG9wbGV2ZWwpCisgICAgICAgKCVjb21waWxlci1kZWZ2
YXIgJyx2YXIpKQorICAgICAoZXZhbC13aGVuICg6bG9hZC10b3BsZXZlbCA6ZXhlY3V0ZSkKKyAg
ICAgICAoJWRlZnZhciAnLHZhciAodW5sZXNzIChib3VuZHAgJyx2YXIpICx2YWwpCisgICAgICAg
ICAgICAgICAgJyx2YWxwICxkb2MgJyxkb2NwCisgICAgICAgICAgICAgICAgKHNiIWM6c291cmNl
LWxvY2F0aW9uKQorICAgICAgICAgICAgICAgICMrc2ItdGhyZWFkIHQKKyAgICAgICAgICAgICAg
ICAjLXNiLXRocmVhZCBuaWwpKSkpCiAKIChkZWZtYWNyby1tdW5kYW5lbHkgZGVmcGFyYW1ldGVy
ICh2YXIgdmFsICZvcHRpb25hbCAoZG9jIG5pbCBkb2NwKSkKICAgIyErc2ItZG9jCkBAIC0yNTQs
MTMgKzI3MSwyOCBAQAogICAgICAoZXZhbC13aGVuICg6Y29tcGlsZS10b3BsZXZlbCkKICAgICAg
ICAoJWNvbXBpbGVyLWRlZnZhciAnLHZhcikpCiAgICAgIChldmFsLXdoZW4gKDpsb2FkLXRvcGxl
dmVsIDpleGVjdXRlKQotICAgICAgICglZGVmcGFyYW1ldGVyICcsdmFyICx2YWwgLGRvYyAnLGRv
Y3AgKHNiIWM6c291cmNlLWxvY2F0aW9uKSkpKSkKKyAgICAgICAoJWRlZnBhcmFtZXRlciAnLHZh
ciAsdmFsICxkb2MgJyxkb2NwIChzYiFjOnNvdXJjZS1sb2NhdGlvbikgbmlsKSkpKQorCisoZGVm
bWFjcm8tbXVuZGFuZWx5IGRlZmluZS10aHJlYWQtbG9jYWwtcGFyYW1ldGVyICh2YXIgdmFsICZv
cHRpb25hbCAoZG9jIG5pbCBkb2NwKSkKKyAgIyErc2ItZG9jCisgICJEZWZpbmUgYSBwYXJhbWV0
ZXIgdGhhdCBpcyBub3Qgbm9ybWFsbHkgY2hhbmdlZCBieSB0aGUgcHJvZ3JhbSwKKyAgYnV0IHRo
YXQgbWF5IGJlIGNoYW5nZWQgd2l0aG91dCBjYXVzaW5nIGFuIGVycm9yLiBEZWNsYXJlIHRoZQor
ICB2YXJpYWJsZSBzcGVjaWFsIGFuZCBzZXRzIGl0cyB2YWx1ZSB0byBWQUwsIG92ZXJ3cml0aW5n
IGFueQorICBwcmV2aW91cyB2YWx1ZS4gQWxzbyBhZGQgdGhlIHZhcmlhYmxlIHRvICpkZWZhdWx0
LXNwZWNpYWwtYmluZGluZ3MqLgorICBUaGUgdGhpcmQgYXJndW1lbnQgaXMgYW4gb3B0aW9uYWwg
ZG9jdW1lbnRhdGlvbiBzdHJpbmcgZm9yIHRoZSBwYXJhbWV0ZXIuIgorICBgKHByb2duCisgICAg
IChldmFsLXdoZW4gKDpjb21waWxlLXRvcGxldmVsKQorICAgICAgICglY29tcGlsZXItZGVmdmFy
ICcsdmFyKSkKKyAgICAgKGV2YWwtd2hlbiAoOmxvYWQtdG9wbGV2ZWwgOmV4ZWN1dGUpCisgICAg
ICAgKCVkZWZwYXJhbWV0ZXIgJyx2YXIgLHZhbCAsZG9jICcsZG9jcCAoc2IhYzpzb3VyY2UtbG9j
YXRpb24pCisgICAgICAgICAgICAgICAgICAgICAgIytzYi10aHJlYWQgdAorICAgICAgICAgICAg
ICAgICAgICAgICMtc2ItdGhyZWFkIG5pbCkpKSkKIAogKGRlZnVuICVjb21waWxlci1kZWZ2YXIg
KHZhcikKICAgKHNiIXhjOnByb2NsYWltIGAoc3BlY2lhbCAsdmFyKSkpCiAKICMtc2IteGMtaG9z
dAotKGRlZnVuICVkZWZ2YXIgKHZhciB2YWwgdmFscCBkb2MgZG9jcCBzb3VyY2UtbG9jYXRpb24p
CisoZGVmdW4gJWRlZnZhciAodmFyIHZhbCB2YWxwIGRvYyBkb2NwIHNvdXJjZS1sb2NhdGlvbiB0
aHJlYWQtbG9jYWwtcCkKICAgKCVjb21waWxlci1kZWZ2YXIgdmFyKQogICAod2hlbiB2YWxwCiAg
ICAgKHVubGVzcyAoYm91bmRwIHZhcikKQEAgLTI2OSwxNiArMzAxLDMzIEBACiAgICAgKHNldGYg
KGZkb2N1bWVudGF0aW9uIHZhciAndmFyaWFibGUpIGRvYykpCiAgIChzYiFjOndpdGgtc291cmNl
LWxvY2F0aW9uIChzb3VyY2UtbG9jYXRpb24pCiAgICAgKHNldGYgKGluZm8gOnNvdXJjZS1sb2Nh
dGlvbiA6dmFyaWFibGUgdmFyKSBzb3VyY2UtbG9jYXRpb24pKQorICAod2hlbiB0aHJlYWQtbG9j
YWwtcAorICAgIChsZXQgKChwcmV2IChhc3NvYyB2YXIgc2IhdGhyZWFkOjoqZGVmYXVsdC1zcGVj
aWFsLWJpbmRpbmdzKikpCisgICAgICAgICAgKHZhbHVlIChjb25kICh2YWxwIHZhbCkKKyAgICAg
ICAgICAgICAgICAgICAgICAgOzsgcGlja3VwIHRoZSBvbGQgdmFsdWUgaWYgYm91bmQKKyAgICAg
ICAgICAgICAgICAgICAgICAgKChhbmQgKG5vdCB2YWxwKSAoYm91bmRwIHZhcikpIChzeW1ib2wt
dmFsdWUgdmFyKSkKKyAgICAgICAgICAgICAgICAgICAgICAgKHQgKHNiIWtlcm5lbDptYWtlLWxp
c3Atb2JqCisgICAgICAgICAgICAgICAgICAgICAgICAgICBzYiF2bTo6bm8tdGxzLXZhbHVlLW1h
cmtlci13aWRldGFnKSkpKSkKKyAgICAgIChpZiBwcmV2CisgICAgICAgICAgKHJwbGFjZCBwcmV2
IHZhbHVlKQorICAgICAgICAgIChwdXNoIChjb25zIHZhciB2YWx1ZSkKKyAgICAgICAgICAgICAg
ICBzYiF0aHJlYWQ6OipkZWZhdWx0LXNwZWNpYWwtYmluZGluZ3MqKSkpKQogICB2YXIpCiAKICMt
c2IteGMtaG9zdAotKGRlZnVuICVkZWZwYXJhbWV0ZXIgKHZhciB2YWwgZG9jIGRvY3Agc291cmNl
LWxvY2F0aW9uKQorKGRlZnVuICVkZWZwYXJhbWV0ZXIgKHZhciB2YWwgZG9jIGRvY3Agc291cmNl
LWxvY2F0aW9uIHRocmVhZC1sb2NhbC1wKQogICAoJWNvbXBpbGVyLWRlZnZhciB2YXIpCiAgIChz
ZXQgdmFyIHZhbCkKICAgKHdoZW4gZG9jcAogICAgIChzZXRmIChmZG9jdW1lbnRhdGlvbiB2YXIg
J3ZhcmlhYmxlKSBkb2MpKQogICAoc2IhYzp3aXRoLXNvdXJjZS1sb2NhdGlvbiAoc291cmNlLWxv
Y2F0aW9uKQogICAgIChzZXRmIChpbmZvIDpzb3VyY2UtbG9jYXRpb24gOnZhcmlhYmxlIHZhcikg
c291cmNlLWxvY2F0aW9uKSkKKyAgKHdoZW4gdGhyZWFkLWxvY2FsLXAKKyAgICAobGV0ICgocHJl
diAoYXNzb2MgdmFyIHNiIXRocmVhZDo6KmRlZmF1bHQtc3BlY2lhbC1iaW5kaW5ncyopKSkKKyAg
ICAgIChpZiBwcmV2CisgICAgICAgICAgKHJwbGFjZCBwcmV2IHZhbCkKKyAgICAgICAgICAocHVz
aCAoY29ucyB2YXIgdmFsKQorICAgICAgICAgICAgICAgIHNiIXRocmVhZDo6KmRlZmF1bHQtc3Bl
Y2lhbC1iaW5kaW5ncyopKSkpCiAgIHZhcikKIAwKIDs7OzsgaXRlcmF0aW9uIGNvbnN0cnVjdHMK
SW5kZXg6IHNyYy9jb2RlL2Vhcmx5LXRocmVhZC5saXNwCj09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KUkNTIGZpbGU6IC9j
dnNyb290L3NiY2wvc2JjbC9zcmMvY29kZS9lYXJseS10aHJlYWQubGlzcCx2CnJldHJpZXZpbmcg
cmV2aXNpb24gMS4xCmRpZmYgLXUgLXIxLjEgZWFybHktdGhyZWFkLmxpc3AKLS0tIHNyYy9jb2Rl
L2Vhcmx5LXRocmVhZC5saXNwCTEgSnVsIDIwMDUgMDg6NDg6MzMgLTAwMDAJMS4xCisrKyBzcmMv
Y29kZS9lYXJseS10aHJlYWQubGlzcAkyNyBKdWwgMjAwNiAyMzozNTowMCAtMDAwMApAQCAtMTAs
MyArMTAsNCBAQAogKGluLXBhY2thZ2UgIlNCIVRIUkVBRCIpCiAKIChkZWZ2YXIgKmN1cnJlbnQt
dGhyZWFkKikKKyhkZWZ2YXIgKmRlZmF1bHQtc3BlY2lhbC1iaW5kaW5ncyogbmlsKQpJbmRleDog
c3JjL2NvZGUvcHJpbnQubGlzcAo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ClJDUyBmaWxlOiAvY3Zzcm9vdC9zYmNsL3Ni
Y2wvc3JjL2NvZGUvcHJpbnQubGlzcCx2CnJldHJpZXZpbmcgcmV2aXNpb24gMS42OApkaWZmIC11
IC1yMS42OCBwcmludC5saXNwCi0tLSBzcmMvY29kZS9wcmludC5saXNwCTE2IE1hciAyMDA2IDAz
OjI0OjE4IC0wMDAwCTEuNjgKKysrIHNyYy9jb2RlL3ByaW50Lmxpc3AJMjcgSnVsIDIwMDYgMjM6
MzU6MDEgLTAwMDAKQEAgLTM5OSwxMiArMzk5LDEyIEBACiAKIDs7OyB2YWx1ZXMgb2YgKlBSSU5U
LUNBU0UqIGFuZCAoUkVBRFRBQkxFLUNBU0UgKlJFQURUQUJMRSopIHRoZSBsYXN0CiA7OzsgdGlt
ZSB0aGUgcHJpbnRlciB3YXMgY2FsbGVkCi0oZGVmdmFyICpwcmV2aW91cy1jYXNlKiBuaWwpCi0o
ZGVmdmFyICpwcmV2aW91cy1yZWFkdGFibGUtY2FzZSogbmlsKQorKGRlZmluZS10aHJlYWQtbG9j
YWwtdmFyICpwcmV2aW91cy1jYXNlKiBuaWwpCisoZGVmaW5lLXRocmVhZC1sb2NhbC12YXIgKnBy
ZXZpb3VzLXJlYWR0YWJsZS1jYXNlKiBuaWwpCiAKIDs7OyBUaGlzIHZhcmlhYmxlIGNvbnRhaW5z
IHRoZSBjdXJyZW50IGRlZmluaXRpb24gb2Ygb25lIG9mIHRocmVlCiA7Ozsgc3ltYm9sIHByaW50
ZXJzLiBTRVRVUC1QUklOVEVSLVNUQVRFIHNldHMgdGhpcyB2YXJpYWJsZS4KLShkZWZ2YXIgKmlu
dGVybmFsLXN5bWJvbC1vdXRwdXQtZnVuKiBuaWwpCisoZGVmaW5lLXRocmVhZC1sb2NhbC12YXIg
KmludGVybmFsLXN5bWJvbC1vdXRwdXQtZnVuKiBuaWwpCiAKIDs7OyBUaGlzIGZ1bmN0aW9uIHNl
dHMgdGhlIGludGVybmFsIGdsb2JhbCBzeW1ib2wKIDs7OyAqSU5URVJOQUwtU1lNQk9MLU9VVFBV
VC1GVU4qIHRvIHRoZSByaWdodCBmdW5jdGlvbiBkZXBlbmRpbmcgb24KSW5kZXg6IHNyYy9jb2Rl
L3RhcmdldC10aHJlYWQubGlzcAo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ClJDUyBmaWxlOiAvY3Zzcm9vdC9zYmNsL3Ni
Y2wvc3JjL2NvZGUvdGFyZ2V0LXRocmVhZC5saXNwLHYKcmV0cmlldmluZyByZXZpc2lvbiAxLjU3
CmRpZmYgLXUgLXIxLjU3IHRhcmdldC10aHJlYWQubGlzcAotLS0gc3JjL2NvZGUvdGFyZ2V0LXRo
cmVhZC5saXNwCTE1IEp1bCAyMDA2IDE3OjQwOjA5IC0wMDAwCTEuNTcKKysrIHNyYy9jb2RlL3Rh
cmdldC10aHJlYWQubGlzcAkyNyBKdWwgMjAwNiAyMzozNTowMSAtMDAwMApAQCAtNTc3LDg1ICs1
NzcsOTUgQEAKICAgICAgICAgICAgICAgICAgICAgIChzYiFpbnQ6Zmx1c2gtc3RhbmRhcmQtb3V0
cHV0LXN0cmVhbXMpKSkpKSkKICAgICAgIChtYWtlLXRocmVhZCAjJ3RocmVhZC1yZXBsKSkpKQog
CisKKyMrc2ItdGhyZWFkCisoZGVmdW4gJW1ha2UtYmluZGluZ3MtZm9yLXRocmVhZCAoYmluZGlu
Z3MpCisgIChsb29wIGZvciBiaW5kaW5nIGluIGJpbmRpbmdzCisgICAgIGlmIChub3QgKHN5bWJv
bHAgKGZpcnN0IGJpbmRpbmcpKSkKKyAgICAgZG8gKGVycm9yICJOb24tc3ltYm9sIGluIGRlZmF1
bHQtYmluZGluZ3MiKQorICAgICBlbHNlIGNvbGxlY3QgKGZpcnN0IGJpbmRpbmcpIGludG8gdmFy
cworICAgICBhbmQgY29sbGVjdCAocmVzdCBiaW5kaW5nKSBpbnRvIHZhbHMKKyAgICAgZmluYWxs
eSAocmV0dXJuICh2YWx1ZXMgdmFycyB2YWxzKSkpKQorCiA7Ozs7IHRoZSBiZWVmCiAKLShkZWZ1
biBtYWtlLXRocmVhZCAoZnVuY3Rpb24gJmtleSBuYW1lKQorKGRlZnVuIG1ha2UtdGhyZWFkIChm
dW5jdGlvbiAma2V5IG5hbWUKKyAgICAgICAgICAgICAgICAgICAgKGRlZmF1bHQtYmluZGluZ3Mg
c2IhdGhyZWFkOjoqZGVmYXVsdC1zcGVjaWFsLWJpbmRpbmdzKikpCiAgICMhK3NiLWRvYwogICAi
Q3JlYXRlIGEgbmV3IHRocmVhZCBvZiBOQU1FIHRoYXQgcnVucyBGVU5DVElPTi4gV2hlbiB0aGUg
ZnVuY3Rpb24KLXJldHVybnMgdGhlIHRocmVhZCBleGl0cy4iCi0gICMhLXNiLXRocmVhZCAoZGVj
bGFyZSAoaWdub3JlIGZ1bmN0aW9uIG5hbWUpKQorcmV0dXJucyB0aGUgdGhyZWFkIGV4aXRzLiBE
RUZBVUxULUJJTkRJTkdTIGlzIGFuIGxpc3Qgb2YgKHZhcmlhYmxlIC4gdmFsdWUpCitiaW5kaW5n
cyB3aGljaCB3aWxsIGJlIGJvdW5kIHdoaWxlIEZVTkNUSU9OIGlzIGV4ZWN1dGVkLiIKKyAgIyEt
c2ItdGhyZWFkIChkZWNsYXJlIChpZ25vcmUgZnVuY3Rpb24gbmFtZSBkZWZhdWx0LWJpbmRpbmdz
KSkKICAgIyEtc2ItdGhyZWFkIChlcnJvciAiTm90IHN1cHBvcnRlZCBpbiB1bml0aHJlYWQgYnVp
bGRzLiIpCisgICMhK3NiLXRocmVhZCAoZGVjbGFyZSAodHlwZSBsaXN0IGRlZmF1bHQtYmluZGlu
Z3MpKQogICAjIStzYi10aHJlYWQKLSAgKGxldCogKCh0aHJlYWQgKCVtYWtlLXRocmVhZCA6bmFt
ZSBuYW1lKSkKLSAgICAgICAgIChzZXR1cC1zZW0gKG1ha2Utc2VtYXBob3JlIDpuYW1lICJUaHJl
YWQgc2V0dXAgc2VtYXBob3JlIikpCi0gICAgICAgICAocmVhbC1mdW5jdGlvbiAoY29lcmNlIGZ1
bmN0aW9uICdmdW5jdGlvbikpCi0gICAgICAgICAoaW5pdGlhbC1mdW5jdGlvbgotICAgICAgICAg
IChsYW1iZGEgKCkKLSAgICAgICAgICAgIDs7IEluIHRpbWUgd2UnbGwgbW92ZSBzb21lIG9mIHRo
ZSBiaW5kaW5nIHByZXNlbnRseSBkb25lIGluIEMKLSAgICAgICAgICAgIDs7IGhlcmUgdG9vLgot
ICAgICAgICAgICAgOzsKLSAgICAgICAgICAgIDs7IEtMVURHRTogSGVyZSB3ZSBoYXZlIGEgbWFn
aWMgbGlzdCBvZiB2YXJpYWJsZXMgdGhhdCBhcmUKLSAgICAgICAgICAgIDs7IG5vdCB0aHJlYWQt
c2FmZSBmb3Igb25lIHJlYXNvbiBvciBhbm90aGVyLiAgQXMgcGVvcGxlCi0gICAgICAgICAgICA7
OyByZXBvcnQgcHJvYmxlbXMgd2l0aCB0aGUgdGhyZWFkIHNhZmV0eSBvZiBjZXJ0YWluCi0gICAg
ICAgICAgICA7OyB2YXJpYWJsZXMsIChlLmcuICIqcHJpbnQtY2FzZSogaW4gbXVsdGlwbGUgdGhy
ZWFkcwotICAgICAgICAgICAgOzsgYnJva2VuIiwgc2JjbC1kZXZlbCAyMDA2LTA3LTE0KSwgd2Ug
YWRkIGEgZmV3IG1vcmUKLSAgICAgICAgICAgIDs7IGJpbmRpbmdzIGhlcmUuICBUaGUgUmlnaHQg
VGhpbmcgaXMgcHJvYmFibHkgc29tZSB2YXJpYW50Ci0gICAgICAgICAgICA7OyBvZiBBbGxlZ3Jv
J3MgKmNsLWRlZmF1bHQtc3BlY2lhbC1iaW5kaW5ncyosIGFzIHRoYXQgaXMgYXQKLSAgICAgICAg
ICAgIDs7IGxlYXN0IGFjY2Vzc2libGUgdG8gdXNlcnMgdG8gc2VjdXJlIHRoZWlyIG93biBsaWJy
YXJpZXMuCi0gICAgICAgICAgICA7OyAgIC0tbmpmLCAyMDA2LTA3LTE1Ci0gICAgICAgICAgICAo
bGV0ICgoKmN1cnJlbnQtdGhyZWFkKiB0aHJlYWQpCi0gICAgICAgICAgICAgICAgICAoc2Iha2Vy
bmVsOjoqcmVzdGFydC1jbHVzdGVycyogbmlsKQotICAgICAgICAgICAgICAgICAgKHNiIWtlcm5l
bDo6KmhhbmRsZXItY2x1c3RlcnMqIG5pbCkKLSAgICAgICAgICAgICAgICAgIChzYiFrZXJuZWw6
Oipjb25kaXRpb24tcmVzdGFydHMqIG5pbCkKLSAgICAgICAgICAgICAgICAgIDs7IGludGVybmFs
IHByaW50ZXIgdmFyaWFibGVzCi0gICAgICAgICAgICAgICAgICAoc2IhaW1wbDo6KnByZXZpb3Vz
LWNhc2UqIG5pbCkKLSAgICAgICAgICAgICAgICAgIChzYiFpbXBsOjoqcHJldmlvdXMtcmVhZHRh
YmxlLWNhc2UqIG5pbCkKLSAgICAgICAgICAgICAgICAgIChzYiFpbXBsOjoqaW50ZXJuYWwtc3lt
Ym9sLW91dHB1dC1mdW4qIG5pbCkKLSAgICAgICAgICAgICAgICAgIChzYiFpbXBsOjoqZGVzY3Jp
cHRvci1oYW5kbGVycyogbmlsKSkgOyBzZXJ2ZS1ldmVudAotICAgICAgICAgICAgICAoc2V0ZiAo
dGhyZWFkLW9zLXRocmVhZCB0aHJlYWQpIChjdXJyZW50LXRocmVhZC1zYXAtaWQpKQotICAgICAg
ICAgICAgICAod2l0aC1tdXRleCAoKmFsbC10aHJlYWRzLWxvY2sqKQotICAgICAgICAgICAgICAg
IChwdXNoIHRocmVhZCAqYWxsLXRocmVhZHMqKSkKLSAgICAgICAgICAgICAgKHdpdGgtc2Vzc2lv
bi1sb2NrICgqc2Vzc2lvbiopCi0gICAgICAgICAgICAgICAgKHB1c2ggdGhyZWFkIChzZXNzaW9u
LXRocmVhZHMgKnNlc3Npb24qKSkpCi0gICAgICAgICAgICAgIChzZXRmICh0aHJlYWQtJWFsaXZl
LXAgdGhyZWFkKSB0KQotICAgICAgICAgICAgICAoc2lnbmFsLXNlbWFwaG9yZSBzZXR1cC1zZW0p
Ci0gICAgICAgICAgICAgIDs7IGNhbid0IHVzZSBoYW5kbGluZy1lbmQtb2YtdGhlLXdvcmxkLCBi
ZWNhdXNlIHRoYXQgZmx1c2hlcwotICAgICAgICAgICAgICA7OyBvdXRwdXQgc3RyZWFtcywgYW5k
IHdlIGRvbid0IG5lY2Vzc2FyaWx5IGhhdmUgYW55IChvciB3ZQotICAgICAgICAgICAgICA7OyBj
b3VsZCBiZSBzaGFyaW5nIHRoZW0pCi0gICAgICAgICAgICAgIChjYXRjaCAnc2IhaW1wbDo6dG9w
bGV2ZWwtY2F0Y2hlcgotICAgICAgICAgICAgICAgIChjYXRjaCAnc2IhaW1wbDo6JWVuZC1vZi10
aGUtd29ybGQKLSAgICAgICAgICAgICAgICAgICh3aXRoLXNpbXBsZS1yZXN0YXJ0Ci0gICAgICAg
ICAgICAgICAgICAgICAgKHRlcm1pbmF0ZS10aHJlYWQKLSAgICAgICAgICAgICAgICAgICAgICAg
KGZvcm1hdCBuaWwKLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAifn5APFRlcm1pbmF0
ZSB0aGlzIHRocmVhZCAofkEpfn5AOj4iCi0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
KmN1cnJlbnQtdGhyZWFkKikpCi0gICAgICAgICAgICAgICAgICAgICh1bndpbmQtcHJvdGVjdAot
ICAgICAgICAgICAgICAgICAgICAgICAgIChwcm9nbgotICAgICAgICAgICAgICAgICAgICAgICAg
ICAgOzsgbm93IHRoYXQgbW9zdCB0aGluZ3MgaGF2ZSBhIGNoYW5jZSB0bwotICAgICAgICAgICAg
ICAgICAgICAgICAgICAgOzsgd29yayBwcm9wZXJseSB3aXRob3V0IG1lc3NpbmcgdXAgb3RoZXIK
LSAgICAgICAgICAgICAgICAgICAgICAgICAgIDs7IHRocmVhZHMsIGl0J3MgdGltZSB0byBlbmFi
bGUgc2lnbmFscwotICAgICAgICAgICAgICAgICAgICAgICAgICAgKHNiIXVuaXg6OnJlc2V0LXNp
Z25hbC1tYXNrKQotICAgICAgICAgICAgICAgICAgICAgICAgICAgKGZ1bmNhbGwgcmVhbC1mdW5j
dGlvbikpCi0gICAgICAgICAgICAgICAgICAgICAgOzsgd2UncmUgZ29pbmcgZG93biwgY2FuJ3Qg
aGFuZGxlCi0gICAgICAgICAgICAgICAgICAgICAgOzsgaW50ZXJydXB0cyBzYW5lbHkgYW55bW9y
ZQotICAgICAgICAgICAgICAgICAgICAgIChsZXQgKChzYiFpbXBsOjoqZ2MtaW5oaWJpdCogdCkp
Ci0gICAgICAgICAgICAgICAgICAgICAgICAoYmxvY2stYmxvY2thYmxlLXNpZ25hbHMpCi0gICAg
ICAgICAgICAgICAgICAgICAgICAoc2V0ZiAodGhyZWFkLSVhbGl2ZS1wIHRocmVhZCkgbmlsKQot
ICAgICAgICAgICAgICAgICAgICAgICAgKHNldGYgKHRocmVhZC1vcy10aHJlYWQgdGhyZWFkKSBu
aWwpCi0gICAgICAgICAgICAgICAgICAgICAgICA7OyBhbmQgcmVtb3ZlIHdoYXQgY2FuIGJlIHRo
ZSBsYXN0Ci0gICAgICAgICAgICAgICAgICAgICAgICA7OyByZWZlcmVuY2UgdG8gdGhpcyB0aHJl
YWQKLSAgICAgICAgICAgICAgICAgICAgICAgIChoYW5kbGUtdGhyZWFkLWV4aXQgdGhyZWFkKSkp
KSkpKQotICAgICAgICAgICAgKHZhbHVlcykpKSkKLSAgICA7OyBLZWVwIElOSVRJQUwtRlVOQ1RJ
T04gcGlubmVkIHVudGlsIHRoZSBjaGlsZCB0aHJlYWQgaXMKLSAgICA7OyBpbml0aWFsaXplZCBw
cm9wZXJseS4KLSAgICAod2l0aC1waW5uZWQtb2JqZWN0cyAoaW5pdGlhbC1mdW5jdGlvbikKLSAg
ICAgIChsZXQgKChvcy10aHJlYWQKLSAgICAgICAgICAgICAoJWNyZWF0ZS10aHJlYWQKLSAgICAg
ICAgICAgICAgKHNiIWtlcm5lbDpnZXQtbGlzcC1vYmotYWRkcmVzcyBpbml0aWFsLWZ1bmN0aW9u
KSkpKQotICAgICAgICAod2hlbiAoemVyb3Agb3MtdGhyZWFkKQotICAgICAgICAgIChlcnJvciAi
Q2FuJ3QgY3JlYXRlIGEgbmV3IHRocmVhZCIpKQotICAgICAgICAod2FpdC1vbi1zZW1hcGhvcmUg
c2V0dXAtc2VtKQotICAgICAgICB0aHJlYWQpKSkpCisgIChtdWx0aXBsZS12YWx1ZS1iaW5kIChk
ZWZhdWx0LWJpbmRpbmdzLXZhcnMgZGVmYXVsdC1iaW5kaW5ncy12YWxzKQorICAgICAgKCVtYWtl
LWJpbmRpbmdzLWZvci10aHJlYWQgZGVmYXVsdC1iaW5kaW5ncykKKyAgICAobGV0KiAoKHRocmVh
ZCAoJW1ha2UtdGhyZWFkIDpuYW1lIG5hbWUpKQorICAgICAgICAgICAoc2V0dXAtc2VtIChtYWtl
LXNlbWFwaG9yZSA6bmFtZSAiVGhyZWFkIHNldHVwIHNlbWFwaG9yZSIpKQorICAgICAgICAgICAo
cmVhbC1mdW5jdGlvbiAoY29lcmNlIGZ1bmN0aW9uICdmdW5jdGlvbikpCisgICAgICAgICAgIChp
bml0aWFsLWZ1bmN0aW9uCisgICAgICAgICAgICAobGFtYmRhICgpCisgICAgICAgICAgICAgIDs7
IEluIHRpbWUgd2UnbGwgbW92ZSBzb21lIG9mIHRoZSBiaW5kaW5nIHByZXNlbnRseSBkb25lIGlu
IEMKKyAgICAgICAgICAgICAgOzsgaGVyZSB0b28uCisgICAgICAgICAgICAgIDs7CisgICAgICAg
ICAgICAgIDs7IEJpbmQgc29tZSBzdXBlci1jcml0aWFsIHZhcmlhYmxlcyBtYW51YWxseSwgdGhl
IHJlc3QKKyAgICAgICAgICAgICAgOzsgYXJlIGhhbmRsZWQgdmlhICpERUZBVUxULVNQRUNJQUwt
QklORElOR1MqCisgICAgICAgICAgICAgIDs7CisgICAgICAgICAgICAgIDs7IFRoZSByZWFzb24g
aXMgdGhhdCB3ZSB3YW50IHRocmVhZGluZyBhdCBsZWFzdAorICAgICAgICAgICAgICA7OyBzb21l
d2hhdCB3b3JraW5nIGV2ZW4gaWYgdXNlciBzaG9vdHMgdGhlbXNlbGYKKyAgICAgICAgICAgICAg
OzsgaW4gYSBmb290IGFuZCBwYXNzZXMgREVGQVVMVC1CSU5ESU5HUyBhcyBuaWwKKyAgICAgICAg
ICAgICAgOzsgb3Igc2V0cyAqREVGQVVMVC1TUEVDSUFMLUJJTkRJTkdTKiBuaWwKKyAgICAgICAg
ICAgICAgKGxldCAoKCpjdXJyZW50LXRocmVhZCogdGhyZWFkKQorICAgICAgICAgICAgICAgICAg
ICAoc2Iha2VybmVsOjoqcmVzdGFydC1jbHVzdGVycyogbmlsKQorICAgICAgICAgICAgICAgICAg
ICAoc2Iha2VybmVsOjoqaGFuZGxlci1jbHVzdGVycyogbmlsKQorICAgICAgICAgICAgICAgICAg
ICAoc2Iha2VybmVsOjoqY29uZGl0aW9uLXJlc3RhcnRzKiBuaWwpCisgICAgICAgICAgICAgICAg
ICAgIChzYiFpbXBsOjoqZGVzY3JpcHRvci1oYW5kbGVycyogbmlsKSkgOyBzZXJ2ZS1ldmVudAor
ICAgICAgICAgICAgICAgIChzZXRmICh0aHJlYWQtb3MtdGhyZWFkIHRocmVhZCkgKGN1cnJlbnQt
dGhyZWFkLXNhcC1pZCkpCisgICAgICAgICAgICAgICAgKHdpdGgtbXV0ZXggKCphbGwtdGhyZWFk
cy1sb2NrKikKKyAgICAgICAgICAgICAgICAgIChwdXNoIHRocmVhZCAqYWxsLXRocmVhZHMqKSkK
KyAgICAgICAgICAgICAgICAod2l0aC1zZXNzaW9uLWxvY2sgKCpzZXNzaW9uKikKKyAgICAgICAg
ICAgICAgICAgIChwdXNoIHRocmVhZCAoc2Vzc2lvbi10aHJlYWRzICpzZXNzaW9uKikpKQorICAg
ICAgICAgICAgICAgIChzZXRmICh0aHJlYWQtJWFsaXZlLXAgdGhyZWFkKSB0KQorICAgICAgICAg
ICAgICAgIDs7IGNhbid0IHVzZSBoYW5kbGluZy1lbmQtb2YtdGhlLXdvcmxkLCBiZWNhdXNlIHRo
YXQgZmx1c2hlcworICAgICAgICAgICAgICAgIDs7IG91dHB1dCBzdHJlYW1zLCBhbmQgd2UgZG9u
J3QgbmVjZXNzYXJpbHkgaGF2ZSBhbnkgKG9yIHdlCisgICAgICAgICAgICAgICAgOzsgY291bGQg
YmUgc2hhcmluZyB0aGVtKQorICAgICAgICAgICAgICAgIChwcm9ndiBkZWZhdWx0LWJpbmRpbmdz
LXZhcnMgZGVmYXVsdC1iaW5kaW5ncy12YWxzCisgICAgICAgICAgICAgICAgICAoc2lnbmFsLXNl
bWFwaG9yZSBzZXR1cC1zZW0pCisgICAgICAgICAgICAgICAgICAoY2F0Y2ggJ3NiIWltcGw6OnRv
cGxldmVsLWNhdGNoZXIKKyAgICAgICAgICAgICAgICAgICAgKGNhdGNoICdzYiFpbXBsOjolZW5k
LW9mLXRoZS13b3JsZAorICAgICAgICAgICAgICAgICAgICAgICh3aXRoLXNpbXBsZS1yZXN0YXJ0
CisgICAgICAgICAgICAgICAgICAgICAgICAgICh0ZXJtaW5hdGUtdGhyZWFkCisgICAgICAgICAg
ICAgICAgICAgICAgICAgICAoZm9ybWF0IG5pbAorICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAifn5APFRlcm1pbmF0ZSB0aGlzIHRocmVhZCAofkEpfn5AOj4iCisgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICpjdXJyZW50LXRocmVhZCopKQorICAgICAgICAgICAg
ICAgICAgICAgICAgKHVud2luZC1wcm90ZWN0CisgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IChwcm9nbgorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDs7IG5vdyB0aGF0IG1vc3Qg
dGhpbmdzIGhhdmUgYSBjaGFuY2UgdG8KKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7
OyB3b3JrIHByb3Blcmx5IHdpdGhvdXQgbWVzc2luZyB1cCBvdGhlcgorICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIDs7IHRocmVhZHMsIGl0J3MgdGltZSB0byBlbmFibGUgc2lnbmFscwor
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzYiF1bml4OjpyZXNldC1zaWduYWwtbWFz
aykKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZnVuY2FsbCByZWFsLWZ1bmN0aW9u
KSkKKyAgICAgICAgICAgICAgICAgICAgICAgICAgOzsgd2UncmUgZ29pbmcgZG93biwgY2FuJ3Qg
aGFuZGxlCisgICAgICAgICAgICAgICAgICAgICAgICAgIDs7IGludGVycnVwdHMgc2FuZWx5IGFu
eW1vcmUKKyAgICAgICAgICAgICAgICAgICAgICAgICAgKGxldCAoKHNiIWltcGw6OipnYy1pbmhp
Yml0KiB0KSkKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAoYmxvY2stYmxvY2thYmxlLXNp
Z25hbHMpCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHNldGYgKHRocmVhZC0lYWxpdmUt
cCB0aHJlYWQpIG5pbCkKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAoc2V0ZiAodGhyZWFk
LW9zLXRocmVhZCB0aHJlYWQpIG5pbCkKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICA7OyBh
bmQgcmVtb3ZlIHdoYXQgY2FuIGJlIHRoZSBsYXN0CisgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgOzsgcmVmZXJlbmNlIHRvIHRoaXMgdGhyZWFkCisgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgKGhhbmRsZS10aHJlYWQtZXhpdCB0aHJlYWQpKSkpKSkpKQorICAgICAgICAgICAgICAodmFs
dWVzKSkpKQorICAgICAgOzsgS2VlcCBJTklUSUFMLUZVTkNUSU9OIHBpbm5lZCB1bnRpbCB0aGUg
Y2hpbGQgdGhyZWFkIGlzCisgICAgICA7OyBpbml0aWFsaXplZCBwcm9wZXJseS4KKyAgICAgICh3
aXRoLXBpbm5lZC1vYmplY3RzIChpbml0aWFsLWZ1bmN0aW9uKQorICAgICAgICAobGV0ICgob3Mt
dGhyZWFkCisgICAgICAgICAgICAgICAoJWNyZWF0ZS10aHJlYWQKKyAgICAgICAgICAgICAgICAo
c2Iha2VybmVsOmdldC1saXNwLW9iai1hZGRyZXNzIGluaXRpYWwtZnVuY3Rpb24pKSkpCisgICAg
ICAgICAgKHdoZW4gKHplcm9wIG9zLXRocmVhZCkKKyAgICAgICAgICAgIChlcnJvciAiQ2FuJ3Qg
Y3JlYXRlIGEgbmV3IHRocmVhZCIpKQorICAgICAgICAgICh3YWl0LW9uLXNlbWFwaG9yZSBzZXR1
cC1zZW0pCisgICAgICAgICAgdGhyZWFkKSkpKSkKIAogKGRlZnVuIGRlc3Ryb3ktdGhyZWFkICh0
aHJlYWQpCiAgICMhK3NiLWRvYwo=
===File ~/cvs/sbcl/default-special-bindings.patch===========
Index: package-data-list.lisp-expr
===================================================================
RCS file: /cvsroot/sbcl/sbcl/package-data-list.lisp-expr,v
retrieving revision 1.357
diff -u -r1.357 package-data-list.lisp-expr
--- package-data-list.lisp-expr 20 Jun 2006 05:38:42 -0000 1.357
+++ package-data-list.lisp-expr 27 Jul 2006 23:34:59 -0000
@@ -749,7 +749,12 @@
;; timer
"TIMER" "MAKE-TIMER" "TIMER-NAME" "TIMER-SCHEDULED-P"
- "SCHEDULE-TIMER" "UNSCHEDULE-TIMER" "LIST-ALL-TIMERS"))
+ "SCHEDULE-TIMER" "UNSCHEDULE-TIMER" "LIST-ALL-TIMERS"
+
+ ;; thread-local
+ "DEFINE-THREAD-LOCAL-VAR"
+ "*DEFAULT-SPECIAL-BINDINGS*"
+ ))
#s(sb-cold:package-data
:name "SB!FORMAT"
@@ -1625,7 +1630,10 @@
:name "SB!THREAD"
:use ("CL" "SB!ALIEN" "SB!INT" "SB!SYS")
:doc "public (but low-level): native thread support"
- :export ("*CURRENT-THREAD*" "THREAD" "MAKE-THREAD"
+ :import-from (("SB!EXT" "*DEFAULT-SPECIAL-BINDINGS*"))
+ :reexport ("*DEFAULT-SPECIAL-BINDINGS*")
+ :export ("*CURRENT-THREAD*"
+ "THREAD" "MAKE-THREAD"
"THREAD-NAME" "THREAD-ALIVE-P"
"LIST-ALL-THREADS"
"INTERRUPT-THREAD-ERROR"
Index: src/code/defboot.lisp
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/code/defboot.lisp,v
retrieving revision 1.52
diff -u -r1.52 defboot.lisp
--- src/code/defboot.lisp 15 May 2006 16:11:38 -0000 1.52
+++ src/code/defboot.lisp 27 Jul 2006 23:35:00 -0000
@@ -241,7 +241,24 @@
(eval-when (:load-toplevel :execute)
(%defvar ',var (unless (boundp ',var) ,val)
',valp ,doc ',docp
- (sb!c:source-location)))))
+ (sb!c:source-location) nil))))
+
+(defmacro-mundanely define-thread-local-var (var &optional (val nil valp) (doc nil docp))
+ #!+sb-doc
+ "Define a global variable at top level. Declare the variable
+ SPECIAL and, optionally, initialize it. In addition add the variable
+ to *default-special-bindings* a-list. If the variable already has a
+ value, the old value is not clobbered. The third argument is an optional
+ documentation string for the variable. "
+ `(progn
+ (eval-when (:compile-toplevel)
+ (%compiler-defvar ',var))
+ (eval-when (:load-toplevel :execute)
+ (%defvar ',var (unless (boundp ',var) ,val)
+ ',valp ,doc ',docp
+ (sb!c:source-location)
+ #+sb-thread t
+ #-sb-thread nil))))
(defmacro-mundanely defparameter (var val &optional (doc nil docp))
#!+sb-doc
@@ -254,13 +271,28 @@
(eval-when (:compile-toplevel)
(%compiler-defvar ',var))
(eval-when (:load-toplevel :execute)
- (%defparameter ',var ,val ,doc ',docp (sb!c:source-location)))))
+ (%defparameter ',var ,val ,doc ',docp (sb!c:source-location) nil))))
+
+(defmacro-mundanely define-thread-local-parameter (var val &optional (doc nil docp))
+ #!+sb-doc
+ "Define a parameter that is not normally changed by the program,
+ but that may be changed without causing an error. Declare the
+ variable special and sets its value to VAL, overwriting any
+ previous value. Also add the variable to *default-special-bindings*.
+ The third argument is an optional documentation string for the parameter."
+ `(progn
+ (eval-when (:compile-toplevel)
+ (%compiler-defvar ',var))
+ (eval-when (:load-toplevel :execute)
+ (%defparameter ',var ,val ,doc ',docp (sb!c:source-location)
+ #+sb-thread t
+ #-sb-thread nil))))
(defun %compiler-defvar (var)
(sb!xc:proclaim `(special ,var)))
#-sb-xc-host
-(defun %defvar (var val valp doc docp source-location)
+(defun %defvar (var val valp doc docp source-location thread-local-p)
(%compiler-defvar var)
(when valp
(unless (boundp var)
@@ -269,16 +301,33 @@
(setf (fdocumentation var 'variable) doc))
(sb!c:with-source-location (source-location)
(setf (info :source-location :variable var) source-location))
+ (when thread-local-p
+ (let ((prev (assoc var sb!thread::*default-special-bindings*))
+ (value (cond (valp val)
+ ;; pickup the old value if bound
+ ((and (not valp) (boundp var)) (symbol-value var))
+ (t (sb!kernel:make-lisp-obj
+ sb!vm::no-tls-value-marker-widetag)))))
+ (if prev
+ (rplacd prev value)
+ (push (cons var value)
+ sb!thread::*default-special-bindings*))))
var)
#-sb-xc-host
-(defun %defparameter (var val doc docp source-location)
+(defun %defparameter (var val doc docp source-location thread-local-p)
(%compiler-defvar var)
(set var val)
(when docp
(setf (fdocumentation var 'variable) doc))
(sb!c:with-source-location (source-location)
(setf (info :source-location :variable var) source-location))
+ (when thread-local-p
+ (let ((prev (assoc var sb!thread::*default-special-bindings*)))
+ (if prev
+ (rplacd prev val)
+ (push (cons var val)
+ sb!thread::*default-special-bindings*))))
var)
;;;; iteration constructs
Index: src/code/early-thread.lisp
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/code/early-thread.lisp,v
retrieving revision 1.1
diff -u -r1.1 early-thread.lisp
--- src/code/early-thread.lisp 1 Jul 2005 08:48:33 -0000 1.1
+++ src/code/early-thread.lisp 27 Jul 2006 23:35:00 -0000
@@ -10,3 +10,4 @@
(in-package "SB!THREAD")
(defvar *current-thread*)
+(defvar *default-special-bindings* nil)
Index: src/code/print.lisp
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/code/print.lisp,v
retrieving revision 1.68
diff -u -r1.68 print.lisp
--- src/code/print.lisp 16 Mar 2006 03:24:18 -0000 1.68
+++ src/code/print.lisp 27 Jul 2006 23:35:01 -0000
@@ -399,12 +399,12 @@
;;; values of *PRINT-CASE* and (READTABLE-CASE *READTABLE*) the last
;;; time the printer was called
-(defvar *previous-case* nil)
-(defvar *previous-readtable-case* nil)
+(define-thread-local-var *previous-case* nil)
+(define-thread-local-var *previous-readtable-case* nil)
;;; This variable contains the current definition of one of three
;;; symbol printers. SETUP-PRINTER-STATE sets this variable.
-(defvar *internal-symbol-output-fun* nil)
+(define-thread-local-var *internal-symbol-output-fun* nil)
;;; This function sets the internal global symbol
;;; *INTERNAL-SYMBOL-OUTPUT-FUN* to the right function depending on
Index: src/code/target-thread.lisp
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/code/target-thread.lisp,v
retrieving revision 1.57
diff -u -r1.57 target-thread.lisp
--- src/code/target-thread.lisp 15 Jul 2006 17:40:09 -0000 1.57
+++ src/code/target-thread.lisp 27 Jul 2006 23:35:01 -0000
@@ -577,85 +577,95 @@
(sb!int:flush-standard-output-streams))))))
(make-thread #'thread-repl))))
+
+#+sb-thread
+(defun %make-bindings-for-thread (bindings)
+ (loop for binding in bindings
+ if (not (symbolp (first binding)))
+ do (error "Non-symbol in default-bindings")
+ else collect (first binding) into vars
+ and collect (rest binding) into vals
+ finally (return (values vars vals))))
+
;;;; the beef
-(defun make-thread (function &key name)
+(defun make-thread (function &key name
+ (default-bindings sb!thread::*default-special-bindings*))
#!+sb-doc
"Create a new thread of NAME that runs FUNCTION. When the function
-returns the thread exits."
- #!-sb-thread (declare (ignore function name))
+returns the thread exits. DEFAULT-BINDINGS is an list of (variable . value)
+bindings which will be bound while FUNCTION is executed."
+ #!-sb-thread (declare (ignore function name default-bindings))
#!-sb-thread (error "Not supported in unithread builds.")
+ #!+sb-thread (declare (type list default-bindings))
#!+sb-thread
- (let* ((thread (%make-thread :name name))
- (setup-sem (make-semaphore :name "Thread setup semaphore"))
- (real-function (coerce function 'function))
- (initial-function
- (lambda ()
- ;; In time we'll move some of the binding presently done in C
- ;; here too.
- ;;
- ;; KLUDGE: Here we have a magic list of variables that are
- ;; not thread-safe for one reason or another. As people
- ;; report problems with the thread safety of certain
- ;; variables, (e.g. "*print-case* in multiple threads
- ;; broken", sbcl-devel 2006-07-14), we add a few more
- ;; bindings here. The Right Thing is probably some variant
- ;; of Allegro's *cl-default-special-bindings*, as that is at
- ;; least accessible to users to secure their own libraries.
- ;; --njf, 2006-07-15
- (let ((*current-thread* thread)
- (sb!kernel::*restart-clusters* nil)
- (sb!kernel::*handler-clusters* nil)
- (sb!kernel::*condition-restarts* nil)
- ;; internal printer variables
- (sb!impl::*previous-case* nil)
- (sb!impl::*previous-readtable-case* nil)
- (sb!impl::*internal-symbol-output-fun* nil)
- (sb!impl::*descriptor-handlers* nil)) ; serve-event
- (setf (thread-os-thread thread) (current-thread-sap-id))
- (with-mutex (*all-threads-lock*)
- (push thread *all-threads*))
- (with-session-lock (*session*)
- (push thread (session-threads *session*)))
- (setf (thread-%alive-p thread) t)
- (signal-semaphore setup-sem)
- ;; can't use handling-end-of-the-world, because that flushes
- ;; output streams, and we don't necessarily have any (or we
- ;; could be sharing them)
- (catch 'sb!impl::toplevel-catcher
- (catch 'sb!impl::%end-of-the-world
- (with-simple-restart
- (terminate-thread
- (format nil
- "~~@<Terminate this thread (~A)~~@:>"
- *current-thread*))
- (unwind-protect
- (progn
- ;; now that most things have a chance to
- ;; work properly without messing up other
- ;; threads, it's time to enable signals
- (sb!unix::reset-signal-mask)
- (funcall real-function))
- ;; we're going down, can't handle
- ;; interrupts sanely anymore
- (let ((sb!impl::*gc-inhibit* t))
- (block-blockable-signals)
- (setf (thread-%alive-p thread) nil)
- (setf (thread-os-thread thread) nil)
- ;; and remove what can be the last
- ;; reference to this thread
- (handle-thread-exit thread)))))))
- (values))))
- ;; Keep INITIAL-FUNCTION pinned until the child thread is
- ;; initialized properly.
- (with-pinned-objects (initial-function)
- (let ((os-thread
- (%create-thread
- (sb!kernel:get-lisp-obj-address initial-function))))
- (when (zerop os-thread)
- (error "Can't create a new thread"))
- (wait-on-semaphore setup-sem)
- thread))))
+ (multiple-value-bind (default-bindings-vars default-bindings-vals)
+ (%make-bindings-for-thread default-bindings)
+ (let* ((thread (%make-thread :name name))
+ (setup-sem (make-semaphore :name "Thread setup semaphore"))
+ (real-function (coerce function 'function))
+ (initial-function
+ (lambda ()
+ ;; In time we'll move some of the binding presently done in C
+ ;; here too.
+ ;;
+ ;; Bind some super-critial variables manually, the rest
+ ;; are handled via *DEFAULT-SPECIAL-BINDINGS*
+ ;;
+ ;; The reason is that we want threading at least
+ ;; somewhat working even if user shoots themself
+ ;; in a foot and passes DEFAULT-BINDINGS as nil
+ ;; or sets *DEFAULT-SPECIAL-BINDINGS* nil
+ (let ((*current-thread* thread)
+ (sb!kernel::*restart-clusters* nil)
+ (sb!kernel::*handler-clusters* nil)
+ (sb!kernel::*condition-restarts* nil)
+ (sb!impl::*descriptor-handlers* nil)) ; serve-event
+ (setf (thread-os-thread thread) (current-thread-sap-id))
+ (with-mutex (*all-threads-lock*)
+ (push thread *all-threads*))
+ (with-session-lock (*session*)
+ (push thread (session-threads *session*)))
+ (setf (thread-%alive-p thread) t)
+ ;; can't use handling-end-of-the-world, because that flushes
+ ;; output streams, and we don't necessarily have any (or we
+ ;; could be sharing them)
+ (progv default-bindings-vars default-bindings-vals
+ (signal-semaphore setup-sem)
+ (catch 'sb!impl::toplevel-catcher
+ (catch 'sb!impl::%end-of-the-world
+ (with-simple-restart
+ (terminate-thread
+ (format nil
+ "~~@<Terminate this thread (~A)~~@:>"
+ *current-thread*))
+ (unwind-protect
+ (progn
+ ;; now that most things have a chance to
+ ;; work properly without messing up other
+ ;; threads, it's time to enable signals
+ (sb!unix::reset-signal-mask)
+ (funcall real-function))
+ ;; we're going down, can't handle
+ ;; interrupts sanely anymore
+ (let ((sb!impl::*gc-inhibit* t))
+ (block-blockable-signals)
+ (setf (thread-%alive-p thread) nil)
+ (setf (thread-os-thread thread) nil)
+ ;; and remove what can be the last
+ ;; reference to this thread
+ (handle-thread-exit thread))))))))
+ (values))))
+ ;; Keep INITIAL-FUNCTION pinned until the child thread is
+ ;; initialized properly.
+ (with-pinned-objects (initial-function)
+ (let ((os-thread
+ (%create-thread
+ (sb!kernel:get-lisp-obj-address initial-function))))
+ (when (zerop os-thread)
+ (error "Can't create a new thread"))
+ (wait-on-semaphore setup-sem)
+ thread)))))
(defun destroy-thread (thread)
#!+sb-doc
============================================================
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Sbcl-devel mailing list
Sbcl-...@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sbcl-devel
Yes, this issue has come up many times in the past both internally in
sbcl code and in user code/libraries. As Max and innocent #lisp
bystanders are already aware that - for what it's worth - I'm not
entirely convinced of the correctness of this solution.
Here is a scenario in which this approach fails to protect against
threads sharing a binding. A library has a special that it declares
thread local. Threads started after the library is loaded will
correctly have thread local bindings for the special. But a thread that
was started before the library was loaded will see the global binding
of the special. If such a thread calls into the lib or accesses the
value of the special in another way lossage is imminent. How can such a
thread depend on that special? Lots of ways: defining an around method
on a method which called, calling callbacks, using symbol-value and
find-symbol. Any kind of dependency injection has a chance to fall
flat.
In case it is not clear yet, I argue that this solution is a good one if
and only if there is a single thread in the system at the time of
define-thread-local-*. That constraint is trivially satisfied by sbcl
internals but makes it dangerously overpromising for user code.
How to make it safe for user code?
1) check if there is only one thread at the time of
define-thread-local-*
Bleh. I'd hate not being able to load a library because multiple threads
are running.
or
2) thread local specials must have no global binding
Makes sense to me. How to implement it is another question.
This patch deviates from allegro's *cl-default-special-bindings* in an
important way: in acl the value of that special is an "alist
associating special variable symbols with forms to evaluate for binding
values" which makes to possible to have (*readtable* . (copy-readtable
nil)) copy the current readtable into the child thread or (*db* .
(open-db-connection)) to give each thread its own db connection which I
think is impossible to do here. Truth to tell I dislike even the
allegro way, because it needs to do several little evals at the start
of each thread even if those bindings are never used.
Ideally a lazy initialization mechanism coupled with "thread local
specials have no global binding" may be preferable.
Cheers, Gabor
At Sat, 29 Jul 2006 13:26:35 +0200,
Gábor Melis wrote:
>
> Here is a scenario in which this approach fails to protect against
> threads sharing a binding. A library has a special that it declares
> thread local. Threads started after the library is loaded will
> correctly have thread local bindings for the special. But a thread that
> was started before the library was loaded will see the global binding
> of the special. If such a thread calls into the lib or accesses the
> value of the special in another way lossage is imminent. How can such a
> thread depend on that special? Lots of ways: defining an around method
> on a method which called, calling callbacks, using symbol-value and
> find-symbol. Any kind of dependency injection has a chance to fall
> flat.
>
> In case it is not clear yet, I argue that this solution is a good one if
> and only if there is a single thread in the system at the time of
> define-thread-local-*. That constraint is trivially satisfied by sbcl
> internals but makes it dangerously overpromising for user code.
>
> How to make it safe for user code?
>
> 1) check if there is only one thread at the time of
> define-thread-local-*
>
> Bleh. I'd hate not being able to load a library because multiple threads
> are running.
>
> or
>
> 2) thread local specials must have no global binding
>
> Makes sense to me. How to implement it is another question.
Any critique to the following approach?
Below code is a method of injecting a thread-local value into threads
that are already running, tt handles 2 cases :
a) (defun my-thread () (print *var*) (setq *var* 'local-to-this-thread))
In the above case if the (make-symbol-thread-local) was executed
before thread entered print form, it would get a default per/thread
value. The setq would set a per-thread value
b) (defun my-thread () (let ((*var* 'local-value-a)) (print *var*))
(print *var) (setq *var* 'local-to-this-tread))
In the above case when thread already have a special bound, and
(make-symbol-thread-local...) is executed somewhere else while
thread is inside of the (let) form, then once thread exits the (let)
form then new thread-local value of *var* would be restored instead
of the old global value
(I tested it with as much as 16 threads on 4 way opteron, so IMHO
its pretty safe).
;;; make the symbol thread local and default to value
;;; in all running threads
(defun make-symbol-thread-local (symbol value)
(unless (eq (sb-c::info :variable :kind symbol) :special)
(error "Symbol ~S must be special variable" symbol))
(progv (list symbol) nil
;; above progv binds the symbol in the current thread making
;; sure that TLS index is allocated
(let ((tls-index (sb-vm::symbol-tls-index symbol)))
(sb-vm::without-gcing
(sb-kernel::gc-stop-the-world)
;; all threads except this one are now stopped so
;; we should be safe to do do our thing now
(fix-symbol-value-in-all-threads symbol tls-index value)
(sb-kernel::gc-start-the-world)
)))
(values))
(defun fix-symbol-value-in-all-threads (symbol tls-index value)
(declare (type symbol symbol) (type fixnum tls-index))
(loop
as thread-sap = (alien-sap (extern-alien "all_threads" (* t)))
then (sb-vm::sap-ref-sap thread-sap (* sb-vm:n-word-bytes
sb-vm::thread-next-slot))
while (not (sb-vm::sap= thread-sap (sb-vm::int-sap 0)))
do (fix-symbol-value-in-one-thread thread-sap symbol tls-index value))
(values))
(defun fix-symbol-value-in-one-thread (thread-sap symbol tls-index value)
(declare (type system-area-pointer thread-sap)
(type symbol symbol)
(type fixnum tls-index))
(let ((was-bound-p nil))
(loop
;; search the binding stack for the first binding of symbol
with end = (sb-vm::sap-ref-sap thread-sap (* sb-vm::n-word-bytes
sb-vm::thread-binding-stack-pointer-slot))
as bsp = (sb-vm::sap-ref-sap thread-sap (* sb-vm::n-word-bytes
sb-vm::thread-binding-stack-start-slot))
then (sb-vm::sap+ bsp (* sb-vm::binding-size sb-vm:n-word-bytes))
while (sb-vm::sap< bsp end)
as previous-value = (sb-vm::make-lisp-obj (sb-vm::sap-ref-word bsp 0))
as binding-symbol = (sb-vm::make-lisp-obj (sb-vm::sap-ref-word bsp sb-vm::n-word-bytes))
;; if found the binding for a symbol, update the previous value
;; so that after unbind the new default per-thread value is restored
when (eq binding-symbol symbol)
do (setq was-bound-p t)
and do (setf (sb-vm::sap-ref-word bsp 0)
(sb-kernel::get-lisp-obj-address value))
and return nil)
(unless was-bound-p
;; if symbol was not bound in the thread, then set the TLS value
;; directly. This creates a situation where a thread have a TLS
;; value of a special without the previous value of the special
;; being on the binding stack, therefore such thread would never see
;; the global value even again.
;;
;; In case I discover it does cause problems we can also update
;; the binding stack here and add an entry
(setf (sb-vm::sap-ref-word thread-sap (* sb-vm::n-word-bytes tls-index))
(sb-kernel::get-lisp-obj-address value))))
(values))
;;; testing
(defparameter *test1* 'global-value) ;; will become local
(defun get-symbol-global-value (symbol)
;; below progv forces to use global symbol value
(progv (list symbol) (list (sb-kernel:make-lisp-obj
sb-vm::no-tls-value-marker-widetag))
(symbol-value symbol)))
(defun set-symbol-global-value (symbol value)
;; below progv forces to set global symbol value
(progv (list symbol) (list (sb-kernel:make-lisp-obj
sb-vm::no-tls-value-marker-widetag))
(setf (symbol-value symbol) value)))
(assert (eq (get-symbol-global-value '*test1*) 'global-value))
(defun thread-fun ()
(loop
(cond ((eq *test1* 'global-value) nil)
((eq *test1* 'local-value)
(setq *test1* 'baz) (return nil))
(t (error "Invalid value ~S" *test1*)))))
(defun test-1 ()
(set-symbol-global-value '*test1* 'global-value)
; number of threads to start
(dotimes (i 4) (sb-thread::make-thread #'thread-fun))
(make-symbol-thread-local '*test1* 'local-value)
;; now change global value
(set-symbol-global-value '*test1* 'blah)
(assert (eq (get-symbol-global-value '*test1*) 'blah))
;; this changes this local thread value
(setq *test1* 'foobar)
(assert (eq (symbol-value '*test1*) 'foobar))
)
Sure.
> Below code is a method of injecting a thread-local value into threads
> that are already running, tt handles 2 cases :
>
> a) (defun my-thread () (print *var*) (setq *var*
> 'local-to-this-thread))
>
> In the above case if the (make-symbol-thread-local) was executed
> before thread entered print form, it would get a default per/thread
> value. The setq would set a per-thread value
A separate sunshine scenario. And we saw that it is good.
> b) (defun my-thread () (let ((*var* 'local-value-a)) (print *var*))
> (print *var) (setq *var* 'local-to-this-tread))
>
> In the above case when thread already have a special bound, and
> (make-symbol-thread-local...) is executed somewhere else while
> thread is inside of the (let) form, then once thread exits the
> (let) form then new thread-local value of *var* would be restored
> instead of the old global value
... as if the global value had been changed. I wanted to argue that this
behaviour breaks user expectations, but it is only detectable if one
knows that no other code can set the global value which is not very
different from knowing that no other code can declare the special
thread local. I mean, it's fine. Perhaps warning if the special has a
global binding would be just what the world needs.
Random observation: the only way to make the object used as the default
value eligible for garbage collection is to redeclare the thread local
var with a different default value. That also makes sense.
> (I tested it with as much as 16 threads on 4 way opteron, so IMHO
> its pretty safe).
I see a few issues.
One is that there is no way to make a thread local special go back to
normal. Not that I can unspecial a special. So don't worry about this.
Number two is there should be a without-interrupts right inside
without-gcing because an async interrupt hitting in gc_stop_the_world
unwinding the stack would be most unconvenient. The rest I haven't
noticed :-).
Ah, the third thing: is it possible to declare a special thread local
that is (in each thread) subsequently "bound and then made to have no
value" similar to a progv having less values than symbols?
To reiterate what I said in my previous mail about this patch not doing
exactly what allegro's *cl-def-s-b* mechanism does: it only supports
setting the thread local default to the _same_ object while allegro
evals an expression in each thread and uses the resulting object in
much the same way. AFAIK sbcl internals do not need this, but
gravitating back to the canonical db connection example I can see that
some user code probably does. I'm happy enough to know that threads
cannot share bindings of thread local vars and by providing NIL as the
default value (or thread local unbound as in number three) I get
exactly that. However, that's some way off the convenience of being
able to use the database from any thread: one must do the (unless
*db-connection* (setq *db-connection* (db-connect))) dance himself.
That may be acceptable. (???)
Cheers, Gabor
> Yes, this issue has come up many times in the past both internally in
> sbcl code and in user code/libraries. As Max and innocent #lisp
> bystanders are already aware that - for what it's worth - I'm not
> entirely convinced of the correctness of this solution.
>
> Here is a scenario in which this approach fails to protect against
> threads sharing a binding. A library has a special that it declares
> thread local. Threads started after the library is loaded will
> correctly have thread local bindings for the special. But a thread that
> was started before the library was loaded will see the global binding
> of the special. If such a thread calls into the lib or accesses the
> value of the special in another way lossage is imminent. How can such a
> thread depend on that special? Lots of ways: defining an around method
> on a method which called, calling callbacks, using symbol-value and
> find-symbol. Any kind of dependency injection has a chance to fall
> flat.
I see your point, but I don't think I agree.
Any sort of post-initializion injection of thread-local bindings seems to
me to actually create more interactions between threads, not less, and
hence more grounds for subtle bugs. In comparison, the bugs related to
*default-special-bindings* and already running threads seem relatively
simple "load first, run then" issues.
Rather handwavy, I know. :/
I would also argue, that if a variable is already declared (locally or
globally) special, then any threaded code that manipulates it is
liable to already assume that the binding is either thread-local or shared,
and toggling this from the outside seems rather rude and error-prone.
In the cases where the variable is not special, but úsed via SYMBOL-VALUE
and friends, then I believe in most cases the intention is to explicitly
manipulate the global but unknown at compile-time variable -- not a local
binding.
In cases where the variable is not special when the thread starts and
LOAD/EVAL is called after it has been made special/local, it seems to
me that the dependency order is broken.
I'm not sure if any of this makes sense, but this seems to be the
closest I can come to explaining my unease:
Exhibit 1
(make-thread (lambda () (loop (setf *foo* (eval (foo))))))
If *FOO* is made local while the loop is running, then it
drastically alters the dynamic behaviour.
Exhibit 2
(make-thread (lambda () (loop (setf (symbol-value (foo)) (bar)))))
Ditto, only more so.
Exhibit 3
(make-thread (lambda () (sleep 10) (load something-that-uses-*foo*)))
If the loaded code defines *FOO*, then we have a conflict in any case.
If the loaded code doesn't define *FOO*, then we have a clear dependency.
> 1) check if there is only one thread at the time of
> define-thread-local-*
>
> Bleh. I'd hate not being able to load a library because multiple threads
> are running.
Agreed.
> 2) thread local specials must have no global binding
>
> Makes sense to me. How to implement it is another question.
I'm not sure about this. This make thread local specials strongly
distinct from normal special variables.
> This patch deviates from allegro's *cl-default-special-bindings* in an
> important way: in acl the value of that special is an "alist
> associating special variable symbols with forms to evaluate for binding
> values" which makes to possible to have (*readtable* . (copy-readtable
> nil)) copy the current readtable into the child thread or (*db* .
> (open-db-connection)) to give each thread its own db connection which I
> think is impossible to do here. Truth to tell I dislike even the
> allegro way, because it needs to do several little evals at the start
> of each thread even if those bindings are never used.
One possibility is to keep initialization _functions_, not values or
forms in the *default-special-bindings* alist. More flexible then
just values, and fast compared to EVAL.
(No, I'm not dead set against the injection idea, but I am rather skeptical
of its benefits.)
Cheers,
-- Nikodemus Schemer: "Buddha is small, clean, and serious."
Lispnik: "Buddha is big, has hairy armpits, and laughs."
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
Such a simple thing. But when it leads to thread safety issues it can
become quite tricksome.
> Rather handwavy, I know. :/
>
> I would also argue, that if a variable is already declared (locally
> or globally) special, then any threaded code that manipulates it is
> liable to already assume that the binding is either thread-local or
> shared, and toggling this from the outside seems rather rude and
> error-prone.
What's toggled is the "sharedness" of the global binding, obviously the
thread-local bindings are left alone. How can a thread be confused by
having a special declared thread-local? From the point of view of that
thread that is no different from another thread setting the global
binding. This is more or less the same as what I wrote to Max in my
second mail (see "... as if the global value ..."). This argument holds
no water if there are dependencies between threads that are broken by
thread-localizing the variable. However, I argue that if that is the
case then there is a basic contradiction at the level of intentions:
one can either make it always thread-local or not.
> In the cases where the variable is not special, but úsed via
> SYMBOL-VALUE and friends, then I believe in most cases the intention
> is to explicitly manipulate the global but unknown at compile-time
> variable -- not a local binding.
Already at this point I'm losing it. I resort to question flooding for
the rest of the mail.
> In cases where the variable is not special when the thread starts and
> LOAD/EVAL is called after it has been made special/local, it seems to
> me that the dependency order is broken.
Care to expand on what dependency order you mean here?
> I'm not sure if any of this makes sense, but this seems to be the
> closest I can come to explaining my unease:
>
> Exhibit 1
>
> (make-thread (lambda () (loop (setf *foo* (eval (foo))))))
>
> If *FOO* is made local while the loop is running, then it
> drastically alters the dynamic behaviour.
Exactly how is the dynamic behaviour altered? Is it detectable by the
thread? By other threads? What does (FOO) do? Something that uses the
value of *FOO*?
> Exhibit 2
>
> (make-thread (lambda () (loop (setf (symbol-value (foo)) (bar)))))
>
> Ditto, only more so.
>
> Exhibit 3
>
> (make-thread (lambda () (sleep 10) (load
> something-that-uses-*foo*)))
>
> If the loaded code defines *FOO*, then we have a conflict in any
> case. If the loaded code doesn't define *FOO*, then we have a clear
> dependency.
Maybe if I had understood the first one then I'd stand a chance here.
> > 2) thread local specials must have no global binding
> >
> > Makes sense to me. How to implement it is another question.
>
> I'm not sure about this. This make thread local specials strongly
> distinct from normal special variables.
Well, if you want distinct bindings for each thread then there is no
global binding to speak of, or in other words different threads have
different "global" bindings. This distinction is the crux of the matter
and I can see no way around it, save making thread-local vars even more
different from specials.
> > This patch deviates from allegro's *cl-default-special-bindings* in
> > an important way: in acl the value of that special is an "alist
> > associating special variable symbols with forms to evaluate for
> > binding values" which makes to possible to have (*readtable* .
> > (copy-readtable nil)) copy the current readtable into the child
> > thread or (*db* . (open-db-connection)) to give each thread its own
> > db connection which I think is impossible to do here. Truth to tell
> > I dislike even the allegro way, because it needs to do several
> > little evals at the start of each thread even if those bindings are
> > never used.
>
> One possibility is to keep initialization _functions_, not values or
> forms in the *default-special-bindings* alist. More flexible then
> just values, and fast compared to EVAL.
Good idea. That makes me think that maybe allegro doesn't really eval
them one by one but forms a single LET expression with a funcall in its
body. That could even be compiled. But that would probably need some
kind of protocol for modifying *d-s-b*.
> (No, I'm not dead set against the injection idea, but I am rather
> skeptical of its benefits.)
>
> Cheers,
Gabor
> Such a simple thing. But when it leads to thread safety issues it can
> become quite tricksome.
Quite. ;-)
I was writing an example about how your way was bad, when I finally
saw the light. You are rigth and I was wrong.
The example that made me see it:
Thread T is a worker thread, executing arbitrary code injected to the
system from a trusted source. When T starts, package FOO has not been
loaded yet. FOO:*BAR* is a thread-local special -- or at least should
be. After FOO has been loaded, T will execute code that frobs
FOO:*BAR* with impunity.
I believe this models your canonical case?
If MAKE-SYMBOL-THREAD-LOCAL make FOO:*BAR* local in already running T,
then all is fine and dandy, I guess. I'm happy with your model in
this case.
If MAKE-SYMBOL-THREAD-LOCAL works via just *DEFAULT-BINDINGS* or
similar, then code like this simply cannot work. This may or may not
be a show-stopper, I don't know. What happens if someone unwittingly
tries to make it work? If there are there are multiple worker threads
running when FOO is loaded, then they will mess each other up. Nasty.
I think your earlier position about global bindings was on the right
track, though:
Code used in running threads assumes *FOO* is either thread-local or
global (the example works the same either way), and frobs it with
impunity.
In reality, *FOO* is indeed supposed to be just so (or just the
opposite, the example still works!), but due to the way threads have
been started interleaved with the loading of the code, T has been
started at a point when *FOO* was special, but not yet thread-local.
In this case the code (build-system, whatever) is obviously buggy, and
some lossage is going to happen no matter what we do:
If executing MAKE-SYMBOL-THREAD-LOCAL or equivalent causes *FOO* to
get its own binding in T, then the system is going to behave one way
(correct or wrong) till that point, and just the opposite from then
on.
This sounds like a horribly nasty to track down, especially if *FOO*
is supposed to be local -- something corrupts the system, but when
you inspect the it *FOO* is local in each thread!
I would say that to keep things sane you should not be allowed to
proclaim a variable thread-local if it is already special.
Cheers, (feeling slightly like a weathervane)
Yes, this is what I tried to articulate.
> If MAKE-SYMBOL-THREAD-LOCAL make FOO:*BAR* local in already running
> T, then all is fine and dandy, I guess. I'm happy with your model in
> this case.
>
> If MAKE-SYMBOL-THREAD-LOCAL works via just *DEFAULT-BINDINGS* or
> similar, then code like this simply cannot work. This may or may not
> be a show-stopper, I don't know. What happens if someone unwittingly
> tries to make it work? If there are there are multiple worker
> threads running when FOO is loaded, then they will mess each other
> up. Nasty.
I don't quite get what you say here. Is it that without giving already
running threads separate bindings the example above cannot work?
> I think your earlier position about global bindings was on the right
> track, though:
>
> Code used in running threads assumes *FOO* is either thread-local or
> global (the example works the same either way), and frobs it with
> impunity.
>
> In reality, *FOO* is indeed supposed to be just so (or just the
> opposite, the example still works!), but due to the way threads have
> been started interleaved with the loading of the code, T has been
> started at a point when *FOO* was special, but not yet thread-local.
>
> In this case the code (build-system, whatever) is obviously buggy,
> and some lossage is going to happen no matter what we do:
>
> If executing MAKE-SYMBOL-THREAD-LOCAL or equivalent causes *FOO* to
> get its own binding in T, then the system is going to behave one way
> (correct or wrong) till that point, and just the opposite from then
> on.
This kind of lossage seemed to me to follow from the general
transactionlessness of lisp. There are all kinds of problems with half
loaded code having logical dependency on the yet unloaded part.
/me waves generously in the general direction of the audience
> This sounds like a horribly nasty to track down, especially if *FOO*
> is supposed to be local -- something corrupts the system, but when
> you inspect the it *FOO* is local in each thread!
>
> I would say that to keep things sane you should not be allowed to
> proclaim a variable thread-local if it is already special.
I suggested to Max emitting a warning if there is global binding for the
special at the time of its thread-localization. That was a somewhat
half baked attempt at mimimizing surprises. This is probably better.
>> If MAKE-SYMBOL-THREAD-LOCAL works via just *DEFAULT-BINDINGS* or
>> similar, then code like this simply cannot work. This may or may not
>> be a show-stopper, I don't know. What happens if someone unwittingly
>> tries to make it work? If there are there are multiple worker
>> threads running when FOO is loaded, then they will mess each other
>> up. Nasty.
>
> I don't quite get what you say here. Is it that without giving already
> running threads separate bindings the example above cannot work?
Yes. That was I was trying to say.
>> If executing MAKE-SYMBOL-THREAD-LOCAL or equivalent causes *FOO* to
>> get its own binding in T, then the system is going to behave one way
>> (correct or wrong) till that point, and just the opposite from then
>> on.
>
> This kind of lossage seemed to me to follow from the general
> transactionlessness of lisp. There are all kinds of problems with half
> loaded code having logical dependency on the yet unloaded part.
Right.
There is also the conceptual problem of a variable being first one
kind, then another. Just as a lexical variable cannot suddenly turn
into a special one, I don't think a regular special should turn into a
thread-local one.
Cheers,
Another variation is attached based on Max's code from this thread. The
patch introduces *thread-local-symbols* that is a weak keyed hash table
mapping symbols to initialization functions. It serves the about the
same purpose as *default-special-bindings*. Users don't modify its
value directly, instead they use (define-thread-local-var symbol
initform).
Three primitive functions of questionable usefulness are also added:
set-thread-local-default-binding, remove-thread-local-default-binding
and thread-local-p. They allow finer grained control over which threads
see the global binding. Maybe someone has a use-case for them, maybe
not.
What's missing is an implementation for inserting thread local default
bindings into other threads. The sketch commented out in
define-thread-local-var shows one way of how it could be done and what
problems it would face. Another possibility is Max's stop-the-world
approach but that unfortunately shares the main problem namely that we
cannot safely insert the default binding if the other thread is in the
middle of BIND or UNBIND. More thought is probably needed on this.
Gábor
------------------------------------------------------------------------------