From: Max M. <ma...@op...> - 2006-07-28 19:13:07
|
Here is a proposed patch for review. I verified that it compiles and passes the tests both multi-threaded and unithreaded on amd64. 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 ============================================================ |
From: Max M. <ma...@op...> - 2006-07-29 10:46:56
|
Had some screw up with wonderlust where it put a bunch of base64 encoded stuff in the middle, here its cleaned up. ===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 Sbc...@li... https://lists.sourceforge.net/lists/listinfo/sbcl-devel |
From: <me...@ho...> - 2006-07-29 11:29:24
|
On Friday 28 July 2006 16:10, Max Mikhanosha wrote: > Here is a proposed patch for review. I verified that it compiles and > passes the tests both multi-threaded and unithreaded on amd64. > > 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* > [...] > > Regards, > Max 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 |
From: Max M. <ma...@op...> - 2006-08-02 00:29:57
|
At Sat, 29 Jul 2006 13:26:35 +0200, G=E1bor Melis wrote: >=20 > Here is a scenario in which this approach fails to protect against=20 > threads sharing a binding. A library has a special that it declares=20 > thread local. Threads started after the library is loaded will=20 > correctly have thread local bindings for the special. But a thread that=20 > was started before the library was loaded will see the global binding=20 > of the special. If such a thread calls into the lib or accesses the=20 > value of the special in another way lossage is imminent. How can such a=20 > thread depend on that special? Lots of ways: defining an around method=20 > on a method which called, calling callbacks, using symbol-value and=20 > find-symbol. Any kind of dependency injection has a chance to fall=20 > flat. >=20 > 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=20 > define-thread-local-*. That constraint is trivially satisfied by sbcl=20 > internals but makes it dangerously overpromising for user code. >=20 > How to make it safe for user code? >=20 > 1) check if there is only one thread at the time of=20 > define-thread-local-* >=20 > Bleh. I'd hate not being able to load a library because multiple threads = > are running. >=20 > or >=20 > 2) thread local specials must have no global binding >=20 > 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).=20 ;;; 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=20 (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 =3D (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=3D thread-sap (sb-vm::int-sap 0))) do (fix-symbol-value-in-one-thread thread-sap symbol tls-index value)) (values)) =20 (defun fix-symbol-value-in-one-thread (thread-sap symbol tls-index value) (declare (type system-area-pointer thread-sap)=20 (type symbol symbol)=20 (type fixnum tls-index)) (let ((was-bound-p nil)) (loop=20 ;; search the binding stack for the first binding of symbol with end =3D (sb-vm::sap-ref-sap thread-sap (* sb-vm::n-word-bytes sb-vm::thread-binding-stack-pointer-slot)) as bsp =3D (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 =3D (sb-vm::make-lisp-obj (sb-vm::sap-ref-word bsp= 0)) as binding-symbol =3D (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)=20 (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=20 ;; 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-inde= x)) (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=20 (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)) ) =20 |
From: <me...@ho...> - 2006-08-02 21:04:59
|
On Wednesday 02 August 2006 02:29, Max Mikhanosha wrote: > At Sat, 29 Jul 2006 13:26:35 +0200, G=E1bor Melis wrote: > > 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? 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 =2E.. as if the global value had been changed. I wanted to argue that this= =20 behaviour breaks user expectations, but it is only detectable if one=20 knows that no other code can set the global value which is not very=20 different from knowing that no other code can declare the special=20 thread local. I mean, it's fine. Perhaps warning if the special has a=20 global binding would be just what the world needs. Random observation: the only way to make the object used as the default=20 value eligible for garbage collection is to redeclare the thread local=20 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=20 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=20 without-gcing because an async interrupt hitting in gc_stop_the_world=20 unwinding the stack would be most unconvenient. The rest I haven't=20 noticed :-). Ah, the third thing: is it possible to declare a special thread local=20 that is (in each thread) subsequently "bound and then made to have no=20 value" similar to a progv having less values than symbols? To reiterate what I said in my previous mail about this patch not doing=20 exactly what allegro's *cl-def-s-b* mechanism does: it only supports=20 setting the thread local default to the _same_ object while allegro=20 evals an expression in each thread and uses the resulting object in=20 much the same way. AFAIK sbcl internals do not need this, but=20 gravitating back to the canonical db connection example I can see that=20 some user code probably does. I'm happy enough to know that threads=20 cannot share bindings of thread local vars and by providing NIL as the=20 default value (or thread local unbound as in number three) I get=20 exactly that. However, that's some way off the convenience of being=20 able to use the database from any thread: one must do the (unless=20 *db-connection* (setq *db-connection* (db-connect))) dance himself.=20 That may be acceptable. (???) Cheers, Gabor |
From: Nikodemus S. <nik...@ra...> - 2006-08-08 16:46:28
|
Gábor Melis <me...@ho...> writes: > 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." |
From: <me...@ho...> - 2006-08-08 21:31:08
|
On Tuesday 08 August 2006 18:45, Nikodemus Siivola wrote: > G=C3=A1bor Melis <me...@ho...> writes: > > 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=20 > related to *default-special-bindings* and already running threads > seem relatively simple "load first, run then" issues. Such a simple thing. But when it leads to thread safety issues it can=20 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=20 thread-local bindings are left alone. How can a thread be confused by=20 having a special declared thread-local? From the point of view of that=20 thread that is no different from another thread setting the global=20 binding. This is more or less the same as what I wrote to Max in my=20 second mail (see "... as if the global value ..."). This argument holds=20 no water if there are dependencies between threads that are broken by=20 thread-localizing the variable. However, I argue that if that is the=20 case then there is a basic contradiction at the level of intentions:=20 one can either make it always thread-local or not. > In the cases where the variable is not special, but =C3=BAsed 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=20 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=20 thread? By other threads? What does (FOO) do? Something that uses the=20 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=20 global binding to speak of, or in other words different threads have=20 different "global" bindings. This distinction is the crux of the matter=20 and I can see no way around it, save making thread-local vars even more=20 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=20 them one by one but forms a single LET expression with a funcall in its=20 body. That could even be compiled. But that would probably need some=20 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 > > -- Nikodemus Schemer: "Buddha is small, clean, and > serious." Lispnik: "Buddha is big, has hairy armpits, and laughs." |
From: Nikodemus S. <nik...@ra...> - 2006-08-09 09:11:35
|
Gábor Melis <me...@ho...> writes: > 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) -- Nikodemus Schemer: "Buddha is small, clean, and serious." Lispnik: "Buddha is big, has hairy armpits, and laughs." |
From: <me...@ho...> - 2006-08-09 11:49:24
|
On Wednesday 09 August 2006 11:11, Nikodemus Siivola wrote: > 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? 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. > Cheers, (feeling slightly like a weathervane) > > -- Nikodemus Schemer: "Buddha is small, clean, and > serious." Lispnik: "Buddha is big, has hairy armpits, and laughs." |
From: Nikodemus S. <nik...@ra...> - 2006-08-09 15:20:08
|
Gábor Melis <me...@ho...> writes: >> 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, -- Nikodemus Schemer: "Buddha is small, clean, and serious." Lispnik: "Buddha is big, has hairy armpits, and laughs." |
From: <me...@re...> - 2007-03-25 19:19:28
Attachments:
thread-local.patch
|
On Friday 28 July 2006 16:10, Max Mikhanosha wrote: > Here is a proposed patch for review. I verified that it compiles and > passes the tests both multi-threaded and unithreaded on amd64. > > 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 Another variation is attached based on Max's code from this thread. The=20 patch introduces *thread-local-symbols* that is a weak keyed hash table=20 mapping symbols to initialization functions. It serves the about the=20 same purpose as *default-special-bindings*. Users don't modify its=20 value directly, instead they use (define-thread-local-var symbol=20 initform). Three primitive functions of questionable usefulness are also added:=20 set-thread-local-default-binding, remove-thread-local-default-binding=20 and thread-local-p. They allow finer grained control over which threads=20 see the global binding. Maybe someone has a use-case for them, maybe=20 not. What's missing is an implementation for inserting thread local default=20 bindings into other threads. The sketch commented out in=20 define-thread-local-var shows one way of how it could be done and what=20 problems it would face. Another possibility is Max's stop-the-world=20 approach but that unfortunately shares the main problem namely that we=20 cannot safely insert the default binding if the other thread is in the=20 middle of BIND or UNBIND. More thought is probably needed on this. G=E1bor |
From: Gabor M. <me...@re...> - 2008-12-21 22:20:11
|
FYI, this lives on as: https://bugs.launchpad.net/sbcl/+bug/310204/ |