Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(917)

Delta Between Two Patch Sets: Modules/_threadmodule.c

Issue 15139: Speed up threading.Condition wakeup
Left Patch Set: Created 11 months ago
Right Patch Set: Created 10 months, 3 weeks ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/threading.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 static PyObject *str_dict;
19 19
20 /* Lock objects */ 20 /* Lock objects */
21 21
22 typedef struct { 22 typedef struct {
23 PyObject_HEAD 23 PyObject_HEAD
24 PyThread_type_lock lock_lock; 24 PyThread_type_lock lock_lock;
25 PyObject *in_weakreflist; 25 PyObject *in_weakreflist;
26 char locked; /* for sanity checking */
26 } lockobject; 27 } lockobject;
27 28
28 static void 29 static void
29 lock_dealloc(lockobject *self) 30 lock_dealloc(lockobject *self)
30 { 31 {
31 if (self->in_weakreflist != NULL) 32 if (self->in_weakreflist != NULL)
32 PyObject_ClearWeakRefs((PyObject *) self); 33 PyObject_ClearWeakRefs((PyObject *) self);
33 if (self->lock_lock != NULL) { 34 if (self->lock_lock != NULL) {
34 /* Unlock the lock so it's safe to free it */ 35 /* Unlock the lock so it's safe to free it */
35 PyThread_acquire_lock(self->lock_lock, 0); 36 if (self->locked)
36 PyThread_release_lock(self->lock_lock); 37 PyThread_release_lock(self->lock_lock);
37
38 PyThread_free_lock(self->lock_lock); 38 PyThread_free_lock(self->lock_lock);
39 } 39 }
40 PyObject_Del(self); 40 PyObject_Del(self);
41 } 41 }
42 42
43 /* Helper to acquire an interruptible lock with a timeout. If the lock acquire 43 /* Helper to acquire an interruptible lock with a timeout. If the lock acquire
44 * is interrupted, signal handlers are run, and if they raise an exception, 44 * is interrupted, signal handlers are run, and if they raise an exception,
45 * PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE 45 * PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE
46 * are returned, depending on whether the lock can be acquired withing the 46 * are returned, depending on whether the lock can be acquired withing the
47 * timeout. 47 * timeout.
48 */ 48 */
49 static PyLockStatus 49 static PyLockStatus
50 acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) 50 acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds)
51 { 51 {
52 PyLockStatus r; 52 PyLockStatus r;
53 _PyTime_timeval curtime; 53 _PyTime_timeval curtime;
54 _PyTime_timeval endtime; 54 _PyTime_timeval endtime;
55 55
56 56
57 if (microseconds > 0) { 57 if (microseconds > 0) {
58 _PyTime_gettimeofday(&endtime); 58 _PyTime_gettimeofday(&endtime);
59 endtime.tv_sec += microseconds / (1000 * 1000); 59 endtime.tv_sec += microseconds / (1000 * 1000);
60 endtime.tv_usec += microseconds % (1000 * 1000); 60 endtime.tv_usec += microseconds % (1000 * 1000);
61 } 61 }
62 62
63 63
64 do { 64 do {
65 Py_BEGIN_ALLOW_THREADS 65 /* first a simple non-blocking try without releasing the GIL */
66 r = PyThread_acquire_lock_timed(lock, microseconds, 1); 66 r = PyThread_acquire_lock_timed(lock, 0, 0);
67 Py_END_ALLOW_THREADS 67 if (r == PY_LOCK_FAILURE && microseconds != 0) {
68 Py_BEGIN_ALLOW_THREADS
69 r = PyThread_acquire_lock_timed(lock, microseconds, 1);
70 Py_END_ALLOW_THREADS
71 }
68 72
69 if (r == PY_LOCK_INTR) { 73 if (r == PY_LOCK_INTR) {
70 /* Run signal handlers if we were interrupted. Propagate 74 /* Run signal handlers if we were interrupted. Propagate
71 * exceptions from signal handlers, such as KeyboardInterrupt, by 75 * exceptions from signal handlers, such as KeyboardInterrupt, by
72 * passing up PY_LOCK_INTR. */ 76 * passing up PY_LOCK_INTR. */
73 if (Py_MakePendingCalls() < 0) { 77 if (Py_MakePendingCalls() < 0) {
74 return PY_LOCK_INTR; 78 return PY_LOCK_INTR;
75 } 79 }
76 80
77 /* If we're using a timeout, recompute the timeout after processing 81 /* If we're using a timeout, recompute the timeout after processing
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 return NULL; 132 return NULL;
129 } 133 }
130 microseconds = (PY_TIMEOUT_T) timeout; 134 microseconds = (PY_TIMEOUT_T) timeout;
131 } 135 }
132 136
133 r = acquire_timed(self->lock_lock, microseconds); 137 r = acquire_timed(self->lock_lock, microseconds);
134 if (r == PY_LOCK_INTR) { 138 if (r == PY_LOCK_INTR) {
135 return NULL; 139 return NULL;
136 } 140 }
137 141
142 if (r == PY_LOCK_ACQUIRED)
143 self->locked = 1;
138 return PyBool_FromLong(r == PY_LOCK_ACQUIRED); 144 return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
139 } 145 }
140 146
141 PyDoc_STRVAR(acquire_doc, 147 PyDoc_STRVAR(acquire_doc,
142 "acquire([wait]) -> None or bool\n\ 148 "acquire([wait]) -> None or bool\n\
143 (acquire_lock() is an obsolete synonym)\n\ 149 (acquire_lock() is an obsolete synonym)\n\
144 \n\ 150 \n\
145 Lock the lock. Without argument, this blocks if the lock is already\n\ 151 Lock the lock. Without argument, this blocks if the lock is already\n\
146 locked (even by the same thread), waiting for another thread to release\n\ 152 locked (even by the same thread), waiting for another thread to release\n\
147 the lock, and return None once the lock is acquired.\n\ 153 the lock, and return None once the lock is acquired.\n\
148 With an argument, this will only block if the argument is true,\n\ 154 With an argument, this will only block if the argument is true,\n\
149 and the return value reflects whether the lock is acquired.\n\ 155 and the return value reflects whether the lock is acquired.\n\
150 The blocking operation is interruptible."); 156 The blocking operation is interruptible.");
151 157
152 static PyObject * 158 static PyObject *
153 lock_PyThread_release_lock(lockobject *self) 159 lock_PyThread_release_lock(lockobject *self)
154 { 160 {
155 /* Sanity check: the lock must be locked */ 161 /* Sanity check: the lock must be locked */
156 if (PyThread_acquire_lock(self->lock_lock, 0)) { 162 if (!self->locked) {
157 PyThread_release_lock(self->lock_lock);
158 PyErr_SetString(ThreadError, "release unlocked lock"); 163 PyErr_SetString(ThreadError, "release unlocked lock");
159 return NULL; 164 return NULL;
160 } 165 }
161 166
162 PyThread_release_lock(self->lock_lock); 167 PyThread_release_lock(self->lock_lock);
168 self->locked = 0;
163 Py_INCREF(Py_None); 169 Py_INCREF(Py_None);
164 return Py_None; 170 return Py_None;
165 } 171 }
166 172
167 PyDoc_STRVAR(release_doc, 173 PyDoc_STRVAR(release_doc,
168 "release()\n\ 174 "release()\n\
169 (release_lock() is an obsolete synonym)\n\ 175 (release_lock() is an obsolete synonym)\n\
170 \n\ 176 \n\
171 Release the lock, allowing another thread that is blocked waiting for\n\ 177 Release the lock, allowing another thread that is blocked waiting for\n\
172 the lock to acquire the lock. The lock must be in the locked state,\n\ 178 the lock to acquire the lock. The lock must be in the locked state,\n\
173 but it needn't be locked by the same thread that unlocks it."); 179 but it needn't be locked by the same thread that unlocks it.");
174 180
175 static PyObject * 181 static PyObject *
176 lock_locked_lock(lockobject *self) 182 lock_locked_lock(lockobject *self)
177 { 183 {
178 if (PyThread_acquire_lock(self->lock_lock, 0)) { 184 return PyBool_FromLong((long)self->locked);
179 PyThread_release_lock(self->lock_lock);
180 return PyBool_FromLong(0L);
181 }
182 return PyBool_FromLong(1L);
183 } 185 }
184 186
185 PyDoc_STRVAR(locked_doc, 187 PyDoc_STRVAR(locked_doc,
186 "locked() -> bool\n\ 188 "locked() -> bool\n\
187 (locked_lock() is an obsolete synonym)\n\ 189 (locked_lock() is an obsolete synonym)\n\
188 \n\ 190 \n\
189 Return whether the lock is in the locked state."); 191 Return whether the lock is in the locked state.");
190 192
191 PyDoc_STRVAR(lock_release_save_doc, 193 PyDoc_STRVAR(lock_release_save_doc,
192 "_release_save() -> state\n\ 194 "_release_save() -> state\n\
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 if (self->rlock_count > 0 && tid == self->rlock_owner) { 342 if (self->rlock_count > 0 && tid == self->rlock_owner) {
341 unsigned long count = self->rlock_count + 1; 343 unsigned long count = self->rlock_count + 1;
342 if (count <= self->rlock_count) { 344 if (count <= self->rlock_count) {
343 PyErr_SetString(PyExc_OverflowError, 345 PyErr_SetString(PyExc_OverflowError,
344 "Internal lock count overflowed"); 346 "Internal lock count overflowed");
345 return NULL; 347 return NULL;
346 } 348 }
347 self->rlock_count = count; 349 self->rlock_count = count;
348 Py_RETURN_TRUE; 350 Py_RETURN_TRUE;
349 } 351 }
350 352 r = acquire_timed(self->rlock_lock, microseconds);
351 if (self->rlock_count > 0 ||
352 !PyThread_acquire_lock(self->rlock_lock, 0)) {
353 if (microseconds == 0) {
354 Py_RETURN_FALSE;
355 }
356 r = acquire_timed(self->rlock_lock, microseconds);
357 }
358 if (r == PY_LOCK_ACQUIRED) { 353 if (r == PY_LOCK_ACQUIRED) {
359 assert(self->rlock_count == 0); 354 assert(self->rlock_count == 0);
360 self->rlock_owner = tid; 355 self->rlock_owner = tid;
361 self->rlock_count = 1; 356 self->rlock_count = 1;
362 } 357 }
363 else if (r == PY_LOCK_INTR) { 358 else if (r == PY_LOCK_INTR) {
364 return NULL; 359 return NULL;
365 } 360 }
366 361
367 return PyBool_FromLong(r == PY_LOCK_ACQUIRED); 362 return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 }; 540 };
546 541
547 static lockobject * 542 static lockobject *
548 newlockobject(void) 543 newlockobject(void)
549 { 544 {
550 lockobject *self; 545 lockobject *self;
551 self = PyObject_New(lockobject, &Locktype); 546 self = PyObject_New(lockobject, &Locktype);
552 if (self == NULL) 547 if (self == NULL)
553 return NULL; 548 return NULL;
554 self->lock_lock = PyThread_allocate_lock(); 549 self->lock_lock = PyThread_allocate_lock();
550 self->locked = 0;
555 self->in_weakreflist = NULL; 551 self->in_weakreflist = NULL;
556 if (self->lock_lock == NULL) { 552 if (self->lock_lock == NULL) {
557 Py_DECREF(self); 553 Py_DECREF(self);
558 PyErr_SetString(ThreadError, "can't allocate lock"); 554 PyErr_SetString(ThreadError, "can't allocate lock");
559 return NULL; 555 return NULL;
560 } 556 }
561 return self; 557 return self;
562 } 558 }
563 559
564 static PyObject * 560 static PyObject *
565 lock_acquire_condition(lockobject *self, PyObject *args, PyObject *kwds) 561 lock_acquire_condition(lockobject *self, PyObject *args, PyObject *kwds)
566 { 562 {
567 double timeout; 563 PyObject *timeout_obj;
568 PyObject *outer_lock; 564 PyObject *outer_lock;
569 PyObject *outer_arg; 565 PyObject *outer_arg;
566 double timeout;
567 unsigned long count;
568 long owner;
570 PY_TIMEOUT_T microseconds; 569 PY_TIMEOUT_T microseconds;
571 PyLockStatus r; 570 PyLockStatus r;
572 571
573 if (!PyArg_ParseTuple(args, "dOO:_acquire_condition", &timeout, &outer_lock, &outer_arg)) 572 /* if we can't even parse the arguments, then we cannot re-acquire the outer lock. But that
574 return NULL; 573 * is the same if passing wrong arguments to a _aquire_restore method.
575 574 */
576 if (timeout < 0 && timeout != -1) { 575 if (!PyArg_ParseTuple(args, "OOO:_acquire_condition", &timeout_obj, &outer_l ock, &outer_arg))
577 PyErr_SetString(PyExc_ValueError, "timeout value must be " 576 return NULL;
578 "strictly positive"); 577 if (Py_TYPE(outer_lock) == &RLocktype)
579 return NULL; 578 if (!PyArg_ParseTuple(outer_arg, "kl", &count, &owner))
580 } 579 return NULL;
581 if (timeout == -1) 580
581 /* None is infinite, otherwise a float is the timeout in seconds, negative v alues
582 * are clipped to zero
583 */
584 if (timeout_obj == Py_None) {
582 microseconds = -1; 585 microseconds = -1;
583 else { 586 } else {
584 timeout *= 1e6; 587 timeout = PyFloat_AsDouble(timeout_obj);
585 if (timeout >= (double) PY_TIMEOUT_MAX) { 588 if (timeout == -1.0 && PyErr_Occurred())
586 PyErr_SetString(PyExc_OverflowError, 589 goto ERR;
587 "timeout value is too large"); 590 if (timeout > 0.0) {
588 return NULL; 591 timeout *= 1e6;
589 } 592 if (timeout >= (double) PY_TIMEOUT_MAX) {
590 microseconds = (PY_TIMEOUT_T) timeout; 593 PyErr_SetString(PyExc_OverflowError,
591 } 594 "timeout value is too large");
592 595 goto ERR;
596 }
597 microseconds = (PY_TIMEOUT_T) timeout;
598 } else
599 microseconds = 0;
600 }
601
602 r = PY_LOCK_ACQUIRED;
603 goto ACQUIRE;
604 ERR:
605 r = PY_LOCK_INTR; /* just acquire the outer lock and exit with error */
606 ACQUIRE:
593 /* acquire the condition lock _and_ the outer lock before reacquiring the GI L */ 607 /* acquire the condition lock _and_ the outer lock before reacquiring the GI L */
594 Py_BEGIN_ALLOW_THREADS 608 Py_BEGIN_ALLOW_THREADS
595 r = PyThread_acquire_lock_timed(self->lock_lock, microseconds, 1); 609 if (r == PY_LOCK_ACQUIRED)
610 r = PyThread_acquire_lock_timed(self->lock_lock, microseconds, 1);
596 /* acquire the outer lock if we know it */ 611 /* acquire the outer lock if we know it */
597 if (Py_TYPE(outer_lock) == &Locktype) { 612 if (Py_TYPE(outer_lock) == &Locktype) {
598 PyThread_acquire_lock_timed(((lockobject*)outer_lock)->lock_lock, -1, 0) ; 613 PyThread_acquire_lock_timed(((lockobject*)outer_lock)->lock_lock, -1, 0) ;
599 } else if(Py_TYPE(outer_lock) == &RLocktype) { 614 } else if(Py_TYPE(outer_lock) == &RLocktype) {
600 rlockobject *rlock = (rlockobject*)outer_lock; 615 rlockobject *rlock = (rlockobject*)outer_lock;
601 PyThread_acquire_lock_timed(rlock->rlock_lock, -1, 0); 616 PyThread_acquire_lock_timed(rlock->rlock_lock, -1, 0);
602 } 617 }
603 Py_END_ALLOW_THREADS 618 Py_END_ALLOW_THREADS
604 /* and restore the state of the RLock */ 619 /* and restore the state of the locks */
605 if (Py_TYPE(outer_lock) == &RLocktype) { 620 if (Py_TYPE(outer_lock) == &Locktype) {
621 ((lockobject*)outer_lock)->locked = 1;
622 } else if (Py_TYPE(outer_lock) == &RLocktype) {
606 rlockobject *rlock = (rlockobject*)outer_lock; 623 rlockobject *rlock = (rlockobject*)outer_lock;
607 PyArg_ParseTuple(outer_arg, "kl", &rlock->rlock_count, &rlock->rlock_own er); 624 rlock->rlock_count = count;
625 rlock->rlock_owner = owner;
608 } 626 }
609 627
610 if (r == PY_LOCK_INTR) { 628 if (r == PY_LOCK_INTR) {
611 return NULL; 629 return NULL;
612 } 630 }
613 631
614 return PyBool_FromLong(r == PY_LOCK_ACQUIRED); 632 return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
615 } 633 }
616 634
617 /* Thread-local objects */ 635 /* Thread-local objects */
(...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after
1390 nb_threads = 0; 1408 nb_threads = 0;
1391 1409
1392 str_dict = PyUnicode_InternFromString("__dict__"); 1410 str_dict = PyUnicode_InternFromString("__dict__");
1393 if (str_dict == NULL) 1411 if (str_dict == NULL)
1394 return NULL; 1412 return NULL;
1395 1413
1396 /* Initialize the C thread library */ 1414 /* Initialize the C thread library */
1397 PyThread_init_thread(); 1415 PyThread_init_thread();
1398 return m; 1416 return m;
1399 } 1417 }
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7