1515
1616static PyObject * ThreadError ;
1717static long nb_threads = 0 ;
18+ static PyObject * str_dict ;
1819
1920/* Lock objects */
2021
@@ -586,8 +587,6 @@ typedef struct {
586587 PyObject * key ;
587588 PyObject * args ;
588589 PyObject * kw ;
589- /* The current thread's local dict (necessary for tp_dictoffset) */
590- PyObject * dict ;
591590 PyObject * weakreflist ; /* List of weak references to self */
592591 /* A {localdummy weakref -> localdict} dict */
593592 PyObject * dummies ;
@@ -599,9 +598,9 @@ typedef struct {
599598static PyObject * _ldict (localobject * self );
600599static PyObject * _localdummy_destroyed (PyObject * meth_self , PyObject * dummyweakref );
601600
602- /* Create and register the dummy for the current thread, as well as the
603- corresponding local dict */
604- static int
601+ /* Create and register the dummy for the current thread.
602+ Returns a borrowed reference of the corresponding local dict */
603+ static PyObject *
605604_local_create_dummy (localobject * self )
606605{
607606 PyObject * tdict , * ldict = NULL , * wr = NULL ;
@@ -637,15 +636,14 @@ _local_create_dummy(localobject *self)
637636 goto err ;
638637 Py_CLEAR (dummy );
639638
640- Py_CLEAR (self -> dict );
641- self -> dict = ldict ;
642- return 0 ;
639+ Py_DECREF (ldict );
640+ return ldict ;
643641
644642err :
645643 Py_XDECREF (ldict );
646644 Py_XDECREF (wr );
647645 Py_XDECREF (dummy );
648- return -1 ;
646+ return NULL ;
649647}
650648
651649static PyObject *
@@ -691,7 +689,7 @@ local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
691689 if (self -> wr_callback == NULL )
692690 goto err ;
693691
694- if (_local_create_dummy (self ) < 0 )
692+ if (_local_create_dummy (self ) == NULL )
695693 goto err ;
696694
697695 return (PyObject * )self ;
@@ -707,7 +705,6 @@ local_traverse(localobject *self, visitproc visit, void *arg)
707705 Py_VISIT (self -> args );
708706 Py_VISIT (self -> kw );
709707 Py_VISIT (self -> dummies );
710- Py_VISIT (self -> dict );
711708 return 0 ;
712709}
713710
@@ -718,7 +715,6 @@ local_clear(localobject *self)
718715 Py_CLEAR (self -> args );
719716 Py_CLEAR (self -> kw );
720717 Py_CLEAR (self -> dummies );
721- Py_CLEAR (self -> dict );
722718 Py_CLEAR (self -> wr_callback );
723719 /* Remove all strong references to dummies from the thread states */
724720 if (self -> key
@@ -764,9 +760,9 @@ _ldict(localobject *self)
764760
765761 dummy = PyDict_GetItem (tdict , self -> key );
766762 if (dummy == NULL ) {
767- if (_local_create_dummy (self ) < 0 )
763+ ldict = _local_create_dummy (self );
764+ if (ldict == NULL )
768765 return NULL ;
769- ldict = self -> dict ;
770766
771767 if (Py_TYPE (self )-> tp_init != PyBaseObject_Type .tp_init &&
772768 Py_TYPE (self )-> tp_init ((PyObject * )self ,
@@ -783,44 +779,32 @@ _ldict(localobject *self)
783779 ldict = ((localdummyobject * ) dummy )-> localdict ;
784780 }
785781
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-
794782 return ldict ;
795783}
796784
797785static int
798786local_setattro (localobject * self , PyObject * name , PyObject * v )
799787{
800788 PyObject * ldict ;
789+ int r ;
801790
802791 ldict = _ldict (self );
803792 if (ldict == NULL )
804793 return -1 ;
805794
806- return PyObject_GenericSetAttr ((PyObject * )self , name , v );
807- }
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 ;
808804
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 ;
805+ return _PyObject_GenericSetAttrWithDict ((PyObject * )self , name , v , ldict );
816806}
817807
818- static PyGetSetDef local_getset [] = {
819- {"__dict__" , (getter )local_getdict , (setter )NULL ,
820- "Local-data dictionary" , NULL },
821- {NULL } /* Sentinel */
822- };
823-
824808static PyObject * local_getattro (localobject * , PyObject * );
825809
826810static PyTypeObject localtype = {
@@ -854,12 +838,12 @@ static PyTypeObject localtype = {
854838 /* tp_iternext */ 0 ,
855839 /* tp_methods */ 0 ,
856840 /* tp_members */ 0 ,
857- /* tp_getset */ local_getset ,
841+ /* tp_getset */ 0 ,
858842 /* tp_base */ 0 ,
859843 /* tp_dict */ 0 , /* internal use */
860844 /* tp_descr_get */ 0 ,
861845 /* tp_descr_set */ 0 ,
862- /* tp_dictoffset */ offsetof( localobject , dict ) ,
846+ /* tp_dictoffset */ 0 ,
863847 /* tp_init */ 0 ,
864848 /* tp_alloc */ 0 ,
865849 /* tp_new */ local_new ,
@@ -871,20 +855,29 @@ static PyObject *
871855local_getattro (localobject * self , PyObject * name )
872856{
873857 PyObject * ldict , * value ;
858+ int r ;
874859
875860 ldict = _ldict (self );
876861 if (ldict == NULL )
877862 return NULL ;
878863
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+
879872 if (Py_TYPE (self ) != & localtype )
880873 /* use generic lookup for subtypes */
881- return PyObject_GenericGetAttr ((PyObject * )self , name );
874+ return _PyObject_GenericGetAttrWithDict ((PyObject * )self , name , ldict );
882875
883876 /* Optimization: just look in dict ourselves */
884877 value = PyDict_GetItem (ldict , name );
885878 if (value == NULL )
886879 /* Fall back on generic to get __class__ and __dict__ */
887- return PyObject_GenericGetAttr ((PyObject * )self , name );
880+ return _PyObject_GenericGetAttrWithDict ((PyObject * )self , name , ldict );
888881
889882 Py_INCREF (value );
890883 return value ;
@@ -909,8 +902,6 @@ _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref)
909902 PyObject * ldict ;
910903 ldict = PyDict_GetItem (self -> dummies , dummyweakref );
911904 if (ldict != NULL ) {
912- if (ldict == self -> dict )
913- Py_CLEAR (self -> dict );
914905 PyDict_DelItem (self -> dummies , dummyweakref );
915906 }
916907 if (PyErr_Occurred ())
@@ -1278,6 +1269,10 @@ PyInit__thread(void)
12781269
12791270 nb_threads = 0 ;
12801271
1272+ str_dict = PyUnicode_InternFromString ("__dict__" );
1273+ if (str_dict == NULL )
1274+ return NULL ;
1275+
12811276 /* Initialize the C thread library */
12821277 PyThread_init_thread ();
12831278 return m ;
0 commit comments