Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1daac18

Browse files
committed
update
1 parent 8d0ef46 commit 1daac18

14 files changed

+4588
-398
lines changed

‎README.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# Python 3.9 源代码阅读笔记
22

3-
之前看了 "Python 源码剖析", 这本书是基于 Python 2.5 的, 现在的 Python 已经发生了很大的改变. 因此, 在这里记录下阅读 Python 3.9 的源代码的笔记, 当然阅读内容主要是 Python3 某些新加的特性.
3+
之前看了 "Python 源码剖析", 这本书是基于 Python 2.5 的, 现在的 Python 已经发生了很大的改变, 因此, 我决定重新阅读 Python 的源码.
4+
5+
在这里记录下阅读 [Python 3.9](https://github.com/ausaki/cpython/tree/v3.9.notes) 的源代码的笔记.
46

57
- [Python 虚拟机](ceval.md)
68

79
- [GIL](gil.md)
810

911

1012

11-
[源码注释分支](https://github.com/ausaki/python)
13+
[源码注释分支](https://github.com/ausaki/cpython/tree/v3.9.notes)
1214

‎trashcan.md‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Trashcan
2+
3+
注释已经描述得非常清楚, 无需多言.
4+
5+
```c
6+
//Include/cpython/object.h
7+
8+
/* Trashcan mechanism, thanks to Christian Tismer.
9+
10+
When deallocating a container object, it's possible to trigger an unbounded
11+
chain of deallocations, as each Py_DECREF in turn drops the refcount on "the
12+
next" object in the chain to 0. This can easily lead to stack overflows,
13+
especially in threads (which typically have less stack space to work with).
14+
15+
A container object can avoid this by bracketing the body of its tp_dealloc
16+
function with a pair of macros:
17+
18+
static void
19+
mytype_dealloc(mytype *p)
20+
{
21+
... declarations go here ...
22+
23+
PyObject_GC_UnTrack(p); // must untrack first
24+
Py_TRASHCAN_BEGIN(p, mytype_dealloc)
25+
... The body of the deallocator goes here, including all calls ...
26+
... to Py_DECREF on contained objects. ...
27+
Py_TRASHCAN_END // there should be no code after this
28+
}
29+
30+
CAUTION: Never return from the middle of the body! If the body needs to
31+
"get out early", put a label immediately before the Py_TRASHCAN_END
32+
call, and goto it. Else the call-depth counter (see below) will stay
33+
above 0 forever, and the trashcan will never get emptied.
34+
35+
How it works: The BEGIN macro increments a call-depth counter. So long
36+
as this counter is small, the body of the deallocator is run directly without
37+
further ado. But if the counter gets large, it instead adds p to a list of
38+
objects to be deallocated later, skips the body of the deallocator, and
39+
resumes execution after the END macro. The tp_dealloc routine then returns
40+
without deallocating anything (and so unbounded call-stack depth is avoided).
41+
42+
When the call stack finishes unwinding again, code generated by the END macro
43+
notices this, and calls another routine to deallocate all the objects that
44+
may have been added to the list of deferred deallocations. In effect, a
45+
chain of N deallocations is broken into (N-1)/(PyTrash_UNWIND_LEVEL-1) pieces,
46+
with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL.
47+
48+
Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base
49+
class, we need to ensure that the trashcan is only triggered on the tp_dealloc
50+
of the actual class being deallocated. Otherwise we might end up with a
51+
partially-deallocated object. To check this, the tp_dealloc function must be
52+
passed as second argument to Py_TRASHCAN_BEGIN().
53+
*/
54+
55+
/* This is the old private API, invoked by the macros before 3.2.4.
56+
Kept for binary compatibility of extensions using the stable ABI. */
57+
PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*);
58+
PyAPI_FUNC(void) _PyTrash_destroy_chain(void);
59+
60+
/* This is the old private API, invoked by the macros before 3.9.
61+
Kept for binary compatibility of extensions using the stable ABI. */
62+
PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*);
63+
PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
64+
65+
/* Forward declarations for PyThreadState */
66+
struct _ts;
67+
68+
/* Python 3.9 private API, invoked by the macros below. */
69+
PyAPI_FUNC(int) _PyTrash_begin(struct _ts *tstate, PyObject *op);
70+
PyAPI_FUNC(void) _PyTrash_end(struct _ts *tstate);
71+
72+
#define PyTrash_UNWIND_LEVEL 50
73+
74+
// 注意仔细看 Py_TRASHCAN_BEGIN_CONDITION 这个宏的定义, 它不是一个完整的语句块, do 语句的 body 没有结束.
75+
#define Py_TRASHCAN_BEGIN_CONDITION(op, cond) \
76+
do { \
77+
PyThreadState *_tstate = NULL; \
78+
/* If "cond" is false, then _tstate remains NULL and the deallocator \
79+
* is run normally without involving the trashcan */ \
80+
if (cond) { \
81+
_tstate = PyThreadState_GET(); \
82+
if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \
83+
break; \
84+
} \
85+
}
86+
/* The body of the deallocator is here. */
87+
#define Py_TRASHCAN_END \
88+
if (_tstate) { \
89+
_PyTrash_end(_tstate); \
90+
} \
91+
} while (0);
92+
93+
#define Py_TRASHCAN_BEGIN(op, dealloc) \
94+
Py_TRASHCAN_BEGIN_CONDITION(op, \
95+
Py_TYPE(op)->tp_dealloc == (destructor)(dealloc))
96+
97+
/* For backwards compatibility, these macros enable the trashcan
98+
* unconditionally */
99+
#define Py_TRASHCAN_SAFE_BEGIN(op) Py_TRASHCAN_BEGIN_CONDITION(op, 1)
100+
#define Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_END
101+
```
102+
103+
我最喜欢这样的注释, 对新加的某个特性进行详细的描述. 遗憾的是 CPython 的代码中有许多没有详细注释的代码, 对于刚开始阅读 CPython 代码的人来说非常难以理解.
104+
105+
trashcan 的用法可以查看 tuple 的 tpdealloc 函数.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /