@@ -82,6 +82,99 @@ whose size is determined when the object is allocated.
8282/* PyObject_HEAD defines the initial segment of every PyObject. */
8383#define PyObject_HEAD PyObject ob_base;
8484
85+
86+ /*
87+ ** futex
88+ **
89+ ** linux-specific fast userspace lock
90+ */
91+
92+ #include <errno.h>
93+ #include <linux/futex.h>
94+ #include <pthread.h>
95+ #include <stdio.h>
96+ #include <stdlib.h>
97+ #include <sys/mman.h>
98+ #include <sys/syscall.h>
99+ #include <sys/time.h>
100+ #include <sys/wait.h>
101+ #include <unistd.h>
102+ #include <pyport.h>
103+
104+ Py_LOCAL_INLINE (int ) futex (int * uaddr , int futex_op , int val ,
105+ const struct timespec * timeout , int * uaddr2 , int val3 ) {
106+ return syscall (SYS_futex , uaddr , futex_op , val ,
107+ timeout , uaddr , val3 );
108+ }
109+
110+ #define futex_wait (i_ptr , value ) \
111+ (futex(i_ptr, FUTEX_WAIT, value, NULL, NULL, 0))
112+
113+ #define futex_wake (i_ptr , value ) \
114+ (futex(i_ptr, FUTEX_WAKE, value, NULL, NULL, 0))
115+
116+ Py_LOCAL_INLINE (void ) futex_init (int * f ) {
117+ * f = 0 ;
118+ }
119+
120+ Py_LOCAL_INLINE (void ) futex_lock (int * f ) {
121+ int current = __sync_val_compare_and_swap (f , 0 , 1 );
122+ if (current == 0 )
123+ return ;
124+ if (current != 2 )
125+ current = __sync_lock_test_and_set (f , 2 );
126+ while (current != 0 ) {
127+ futex_wait (f , 2 );
128+ current = __sync_lock_test_and_set (f , 2 );
129+ }
130+ }
131+
132+ Py_LOCAL_INLINE (void ) futex_unlock (int * f ) {
133+ if (__sync_fetch_and_sub (f , 1 ) != 1 ) {
134+ * f = 0 ;
135+ futex_wake (f , 1 );
136+ }
137+ }
138+
139+
140+ /*
141+ ** furtex
142+ **
143+ ** recursive futex lock
144+ */
145+ typedef struct {
146+ int futex ;
147+ int count ;
148+ pthread_t tid ;
149+ } furtex_t ;
150+
151+ Py_LOCAL_INLINE (void ) furtex_init (furtex_t * f ) {
152+ f -> futex = f -> count = 0 ;
153+ f -> tid = 0 ;
154+ }
155+
156+ Py_LOCAL_INLINE (void ) furtex_lock (furtex_t * f ) {
157+ pthread_t tid = pthread_self ();
158+ if (f -> count && pthread_equal (f -> tid , tid )) {
159+ f -> count ++ ;
160+ assert (f -> count > 1 );
161+ return ;
162+ }
163+ futex_lock (& (f -> futex ));
164+ f -> tid = tid ;
165+ assert (f -> count == 0 );
166+ f -> count = 1 ;
167+ }
168+
169+ Py_LOCAL_INLINE (void ) furtex_unlock (furtex_t * f ) {
170+ /* this function assumes we own the lock! */
171+ assert (f -> count > 0 );
172+ if (-- f -> count )
173+ return ;
174+ futex_unlock (& (f -> futex ));
175+ }
176+
177+
85178#define PyObject_HEAD_INIT (type ) \
86179 { _PyObject_EXTRA_INIT \
87180 1, type },
@@ -173,6 +266,7 @@ typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
173266typedef int (* ssizeobjargproc )(PyObject * , Py_ssize_t , PyObject * );
174267typedef int (* ssizessizeobjargproc )(PyObject * , Py_ssize_t , Py_ssize_t , PyObject * );
175268typedef int (* objobjargproc )(PyObject * , PyObject * , PyObject * );
269+ typedef void (* lockfunc )(PyObject * );
176270
177271#ifndef Py_LIMITED_API
178272/* buffer interface */
@@ -421,6 +515,9 @@ typedef struct _typeobject {
421515
422516 destructor tp_finalize ;
423517
518+ lockfunc tp_lock ;
519+ lockfunc tp_unlock ;
520+
424521#ifdef COUNT_ALLOCS
425522 /* these must be last and never explicitly initialized */
426523 Py_ssize_t tp_allocs ;
@@ -776,13 +873,13 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
776873
777874#define Py_INCREF (op ) ( \
778875 _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
779- (( PyObject *)(op))->ob_refcnt++ )
876+ __sync_fetch_and_add(&((( PyObject *)(op))->ob_refcnt), 1) )
780877
781878#define Py_DECREF (op ) \
782879 do { \
783880 PyObject *_py_decref_tmp = (PyObject *)(op); \
784881 if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
785- --( _py_decref_tmp) ->ob_refcnt != 0) \
882+ __sync_sub_and_fetch(&( _py_decref_tmp->ob_refcnt),1) != 0) \
786883 _Py_CHECK_REFCNT(_py_decref_tmp) \
787884 else \
788885 _Py_Dealloc(_py_decref_tmp); \
0 commit comments