OLD | NEW |
1 | 1 |
2 /* Thread module */ | 2 /* Thread module */ |
3 /* Interface to Sjoerd's portable C thread library */ | 3 /* Interface to Sjoerd's portable C thread library */ |
4 | 4 |
5 #include "Python.h" | 5 #include "Python.h" |
6 #include "structmember.h" /* offsetof */ | 6 #include "structmember.h" /* offsetof */ |
7 | 7 |
8 #ifndef WITH_THREAD | 8 #ifndef WITH_THREAD |
9 #error "Error! The rest of Python is not compiled with thread support." | 9 #error "Error! The rest of Python is not compiled with thread support." |
10 #error "Rerun configure, adding a --with-threads option." | 10 #error "Rerun configure, adding a --with-threads option." |
11 #error "Then run `make clean' followed by `make'." | 11 #error "Then run `make clean' followed by `make'." |
12 #endif | 12 #endif |
13 | 13 |
14 #include "pythread.h" | 14 #include "pythread.h" |
15 | 15 |
16 static PyObject *ThreadError; | 16 static PyObject *ThreadError; |
17 static long nb_threads = 0; | 17 static long nb_threads = 0; |
| 18 static PyObject *str_dict; |
18 | 19 |
19 /* Lock objects */ | 20 /* Lock objects */ |
20 | 21 |
21 typedef struct { | 22 typedef struct { |
22 PyObject_HEAD | 23 PyObject_HEAD |
23 PyThread_type_lock lock_lock; | 24 PyThread_type_lock lock_lock; |
24 PyObject *in_weakreflist; | 25 PyObject *in_weakreflist; |
25 } lockobject; | 26 } lockobject; |
26 | 27 |
27 static void | 28 static void |
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 /* tp_richcompare */ 0, | 580 /* tp_richcompare */ 0, |
580 /* tp_weaklistoffset */ offsetof(localdummyobject, weakreflist) | 581 /* tp_weaklistoffset */ offsetof(localdummyobject, weakreflist) |
581 }; | 582 }; |
582 | 583 |
583 | 584 |
584 typedef struct { | 585 typedef struct { |
585 PyObject_HEAD | 586 PyObject_HEAD |
586 PyObject *key; | 587 PyObject *key; |
587 PyObject *args; | 588 PyObject *args; |
588 PyObject *kw; | 589 PyObject *kw; |
589 /* The current thread's local dict (necessary for tp_dictoffset) */ | |
590 PyObject *dict; | |
591 PyObject *weakreflist; /* List of weak references to self */ | 590 PyObject *weakreflist; /* List of weak references to self */ |
592 /* A {localdummy weakref -> localdict} dict */ | 591 /* A {localdummy weakref -> localdict} dict */ |
593 PyObject *dummies; | 592 PyObject *dummies; |
594 /* The callback for weakrefs to localdummies */ | 593 /* The callback for weakrefs to localdummies */ |
595 PyObject *wr_callback; | 594 PyObject *wr_callback; |
596 } localobject; | 595 } localobject; |
597 | 596 |
598 /* Forward declaration */ | 597 /* Forward declaration */ |
599 static PyObject *_ldict(localobject *self); | 598 static PyObject *_ldict(localobject *self); |
600 static PyObject *_localdummy_destroyed(PyObject *meth_self, PyObject *dummyweakr
ef); | 599 static PyObject *_localdummy_destroyed(PyObject *meth_self, PyObject *dummyweakr
ef); |
601 | 600 |
602 /* Create and register the dummy for the current thread, as well as the | 601 /* Create and register the dummy for the current thread. |
603 corresponding local dict */ | 602 Returns a borrowed reference of the corresponding local dict */ |
604 static int | 603 static PyObject * |
605 _local_create_dummy(localobject *self) | 604 _local_create_dummy(localobject *self) |
606 { | 605 { |
607 PyObject *tdict, *ldict = NULL, *wr = NULL; | 606 PyObject *tdict, *ldict = NULL, *wr = NULL; |
608 localdummyobject *dummy = NULL; | 607 localdummyobject *dummy = NULL; |
609 int r; | 608 int r; |
610 | 609 |
611 tdict = PyThreadState_GetDict(); | 610 tdict = PyThreadState_GetDict(); |
612 if (tdict == NULL) { | 611 if (tdict == NULL) { |
613 PyErr_SetString(PyExc_SystemError, | 612 PyErr_SetString(PyExc_SystemError, |
614 "Couldn't get thread-state dictionary"); | 613 "Couldn't get thread-state dictionary"); |
(...skipping 15 matching lines...) Expand all Loading... |
630 dummy gets deleted */ | 629 dummy gets deleted */ |
631 r = PyDict_SetItem(self->dummies, wr, ldict); | 630 r = PyDict_SetItem(self->dummies, wr, ldict); |
632 if (r < 0) | 631 if (r < 0) |
633 goto err; | 632 goto err; |
634 Py_CLEAR(wr); | 633 Py_CLEAR(wr); |
635 r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy); | 634 r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy); |
636 if (r < 0) | 635 if (r < 0) |
637 goto err; | 636 goto err; |
638 Py_CLEAR(dummy); | 637 Py_CLEAR(dummy); |
639 | 638 |
640 Py_CLEAR(self->dict); | 639 Py_DECREF(ldict); |
641 self->dict = ldict; | 640 return ldict; |
642 return 0; | |
643 | 641 |
644 err: | 642 err: |
645 Py_XDECREF(ldict); | 643 Py_XDECREF(ldict); |
646 Py_XDECREF(wr); | 644 Py_XDECREF(wr); |
647 Py_XDECREF(dummy); | 645 Py_XDECREF(dummy); |
648 return -1; | 646 return NULL; |
649 } | 647 } |
650 | 648 |
651 static PyObject * | 649 static PyObject * |
652 local_new(PyTypeObject *type, PyObject *args, PyObject *kw) | 650 local_new(PyTypeObject *type, PyObject *args, PyObject *kw) |
653 { | 651 { |
654 localobject *self; | 652 localobject *self; |
655 PyObject *wr; | 653 PyObject *wr; |
656 static PyMethodDef wr_callback_def = { | 654 static PyMethodDef wr_callback_def = { |
657 "_localdummy_destroyed", (PyCFunction) _localdummy_destroyed, METH_O | 655 "_localdummy_destroyed", (PyCFunction) _localdummy_destroyed, METH_O |
658 }; | 656 }; |
(...skipping 25 matching lines...) Expand all Loading... |
684 /* We use a weak reference to self in the callback closure | 682 /* We use a weak reference to self in the callback closure |
685 in order to avoid spurious reference cycles */ | 683 in order to avoid spurious reference cycles */ |
686 wr = PyWeakref_NewRef((PyObject *) self, NULL); | 684 wr = PyWeakref_NewRef((PyObject *) self, NULL); |
687 if (wr == NULL) | 685 if (wr == NULL) |
688 goto err; | 686 goto err; |
689 self->wr_callback = PyCFunction_New(&wr_callback_def, wr); | 687 self->wr_callback = PyCFunction_New(&wr_callback_def, wr); |
690 Py_DECREF(wr); | 688 Py_DECREF(wr); |
691 if (self->wr_callback == NULL) | 689 if (self->wr_callback == NULL) |
692 goto err; | 690 goto err; |
693 | 691 |
694 if (_local_create_dummy(self) < 0) | 692 if (_local_create_dummy(self) == NULL) |
695 goto err; | 693 goto err; |
696 | 694 |
697 return (PyObject *)self; | 695 return (PyObject *)self; |
698 | 696 |
699 err: | 697 err: |
700 Py_DECREF(self); | 698 Py_DECREF(self); |
701 return NULL; | 699 return NULL; |
702 } | 700 } |
703 | 701 |
704 static int | 702 static int |
705 local_traverse(localobject *self, visitproc visit, void *arg) | 703 local_traverse(localobject *self, visitproc visit, void *arg) |
706 { | 704 { |
707 Py_VISIT(self->args); | 705 Py_VISIT(self->args); |
708 Py_VISIT(self->kw); | 706 Py_VISIT(self->kw); |
709 Py_VISIT(self->dummies); | 707 Py_VISIT(self->dummies); |
710 Py_VISIT(self->dict); | |
711 return 0; | 708 return 0; |
712 } | 709 } |
713 | 710 |
714 static int | 711 static int |
715 local_clear(localobject *self) | 712 local_clear(localobject *self) |
716 { | 713 { |
717 PyThreadState *tstate; | 714 PyThreadState *tstate; |
718 Py_CLEAR(self->args); | 715 Py_CLEAR(self->args); |
719 Py_CLEAR(self->kw); | 716 Py_CLEAR(self->kw); |
720 Py_CLEAR(self->dummies); | 717 Py_CLEAR(self->dummies); |
721 Py_CLEAR(self->dict); | |
722 Py_CLEAR(self->wr_callback); | 718 Py_CLEAR(self->wr_callback); |
723 /* Remove all strong references to dummies from the thread states */ | 719 /* Remove all strong references to dummies from the thread states */ |
724 if (self->key | 720 if (self->key |
725 && (tstate = PyThreadState_Get()) | 721 && (tstate = PyThreadState_Get()) |
726 && tstate->interp) { | 722 && tstate->interp) { |
727 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); | 723 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); |
728 tstate; | 724 tstate; |
729 tstate = PyThreadState_Next(tstate)) | 725 tstate = PyThreadState_Next(tstate)) |
730 if (tstate->dict && | 726 if (tstate->dict && |
731 PyDict_GetItem(tstate->dict, self->key)) | 727 PyDict_GetItem(tstate->dict, self->key)) |
(...skipping 25 matching lines...) Expand all Loading... |
757 | 753 |
758 tdict = PyThreadState_GetDict(); | 754 tdict = PyThreadState_GetDict(); |
759 if (tdict == NULL) { | 755 if (tdict == NULL) { |
760 PyErr_SetString(PyExc_SystemError, | 756 PyErr_SetString(PyExc_SystemError, |
761 "Couldn't get thread-state dictionary"); | 757 "Couldn't get thread-state dictionary"); |
762 return NULL; | 758 return NULL; |
763 } | 759 } |
764 | 760 |
765 dummy = PyDict_GetItem(tdict, self->key); | 761 dummy = PyDict_GetItem(tdict, self->key); |
766 if (dummy == NULL) { | 762 if (dummy == NULL) { |
767 if (_local_create_dummy(self) < 0) | 763 ldict = _local_create_dummy(self); |
| 764 if (ldict == NULL) |
768 return NULL; | 765 return NULL; |
769 ldict = self->dict; | |
770 | 766 |
771 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && | 767 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && |
772 Py_TYPE(self)->tp_init((PyObject*)self, | 768 Py_TYPE(self)->tp_init((PyObject*)self, |
773 self->args, self->kw) < 0) { | 769 self->args, self->kw) < 0) { |
774 /* we need to get rid of ldict from thread so | 770 /* we need to get rid of ldict from thread so |
775 we create a new one the next time we do an attr | 771 we create a new one the next time we do an attr |
776 acces */ | 772 acces */ |
777 PyDict_DelItem(tdict, self->key); | 773 PyDict_DelItem(tdict, self->key); |
778 return NULL; | 774 return NULL; |
779 } | 775 } |
780 } | 776 } |
781 else { | 777 else { |
782 assert(Py_TYPE(dummy) == &localdummytype); | 778 assert(Py_TYPE(dummy) == &localdummytype); |
783 ldict = ((localdummyobject *) dummy)->localdict; | 779 ldict = ((localdummyobject *) dummy)->localdict; |
784 } | 780 } |
785 | 781 |
786 /* The call to tp_init above may have caused another thread to run. | |
787 Install our ldict again. */ | |
788 if (self->dict != ldict) { | |
789 Py_INCREF(ldict); | |
790 Py_CLEAR(self->dict); | |
791 self->dict = ldict; | |
792 } | |
793 | |
794 return ldict; | 782 return ldict; |
795 } | 783 } |
796 | 784 |
797 static int | 785 static int |
798 local_setattro(localobject *self, PyObject *name, PyObject *v) | 786 local_setattro(localobject *self, PyObject *name, PyObject *v) |
799 { | 787 { |
800 PyObject *ldict; | 788 PyObject *ldict; |
| 789 int r; |
801 | 790 |
802 ldict = _ldict(self); | 791 ldict = _ldict(self); |
803 if (ldict == NULL) | 792 if (ldict == NULL) |
804 return -1; | 793 return -1; |
805 | 794 |
806 return PyObject_GenericSetAttr((PyObject *)self, name, v); | 795 r = PyObject_RichCompareBool(name, str_dict, Py_EQ); |
| 796 if (r == 1) { |
| 797 PyErr_Format(PyExc_AttributeError, |
| 798 "'%.50s' object attribute '%U' is read-only", |
| 799 Py_TYPE(self)->tp_name, name); |
| 800 return -1; |
| 801 } |
| 802 if (r == -1) |
| 803 return -1; |
| 804 |
| 805 return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict); |
807 } | 806 } |
808 | 807 |
809 static PyObject * | |
810 local_getdict(localobject *self, void *closure) | |
811 { | |
812 PyObject *ldict; | |
813 ldict = _ldict(self); | |
814 Py_XINCREF(ldict); | |
815 return ldict; | |
816 } | |
817 | |
818 static PyGetSetDef local_getset[] = { | |
819 {"__dict__", (getter)local_getdict, (setter)NULL, | |
820 "Local-data dictionary", NULL}, | |
821 {NULL} /* Sentinel */ | |
822 }; | |
823 | |
824 static PyObject *local_getattro(localobject *, PyObject *); | 808 static PyObject *local_getattro(localobject *, PyObject *); |
825 | 809 |
826 static PyTypeObject localtype = { | 810 static PyTypeObject localtype = { |
827 PyVarObject_HEAD_INIT(NULL, 0) | 811 PyVarObject_HEAD_INIT(NULL, 0) |
828 /* tp_name */ "_thread._local", | 812 /* tp_name */ "_thread._local", |
829 /* tp_basicsize */ sizeof(localobject), | 813 /* tp_basicsize */ sizeof(localobject), |
830 /* tp_itemsize */ 0, | 814 /* tp_itemsize */ 0, |
831 /* tp_dealloc */ (destructor)local_dealloc, | 815 /* tp_dealloc */ (destructor)local_dealloc, |
832 /* tp_print */ 0, | 816 /* tp_print */ 0, |
833 /* tp_getattr */ 0, | 817 /* tp_getattr */ 0, |
(...skipping 13 matching lines...) Expand all Loading... |
847 | Py_TPFLAGS_HAVE_GC, | 831 | Py_TPFLAGS_HAVE_GC, |
848 /* tp_doc */ "Thread-local data", | 832 /* tp_doc */ "Thread-local data", |
849 /* tp_traverse */ (traverseproc)local_traverse, | 833 /* tp_traverse */ (traverseproc)local_traverse, |
850 /* tp_clear */ (inquiry)local_clear, | 834 /* tp_clear */ (inquiry)local_clear, |
851 /* tp_richcompare */ 0, | 835 /* tp_richcompare */ 0, |
852 /* tp_weaklistoffset */ offsetof(localobject, weakreflist), | 836 /* tp_weaklistoffset */ offsetof(localobject, weakreflist), |
853 /* tp_iter */ 0, | 837 /* tp_iter */ 0, |
854 /* tp_iternext */ 0, | 838 /* tp_iternext */ 0, |
855 /* tp_methods */ 0, | 839 /* tp_methods */ 0, |
856 /* tp_members */ 0, | 840 /* tp_members */ 0, |
857 /* tp_getset */ local_getset, | 841 /* tp_getset */ 0, |
858 /* tp_base */ 0, | 842 /* tp_base */ 0, |
859 /* tp_dict */ 0, /* internal use */ | 843 /* tp_dict */ 0, /* internal use */ |
860 /* tp_descr_get */ 0, | 844 /* tp_descr_get */ 0, |
861 /* tp_descr_set */ 0, | 845 /* tp_descr_set */ 0, |
862 /* tp_dictoffset */ offsetof(localobject, dict), | 846 /* tp_dictoffset */ 0, |
863 /* tp_init */ 0, | 847 /* tp_init */ 0, |
864 /* tp_alloc */ 0, | 848 /* tp_alloc */ 0, |
865 /* tp_new */ local_new, | 849 /* tp_new */ local_new, |
866 /* tp_free */ 0, /* Low-level free-mem routine */ | 850 /* tp_free */ 0, /* Low-level free-mem routine */ |
867 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ | 851 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ |
868 }; | 852 }; |
869 | 853 |
870 static PyObject * | 854 static PyObject * |
871 local_getattro(localobject *self, PyObject *name) | 855 local_getattro(localobject *self, PyObject *name) |
872 { | 856 { |
873 PyObject *ldict, *value; | 857 PyObject *ldict, *value; |
| 858 int r; |
874 | 859 |
875 ldict = _ldict(self); | 860 ldict = _ldict(self); |
876 if (ldict == NULL) | 861 if (ldict == NULL) |
877 return NULL; | 862 return NULL; |
878 | 863 |
| 864 r = PyObject_RichCompareBool(name, str_dict, Py_EQ); |
| 865 if (r == 1) { |
| 866 Py_INCREF(ldict); |
| 867 return ldict; |
| 868 } |
| 869 if (r == -1) |
| 870 return NULL; |
| 871 |
879 if (Py_TYPE(self) != &localtype) | 872 if (Py_TYPE(self) != &localtype) |
880 /* use generic lookup for subtypes */ | 873 /* use generic lookup for subtypes */ |
881 return PyObject_GenericGetAttr((PyObject *)self, name); | 874 return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict); |
882 | 875 |
883 /* Optimization: just look in dict ourselves */ | 876 /* Optimization: just look in dict ourselves */ |
884 value = PyDict_GetItem(ldict, name); | 877 value = PyDict_GetItem(ldict, name); |
885 if (value == NULL) | 878 if (value == NULL) |
886 /* Fall back on generic to get __class__ and __dict__ */ | 879 /* Fall back on generic to get __class__ and __dict__ */ |
887 return PyObject_GenericGetAttr((PyObject *)self, name); | 880 return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict); |
888 | 881 |
889 Py_INCREF(value); | 882 Py_INCREF(value); |
890 return value; | 883 return value; |
891 } | 884 } |
892 | 885 |
893 /* Called when a dummy is destroyed. */ | 886 /* Called when a dummy is destroyed. */ |
894 static PyObject * | 887 static PyObject * |
895 _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) | 888 _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) |
896 { | 889 { |
897 PyObject *obj; | 890 PyObject *obj; |
898 localobject *self; | 891 localobject *self; |
899 assert(PyWeakref_CheckRef(localweakref)); | 892 assert(PyWeakref_CheckRef(localweakref)); |
900 obj = PyWeakref_GET_OBJECT(localweakref); | 893 obj = PyWeakref_GET_OBJECT(localweakref); |
901 if (obj == Py_None) | 894 if (obj == Py_None) |
902 Py_RETURN_NONE; | 895 Py_RETURN_NONE; |
903 Py_INCREF(obj); | 896 Py_INCREF(obj); |
904 assert(PyObject_TypeCheck(obj, &localtype)); | 897 assert(PyObject_TypeCheck(obj, &localtype)); |
905 /* If the thread-local object is still alive and not being cleared, | 898 /* If the thread-local object is still alive and not being cleared, |
906 remove the corresponding local dict */ | 899 remove the corresponding local dict */ |
907 self = (localobject *) obj; | 900 self = (localobject *) obj; |
908 if (self->dummies != NULL) { | 901 if (self->dummies != NULL) { |
909 PyObject *ldict; | 902 PyObject *ldict; |
910 ldict = PyDict_GetItem(self->dummies, dummyweakref); | 903 ldict = PyDict_GetItem(self->dummies, dummyweakref); |
911 if (ldict != NULL) { | 904 if (ldict != NULL) { |
912 if (ldict == self->dict) | |
913 Py_CLEAR(self->dict); | |
914 PyDict_DelItem(self->dummies, dummyweakref); | 905 PyDict_DelItem(self->dummies, dummyweakref); |
915 } | 906 } |
916 if (PyErr_Occurred()) | 907 if (PyErr_Occurred()) |
917 PyErr_WriteUnraisable(obj); | 908 PyErr_WriteUnraisable(obj); |
918 } | 909 } |
919 Py_DECREF(obj); | 910 Py_DECREF(obj); |
920 Py_RETURN_NONE; | 911 Py_RETURN_NONE; |
921 } | 912 } |
922 | 913 |
923 /* Module functions */ | 914 /* Module functions */ |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1271 Py_INCREF(&RLocktype); | 1262 Py_INCREF(&RLocktype); |
1272 if (PyModule_AddObject(m, "RLock", (PyObject *)&RLocktype) < 0) | 1263 if (PyModule_AddObject(m, "RLock", (PyObject *)&RLocktype) < 0) |
1273 return NULL; | 1264 return NULL; |
1274 | 1265 |
1275 Py_INCREF(&localtype); | 1266 Py_INCREF(&localtype); |
1276 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) | 1267 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) |
1277 return NULL; | 1268 return NULL; |
1278 | 1269 |
1279 nb_threads = 0; | 1270 nb_threads = 0; |
1280 | 1271 |
| 1272 str_dict = PyUnicode_InternFromString("__dict__"); |
| 1273 if (str_dict == NULL) |
| 1274 return NULL; |
| 1275 |
1281 /* Initialize the C thread library */ | 1276 /* Initialize the C thread library */ |
1282 PyThread_init_thread(); | 1277 PyThread_init_thread(); |
1283 return m; | 1278 return m; |
1284 } | 1279 } |
OLD | NEW |